Whatever we call it, no matter how we do it - we need live data / remote view into rusEFI actual state #3353

progress
This commit is contained in:
rusefillc 2021-10-14 14:46:05 -04:00
parent 372ad65894
commit 184fe9c213
7 changed files with 232 additions and 93 deletions

View File

@ -0,0 +1,146 @@
package com.rusefi.livedata;
import com.devexperts.logging.Logging;
import com.rusefi.livedata.generated.CPP14Lexer;
import com.rusefi.livedata.generated.CPP14Parser;
import com.rusefi.livedata.generated.CPP14ParserBaseListener;
import com.rusefi.ui.livedata.Range;
import com.rusefi.ui.livedata.SourceCodePainter;
import com.rusefi.ui.livedata.VariableValueSource;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Stack;
import static com.devexperts.logging.Logging.getLogging;
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
public class LiveDataParserPanel {
private static final Logging log = getLogging(LiveDataParserPanel.class);
private final JPanel content = new JPanel(new BorderLayout());
public LiveDataParserPanel(VariableValueSource valueSource) {
JTextPane text = new JTextPane();
JScrollPane rightScrollPane = new JScrollPane(text,
VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
content.add(rightScrollPane);
try {
String sourceCode = getContent(getClass(), "ac_control.cpp");
text.setText(sourceCode);
ParseTree tree = getParseTree(sourceCode);
StyleContext sc = StyleContext.getDefaultStyleContext();
StyledDocument style = text.getStyledDocument();
AttributeSet oldSet = style.getCharacterElement(0).getAttributes();
applyVariables(valueSource, sourceCode, new SourceCodePainter() {
@Override
public void paint(Color color, Range range) {
AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Background, color);
style.setCharacterAttributes(range.getStart(), range.getLength(), s, true);
}
}, tree);
} catch (IOException | URISyntaxException e) {
log.warn("Error reading: " + e);
}
}
public static String getContent(Class<?> clazz, String fileName) throws IOException, URISyntaxException {
URL cpp = clazz.getResource("/c_sources/" + fileName);
String line;
StringBuilder result = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(new File(cpp.toURI())))) {
while ((line = br.readLine()) != null) {
result.append(line + "\n");
}
}
return result.toString();
}
@NotNull
public static ParseTree getParseTree(String sourceCode) throws IOException {
CharStream in = new ANTLRInputStream(new ByteArrayInputStream(sourceCode.getBytes()));
CPP14Parser parser = new CPP14Parser(new CommonTokenStream(new CPP14Lexer(in)));
return parser.translationUnit();
}
public static void applyVariables(VariableValueSource valueSource, String s, SourceCodePainter painter, ParseTree tree) {
Stack<Boolean> currentState = new Stack<>();
currentState.add(Boolean.TRUE);
new ParseTreeWalker().walk(new CPP14ParserBaseListener() {
@Override
public void enterStatement(CPP14Parser.StatementContext ctx) {
String origin = getOrigin(ctx, s);
System.out.println("enter statement [" + origin + "]");
}
@Override
public void enterCondition(CPP14Parser.ConditionContext ctx) {
String conditionVariable = ctx.getText();
System.out.println("REQUESTING VALUE " + conditionVariable);
System.out.println("exp " + getOrigin(ctx.expression(), s));
Boolean state = (Boolean) valueSource.getValue(conditionVariable);
if (state == null) {
// todo: fail on unknown condition variables
return;
}
if (state) {
painter.paint(Color.GREEN, new Range(ctx));
} else {
painter.paint(Color.RED, new Range(ctx));
}
}
@Override
public void enterSelectionStatement(CPP14Parser.SelectionStatementContext ctx) {
super.enterSelectionStatement(ctx);
System.out.println("Else terminal " + ctx.Else());
}
@Override
public void enterJumpStatement(CPP14Parser.JumpStatementContext ctx) {
}
}, tree);
}
@NotNull
private static String getOrigin(ParserRuleContext ctx, String s) {
Range range = new Range(ctx);
return s.substring(range.getStart(), range.getStop());
}
public JPanel getContent() {
return content;
}
}

View File

@ -0,0 +1,29 @@
package com.rusefi.ui.livedata;
import org.antlr.v4.runtime.ParserRuleContext;
public class Range {
private final int start;
private final int stop;
public Range(int start, int stop) {
this.start = start;
this.stop = stop;
}
public Range(ParserRuleContext context) {
this(context.start.getStartIndex(), context.stop.getStopIndex() + 1);
}
public int getStart() {
return start;
}
public int getStop() {
return stop;
}
public int getLength() {
return stop - start;
}
}

View File

@ -0,0 +1,7 @@
package com.rusefi.ui.livedata;
import java.awt.*;
public interface SourceCodePainter {
void paint(Color color, Range range);
}

View File

@ -0,0 +1,5 @@
package com.rusefi.ui.livedata;
public interface VariableValueSource {
Object getValue(String name);
}

View File

@ -0,0 +1,27 @@
package com.rusefi.livedata;
import com.rusefi.core.ValueSource;
import com.rusefi.ui.livedata.LiveDataParserTest;
import com.rusefi.ui.livedata.VariableValueSource;
import com.rusefi.ui.util.FrameHelper;
import java.util.Map;
import java.util.TreeMap;
public class LiveDataParserSandbox {
public static void main(String[] args) {
Map<String, Object> values = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
values.put("engineTooSlow", Boolean.TRUE);
values.put("engineTooFast", Boolean.FALSE);
VariableValueSource valueSource = new VariableValueSource() {
@Override
public Object getValue(String name) {
return values.get(name);
}
};
new FrameHelper().showFrame(new LiveDataParserPanel(valueSource).getContent());
}
}

View File

@ -1,11 +1,6 @@
package com.rusefi.ui.livedata;
import com.rusefi.livedata.generated.CPP14Lexer;
import com.rusefi.livedata.generated.CPP14Parser;
import com.rusefi.livedata.generated.CPP14ParserBaseListener;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import com.rusefi.livedata.LiveDataParserPanel;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
@ -13,11 +8,8 @@ import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
public class LiveDataParserTest {
@ -27,14 +19,13 @@ public class LiveDataParserTest {
values.put("engineTooSlow", Boolean.TRUE);
values.put("engineTooFast", Boolean.FALSE);
ValueSource valueSource = new ValueSource() {
VariableValueSource valueSource = new VariableValueSource() {
@Override
public Object getValue(String name) {
return values.get(name);
}
};
String s = "bool AcState::getAcState(DECLARE_ENGINE_PARAMETER_SIGNATURE) {\n" +
"\tauto rpm = Sensor::getOrZero(SensorType::Rpm);\n" +
"\n" +
@ -51,85 +42,19 @@ public class LiveDataParserTest {
"\t} \n " +
"return ff;\n" +
"}";
CharStream in = new ANTLRInputStream(new ByteArrayInputStream(s.getBytes()));
CPP14Parser parser = new CPP14Parser(new CommonTokenStream(new CPP14Lexer(in)));
ParseTree tree = parser.translationUnit();
SourceCodePainter painter = new SourceCodePainter() {
@Override
public void paint(Color color, Range range) {
System.out.println("paint " + color + " " + range);
}
};
ParseTree tree = LiveDataParserPanel.getParseTree(s);
new ParseTreeWalker().walk(new PrintCPP14ParserListener(), tree);
Stack<Boolean> currentState = new Stack<>();
currentState.add(Boolean.TRUE);
LiveDataParserPanel.applyVariables(valueSource, s, painter, tree);
new ParseTreeWalker().walk(new CPP14ParserBaseListener() {
@Override
public void enterStatement(CPP14Parser.StatementContext ctx) {
String origin = getOrigin(ctx, s);
System.out.println("enter statement [" + origin + "]");
}
@Override
public void enterCondition(CPP14Parser.ConditionContext ctx) {
String conditionVariable = ctx.getText();
System.out.println("REQUESTING VALUE " + conditionVariable);
System.out.println("exp " + getOrigin(ctx.expression(), s));
Boolean state = (Boolean) valueSource.getValue(conditionVariable);
if (state == null) {
// todo: fail on unknown condition variables
return;
}
if (state) {
//paint(Color.GREEN, ctx.)
}
}
@Override
public void enterSelectionStatement(CPP14Parser.SelectionStatementContext ctx) {
super.enterSelectionStatement(ctx);
System.out.println("Else terminal " + ctx.Else());
}
@Override
public void enterJumpStatement(CPP14Parser.JumpStatementContext ctx) {
}
}, tree);
}
@NotNull
private String getOrigin(ParserRuleContext ctx, String s) {
Range range = new Range(ctx);
return s.substring(range.start, range.stop);
}
interface ValueSource {
Object getValue(String name);
}
static class Range {
private final int start;
private final int stop;
public Range(int start, int stop) {
this.start = start;
this.stop = stop;
}
public Range(ParserRuleContext context) {
this(context.start.getStartIndex(), context.stop.getStopIndex() + 1);
}
public int getStart() {
return start;
}
public int getStop() {
return stop;
}
}
}

View File

@ -1,20 +1,20 @@
package com.rusefi.ui.livedata;
import com.rusefi.livedata.LiveDataParserPanel;
import org.junit.Test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import static org.junit.Assert.assertNotNull;
public class SourceReaderTest {
@Test
public void testResourceLocated() throws URISyntaxException, FileNotFoundException {
URL cpp = getClass().getResource("/c_sources/ac_control.cpp");
assertNotNull(cpp);
new FileReader(new File(cpp.toURI()));
public void testResourceLocated() throws URISyntaxException, IOException {
String fileName = "ac_control.cpp";
String content = LiveDataParserPanel.getContent(getClass(), fileName);
assertNotNull(content);
}
}