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

This commit is contained in:
rusefillc 2023-06-16 14:38:56 -04:00
parent e6ca0a42ba
commit 752a10ee05
10 changed files with 1 additions and 1126 deletions

Binary file not shown.

View File

@ -452,78 +452,6 @@ public class ParseState implements DefinitionsState {
@Override
public void exitArrayField(RusefiConfigGrammarParser.ArrayFieldContext ctx) {
String type = ctx.identifier(0).getText();
String name = ctx.identifier(1).getText();
int[] length = this.arrayDim;
// check if the iterate token is present
boolean iterate = ctx.Iterate() != null;
boolean autoscale = ctx.Autoscale() != null;
if (iterate && length.length != 1) {
throw new IllegalStateException("Cannot iterate multi dimensional array: " + name);
}
// First check if this is an array of structs
if (structs.containsKey(type)) {
// iterate required for structs
assert(iterate);
scope.structFields.add(new ArrayField<>(new StructField(structs.get(type), name), length, iterate));
return;
}
// Check first if we have a typedef for this type
Typedef typedef = typedefs.get(type);
FieldOptions options;
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();
handleFieldOptionsList(options, ctx.fieldOptionsList());
EnumField prototype = new EnumField(bTypedef.type, type, name, bTypedef.endBit, bTypedef.values, options);
scope.structFields.add(new ArrayField<>(prototype, length, iterate));
return;
} else if (typedef instanceof StringTypedef) {
StringTypedef sTypedef = (StringTypedef) typedef;
// iterate required for strings
assert(iterate);
options = new FieldOptions();
handleFieldOptionsList(options, ctx.fieldOptionsList());
StringField prototype = new StringField(name, sTypedef.size, options.comment);
scope.structFields.add(new ArrayField<>(prototype, length, iterate));
return;
} else {
throw new RuntimeException("didn't understand type " + type + " for element " + name);
}
} 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());
ScalarField prototype = new ScalarField(Type.findByCtype(type).get(), name, options, autoscale);
scope.structFields.add(new ArrayField<>(prototype, length, iterate));
}
private int[] arrayDim = null;

View File

@ -1,32 +0,0 @@
package com.rusefi.newparse.outputs;
import com.rusefi.newparse.ParseState;
import com.rusefi.newparse.layout.StructLayout;
import com.rusefi.newparse.parsing.Struct;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class CStructWriter {
public void writeCStructs(ParseState parser, String outputFile) throws FileNotFoundException {
writeCStructs(parser, new PrintStreamAlwaysUnix(new FileOutputStream(outputFile)));
}
public void writeCStructs(ParseState parser, PrintStream ps) {
ps.println(
"// begin\n" +
"#pragma once\n" +
"#include \"rusefi_types.h\""
);
for (Struct s : parser.getStructs()) {
StructLayout sl = new StructLayout(0, "root", s);
sl.writeCLayoutRoot(ps);
}
ps.println("// end");
ps.close();
}
}

View File

@ -1,37 +0,0 @@
package com.rusefi.newparse.outputs;
import com.rusefi.newparse.ParseState;
import com.rusefi.newparse.layout.StructLayout;
import com.rusefi.newparse.parsing.Struct;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* As of Nov 2022 this implementation is not used in prod :(
*/
public class OutputChannelWriter {
private final PrintStream ps;
public OutputChannelWriter(String outputFile) throws FileNotFoundException {
this.ps = new PrintStreamAlwaysUnix(new FileOutputStream(outputFile));
}
public OutputChannelWriter(PrintStream ps) {
this.ps = ps;
}
private int cumulativeSize = 0;
public void writeOutputChannels(ParseState parser, String namePrefix) {
// Assume the last struct is the one we want...
Struct s = parser.getStructs().get(parser.getStructs().size() - 1);
StructLayout sl = new StructLayout(0, "root", s);
sl.writeOutputChannelLayout(ps, namePrefix, cumulativeSize);
cumulativeSize += sl.getSize();
ps.println("; total TS size = " + cumulativeSize);
}
}

View File

@ -1,106 +0,0 @@
package com.rusefi.newparse.outputs;
import com.rusefi.newparse.ParseState;
import com.rusefi.newparse.layout.StructLayout;
import com.rusefi.newparse.parsing.Definition;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* As of Nov 2022 this implementation is not used in prod :(
*/
public class TsWriter {
// matches strings in the form of @@MY_var_123@@
private static final Pattern VAR = Pattern.compile("@@([a-zA-Z0-9_]+?)@@");
private static final Pattern OPTIONAL_LINE = Pattern.compile("@@if_([a-zA-Z0-9_]+)");
// TODO: We have to move either forward or backwards with newparse #4441
public void writeTunerstudio(ParseState parser, String inputFile, String outputFile) throws IOException {
PrintStream ps = new PrintStreamAlwaysUnix(new FileOutputStream(outputFile));
writeTunerstudio(parser, inputFile, ps);
ps.close();
}
public void writeTunerstudio(ParseState parser, String inputFile, PrintStream ps) throws IOException {
BufferedReader is = new BufferedReader(new FileReader(inputFile));
while (is.ready()) {
String line = is.readLine();
if (line.contains("CONFIG_DEFINITION_START")) {
writeLayoutAndComments(parser, ps);
continue;
}
// Check if this line has a "skip me" suffix
Matcher match = OPTIONAL_LINE.matcher(line);
if (match.find()) {
String varName = match.group(1);
Definition def = parser.findDefinition(varName);
if (def == null || def.toString().equals("false")) {
// Definition was missing or false, skip this line
continue;
}
// Delete that part of the line
line = line.replace(match.group(0), "");
}
// Don't strip surrounding quotes of the FIRST replace of the line - only do it in nested replacements
boolean isNested = false;
// While there is a line to replace, do it
while (line.contains("@@")) {
match = VAR.matcher(line);
if (!match.find()) {
throw new RuntimeException("Failed to resolve definition in line: " + line);
}
String varName = match.group(1);
Definition def = parser.findDefinition(varName);
String replacement = def != null ? def.toString() : "MISSING DEFINITION";
// Strip off any quotes from the resolved string - we may be trying to concatenate inside a string literal where quotes aren't allowed
while (isNested && replacement.startsWith("\"") && replacement.endsWith("\"")) {
replacement = replacement.substring(1, replacement.length() - 1);
}
line = line.replaceAll(match.group(0), replacement);
if (!isNested) {
isNested = true;
}
}
// TODO: remove extra whitespace from the line
// Copy the line to the output stream
ps.println(line);
}
is.close();
}
public void writeLayoutAndComments(ParseState parser, PrintStream ps) {
StructLayout root = new StructLayout(0, "root", parser.getLastStruct());
TsMetadata meta = new TsMetadata();
// Print configuration layout
int size = root.getSize();
ps.println("pageSize = " + size);
ps.println("page = 1");
root.writeTunerstudioLayout(ps, meta);
ps.println("; total TS size = " + size);
// Print context help
ps.println("[SettingContextHelp]");
meta.writeComments(ps);
}
}

View File

@ -2,22 +2,17 @@ package com.rusefi.test;
import com.rusefi.BitState;
import com.rusefi.ReaderStateImpl;
import com.rusefi.newparse.outputs.OutputChannelWriter;
import com.rusefi.output.DataLogConsumer;
import com.rusefi.output.GaugeConsumer;
import com.rusefi.output.GetOutputValueConsumer;
import com.rusefi.output.OutputsSectionConsumer;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.IOException;
import static com.rusefi.test.newParse.NewParseHelper.parseToOutputChannels;
import static org.junit.Assert.assertEquals;
public class OutputsTest {
@Test
public void generateSomething() throws IOException {
public void generateSomething() {
ReaderStateImpl state = new ReaderStateImpl();
state.getVariableRegistry().register("GAUGE_NAME_FUEL_WALL_CORRECTION", "wall");
String test = "struct total\n" +
@ -29,15 +24,6 @@ public class OutputsTest {
"float tCharge;speed density\n" +
"end_struct\n";
String expected = "root_afr_type = scalar, F32, 0, \"ms\", 1, 0\n" +
"root_afr_typet = scalar, U08, 4, \"ms\", 1, 0\n" +
"root_isForcedInduction = bits, U32, 8, [0:0]\n" +
"root_enableFan1WithAc = bits, U32, 8, [1:1]\n" +
"root_m_requested_pump = scalar, F32, 12, \"\", 1, 0\n" +
"root_tCharge = scalar, F32, 16, \"\", 1, 0\n" +
"; total TS size = 20\n";
assertEquals(expected, parseToOutputChannels(test));
String expectedLegacy = "afr_type = scalar, F32, 0, \"ms\", 1, 0\n" +
"afr_typet = scalar, U08, 4, \"ms\", 1, 0\n" +
"isForcedInduction = bits, U32, 8, [0:0]\n" +
@ -59,9 +45,6 @@ public class OutputsTest {
runOriginalImplementation(test);
}
/**
* while we have {@link OutputChannelWriter} here we use the current 'legacy' implementation
*/
private static OutputsSectionConsumer runOriginalImplementation(String test) {
ReaderStateImpl state = new ReaderStateImpl();

View File

@ -1,307 +0,0 @@
package com.rusefi.test.newParse;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import static com.rusefi.test.newParse.NewParseHelper.parseToOutputChannels;
import static com.rusefi.test.newParse.NewParseHelper.parseToTs;
import static org.junit.Assert.assertEquals;
public class LayoutTest {
@Test
public void singleField() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"int8_t xyz;comment;\"units\", 1, 2, 3, 4, 5\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 4\n" +
"page = 1\n" +
"xyz = scalar, S08, 0, \"units\", 1, 2, 3, 4, 5\n" +
"; unused 3 bytes at offset 1\n" +
"; total TS size = 4\n" +
"[SettingContextHelp]\n" +
"\txyz = \"comment\"\n", parseToTs(input));
Assert.assertEquals(
"xyz = scalar, S08, 0, \"units\", 1, 2\n" +
"; total TS size = 4\n"
, parseToOutputChannels(input));
}
@Test
public void twoFieldsSameSize() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"int32_t abc;;\"\", 1, 2, 3, 4, 5\n" +
"int32_t xyz;;\"\", 6, 7, 8, 9, 10\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 8\n" +
"page = 1\n" +
"abc = scalar, S32, 0, \"\", 1, 2, 3, 4, 5\n" +
"xyz = scalar, S32, 4, \"\", 6, 7, 8, 9, 10\n" +
"; total TS size = 8\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"abc = scalar, S32, 0, \"\", 1, 2\n" +
"xyz = scalar, S32, 4, \"\", 6, 7\n" +
"; total TS size = 8\n", parseToOutputChannels(input));
}
@Test
public void twoFieldsBigThenSmall() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"int32_t abc;;\"\", 1, 2, 3, 4, 5\n" +
"int8_t xyz;;\"\", 6, 7, 8, 9, 10\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 8\n" +
"page = 1\n" +
"abc = scalar, S32, 0, \"\", 1, 2, 3, 4, 5\n" +
"xyz = scalar, S08, 4, \"\", 6, 7, 8, 9, 10\n" +
"; unused 3 bytes at offset 5\n" +
"; total TS size = 8\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"abc = scalar, S32, 0, \"\", 1, 2\n" +
"xyz = scalar, S08, 4, \"\", 6, 7\n" +
"; total TS size = 8\n", parseToOutputChannels(input));
}
@Test
public void twoFieldsSmallThenBig() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"int8_t abc;;\"\", 1, 2, 3, 4, 5\n" +
"int32_t xyz;;\"\", 6, 7, 8, 9, 10\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 8\n" +
"page = 1\n" +
"abc = scalar, S08, 0, \"\", 1, 2, 3, 4, 5\n" +
"; unused 3 bytes at offset 1\n" +
"xyz = scalar, S32, 4, \"\", 6, 7, 8, 9, 10\n" +
"; total TS size = 8\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"abc = scalar, S08, 0, \"\", 1, 2\n" +
"xyz = scalar, S32, 4, \"\", 6, 7\n" +
"; total TS size = 8\n", parseToOutputChannels(input));
}
@Test
public void threeFieldsSmallInMisalignment() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"int16_t abc\n" +
"int8_t def\n" +
"int32_t xyz\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 8\n" +
"page = 1\n" +
"abc = scalar, S16, 0, \"\", 1, 0, 0, 0, 0\n" +
"def = scalar, S08, 2, \"\", 1, 0, 0, 0, 0\n" +
"; unused 1 bytes at offset 3\n" +
"xyz = scalar, S32, 4, \"\", 1, 0, 0, 0, 0\n" +
"; total TS size = 8\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"abc = scalar, S16, 0, \"\", 1, 0\n" +
"def = scalar, S08, 2, \"\", 1, 0\n" +
"xyz = scalar, S32, 4, \"\", 1, 0\n" +
"; total TS size = 8\n", parseToOutputChannels(input));
}
@Test
public void twoFieldsArrayThenBig() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"int8_t[10] abc;;\"\", 1, 2, 3, 4, 5\n" +
"int32_t xyz;;\"\", 6, 7, 8, 9, 10\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 16\n" +
"page = 1\n" +
"abc = array, S08, 0, [10], \"\", 1, 2, 3, 4, 5\n" +
"; unused 2 bytes at offset 10\n" +
"xyz = scalar, S32, 12, \"\", 6, 7, 8, 9, 10\n" +
"; total TS size = 16\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"abc1 = scalar, S08, 0, \"\", 1, 2\n" +
"abc2 = scalar, S08, 1, \"\", 1, 2\n" +
"abc3 = scalar, S08, 2, \"\", 1, 2\n" +
"abc4 = scalar, S08, 3, \"\", 1, 2\n" +
"abc5 = scalar, S08, 4, \"\", 1, 2\n" +
"abc6 = scalar, S08, 5, \"\", 1, 2\n" +
"abc7 = scalar, S08, 6, \"\", 1, 2\n" +
"abc8 = scalar, S08, 7, \"\", 1, 2\n" +
"abc9 = scalar, S08, 8, \"\", 1, 2\n" +
"abc10 = scalar, S08, 9, \"\", 1, 2\n" +
"xyz = scalar, S32, 12, \"\", 6, 7\n" +
"; total TS size = 16\n", parseToOutputChannels(input));
}
@Test
public void singleFieldMultiDimArray() throws IOException {
String ts = parseToTs("struct_no_prefix myStruct\n" +
"int8_t[10 x 5] abc;;\"\", 1, 2, 3, 4, 5\n" +
"end_struct");
Assert.assertEquals(
"pageSize = 52\n" +
"page = 1\n" +
"abc = array, S08, 0, [10x5], \"\", 1, 2, 3, 4, 5\n" +
"; unused 2 bytes at offset 50\n" +
"; total TS size = 52\n" +
"[SettingContextHelp]\n", ts);
}
@Test
public void structs() throws IOException {
String ts = parseToTs(
"struct s1\n" +
"int32_t abc\n" +
"uint8_t def\n" +
"end_struct\n" +
"struct_no_prefix rootStruct\n" +
"s1 a\n" +
"s1 b\n" +
"end_struct");
Assert.assertEquals(
"pageSize = 16\n" +
"page = 1\n" +
"a_abc = scalar, S32, 0, \"\", 1, 0, 0, 0, 0\n" +
"a_def = scalar, U08, 4, \"\", 1, 0, 0, 0, 0\n" +
"; unused 3 bytes at offset 5\n" +
"b_abc = scalar, S32, 8, \"\", 1, 0, 0, 0, 0\n" +
"b_def = scalar, U08, 12, \"\", 1, 0, 0, 0, 0\n" +
"; unused 3 bytes at offset 13\n" +
"; total TS size = 16\n" +
"[SettingContextHelp]\n", ts);
}
@Test
public void arrayIterate() throws IOException {
String input = "struct_no_prefix rootStruct\n" +
"int32_t[4 iterate] myArr\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 16\n" +
"page = 1\n" +
"myArr1 = scalar, S32, 0, \"\", 1, 0, 0, 0, 0\n" +
"myArr2 = scalar, S32, 4, \"\", 1, 0, 0, 0, 0\n" +
"myArr3 = scalar, S32, 8, \"\", 1, 0, 0, 0, 0\n" +
"myArr4 = scalar, S32, 12, \"\", 1, 0, 0, 0, 0\n" +
"; total TS size = 16\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"myArr1 = scalar, S32, 0, \"\", 1, 0\n" +
"myArr2 = scalar, S32, 4, \"\", 1, 0\n" +
"myArr3 = scalar, S32, 8, \"\", 1, 0\n" +
"myArr4 = scalar, S32, 12, \"\", 1, 0\n" +
"; total TS size = 16\n", parseToOutputChannels(input));
}
@Test
public void arrayZeroLength() throws IOException {
String ts = parseToTs(
"struct_no_prefix rootStruct\n" +
"int32_t[0] myArr\n" +
"end_struct");
Assert.assertEquals(
"pageSize = 0\n" +
"page = 1\n" +
"; total TS size = 0\n" +
"[SettingContextHelp]\n", ts);
}
@Test
public void arrayOfStructsIterate() throws IOException {
String ts = parseToTs(
"struct s1\n" +
"uint8_t var1\n" +
"uint16_t var2\n" +
"end_struct\n" +
"struct_no_prefix rootStruct\n" +
"s1[4 iterate] arr\n" +
"end_struct");
Assert.assertEquals(
"pageSize = 16\n" +
"page = 1\n" +
"arr1_var1 = scalar, U08, 0, \"\", 1, 0, 0, 0, 0\n" +
"; unused 1 bytes at offset 1\n" +
"arr1_var2 = scalar, U16, 2, \"\", 1, 0, 0, 0, 0\n" +
"arr2_var1 = scalar, U08, 4, \"\", 1, 0, 0, 0, 0\n" +
"; unused 1 bytes at offset 5\n" +
"arr2_var2 = scalar, U16, 6, \"\", 1, 0, 0, 0, 0\n" +
"arr3_var1 = scalar, U08, 8, \"\", 1, 0, 0, 0, 0\n" +
"; unused 1 bytes at offset 9\n" +
"arr3_var2 = scalar, U16, 10, \"\", 1, 0, 0, 0, 0\n" +
"arr4_var1 = scalar, U08, 12, \"\", 1, 0, 0, 0, 0\n" +
"; unused 1 bytes at offset 13\n" +
"arr4_var2 = scalar, U16, 14, \"\", 1, 0, 0, 0, 0\n" +
"; total TS size = 16\n" +
"[SettingContextHelp]\n", ts);
}
@Test
public void bits() throws IOException {
String input = "struct_no_prefix myStruct\n" +
"bit first\n" +
"bit second\n" +
"bit withOpt,\"a\",\"b\"\n" +
"end_struct";
Assert.assertEquals(
"pageSize = 4\n" +
"page = 1\n" +
"first = bits, U32, 0, [0:0], \"false\", \"true\"\n" +
"second = bits, U32, 0, [1:1], \"false\", \"true\"\n" +
"withOpt = bits, U32, 0, [2:2], \"b\", \"a\"\n" +
"; total TS size = 4\n" +
"[SettingContextHelp]\n", parseToTs(input));
Assert.assertEquals(
"first = bits, U32, 0, [0:0]\n" +
"second = bits, U32, 0, [1:1]\n" +
"withOpt = bits, U32, 0, [2:2]\n" +
"; total TS size = 4\n"
, parseToOutputChannels(input));
}
@Test
public void bigOutputChannels() throws IOException {
String input = "struct_no_prefix total\n" +
"float afr_type;PID dTime;\"ms\", 1, 0, 0, 3000, 0\n" +
"uint8_t afr_typet;@@GAUGE_NAME_FUEL_WALL_CORRECTION@@;\"ms\", 1, 0, 0, 3000, 0\n" +
"bit isForcedInduction;isForcedInduction\\nDoes the vehicle have a turbo or supercharger?\n" +
"bit enableFan1WithAc;+Turn on this fan when AC is on.\n" +
"angle_t m_requested_pump;Computed requested pump \n" +
"float tCharge;speed density\n" +
"end_struct\n";
assertEquals("afr_type = scalar, F32, 0, \"ms\", 1, 0\n" +
"afr_typet = scalar, U08, 4, \"ms\", 1, 0\n" +
"isForcedInduction = bits, U32, 8, [0:0]\n" +
"enableFan1WithAc = bits, U32, 8, [1:1]\n" +
"m_requested_pump = scalar, F32, 12, \"\", 1, 0\n" +
"tCharge = scalar, F32, 16, \"\", 1, 0\n" +
"; total TS size = 20\n", parseToOutputChannels(input));
}
}

View File

@ -1,65 +0,0 @@
package com.rusefi.test.newParse;
import com.rusefi.RusefiParseErrorStrategy;
import com.rusefi.newparse.ParseState;
import com.rusefi.newparse.outputs.CStructWriter;
import com.rusefi.newparse.outputs.OutputChannelWriter;
import com.rusefi.newparse.outputs.PrintStreamAlwaysUnix;
import com.rusefi.newparse.outputs.TsWriter;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class NewParseHelper {
public static ParseState parse(String input) throws IOException {
ParseState parseState = new ParseState();
RusefiParseErrorStrategy.parseDefinitionString(parseState.getListener(), input);
return parseState;
}
// TODO: We have to move either forward or backwards with newparse #4441
public static String parseToTs(String input) throws IOException {
ParseState state = parse(input);
TsWriter writer = new TsWriter();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final String utf8 = StandardCharsets.UTF_8.name();
PrintStream ps = new PrintStreamAlwaysUnix(baos, true, utf8);
writer.writeLayoutAndComments(state, ps);
return baos.toString(utf8);
}
public static String parseToOutputChannels(String input) throws IOException {
ParseState state = parse(input);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final String utf8 = StandardCharsets.UTF_8.name();
PrintStream ps = new PrintStreamAlwaysUnix(baos, true, utf8);
OutputChannelWriter writer = new OutputChannelWriter(ps);
writer.writeOutputChannels(state, null);
return baos.toString(utf8);
}
// TODO: We have to move either forward or backwards with newparse #4441
public static String parseToC(String input) throws IOException {
ParseState state = parse(input);
CStructWriter writer = new CStructWriter();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final String utf8 = StandardCharsets.UTF_8.name();
PrintStream ps = new PrintStreamAlwaysUnix(baos, true, utf8);
writer.writeCStructs(state, ps);
return baos.toString(utf8);
}
}

View File

@ -1,147 +0,0 @@
package com.rusefi.test.newParse;
import com.rusefi.RusefiParseErrorStrategy;
import com.rusefi.newparse.ParseState;
import com.rusefi.newparse.parsing.Definition;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import static com.rusefi.test.newParse.NewParseHelper.parse;
public class ParseDefinitionsTest {
@Test
public void basicIntegerDefinition() throws IOException {
ParseState state = parse("#define foo 123");
Assert.assertNull(state.findDefinition("notFoo"));
Definition def = state.findDefinition("foo");
Assert.assertTrue(def.isNumeric());
Assert.assertEquals(123, def.asDouble(), 1e-5);
Definition defHex = state.findDefinition("foo_16_hex");
Assert.assertFalse(defHex.isNumeric());
Assert.assertEquals("\\x00\\x7b", defHex.value);
}
@Test
public void basicDoubleDefinition() throws IOException {
ParseState state = parse("#define foo 123.5");
Definition def = state.findDefinition("foo");
Assert.assertTrue(def.isNumeric());
Assert.assertEquals(123.5, def.asDouble(), 1e-5);
}
@Test
public void basicStringDefinition() throws IOException {
ParseState state = parse("#define foo \"fooValue\"");
Definition def = state.findDefinition("foo");
Assert.assertFalse(def.isNumeric());
Assert.assertTrue(def.value instanceof String);
Assert.assertEquals("\"fooValue\"", def.value);
}
@Test
public void definitionWithNumexprValue() throws IOException {
ParseState state = parse("#define foo 5 + 8 * 2 + 3");
Definition def = state.findDefinition("foo");
Assert.assertTrue(def.isNumeric());
Assert.assertEquals(24, def.asDouble(), 1e-5);
}
@Test
public void definitionWithAnotherDefinition() throws IOException {
ParseState state = parse(
"#define val1 20\n" +
"#define val2 val1 + 1\n" +
"#define val3 3 * @@val2@@");
Definition def1 = state.findDefinition("val1");
Assert.assertTrue(def1.isNumeric());
Assert.assertEquals(20, def1.asDouble(), 1e-5);
Definition def2 = state.findDefinition("val2");
Assert.assertTrue(def2.isNumeric());
Assert.assertEquals(21, def2.asDouble(), 1e-5);
Definition def3 = state.findDefinition("val3");
Assert.assertTrue(def3.isNumeric());
Assert.assertEquals(63, def3.asDouble(), 1e-5);
}
@Test(expected = RuntimeException.class)
public void definitionEvalMissingDefinition() throws IOException {
parse(
"#define val1 20\n" +
"#define val2 val1 + 1\n" +
"#define val3 3 * valgggggg"
);
}
@Test(expected = RuntimeException.class)
public void definitionEvalNonNumeric() throws IOException {
parse(
"#define val1 \"foo\"\n" +
"#define val2 val1 + 1"
);
}
@Test
public void definitionOverwritePolicyReplace() throws IOException {
ParseState state = new ParseState();
state.setDefinitionPolicy(Definition.OverwritePolicy.Replace);
RusefiParseErrorStrategy.parseDefinitionString(state.getListener(), "#define val 20");
Definition def = state.findDefinition("val");
Assert.assertEquals(20, def.asDouble(), 1e-5);
// Now parse another definition with the same name
RusefiParseErrorStrategy.parseDefinitionString(state.getListener(), "#define val 40");
// Should get back the new definition, not the old one
Definition def2 = state.findDefinition("val");
Assert.assertTrue(def != def2);
Assert.assertEquals(40, def2.asDouble(), 1e-5);
}
@Test
public void definitionOverwritePolicyIgnoreNew() throws IOException {
ParseState state = new ParseState();
state.setDefinitionPolicy(Definition.OverwritePolicy.IgnoreNew);
RusefiParseErrorStrategy.parseDefinitionString(state.getListener(), "#define val 20");
Definition def = state.findDefinition("val");
Assert.assertEquals(20, def.asDouble(), 1e-5);
// Now parse another definition with the same name
state.setDefinitionPolicy(Definition.OverwritePolicy.IgnoreNew);
RusefiParseErrorStrategy.parseDefinitionString(state.getListener(), "#define val 40");
// New one ignored, still returns the same old one.
Assert.assertEquals(def, state.findDefinition("val"));
Assert.assertEquals(20, def.asDouble(), 1e-5);
}
@Test(expected = IllegalStateException.class)
public void definitionOverwritePolicyNotAllowed() throws IOException {
ParseState state = new ParseState();
state.setDefinitionPolicy(Definition.OverwritePolicy.NotAllowed);
RusefiParseErrorStrategy.parseDefinitionString(state.getListener(), "#define val 20");
Definition def = state.findDefinition("val");
Assert.assertEquals(20, def.asDouble(), 1e-5);
// Now parse another definition with the same name, this should throw
RusefiParseErrorStrategy.parseDefinitionString(state.getListener(), "#define val 40");
}
}

View File

@ -1,342 +0,0 @@
package com.rusefi.test.newParse;
import com.rusefi.newparse.ParseState;
import com.rusefi.newparse.parsing.*;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static com.rusefi.test.newParse.NewParseHelper.parse;
public class ParseStructTest {
@Test
public void structEmpty() throws IOException {
ParseState state = parse(
"struct myStruct\n\n" +
"end_struct\n"
);
// Parsed exactly one struct
Assert.assertEquals(1, state.getStructs().size());
Struct myStruct = state.getStructs().get(0);
// It's a real struct!
Assert.assertNotNull(myStruct);
// Check that it was parsed correctly
Assert.assertEquals("myStruct", myStruct.name);
Assert.assertEquals(0, myStruct.fields.size());
Assert.assertEquals(false, myStruct.noPrefix);
Assert.assertEquals(state.getStructs().get(0), state.getLastStruct());
}
@Test
public void structEmptyNoPrefix() throws IOException {
ParseState state = parse(
"struct_no_prefix myStruct\n\n" +
"end_struct\n"
);
Struct myStruct = state.getStructs().get(0);
// Check that this one is marked as no prefix
Assert.assertEquals(true, myStruct.noPrefix);
}
@Test
public void structMultiple() throws IOException {
ParseState state = parse(
"struct myStruct1\n\n" +
"end_struct\n" +
"struct myStruct2\n\n" +
"end_struct\n"
);
// Now there are two structs!
Assert.assertEquals(2, state.getStructs().size());
Assert.assertEquals("myStruct1", state.getStructs().get(0).name);
Assert.assertEquals("myStruct2", state.getStructs().get(1).name);
// Check that get last struct returns the last one
Assert.assertEquals(state.getStructs().get(1), state.getLastStruct());
}
@Test
public void structNested() throws IOException {
ParseState state = parse(
"struct myStructOuter\n" +
"struct myStructInner\n\n" +
"end_struct\n" +
"end_struct\n"
);
// Now there are two structs!
Assert.assertEquals(2, state.getStructs().size());
Assert.assertEquals("myStructInner", state.getStructs().get(0).name);
Assert.assertEquals("myStructOuter", state.getStructs().get(1).name);
// Check that get last struct returns the outer one
Assert.assertEquals(state.getStructs().get(1), state.getLastStruct());
}
@Test
public void structContainsStruct() throws IOException {
ParseState state = parse(
"struct myStruct\n\n" +
"end_struct\n" +
"struct myStruct2\n" +
"myStruct foo\n" +
"end_struct"
);
Assert.assertEquals(2, state.getStructs().size());
Struct inner = state.getStructs().get(0);
Assert.assertEquals(0, inner.fields.size());
// Check that the outer contains a struct
Struct outer = state.getStructs().get(1);
Assert.assertEquals(1, outer.fields.size());
Assert.assertTrue(outer.fields.get(0) instanceof StructField);
}
@Test(expected = RuntimeException.class)
public void structMissingStruct() throws IOException {
parse(
"struct myStruct2\n" +
"myStruct foo\n" +
"end_struct"
);
}
private static Field parseSingleField(String fieldLine) throws IOException {
ParseState state = parse(
"struct myStruct\n" +
fieldLine + "\n" +
"end_struct\n"
);
List<Field> fields = state.getLastStruct().fields;
Assert.assertEquals(1, fields.size());
return fields.get(0);
}
@Test
public void scalarOptions() throws IOException {
Field f = parseSingleField("int foo;comment;\"units\", 1, 2, 3, 4, 5");
ScalarField sf = (ScalarField) f;
FieldOptions opt = sf.options;
Assert.assertEquals("comment", opt.comment);
Assert.assertEquals("\"units\"", opt.units);
Assert.assertEquals(1, opt.scale, 0.001f);
Assert.assertEquals(2, opt.offset, 0.001f);
Assert.assertEquals(3, opt.min, 0.001f);
Assert.assertEquals(4, opt.max, 0.001f);
Assert.assertEquals(5, opt.digits);
}
private static void checkType(String inputType, int size, String cType, String tsType) throws IOException {
ScalarField sf = (ScalarField) parseSingleField(inputType + " foo");
Assert.assertEquals("foo", sf.name);
Assert.assertEquals(false, sf.autoscale);
Assert.assertEquals(size, sf.type.size);
Assert.assertEquals(cType, sf.type.cType);
Assert.assertEquals(tsType, sf.type.tsType);
}
@Test
public void typeMappings() throws IOException {
checkType("int", 4, "int", "S32");
checkType("int8_t", 1, "int8_t", "S08");
checkType("int16_t", 2, "int16_t", "S16");
checkType("int32_t", 4, "int32_t", "S32");
checkType("uint8_t", 1, "uint8_t", "U08");
checkType("uint16_t", 2, "uint16_t", "U16");
checkType("uint32_t", 4, "uint32_t", "U32");
checkType("float", 4, "float", "F32");
}
@Test
public void arraySingleDimension() throws IOException {
Field f = parseSingleField("uint8_t[10] testBins");
Assert.assertTrue(f instanceof ArrayField);
ArrayField af = (ArrayField)f;
Assert.assertEquals(1, af.length.length);
Assert.assertEquals(10, af.length[0]);
PrototypeField prototype = af.prototype;
Assert.assertTrue(prototype instanceof ScalarField);
}
@Test
public void arrayMultiDimension() throws IOException {
Field f = parseSingleField("uint8_t[5 x 8] testBins");
Assert.assertTrue(f instanceof ArrayField);
ArrayField af = (ArrayField)f;
Assert.assertEquals(2, af.length.length);
Assert.assertEquals(5, af.length[0]);
Assert.assertEquals(8, af.length[1]);
}
@Test
public void arrayIterate() throws IOException {
Field f = parseSingleField("uint8_t[10 iterate] testBins");
Assert.assertTrue(f instanceof ArrayField);
ArrayField af = (ArrayField)f;
Assert.assertEquals(true, af.iterate);
}
@Test(expected = IllegalStateException.class)
public void checkMultiDimensionArrayIterateThrows() throws IOException {
parseSingleField("uint8_t[5 x 8 iterate] testBins");
}
@Test
public void arrayOfStructs() throws IOException {
ParseState state = parse(
"struct myStruct\n\n" +
"end_struct\n" +
"struct myStruct2\n" +
"myStruct[5 iterate] foo\n" +
"end_struct"
);
Assert.assertEquals(2, state.getStructs().size());
// Inner should be empty
Struct inner = state.getStructs().get(0);
Assert.assertEquals(0, inner.fields.size());
// Check that the outer contains an array of structs
Struct outer = state.getStructs().get(1);
Assert.assertEquals(1, outer.fields.size());
ArrayField af = (ArrayField)outer.fields.get(0);
// Check length and that it contains a struct
Assert.assertEquals(1, af.length.length);
Assert.assertEquals(5, af.length[0]);
Assert.assertTrue(af.prototype instanceof StructField);
}
@Test
public void typedefScalar() throws IOException {
ParseState ps = parse("custom myTypedef 4 scalar, F32, @OFFSET@, \"unit\", 1, 2, 3, 4, 5\n" +
"struct myStruct\n" +
"myTypedef foo;comment\n" +
"end_struct");
ScalarField sf = (ScalarField)ps.getLastStruct().fields.get(0);
Assert.assertEquals("foo", sf.name);
Assert.assertEquals(false, sf.autoscale);
Assert.assertEquals(4, sf.type.size);
Assert.assertEquals("float", sf.type.cType);
Assert.assertEquals("F32", sf.type.tsType);
FieldOptions opt = sf.options;
Assert.assertEquals("comment", opt.comment);
Assert.assertEquals("\"unit\"", opt.units);
Assert.assertEquals(1, opt.scale, 0.001f);
Assert.assertEquals(2, opt.offset, 0.001f);
Assert.assertEquals(3, opt.min, 0.001f);
Assert.assertEquals(4, opt.max, 0.001f);
Assert.assertEquals(5, opt.digits);
}
@Test
public void typedefString() throws IOException {
ParseState ps = parse("custom lua_script_t 1000 string, ASCII, @OFFSET@, 1000\n" +
"struct myStruct\n" +
"lua_script_t luaScript\n" +
"end_struct");
StringField sf = (StringField)ps.getLastStruct().fields.get(0);
Assert.assertEquals("luaScript", sf.name);
Assert.assertEquals(1000, sf.size);
}
@Test
public void unused() throws IOException {
ParseState state = parse(
"struct_no_prefix myStruct\n" +
"unused 27\n" +
"end_struct\n"
);
UnusedField uf = (UnusedField)state.getLastStruct().fields.get(0);
Assert.assertEquals(27, uf.size);
}
@Test
public void bitFieldsBasic() throws IOException {
ParseState state = parse(
"struct_no_prefix myStruct\n" +
"bit myBit1\n" +
"bit myBit2\n" +
"end_struct\n"
);
BitGroup bf = (BitGroup)state.getLastStruct().fields.get(0);
Assert.assertEquals(2, bf.bitFields.size());
Assert.assertEquals("myBit1", bf.bitFields.get(0).name);
Assert.assertEquals("myBit2", bf.bitFields.get(1).name);
}
@Test
public void bitFieldsAdvanced() throws IOException {
ParseState state = parse(
"struct_no_prefix myStruct\n" +
"bit myBit,\"a\",\"b\";comment\n" +
"end_struct\n"
);
BitGroup bg = (BitGroup)state.getLastStruct().fields.get(0);
BitField bf = bg.bitFields.get(0);
Assert.assertEquals("myBit", bf.name);
Assert.assertEquals("\"a\"", bf.trueValue);
Assert.assertEquals("\"b\"", bf.falseValue);
Assert.assertEquals("comment", bf.comment);
}
@Test
public void bitFieldsThirtyThreeBits() throws IOException {
StringBuilder input = new StringBuilder("struct myStruct\n");
for (int i = 0; i < 33; i++) {
input.append("bit myBit").append(i).append("\n");
}
input.append("end_struct\n");
ParseState state = parse(input.toString());
Assert.assertEquals(2, state.getLastStruct().fields.size());
Assert.assertEquals(32, ((BitGroup)state.getLastStruct().fields.get(0)).bitFields.size());
Assert.assertEquals(1, ((BitGroup)state.getLastStruct().fields.get(1)).bitFields.size());
}
}