We have to move either forward or backwards with newparse #4441
This commit is contained in:
parent
752a10ee05
commit
438155dcbb
|
@ -6,5 +6,4 @@ import com.rusefi.newparse.parsing.Definition;
|
|||
public interface DefinitionsState {
|
||||
void addDefinition(VariableRegistry variableRegistry, String name, String value, Definition.OverwritePolicy overwritePolicy);
|
||||
|
||||
void setDefinitionPolicy(Definition.OverwritePolicy policy);
|
||||
}
|
||||
|
|
|
@ -144,11 +144,6 @@ public class ParseState implements DefinitionsState {
|
|||
addDefinition(name, value, definitionOverwritePolicy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefinitionPolicy(Definition.OverwritePolicy policy) {
|
||||
this.definitionOverwritePolicy = policy;
|
||||
}
|
||||
|
||||
public ParseTreeListener getListener() {
|
||||
return new RusefiConfigGrammarBaseListener() {
|
||||
|
||||
|
@ -204,63 +199,14 @@ public class ParseState implements DefinitionsState {
|
|||
|
||||
@Override
|
||||
public void exitScalarTypedefSuffix(RusefiConfigGrammarParser.ScalarTypedefSuffixContext ctx) {
|
||||
Type datatype = Type.findByTsType(ctx.Datatype().getText());
|
||||
|
||||
FieldOptions options = new FieldOptions();
|
||||
handleFieldOptionsList(options, ctx.fieldOptionsList());
|
||||
|
||||
typedefs.put(typedefName, new ScalarTypedef(typedefName, datatype, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterEnumTypedefSuffix(RusefiConfigGrammarParser.EnumTypedefSuffixContext ctx) {
|
||||
int endBit = Integer.parseInt(ctx.integer(1).getText());
|
||||
|
||||
Type datatype = Type.findByTsType(ctx.Datatype().getText());
|
||||
|
||||
String rhs = ctx.enumRhs().getText();
|
||||
|
||||
String[] values = null;
|
||||
|
||||
if (rhs.startsWith("@@")) {
|
||||
String defName = rhs.replaceAll("@", "");
|
||||
|
||||
if (defName.endsWith(AUTO_ENUM_SUFFIX)) {
|
||||
// clip off the "_auto_enum" part
|
||||
defName = defName.substring(0, defName.length() - 10);
|
||||
values = resolveEnumValues(defName);
|
||||
} else {
|
||||
Definition def = definitions.get(defName);
|
||||
|
||||
if (def == null) {
|
||||
throw new RuntimeException("couldn't find definition for " + rhs);
|
||||
}
|
||||
|
||||
Object value = def.value;
|
||||
|
||||
if (!(value instanceof String)) {
|
||||
throw new RuntimeException("Found definition for " + rhs + " but it wasn't a string as expected");
|
||||
}
|
||||
|
||||
rhs = (String)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (values == null) {
|
||||
values = Arrays.stream(rhs.split(",")) // Split on commas
|
||||
.map(String::trim) // trim whitespace
|
||||
.map(s -> s.replaceAll("\"", "")) // Remove quotes
|
||||
.toArray(String[]::new); // Convert back to array
|
||||
}
|
||||
|
||||
typedefs.put(typedefName, new EnumTypedef(typedefName, datatype, endBit, values));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitStringTypedefSuffix(RusefiConfigGrammarParser.StringTypedefSuffixContext ctx) {
|
||||
Double stringLength = ParseState.this.evalResults.remove();
|
||||
|
||||
ParseState.this.typedefs.put(ParseState.this.typedefName, new StringTypedef(ParseState.this.typedefName, stringLength.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -355,61 +301,6 @@ public class ParseState implements DefinitionsState {
|
|||
|
||||
@Override
|
||||
public void exitScalarField(RusefiConfigGrammarParser.ScalarFieldContext ctx) {
|
||||
String type = ctx.identifier(0).getText();
|
||||
String name = ctx.identifier(1).getText();
|
||||
boolean autoscale = ctx.Autoscale() != null;
|
||||
|
||||
// First check if this is an instance of a struct
|
||||
if (structs.containsKey(type)) {
|
||||
scope.structFields.add(new StructField(structs.get(type), name));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check first if we have a typedef for this type
|
||||
Typedef typedef = typedefs.get(type);
|
||||
|
||||
FieldOptions options = null;
|
||||
if (typedef != null) {
|
||||
if (typedef instanceof ScalarTypedef) {
|
||||
ScalarTypedef scTypedef = (ScalarTypedef)typedef;
|
||||
// Copy the typedef's options list - we don't want to edit it
|
||||
options = scTypedef.options.copy();
|
||||
// Switch to the "real" type, that is the typedef's type
|
||||
type = scTypedef.type.cType;
|
||||
} else if (typedef instanceof EnumTypedef) {
|
||||
EnumTypedef bTypedef = (EnumTypedef) typedef;
|
||||
|
||||
options = new FieldOptions();
|
||||
|
||||
// Merge the read-in options list with the default from the typedef (if exists)
|
||||
handleFieldOptionsList(options, ctx.fieldOptionsList());
|
||||
|
||||
scope.structFields.add(new EnumField(bTypedef.type, type, name, bTypedef.endBit, bTypedef.values, options));
|
||||
return;
|
||||
} else if (typedef instanceof StringTypedef) {
|
||||
options = new FieldOptions();
|
||||
handleFieldOptionsList(options, ctx.fieldOptionsList());
|
||||
|
||||
StringTypedef sTypedef = (StringTypedef) typedef;
|
||||
scope.structFields.add(new StringField(name, sTypedef.size, options.comment));
|
||||
return;
|
||||
} else {
|
||||
// TODO: throw
|
||||
}
|
||||
} else {
|
||||
// If no typedef found, it MUST be a native type
|
||||
if (!Type.findByCtype(type).isPresent()) {
|
||||
throw new RuntimeException("didn't understand type " + type + " for element " + name);
|
||||
}
|
||||
|
||||
// no typedef found, create new options list
|
||||
options = new FieldOptions();
|
||||
}
|
||||
|
||||
// Merge the read-in options list with the default from the typedef (if exists)
|
||||
handleFieldOptionsList(options, ctx.fieldOptionsList());
|
||||
|
||||
scope.structFields.add(new ScalarField(Type.findByCtype(type).get(), name, options, autoscale));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -454,17 +345,8 @@ public class ParseState implements DefinitionsState {
|
|||
public void exitArrayField(RusefiConfigGrammarParser.ArrayFieldContext ctx) {
|
||||
}
|
||||
|
||||
private int[] arrayDim = null;
|
||||
|
||||
@Override
|
||||
public void exitArrayLengthSpec(RusefiConfigGrammarParser.ArrayLengthSpecContext ctx) {
|
||||
int arrayDim0 = evalResults.remove().intValue();
|
||||
|
||||
if (ctx.ArrayDimensionSeparator() != null) {
|
||||
this.arrayDim = new int[] { arrayDim0, evalResults.remove().intValue() };
|
||||
} else {
|
||||
this.arrayDim = new int[] { arrayDim0 };
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.*;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class ArrayIterateScalarLayout extends ArrayLayout {
|
||||
public ArrayIterateScalarLayout(PrototypeField prototype, int[] length) {
|
||||
super(prototype, length);
|
||||
}
|
||||
|
||||
private void emitOne(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offset, int idx) {
|
||||
// Set element's position within the array
|
||||
this.prototypeLayout.setOffset(offset + this.prototypeLayout.getSize() * idx);
|
||||
|
||||
// Put a 1-based index on the end of the name to distinguish in TS
|
||||
prefixer.setIndex(idx);
|
||||
this.prototypeLayout.writeTunerstudioLayout(ps, meta, prefixer, 0);
|
||||
prefixer.clearIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
// Time to iterate: emit one scalar per array element, with the name modified accordingly
|
||||
|
||||
for (int i = 0; i < this.length[0]; i++) {
|
||||
emitOne(ps, meta, prefixer, this.offset + offsetAdd, i);
|
||||
}
|
||||
}
|
||||
|
||||
// C layout is the same if iterated or not, use default implementation
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.*;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class ArrayIterateStructLayout extends ArrayLayout {
|
||||
public ArrayIterateStructLayout(StructField prototype, int[] length) {
|
||||
super(prototype, length);
|
||||
}
|
||||
|
||||
private void emitOne(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offset, int idx) {
|
||||
// Set element's position within the array
|
||||
int offsetAdd = offset + this.prototypeLayout.getSize() * idx;
|
||||
|
||||
// Put a 1-based index on the end of the name to distinguish in TS
|
||||
prefixer.setIndex(idx);
|
||||
this.prototypeLayout.writeTunerstudioLayout(ps, meta, prefixer, offsetAdd);
|
||||
prefixer.clearIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
// Time to iterate: emit one scalar per array element, with the name modified accordingly
|
||||
|
||||
for (int i = 0; i < this.length[0]; i++) {
|
||||
emitOne(ps, meta, prefixer, this.offset + offsetAdd, i);
|
||||
}
|
||||
}
|
||||
|
||||
// C layout is the same if iterated or not, use default implementation
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.*;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class ArrayLayout extends Layout {
|
||||
protected final int[] length;
|
||||
|
||||
protected final Layout prototypeLayout;
|
||||
|
||||
public ArrayLayout(PrototypeField prototype, int[] length) {
|
||||
this.length = length;
|
||||
|
||||
if (prototype instanceof ScalarField) {
|
||||
prototypeLayout = new ScalarLayout((ScalarField)prototype);
|
||||
} else if (prototype instanceof EnumField) {
|
||||
prototypeLayout = new EnumLayout((EnumField) prototype);
|
||||
} else if (prototype instanceof StringField) {
|
||||
prototypeLayout = new StringLayout((StringField) prototype);
|
||||
} else if (prototype instanceof StructField) {
|
||||
StructField structPrototype = (StructField)prototype;
|
||||
prototypeLayout = new StructLayout(0, prototype.name, structPrototype.struct);
|
||||
} else {
|
||||
throw new RuntimeException("unexpected field type during array layout");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
int size = this.prototypeLayout.getSize();
|
||||
|
||||
for (int x : this.length) {
|
||||
size *= x;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
// Arrays only need to be aligned on the alignment of the element, not the whole array
|
||||
return this.prototypeLayout.getAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffset(int offset) {
|
||||
super.setOffset(offset);
|
||||
this.prototypeLayout.setOffset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffsetWithinStruct(int offset) {
|
||||
super.setOffsetWithinStruct(offset);
|
||||
this.prototypeLayout.setOffsetWithinStruct(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Array of " + this.prototypeLayout + " length " + this.length[0] + " " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
this.prototypeLayout.writeTunerstudioLayout(ps, meta, prefixer, offsetAdd, this.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
// Skip zero length arrays, they may be used for padding
|
||||
if (this.length[0] > 0) {
|
||||
this.prototypeLayout.writeCLayout(ps, this.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
this.prototypeLayout.writeOutputChannelLayout(ps, prefixer, offsetAdd, this.length);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.BitGroup;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BitGroupLayout extends Layout {
|
||||
private static class BitLayout {
|
||||
public final String name;
|
||||
public final String comment;
|
||||
public final String trueValue;
|
||||
public final String falseValue;
|
||||
|
||||
public BitLayout(String name, String comment, String trueValue, String falseValue) {
|
||||
this.name = name;
|
||||
this.comment = comment;
|
||||
this.trueValue = trueValue;
|
||||
this.falseValue = falseValue;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<BitLayout> bits;
|
||||
|
||||
public BitGroupLayout(BitGroup bitGroup) {
|
||||
int size = bitGroup.bitFields.size();
|
||||
if (size > 32) {
|
||||
throw new RuntimeException("tried to create bit group starting with " + bitGroup.bitFields.get(0).name + " but it contained " + size + " which is more than the maximum of 32.");
|
||||
}
|
||||
|
||||
this.bits = bitGroup.bitFields.stream().map(bf -> new BitLayout(bf.name, bf.comment, bf.trueValue, bf.falseValue)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Bit group " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
int actualOffset = this.offset + offsetAdd;
|
||||
|
||||
for (int i = 0; i < bits.size(); i++) {
|
||||
BitLayout bit = bits.get(i);
|
||||
|
||||
String name = prefixer.get(bit.name);
|
||||
|
||||
ps.print(name);
|
||||
ps.print(" = bits, U32, ");
|
||||
ps.print(actualOffset);
|
||||
ps.print(", [");
|
||||
ps.print(i + ":" + i);
|
||||
|
||||
ps.print("], " + bit.falseValue + ", " + bit.trueValue);
|
||||
|
||||
ps.println();
|
||||
|
||||
meta.addComment(name, bit.comment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
// always emit all 32 bits
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ps.print("\t/**\n\t");
|
||||
|
||||
if (i < bits.size()) {
|
||||
BitLayout bit = this.bits.get(i);
|
||||
|
||||
if (bit.comment != null) {
|
||||
ps.println(" * " + bit.comment.replaceAll("[+]", "").replaceAll(";", "").replace("\\n", "\n\t * "));
|
||||
ps.print('\t');
|
||||
}
|
||||
|
||||
ps.println("offset " + this.offsetWithinStruct + " bit " + i + " */");
|
||||
ps.println("\tbool " + bit.name + " : 1 {};");
|
||||
} else {
|
||||
// Force pad out all bit groups to a full 32b/4B
|
||||
ps.println("offset " + this.offsetWithinStruct + " bit " + i + " */");
|
||||
ps.println("\tbool unusedBit_" + this.offsetWithinStruct + "_" + i + " : 1 {};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
int actualOffset = this.offset + offsetAdd;
|
||||
|
||||
for (int i = 0; i < bits.size(); i++) {
|
||||
BitLayout bit = bits.get(i);
|
||||
|
||||
ps.print(prefixer.get(bit.name));
|
||||
ps.print(" = bits, U32, ");
|
||||
ps.print(actualOffset);
|
||||
ps.print(", [");
|
||||
ps.print(i + ":" + i);
|
||||
|
||||
ps.print("]");
|
||||
|
||||
ps.println();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.EnumField;
|
||||
import com.rusefi.newparse.parsing.FieldOptions;
|
||||
import com.rusefi.newparse.parsing.Type;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class EnumLayout extends Layout {
|
||||
private final String name;
|
||||
private final Type type;
|
||||
private final String enumType;
|
||||
private final int endBit;
|
||||
private final String[] values;
|
||||
private final FieldOptions options;
|
||||
|
||||
public EnumLayout(EnumField field) {
|
||||
this.name = field.name;
|
||||
this.type = field.type;
|
||||
this.enumType = field.enumType;
|
||||
this.endBit = field.endBit;
|
||||
this.values = field.values;
|
||||
this.options = field.options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.type.size;
|
||||
}
|
||||
|
||||
private static void writeEnumVal(PrintStream ps, String enumVal) {
|
||||
ps.print('"');
|
||||
ps.print(enumVal);
|
||||
ps.print('"');
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
String name = prefixer.get(this.name);
|
||||
ps.print(name);
|
||||
ps.print(" = bits, ");
|
||||
ps.print(this.type.tsType);
|
||||
ps.print(", ");
|
||||
ps.print(this.offset + offsetAdd);
|
||||
ps.print(", ");
|
||||
|
||||
ps.print("[0:");
|
||||
ps.print(this.endBit);
|
||||
ps.print("], ");
|
||||
|
||||
writeEnumVal(ps, this.values[0]);
|
||||
|
||||
for (int i = 1; i < this.values.length; i++) {
|
||||
ps.print(", ");
|
||||
writeEnumVal(ps, this.values[i]);
|
||||
}
|
||||
|
||||
ps.println();
|
||||
|
||||
meta.addComment(name, this.options.comment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
this.writeCOffsetHeader(ps, this.options.comment, this.options.units);
|
||||
ps.println("\t" + this.enumType + " " + this.name + ";");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps, int[] arrayLength) {
|
||||
this.writeCOffsetHeader(ps, this.options.comment, this.options.units);
|
||||
ps.println("\t" + this.enumType + " " + this.name + "[" + arrayLength[0] + "];");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
// Output an enum as a scalar, since there's no TS support for enum output channels
|
||||
ps.print(prefixer.get(name));
|
||||
ps.print(" = scalar, ");
|
||||
ps.print(this.type.tsType);
|
||||
ps.print(", ");
|
||||
ps.print(this.offset + offsetAdd);
|
||||
ps.println(", \"\", 1, 0");
|
||||
}
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.ConfigDefinition;
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.FieldOptions;
|
||||
import com.rusefi.newparse.parsing.ScalarField;
|
||||
import com.rusefi.newparse.parsing.Type;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class ScalarLayout extends Layout {
|
||||
public final String name;
|
||||
private final Type type;
|
||||
private final FieldOptions options;
|
||||
private final boolean autoscale;
|
||||
|
||||
public ScalarLayout(ScalarField field) {
|
||||
this.name = field.name;
|
||||
this.options = field.options;
|
||||
this.type = field.type;
|
||||
this.autoscale = field.autoscale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.type.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Scalar " + type.cType + " " + super.toString();
|
||||
}
|
||||
|
||||
private void printBeforeArrayLength(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, String fieldType, int offsetAdd) {
|
||||
String name = prefixer.get(this.name);
|
||||
ps.print(name);
|
||||
ps.print(" = " + fieldType + ", ");
|
||||
ps.print(this.type.tsType);
|
||||
ps.print(", ");
|
||||
ps.print(this.offset + offsetAdd);
|
||||
ps.print(", ");
|
||||
|
||||
meta.addComment(name, this.options.comment);
|
||||
}
|
||||
|
||||
private void printAfterArrayLength(PrintStream ps) {
|
||||
options.printTsFormat(ps);
|
||||
|
||||
ps.println();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd, int[] arrayLength) {
|
||||
if (arrayLength[0] == 0) {
|
||||
// Skip zero length arrays, they may be used for dynamic padding but TS doesn't like them
|
||||
return;
|
||||
} else if (arrayLength[0] == 1) {
|
||||
// For 1-length arrays, emit as a plain scalar instead
|
||||
writeTunerstudioLayout(ps, meta, prefixer, offsetAdd);
|
||||
return;
|
||||
}
|
||||
|
||||
printBeforeArrayLength(ps, meta, prefixer, "array", offsetAdd);
|
||||
|
||||
ps.print("[");
|
||||
ps.print(arrayLength[0]);
|
||||
|
||||
for (int i = 1; i < arrayLength.length; i++) {
|
||||
if (arrayLength[i] == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ps.print('x');
|
||||
ps.print(arrayLength[i]);
|
||||
}
|
||||
|
||||
ps.print("], ");
|
||||
|
||||
printAfterArrayLength(ps);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
printBeforeArrayLength(ps, meta, prefixer, "scalar", offsetAdd);
|
||||
printAfterArrayLength(ps);
|
||||
}
|
||||
|
||||
private String makeScaleString() {
|
||||
double scale = this.options.scale;
|
||||
|
||||
long mul, div;
|
||||
|
||||
if (scale < 1) {
|
||||
mul = Math.round(1 / scale);
|
||||
div = 1;
|
||||
} else {
|
||||
mul = 1;
|
||||
div = Math.round(scale);
|
||||
}
|
||||
|
||||
double actualScale = (double)mul / div;
|
||||
|
||||
if (mul < 1 || div < 1 || (Math.abs(scale - actualScale) < 0.0001)) {
|
||||
throw new RuntimeException("assertion failure: scale string generation failure for " + this.name);
|
||||
}
|
||||
|
||||
return mul + ", " + div;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
this.writeCOffsetHeader(ps, this.options.comment, this.options.units);
|
||||
|
||||
String cTypeName = this.type.cType.replaceAll("^int32_t$", "int");
|
||||
|
||||
if (this.autoscale) {
|
||||
cTypeName = "scaled_channel<" + cTypeName + ", " + makeScaleString() + ">";
|
||||
}
|
||||
|
||||
ps.print("\t" + cTypeName + " " + this.name);
|
||||
|
||||
if (ConfigDefinition.needZeroInit) {
|
||||
ps.print(" = (" + this.type.cType.replaceAll("^int32_t$", "int") + ")0");
|
||||
}
|
||||
|
||||
ps.println(";");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps, int[] arrayLength) {
|
||||
this.writeCOffsetHeader(ps, this.options.comment, this.options.units);
|
||||
|
||||
StringBuilder al = new StringBuilder();
|
||||
|
||||
al.append(arrayLength[0]);
|
||||
|
||||
for (int i = 1; i < arrayLength.length; i++) {
|
||||
al.append("][");
|
||||
al.append(arrayLength[i]);
|
||||
}
|
||||
|
||||
String cTypeName = this.type.cType.replaceAll("^int32_t$", "int");
|
||||
|
||||
if (this.autoscale) {
|
||||
cTypeName = "scaled_channel<" + cTypeName + ", " + makeScaleString() + ">";
|
||||
}
|
||||
|
||||
ps.println("\t" + cTypeName + " " + this.name + "[" + al + "];");
|
||||
}
|
||||
|
||||
private void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd, String name) {
|
||||
ps.print(prefixer.get(name));
|
||||
//ps.print(" = " + fieldType + ", ");
|
||||
ps.print(" = scalar, ");
|
||||
ps.print(this.type.tsType);
|
||||
ps.print(", ");
|
||||
ps.print(this.offset + offsetAdd);
|
||||
ps.print(", ");
|
||||
ps.print(this.options.units);
|
||||
ps.print(", ");
|
||||
ps.print(FieldOptions.tryRound(this.options.scale));
|
||||
ps.print(", ");
|
||||
ps.print(FieldOptions.tryRound(this.options.offset));
|
||||
|
||||
ps.println();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
writeOutputChannelLayout(ps, prefixer, offsetAdd, this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd, int[] arrayLength) {
|
||||
if (arrayLength.length != 1) {
|
||||
throw new IllegalStateException("Output channels don't support multi dimension arrays");
|
||||
}
|
||||
|
||||
int elementOffset = offsetAdd;
|
||||
|
||||
for (int i = 0; i < arrayLength[0]; i++) {
|
||||
writeOutputChannelLayout(ps, prefixer, elementOffset, this.name + (i + 1));
|
||||
elementOffset += type.size;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.StringField;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class StringLayout extends Layout {
|
||||
private final String name;
|
||||
private final int size;
|
||||
private final String comment;
|
||||
|
||||
public StringLayout(StringField field) {
|
||||
this.name = field.name;
|
||||
this.size = field.size;
|
||||
this.comment = field.comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
// char can be single aligned
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "String " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
String name = prefixer.get(this.name);
|
||||
ps.print(name);
|
||||
ps.print(" = string, ASCII, ");
|
||||
ps.print(this.offset + offsetAdd);
|
||||
ps.print(", ");
|
||||
ps.print(size);
|
||||
|
||||
ps.println();
|
||||
|
||||
if (!this.comment.isEmpty()) {
|
||||
meta.addComment(name, comment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
this.writeCOffsetHeader(ps, null, null);
|
||||
ps.println("\tchar " + this.name + "[" + this.size + "];");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps, int[] arrayLength) {
|
||||
this.writeCOffsetHeader(ps, null, null);
|
||||
ps.println("\tchar " + this.name + "[" + arrayLength[0] + "][" + this.size + "];");
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.*;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class StructLayout extends Layout {
|
||||
/*private*/public final List<Layout> children = new ArrayList<>();
|
||||
|
||||
public final String typeName;
|
||||
private final String name;
|
||||
private final String comment;
|
||||
private final Boolean noPrefix;
|
||||
private final int size;
|
||||
|
||||
private static int getAlignedOffset(int offset, int alignment) {
|
||||
// Align each element to its own size
|
||||
if ((offset % alignment) != 0) {
|
||||
return offset + alignment - (offset % alignment);
|
||||
} else {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
int padOffsetWithUnused(int offset, int align) {
|
||||
int alignedOffset = getAlignedOffset(offset, align);
|
||||
|
||||
int needsUnused = alignedOffset - offset;
|
||||
|
||||
if (needsUnused > 0) {
|
||||
UnusedLayout ul = new UnusedLayout(needsUnused);
|
||||
ul.setOffset(offset);
|
||||
ul.setOffsetWithinStruct(offset - this.offset);
|
||||
children.add(ul);
|
||||
return alignedOffset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public StructLayout(int offset, String name, Struct parsedStruct) {
|
||||
setOffset(offset);
|
||||
|
||||
this.typeName = parsedStruct.name;
|
||||
this.name = name;
|
||||
this.comment = parsedStruct.comment;
|
||||
this.noPrefix = parsedStruct.noPrefix;
|
||||
|
||||
int initialOffest = offset;
|
||||
|
||||
for (Field f : parsedStruct.fields) {
|
||||
if (f instanceof ArrayField) {
|
||||
ArrayField asf = (ArrayField)f;
|
||||
|
||||
// If not a scalar, you must iterate
|
||||
assert(asf.prototype instanceof ScalarField || asf.iterate);
|
||||
|
||||
if (asf.iterate) {
|
||||
if (asf.prototype instanceof StructField) {
|
||||
// Struct: special case of a struct array
|
||||
offset = addItem(offset, new ArrayIterateStructLayout((StructField)asf.prototype, asf.length));
|
||||
} else {
|
||||
// array of scalars (or enums)
|
||||
offset = addItem(offset, new ArrayIterateScalarLayout(asf.prototype, asf.length));
|
||||
}
|
||||
} else /* not iterate */ {
|
||||
// If not a scalar, you must iterate
|
||||
assert(asf.prototype instanceof ScalarField);
|
||||
|
||||
ScalarField prototype = (ScalarField)asf.prototype;
|
||||
offset = addItem(offset, new ArrayLayout(prototype, asf.length));
|
||||
}
|
||||
} else {
|
||||
offset = addItem(offset, f);
|
||||
}
|
||||
}
|
||||
|
||||
// Structs are always a multiple of 4 bytes long, pad the end appropriately
|
||||
offset = padOffsetWithUnused(offset, 4);
|
||||
|
||||
size = offset - initialOffest;
|
||||
}
|
||||
|
||||
private int addItem(int offset, Field f) {
|
||||
if (f instanceof StructField) {
|
||||
// Special case for structs - we have to compute base offset first
|
||||
StructField sf = (StructField) f;
|
||||
|
||||
return addStruct(offset, sf.struct, sf.name);
|
||||
}
|
||||
|
||||
Layout l;
|
||||
if (f instanceof ScalarField) {
|
||||
l = new ScalarLayout((ScalarField)f);
|
||||
} else if (f instanceof EnumField) {
|
||||
l = new EnumLayout((EnumField)f);
|
||||
} else if (f instanceof UnusedField) {
|
||||
l = new UnusedLayout((UnusedField) f);
|
||||
} else if (f instanceof BitGroup) {
|
||||
l = new BitGroupLayout((BitGroup) f);
|
||||
} else if (f instanceof StringField) {
|
||||
l = new StringLayout((StringField) f);
|
||||
} else if (f instanceof Union) {
|
||||
l = new UnionLayout((Union)f);
|
||||
} else {
|
||||
throw new RuntimeException("unexpected field type during layout");
|
||||
}
|
||||
|
||||
return addItem(offset, l);
|
||||
}
|
||||
|
||||
private int addItem(int offset, Layout l) {
|
||||
// Slide the offset up by the required alignment of this element
|
||||
offset = padOffsetWithUnused(offset, l.getAlignment());
|
||||
|
||||
// place the element
|
||||
l.setOffset(offset);
|
||||
l.setOffsetWithinStruct(offset - this.offset);
|
||||
children.add(l);
|
||||
|
||||
return offset + l.getSize();
|
||||
}
|
||||
|
||||
private int addStruct(int offset, Struct struct, String name) {
|
||||
offset = padOffsetWithUnused(offset, 4);
|
||||
|
||||
// Recurse and build this new struct
|
||||
StructLayout sl = new StructLayout(offset, name, struct);
|
||||
|
||||
sl.setOffsetWithinStruct(offset - this.offset);
|
||||
this.children.add(sl);
|
||||
|
||||
// Update offset with the struct size - it's guaranteed to be a multiple of 4 bytes
|
||||
int structSize = sl.getSize();
|
||||
return offset + structSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
// All structs should be aligned on a 4 byte boundary
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Struct " + this.typeName + " " + super.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
if (!this.noPrefix) {
|
||||
prefixer.push(this.name);
|
||||
}
|
||||
|
||||
// print all children in sequence
|
||||
this.children.forEach(c -> c.writeTunerstudioLayout(ps, meta, prefixer, offsetAdd));
|
||||
|
||||
if (!this.noPrefix) {
|
||||
prefixer.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
this.writeCOffsetHeader(ps, null, null);
|
||||
ps.println("\t" + this.typeName + " " + this.name + ";");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps, int[] arrayLength) {
|
||||
this.writeCOffsetHeader(ps, null, null);
|
||||
ps.println("\t" + this.typeName + " " + this.name + "[" + arrayLength[0] + "];");
|
||||
}
|
||||
|
||||
public void writeCLayoutRoot(PrintStream ps) {
|
||||
if (this.comment != null) {
|
||||
ps.println("/**\n * @brief " + this.comment);
|
||||
ps.println("*/");
|
||||
}
|
||||
|
||||
ps.println("// start of " + this.typeName);
|
||||
ps.println("struct " + this.typeName + " {");
|
||||
|
||||
this.children.forEach(c -> c.writeCLayout(ps));
|
||||
|
||||
ps.println("};");
|
||||
ps.println("static_assert(sizeof(" + this.typeName + ") == " + getSize() + ");");
|
||||
|
||||
ps.println();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
if (!this.noPrefix) {
|
||||
prefixer.push(this.name);
|
||||
}
|
||||
|
||||
this.children.forEach(c -> c.writeOutputChannelLayout(ps, prefixer, offsetAdd));
|
||||
|
||||
if (!this.noPrefix) {
|
||||
prefixer.pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.ArrayField;
|
||||
import com.rusefi.newparse.parsing.Field;
|
||||
import com.rusefi.newparse.parsing.ScalarField;
|
||||
import com.rusefi.newparse.parsing.Union;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UnionLayout extends Layout {
|
||||
private final List<Layout> children = new ArrayList<>();
|
||||
|
||||
public UnionLayout(Union u) {
|
||||
for (Field f : u.fields) {
|
||||
// For every child, check if it is the largest, and grow if so
|
||||
if (f instanceof ArrayField) {
|
||||
ArrayField af = (ArrayField)f;
|
||||
|
||||
// we probably don't need union of iterate?
|
||||
assert(!af.iterate);
|
||||
|
||||
ScalarField prototype = (ScalarField)af.prototype;
|
||||
this.children.add(new ArrayLayout(prototype, af.length));
|
||||
} else if (f instanceof ScalarField) {
|
||||
this.children.add(new ScalarLayout((ScalarField)f));
|
||||
} else {
|
||||
throw new RuntimeException("Tried to create union with member type " + f.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffset(int offset) {
|
||||
super.setOffset(offset);
|
||||
this.children.forEach(c -> c.setOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffsetWithinStruct(int offset) {
|
||||
super.setOffsetWithinStruct(offset);
|
||||
this.children.forEach(c -> c.setOffsetWithinStruct(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.children.stream().map(Layout::getSize).max(Integer::compare).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
// The alignment of the union is the largest alignment required by one of the members
|
||||
return this.children.stream().map(Layout::getAlignment).max(Integer::compare).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
// Simply write out all children - no container necessary as fields can overlap in TS
|
||||
this.children.forEach(c -> c.writeTunerstudioLayout(ps, meta, prefixer, offsetAdd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
this.writeCOffsetHeader(ps, "union size " + this.getSize() + ", " + this.children.size() + " members", null);
|
||||
|
||||
// emit an anonymous union that contains all our members
|
||||
ps.println("\tunion {");
|
||||
this.children.forEach(c -> c.writeCLayout(ps));
|
||||
ps.println("\t};");
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package com.rusefi.newparse.layout;
|
||||
|
||||
import com.rusefi.newparse.outputs.TsMetadata;
|
||||
import com.rusefi.newparse.parsing.UnusedField;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class UnusedLayout extends Layout {
|
||||
private final int size;
|
||||
|
||||
public UnusedLayout(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public UnusedLayout(UnusedField field) {
|
||||
this.size = field.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Unused " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {
|
||||
ps.println("; unused " + this.size + " bytes at offset " + (this.offset + offsetAdd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCLayout(PrintStream ps) {
|
||||
this.writeCOffsetHeader(ps, null, null);
|
||||
ps.println("\tchar unused" + this.offsetWithinStruct + "[" + this.size + "];");
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public class ArrayField<PrototypeType extends PrototypeField> implements Field {
|
||||
public final int[] length;
|
||||
public final Boolean iterate;
|
||||
public final PrototypeType prototype;
|
||||
|
||||
public ArrayField(PrototypeType prototype, int[] length, Boolean iterate) {
|
||||
this.length = length;
|
||||
this.iterate = iterate;
|
||||
this.prototype = prototype;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public class EnumField extends PrototypeField {
|
||||
public final Type type;
|
||||
public final String enumType;
|
||||
public final int endBit;
|
||||
public final String[] values;
|
||||
public final FieldOptions options;
|
||||
|
||||
public EnumField(Type type, String enumType, String name, int endBit, String[] values, FieldOptions options) {
|
||||
super(name);
|
||||
|
||||
this.type = type;
|
||||
this.enumType = enumType;
|
||||
this.endBit = endBit;
|
||||
this.values = values;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "enum " + type.cType + " " + this.name;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public class EnumTypedef extends Typedef {
|
||||
public final Type type;
|
||||
public final int endBit;
|
||||
public final String[] values;
|
||||
|
||||
public EnumTypedef(String name, Type type, int endBit, String[] values) {
|
||||
super(name);
|
||||
|
||||
this.type = type;
|
||||
this.endBit = endBit;
|
||||
this.values = values;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public abstract class PrototypeField implements Field {
|
||||
public final String name;
|
||||
|
||||
protected PrototypeField(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public class ScalarField extends PrototypeField {
|
||||
public final Type type;
|
||||
public final FieldOptions options;
|
||||
public final Boolean autoscale;
|
||||
|
||||
public ScalarField(Type type, String name, FieldOptions options, boolean autoscale) {
|
||||
super(name);
|
||||
|
||||
this.type = type;
|
||||
this.options = options;
|
||||
this.autoscale = autoscale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.cType + " " + name;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public class StringField extends PrototypeField {
|
||||
public final int size;
|
||||
public final String comment;
|
||||
|
||||
public StringField(String name, int size, String comment) {
|
||||
super(name);
|
||||
|
||||
this.size = size;
|
||||
this.comment = comment;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.rusefi.newparse.parsing;
|
||||
|
||||
public class StructField extends PrototypeField {
|
||||
public final Struct struct;
|
||||
|
||||
public StructField(Struct struct, String name) {
|
||||
super(name);
|
||||
|
||||
this.struct = struct;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue