mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpimath] Use jinja for codegen (#3574)
While not really needed for wpimath, it will make more complex codegen in the future significantly easier.
This commit is contained in:
8
.github/workflows/cmake.yml
vendored
8
.github/workflows/cmake.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
name: Linux
|
||||
container: wpilib/roborio-cross-ubuntu:2021-18.04
|
||||
container: wpilib/roborio-cross-ubuntu:2021-20.04
|
||||
flags: ""
|
||||
- os: macos-latest
|
||||
name: macOS
|
||||
@@ -26,6 +26,12 @@ jobs:
|
||||
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||
brew install opencv
|
||||
fi
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake ${{ matrix.flags }} ..
|
||||
- name: build
|
||||
|
||||
2
.github/workflows/lint-format.yml
vendored
2
.github/workflows/lint-format.yml
vendored
@@ -63,6 +63,8 @@ jobs:
|
||||
sudo apt-get install -y clang-tidy-12 clang-format-12
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: Create compile_commands.json
|
||||
run: mkdir build-cmake && cd build-cmake && cmake -DWITH_OLD_COMMANDS=ON -DWITH_EXAMPLES=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=YES ..
|
||||
- name: List changed files
|
||||
|
||||
8
.github/workflows/sanitizers.yml
vendored
8
.github/workflows/sanitizers.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
flags: "-DCMAKE_BUILD_TYPE=Ubsan"
|
||||
name: "${{ matrix.name }}"
|
||||
runs-on: ubuntu-latest
|
||||
container: wpilib/roborio-cross-ubuntu:2021-18.04
|
||||
container: wpilib/roborio-cross-ubuntu:2021-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
@@ -27,6 +27,12 @@ jobs:
|
||||
--install /usr/bin/gcc gcc /usr/bin/gcc-11 11 \
|
||||
--slave /usr/bin/g++ g++ /usr/bin/g++-11
|
||||
sudo update-alternatives --set gcc /usr/bin/gcc-11
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake ${{ matrix.flags }} ..
|
||||
- name: build
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import edu.wpi.first.toolchain.*
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.hubspot.jinjava:jinjava:2.5.8'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'base'
|
||||
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '4.1.0'
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import com.hubspot.jinjava.Jinjava;
|
||||
import com.hubspot.jinjava.JinjavaConfig;
|
||||
|
||||
ext {
|
||||
useJava = true
|
||||
useCpp = true
|
||||
@@ -66,9 +69,8 @@ dependencies {
|
||||
api "com.fasterxml.jackson.core:jackson-databind:2.10.0"
|
||||
}
|
||||
|
||||
def wpilibNumberFileInput = file("src/generate/GenericNumber.java.in")
|
||||
def natFileInput = file("src/generate/Nat.java.in")
|
||||
def natGetterInput = file("src/generate/NatGetter.java.in")
|
||||
def wpilibNumberFileInput = file("src/generate/GenericNumber.java.jinja")
|
||||
def natFileInput = file("src/generate/Nat.java.jinja")
|
||||
def wpilibNumberFileOutputDir = file("$buildDir/generated/java/edu/wpi/first/math/numbers")
|
||||
def wpilibNatFileOutput = file("$buildDir/generated/java/edu/wpi/first/math/Nat.java")
|
||||
def maxNum = 20
|
||||
@@ -86,10 +88,17 @@ task generateNumbers() {
|
||||
}
|
||||
wpilibNumberFileOutputDir.mkdirs()
|
||||
|
||||
def config = new JinjavaConfig()
|
||||
def jinjava = new Jinjava(config)
|
||||
|
||||
def template = wpilibNumberFileInput.text
|
||||
|
||||
for(i in 0..maxNum) {
|
||||
def outputFile = new File(wpilibNumberFileOutputDir, "N${i}.java")
|
||||
def read = wpilibNumberFileInput.text.replace('${num}', i.toString())
|
||||
outputFile.write(read)
|
||||
def replacements = new HashMap<String,?>()
|
||||
replacements.put("num", i)
|
||||
def output = jinjava.render(template, replacements)
|
||||
outputFile.write(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +106,7 @@ task generateNumbers() {
|
||||
task generateNat() {
|
||||
description = "Generates Nat.java"
|
||||
group = "WPILib"
|
||||
inputs.files([natFileInput, natGetterInput])
|
||||
inputs.file natFileInput
|
||||
outputs.file wpilibNatFileOutput
|
||||
dependsOn generateNumbers
|
||||
|
||||
@@ -106,19 +115,16 @@ task generateNat() {
|
||||
wpilibNatFileOutput.delete()
|
||||
}
|
||||
|
||||
def template = natFileInput.text + "\n"
|
||||
def config = new JinjavaConfig()
|
||||
def jinjava = new Jinjava(config)
|
||||
|
||||
def importsString = "";
|
||||
def template = natFileInput.text
|
||||
|
||||
for(i in 0..maxNum) {
|
||||
importsString += "import edu.wpi.first.math.numbers.N${i};\n"
|
||||
template += natGetterInput.text.replace('${num}', i.toString()) + "\n"
|
||||
}
|
||||
template += "}\n" // Close the class body
|
||||
def replacements = new HashMap<String,?>()
|
||||
replacements.put("nums", 0..maxNum)
|
||||
|
||||
template = template.replace('{{REPLACEWITHIMPORTS}}', importsString)
|
||||
|
||||
wpilibNatFileOutput.write(template)
|
||||
def output = jinjava.render(template, replacements)
|
||||
wpilibNatFileOutput.write(output)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# Copyright (c) FIRST and other WPILib contributors.
|
||||
# Open Source Software; you can modify and/or share it under the terms of
|
||||
# the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
|
||||
def output(outPath, outfn, contents):
|
||||
if not os.path.exists(outPath):
|
||||
os.makedirs(outPath)
|
||||
|
||||
outpathname = f"{outPath}/{outfn}"
|
||||
|
||||
if os.path.exists(outpathname):
|
||||
with open(outpathname, "r") as f:
|
||||
if f.read() == contents:
|
||||
return
|
||||
|
||||
# File either doesn't exist or has different contents
|
||||
with open(outpathname, "w") as f:
|
||||
f.write(contents)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -8,51 +29,21 @@ def main():
|
||||
dirname, _ = os.path.split(os.path.abspath(__file__))
|
||||
cmake_binary_dir = sys.argv[1]
|
||||
|
||||
with open(f"{dirname}/src/generate/GenericNumber.java.in",
|
||||
"r") as templateFile:
|
||||
template = templateFile.read()
|
||||
rootPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math/numbers"
|
||||
env = Environment(loader=FileSystemLoader(f"{dirname}/src/generate"),
|
||||
autoescape=False,
|
||||
keep_trailing_newline=True)
|
||||
|
||||
if not os.path.exists(rootPath):
|
||||
os.makedirs(rootPath)
|
||||
template = env.get_template("GenericNumber.java.jinja")
|
||||
rootPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math/numbers"
|
||||
|
||||
for i in range(MAX_NUM + 1):
|
||||
new_contents = template.replace("${num}", str(i))
|
||||
for i in range(MAX_NUM + 1):
|
||||
contents = template.render(num=i)
|
||||
output(rootPath, f"N{i}.java", contents)
|
||||
|
||||
if os.path.exists(f"{rootPath}/N{i}.java"):
|
||||
with open(f"{rootPath}/N{i}.java", "r") as f:
|
||||
if f.read() == new_contents:
|
||||
continue
|
||||
|
||||
# File either doesn't exist or has different contents
|
||||
with open(f"{rootPath}/N{i}.java", "w") as f:
|
||||
f.write(new_contents)
|
||||
|
||||
with open(f"{dirname}/src/generate/Nat.java.in", "r") as templateFile:
|
||||
template = templateFile.read()
|
||||
outputPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math/Nat.java"
|
||||
with open(f"{dirname}/src/generate/NatGetter.java.in",
|
||||
"r") as getterFile:
|
||||
getter = getterFile.read()
|
||||
|
||||
importsString = ""
|
||||
|
||||
for i in range(MAX_NUM + 1):
|
||||
importsString += f"import edu.wpi.first.math.numbers.N{i};\n"
|
||||
template += getter.replace("${num}", str(i))
|
||||
|
||||
template += "}\n"
|
||||
|
||||
template = template.replace('{{REPLACEWITHIMPORTS}}', importsString)
|
||||
|
||||
if os.path.exists(outputPath):
|
||||
with open(outputPath, "r") as f:
|
||||
if f.read() == template:
|
||||
return 0
|
||||
|
||||
# File either doesn't exist or has different contents
|
||||
with open(outputPath, "w") as f:
|
||||
f.write(template)
|
||||
template = env.get_template("Nat.java.jinja")
|
||||
rootPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math"
|
||||
contents = template.render(nums=range(MAX_NUM + 1))
|
||||
output(rootPath, "Nat.java", contents)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.math.numbers;
|
||||
|
||||
import edu.wpi.first.math.Nat;
|
||||
import edu.wpi.first.math.Num;
|
||||
|
||||
/**
|
||||
* A class representing the number ${num}.
|
||||
*/
|
||||
public final class N${num} extends Num implements Nat<N${num}> {
|
||||
private N${num}() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The integer this class represents.
|
||||
*
|
||||
* @return The literal number ${num}.
|
||||
*/
|
||||
@Override
|
||||
public int getNum() {
|
||||
return ${num};
|
||||
}
|
||||
|
||||
/**
|
||||
* The singleton instance of this class.
|
||||
*/
|
||||
public static final N${num} instance = new N${num}();
|
||||
}
|
||||
31
wpimath/src/generate/GenericNumber.java.jinja
Normal file
31
wpimath/src/generate/GenericNumber.java.jinja
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.math.numbers;
|
||||
|
||||
import edu.wpi.first.math.Nat;
|
||||
import edu.wpi.first.math.Num;
|
||||
|
||||
/**
|
||||
* A class representing the number {{ num }}.
|
||||
*/
|
||||
public final class N{{ num }} extends Num implements Nat<N{{ num }}> {
|
||||
private N{{ num }}() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The integer this class represents.
|
||||
*
|
||||
* @return The literal number {{ num }}.
|
||||
*/
|
||||
@Override
|
||||
public int getNum() {
|
||||
return {{ num }};
|
||||
}
|
||||
|
||||
/**
|
||||
* The singleton instance of this class.
|
||||
*/
|
||||
public static final N{{ num }} instance = new N{{ num }}();
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.math;
|
||||
|
||||
//CHECKSTYLE.OFF: ImportOrder
|
||||
{{REPLACEWITHIMPORTS}}
|
||||
//CHECKSTYLE.ON
|
||||
|
||||
/**
|
||||
* A natural number expressed as a java class.
|
||||
* The counterpart to {@link Num} that should be used as a concrete value.
|
||||
*
|
||||
* @param <T> The {@link Num} this represents.
|
||||
*/
|
||||
@SuppressWarnings({"MethodName", "unused"})
|
||||
public interface Nat<T extends Num> {
|
||||
/**
|
||||
* The number this interface represents.
|
||||
*
|
||||
* @return The number backing this value.
|
||||
*/
|
||||
int getNum();
|
||||
32
wpimath/src/generate/Nat.java.jinja
Normal file
32
wpimath/src/generate/Nat.java.jinja
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.math;
|
||||
|
||||
//CHECKSTYLE.OFF: ImportOrder
|
||||
{% for num in nums %}
|
||||
import edu.wpi.first.math.numbers.N{{ num }};
|
||||
{%- endfor %}
|
||||
//CHECKSTYLE.ON
|
||||
|
||||
/**
|
||||
* A natural number expressed as a java class.
|
||||
* The counterpart to {@link Num} that should be used as a concrete value.
|
||||
*
|
||||
* @param <T> The {@link Num} this represents.
|
||||
*/
|
||||
@SuppressWarnings({"MethodName", "unused"})
|
||||
public interface Nat<T extends Num> {
|
||||
/**
|
||||
* The number this interface represents.
|
||||
*
|
||||
* @return The number backing this value.
|
||||
*/
|
||||
int getNum();
|
||||
{% for num in nums %}
|
||||
static Nat<N{{ num }}> N{{ num }}() {
|
||||
return N{{ num }}.instance;
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
static Nat<N${num}> N${num}() {
|
||||
return N${num}.instance;
|
||||
}
|
||||
Reference in New Issue
Block a user