We have to move either forward or backwards with newparse #4441

This commit is contained in:
rusefillc 2023-06-16 14:54:11 -04:00
parent 438155dcbb
commit 18a92a958c
17 changed files with 5 additions and 774 deletions

Binary file not shown.

View File

@ -3,41 +3,19 @@ package com.rusefi.newparse;
import com.rusefi.EnumsReader;
import com.rusefi.VariableRegistry;
import com.rusefi.enum_reader.Value;
import com.rusefi.generated.RusefiConfigGrammarBaseListener;
import com.rusefi.generated.RusefiConfigGrammarParser;
import com.rusefi.newparse.parsing.*;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import com.rusefi.newparse.parsing.Definition;
import java.util.*;
import java.util.regex.Pattern;
import static com.rusefi.VariableRegistry.AUTO_ENUM_SUFFIX;
import java.util.HashMap;
import java.util.Map;
public class ParseState implements DefinitionsState {
private final Map<String, Definition> definitions = new HashMap<>();
private final Map<String, Struct> structs = new HashMap<>();
private final List<Struct> structList = new ArrayList<>();
private final Map<String, Typedef> typedefs = new HashMap<>();
private static final Pattern CHAR_LITERAL = Pattern.compile("'.'");
private final EnumsReader enumsReader;
private Definition.OverwritePolicy definitionOverwritePolicy = Definition.OverwritePolicy.NotAllowed;
private String typedefName = null;
private final Queue<Double> evalResults = new LinkedList<>();
private Scope scope = null;
private final Stack<Scope> scopes = new Stack<>();
private Struct lastStruct = null;
public ParseState() {
this.enumsReader = null;
}
private final Definition.OverwritePolicy definitionOverwritePolicy = Definition.OverwritePolicy.NotAllowed;
public ParseState(EnumsReader enumsReader) {
this.enumsReader = enumsReader;
for (Map.Entry<String, EnumsReader.EnumState> enumType : this.enumsReader.getEnums().entrySet()) {
for (Map.Entry<String, EnumsReader.EnumState> enumType : enumsReader.getEnums().entrySet()) {
String name = enumType.getKey();
for (Value enumValue : enumType.getValue().values()) {
@ -59,57 +37,6 @@ public class ParseState implements DefinitionsState {
addDefinition(name + "_16_hex", String.format("\\x%02x\\x%02x", (value >> 8) & 0xFF, value & 0xFF));
}
private static boolean isNumeric(String str) {
try {
Integer.parseInt(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
public Struct getLastStruct() {
return lastStruct;
}
private String[] resolveEnumValues(String enumName) {
if (this.enumsReader == null) {
return new String[0];
}
TreeMap<Integer, String> valueNameById = new TreeMap<>();
EnumsReader.EnumState stringValueMap = this.enumsReader.getEnums().get(enumName);
if (stringValueMap == null)
return null;
for (Value value : stringValueMap.values()) {
if (isNumeric(value.getValue())) {
valueNameById.put(value.getIntValue(), value.getName());
} else {
Definition def = this.definitions.get(value.getValue());
if (def == null)
throw new IllegalStateException("No value for " + value);
valueNameById.put((Integer)def.value, value.getName());
}
}
// Now iterate over all values, assembling as an array in-order
String[] result = new String[valueNameById.lastKey() + 1];
for (int i = 0; i < result.length; i++) {
result[i] = valueNameById.getOrDefault(i, "INVALID");
}
return result;
}
public List<Struct> getStructs() {
return structList;
}
public Definition findDefinition(String name) {
return definitions.getOrDefault(name, null);
}
/**
* we are in a lengthy period of transition between two implementations
*/
@ -143,322 +70,4 @@ public class ParseState implements DefinitionsState {
private void addDefinition(String name, Object value) {
addDefinition(name, value, definitionOverwritePolicy);
}
public ParseTreeListener getListener() {
return new RusefiConfigGrammarBaseListener() {
@Override
public void exitContent(RusefiConfigGrammarParser.ContentContext ctx) {
assert(scopes.empty());
assert(scope == null);
assert(typedefName == null);
assert(evalResults.isEmpty());
assert(evalStack.empty());
}
@Override
public void exitDefinition(RusefiConfigGrammarParser.DefinitionContext ctx) {
String name = ctx.identifier().getText();
if (ctx.integer() != null) {
handleIntDefinition(name, Integer.parseInt(ctx.integer().getText()));
} else if (ctx.floatNum() != null) {
addDefinition(name, Double.parseDouble(ctx.floatNum().getText()));
} else if (ctx.numexpr() != null) {
double evalResult = evalResults.remove();
int floored = (int)Math.floor(evalResult);
if (Math.abs(floored - evalResult) < 0.001) {
// value is an int, process as such
handleIntDefinition(name, floored);
} else {
// Value is a double, add it
addDefinition(name, evalResult);
}
} else {
// glue the list of definitions back together
String defText = ctx.restOfLine().getText();
addDefinition(name, defText);
// If the definition matches a char literal, add a special definition for that
if (CHAR_LITERAL.matcher(defText).find()) {
addDefinition(name + "_char", defText.charAt(1));
}
}
}
@Override
public void enterTypedef(RusefiConfigGrammarParser.TypedefContext ctx) {
typedefName = ctx.identifier().getText();
}
@Override
public void exitTypedef(RusefiConfigGrammarParser.TypedefContext ctx) {
typedefName = null;
}
@Override
public void exitScalarTypedefSuffix(RusefiConfigGrammarParser.ScalarTypedefSuffixContext ctx) {
}
@Override
public void enterEnumTypedefSuffix(RusefiConfigGrammarParser.EnumTypedefSuffixContext ctx) {
}
@Override
public void exitStringTypedefSuffix(RusefiConfigGrammarParser.StringTypedefSuffixContext ctx) {
}
@Override
public void enterStruct(RusefiConfigGrammarParser.StructContext ctx) {
// If we're already inside a struct, push that context on to the stack
if (scope != null) {
scopes.push(scope);
}
// Create new scratch space for this scope
scope = new Scope();
}
@Override
public void enterUnionField(RusefiConfigGrammarParser.UnionFieldContext ctx) {
// Unions behave like a struct as far as scope is concerned (but is processed differently later
// to overlap all members, instead of placing them in sequence as in a struct)
enterStruct(null);
}
void handleFieldOptionsList(FieldOptions options, RusefiConfigGrammarParser.FieldOptionsListContext ctx) {
// Null means no options were configured, use defaults
if (ctx == null) {
return;
}
if (ctx.fieldOption().size() == 0) {
if (ctx.SemicolonedString() != null) {
String text = ctx.SemicolonedString().getText();
options.comment = text.substring(1, text.length() - 1).trim();
} else if (ctx.SemicolonedSuffix() != null) {
options.comment = ctx.SemicolonedSuffix().getText().substring(1).trim();
} else {
options.comment = "";
}
// this is a legacy field option list, parse it as such
if (!ctx.numexpr().isEmpty()) {
options.units = ctx.QuotedString().getText();
options.scale = evalResults.remove();
options.offset = evalResults.remove();
options.min = evalResults.remove();
options.max = evalResults.remove();
options.digits = Integer.parseInt(ctx.integer().getText());
// we should have consumed everything on the results list
assert(evalResults.size() == 0);
}
return;
}
for (RusefiConfigGrammarParser.FieldOptionContext fo : ctx.fieldOption()) {
String key = fo.getChild(0).getText();
String sValue = fo.getChild(2).getText();
switch (key) {
case "unit":
options.units = sValue;
break;
case "comment":
options.comment = sValue;
break;
case "digits":
options.digits = Integer.parseInt(sValue);
break;
default:
Double value = evalResults.remove();
switch (key) {
case "min":
options.min = value;
break;
case "max":
options.max = value;
break;
case "scale":
options.scale = value;
break;
case "offset":
options.offset = value;
break;
}
break;
}
}
// we should have consumed everything on the results list
assert(evalResults.size() == 0);
}
@Override
public void exitScalarField(RusefiConfigGrammarParser.ScalarFieldContext ctx) {
}
@Override
public void enterBitField(RusefiConfigGrammarParser.BitFieldContext ctx) {
String name = ctx.identifier().getText();
// Check if there's already a bit group at the end of the current struct
BitGroup group = null;
if (!scope.structFields.isEmpty()) {
Object lastElement = scope.structFields.get(scope.structFields.size() - 1);
if (lastElement instanceof BitGroup) {
group = (BitGroup)lastElement;
// If this group is full, create a new one instead of continuing on here.
if (group.bitFields.size() == 32) {
group = null;
}
}
}
// there was no group, create and add it
if (group == null) {
group = new BitGroup();
scope.structFields.add(group);
}
String comment = ctx.SemicolonedSuffix() == null ? null : ctx.SemicolonedSuffix().getText().substring(1).trim();
String trueValue = "\"true\"";
String falseValue = "\"false\"";
if (!ctx.QuotedString().isEmpty()) {
trueValue = ctx.QuotedString(0).getText();
falseValue = ctx.QuotedString(1).getText();
}
group.addBitField(new BitField(name, comment, trueValue, falseValue));
}
@Override
public void exitArrayField(RusefiConfigGrammarParser.ArrayFieldContext ctx) {
}
@Override
public void exitArrayLengthSpec(RusefiConfigGrammarParser.ArrayLengthSpecContext ctx) {
}
@Override
public void enterUnusedField(RusefiConfigGrammarParser.UnusedFieldContext ctx) {
scope.structFields.add(new UnusedField(Integer.parseInt(ctx.integer().getText())));
}
@Override
public void exitStruct(RusefiConfigGrammarParser.StructContext ctx) {
String structName = ctx.identifier().getText();
assert(scope != null);
String comment = ctx.restOfLine() == null ? null : ctx.restOfLine().getText();
Struct s = new Struct(structName, scope.structFields, ctx.StructNoPrefix() != null, comment);
structs.put(structName, s);
structList.add(s);
lastStruct = s;
// We're leaving with this struct, re-apply the next struct out so more fields can be added to it
if (scopes.empty()) {
scope = null;
} else {
scope = scopes.pop();
}
}
@Override
public void exitUnionField(RusefiConfigGrammarParser.UnionFieldContext ctx) {
assert(scope != null);
// unions must have at least 1 member
assert(!scope.structFields.isEmpty());
Union u = new Union(scope.structFields);
// Restore the containing scope
scope = scopes.pop();
// Lastly, add the union to the scope
scope.structFields.add(u);
}
private final Stack<Double> evalStack = new Stack<>();
@Override
public void exitEvalNumber(RusefiConfigGrammarParser.EvalNumberContext ctx) {
evalStack.push(Double.parseDouble(ctx.floatNum().getText()));
}
@Override
public void exitEvalReplacement(RusefiConfigGrammarParser.EvalReplacementContext ctx) {
// Strip any @@ symbols
String defName = ctx.getText().replaceAll("@", "");
if (!definitions.containsKey(defName)) {
throw new RuntimeException("Definition not found for " + ctx.getText());
}
// Find the matching definition and push on to the eval stack
Definition def = definitions.get(defName);
if (!def.isNumeric()) {
throw new RuntimeException("Tried to use symbol " + defName + " in an expression, but it wasn't a number");
}
evalStack.push(def.asDouble());
}
@Override
public void exitEvalMul(RusefiConfigGrammarParser.EvalMulContext ctx) {
Double right = evalStack.pop();
Double left = evalStack.pop();
evalStack.push(left * right);
}
@Override
public void exitEvalDiv(RusefiConfigGrammarParser.EvalDivContext ctx) {
Double right = evalStack.pop();
Double left = evalStack.pop();
evalStack.push(left / right);
}
@Override
public void exitEvalAdd(RusefiConfigGrammarParser.EvalAddContext ctx) {
Double right = evalStack.pop();
Double left = evalStack.pop();
evalStack.push(left + right);
}
@Override
public void exitEvalSub(RusefiConfigGrammarParser.EvalSubContext ctx) {
Double right = evalStack.pop();
Double left = evalStack.pop();
evalStack.push(left - right);
}
@Override
public void exitNumexpr(RusefiConfigGrammarParser.NumexprContext ctx) {
assert(evalStack.size() == 1);
evalResults.add(evalStack.pop());
}
};
}
static class Scope {
public final List<Field> structFields = new ArrayList<>();
}
}

View File

@ -1,86 +0,0 @@
package com.rusefi.newparse.layout;
import com.rusefi.newparse.outputs.TsMetadata;
import java.io.PrintStream;
public abstract class Layout {
public int offset = -1;
public int offsetWithinStruct = -1;
public abstract int getSize();
public int getAlignment() {
// Default to size
return this.getSize();
}
public void setOffset(int offset) {
this.offset = offset;
}
public void setOffsetWithinStruct(int offset) {
offsetWithinStruct = offset;
}
@Override
public String toString() {
return "offset = " + offset + " size = " + this.getSize();
}
public final void writeTunerstudioLayout(PrintStream ps, TsMetadata meta) {
writeTunerstudioLayout(ps, meta, new StructNamePrefixer(), 0);
}
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd) {}
protected void writeTunerstudioLayout(PrintStream ps, TsMetadata meta, StructNamePrefixer prefixer, int offsetAdd, int[] arrayLength) {
throw new IllegalStateException("This type can't be in an array!");
}
protected void writeCOffsetHeader(PrintStream ps, String comment, String units) {
ps.println("\t/**");
if (comment != null) {
comment = comment.replaceAll("[+]", "");
comment = comment.replaceAll("\\n", "\n\t * ");
if (comment.length() == 0) {
comment = null;
}
}
if (comment != null) {
comment = comment.replaceAll("\\\\n", "\n\t * ");
ps.println("\t * " + comment);
}
if (units != null && units.length() > 2) {
ps.println("\t" + units.replace("\"", ""));
}
ps.println("\t * offset " + this.offsetWithinStruct);
ps.println("\t */");
}
public void writeCLayout(PrintStream ps) { }
public void writeCLayout(PrintStream ps, int[] arrayLength) {
throw new IllegalStateException("This type can't be in an array!");
}
public void writeOutputChannelLayout(PrintStream ps, String prefix, int offsetAdd) {
StructNamePrefixer prefixer = new StructNamePrefixer();
if (prefix != null) {
prefixer.push(prefix);
}
writeOutputChannelLayout(ps, prefixer, offsetAdd);
}
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd) { }
protected void writeOutputChannelLayout(PrintStream ps, StructNamePrefixer prefixer, int offsetAdd, int[] arrayLength) {
throw new IllegalStateException("This type can't be in an array!");
}
}

View File

@ -1,47 +0,0 @@
package com.rusefi.newparse.layout;
import java.util.Stack;
public class StructNamePrefixer {
private final Stack<String> stack = new Stack<>();
private int idx = -1;
public void pop() {
stack.pop();
}
public void push(String name) {
if (this.idx != -1) {
// If we push with an index set, it means we're inside an array of structs.
// In that case, we embed the index (of the struct in the array) within the array's name
name = name + this.idx;
this.idx = -1;
}
stack.push(name + "_");
}
void setIndex(int idx) {
if (idx >= 0) {
this.idx = idx + 1;
} else {
throw new RuntimeException("Invalid StructNamePrefixer index: " + idx);
}
}
void clearIndex() {
this.idx = -1;
}
String get(String name) {
// stack has no prefixes, just return the plain name (no join necessary)
name = String.join("", stack) + name;
// Append the array index if necessary (for iterated arrays)
if (this.idx != -1) {
return name + idx;
} else {
return name;
}
}
}

View File

@ -1,26 +0,0 @@
package com.rusefi.newparse.outputs;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
public class PrintStreamAlwaysUnix extends PrintStream {
public PrintStreamAlwaysUnix(OutputStream out) {
super(out);
}
public PrintStreamAlwaysUnix(OutputStream out, boolean autoFlush, String encoding) throws UnsupportedEncodingException {
super(out, autoFlush, encoding);
}
@Override
public void println() {
print('\n');
}
@Override
public void println(String s) {
print(s);
println();
}
}

View File

@ -1,32 +0,0 @@
package com.rusefi.newparse.outputs;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class TsMetadata {
private final List<String> comments = new ArrayList<>();
public void addComment(String name, String comment) {
if (comment == null) {
return;
}
comment = comment.trim();
// LEGACY FEATURE: clips off the previously-required +
if (comment.startsWith("+")) {
// Clip off leading +, and any leading/trailing whitespace
comment = comment.substring(1).trim();
}
if (comment.length() == 0) {
return;
}
comments.add("\t" + name + " = \"" + comment + "\"");
}
public void writeComments(PrintStream ps) {
this.comments.forEach(ps::println);
}
}

View File

@ -1,20 +0,0 @@
package com.rusefi.newparse.parsing;
public class BitField {
public final String name;
public final String comment;
public final String trueValue;
public final String falseValue;
public BitField(String name, String comment, String trueValue, String falseValue) {
this.name = name;
this.comment = comment;
this.trueValue = trueValue;
this.falseValue = falseValue;
}
@Override
public String toString() {
return "BitField: " + this.name;
}
}

View File

@ -1,17 +0,0 @@
package com.rusefi.newparse.parsing;
import java.util.ArrayList;
import java.util.List;
public class BitGroup implements Field {
public final List<BitField> bitFields = new ArrayList<>();
public void addBitField(BitField b) {
bitFields.add(b);
}
@Override
public String toString() {
return "BitGroup: " + bitFields.size() + " bits";
}
}

View File

@ -1,4 +0,0 @@
package com.rusefi.newparse.parsing;
public interface Field {
}

View File

@ -1,63 +0,0 @@
package com.rusefi.newparse.parsing;
import java.io.PrintStream;
public class FieldOptions {
public double min;
public double max;
public double scale;
public double offset;
public int digits;
public String units;
public String comment;
public FieldOptions() {
min = 0;
max = 0;
scale = 1;
offset = 0;
digits = 0;
units = "\"\"";
comment = "";
}
// Produce a deep copy of this object
public FieldOptions copy() {
FieldOptions other = new FieldOptions();
other.min = this.min;
other.max = this.max;
other.scale = this.scale;
other.offset = this.offset;
other.digits = this.digits;
other.units = this.units;
other.comment = this.comment;
return other;
}
public static String tryRound(double value) {
long longVal = Math.round(value);
// If the rounded value can exactly represent this float, then print as an integer
if (value == longVal) {
return Long.toString(longVal);
} else {
return Double.toString(value);
}
}
public void printTsFormat(PrintStream ps) {
ps.print(units);
ps.print(", ");
ps.print(tryRound(scale));
ps.print(", ");
ps.print(tryRound(offset));
ps.print(", ");
ps.print(tryRound(min));
ps.print(", ");
ps.print(tryRound(max));
ps.print(", ");
ps.print(digits);
}
}

View File

@ -1,13 +0,0 @@
package com.rusefi.newparse.parsing;
public class ScalarTypedef extends Typedef {
public final FieldOptions options;
public final Type type;
public ScalarTypedef(String name, Type type, FieldOptions options) {
super(name);
this.options = options;
this.type = type;
}
}

View File

@ -1,12 +0,0 @@
package com.rusefi.newparse.parsing;
public class StringTypedef extends Typedef {
public final int size;
public StringTypedef(String name, int size) {
super(name);
this.size = size;
}
}

View File

@ -1,17 +0,0 @@
package com.rusefi.newparse.parsing;
import java.util.List;
public class Struct implements Field {
public final String name;
public final Boolean noPrefix;
public final List<Field> fields;
public final String comment;
public Struct(String name, List<Field> fields, boolean noPrefix, String comment) {
this.name = name;
this.noPrefix = noPrefix;
this.fields = fields;
this.comment = comment;
}
}

View File

@ -1,8 +1,5 @@
package com.rusefi.newparse.parsing;
import java.util.Arrays;
import java.util.Optional;
public enum Type {
U08("uint8_t", "U08", 1),
S08("int8_t", "S08", 1),
@ -26,13 +23,4 @@ public enum Type {
this.size = size;
}
public static Optional<Type> findByCtype(String cType) {
// todo: better implementation of type aliases!
String cTypeWithAlas = "floatms_t".equals(cType) ? "float" : cType;
return Arrays.stream(Type.values()).filter(t -> t.cType.equals(cTypeWithAlas)).findFirst();
}
public static Type findByTsType(String tsType) {
return Arrays.stream(Type.values()).filter(t -> t.tsType.equals(tsType)).findFirst().get();
}
}

View File

@ -1,9 +0,0 @@
package com.rusefi.newparse.parsing;
public class Typedef {
public final String name;
protected Typedef (String name) {
this.name = name;
}
}

View File

@ -1,11 +0,0 @@
package com.rusefi.newparse.parsing;
import java.util.List;
public class Union implements Field {
public final List<Field> fields;
public Union(List<Field> fields) {
this.fields = fields;
}
}

View File

@ -1,9 +0,0 @@
package com.rusefi.newparse.parsing;
public class UnusedField implements Field {
public final int size;
public UnusedField(int size) {
this.size = size;
}
}