From 91824e9d9c0fb18b91b9bca629ffe088cf260104 Mon Sep 17 00:00:00 2001 From: Nik Klassen Date: Mon, 13 Jun 2016 11:23:34 -0400 Subject: [PATCH 1/3] Convert imports to expressions --- src/main/antlr4/Manifold.g4 | 8 +- .../front/ExpressionContextVisitor.java | 73 +++++++++++- .../compiler/front/ExpressionGraph.java | 28 ++++- .../compiler/front/ExpressionGraphParser.java | 86 ++++++++++++++ .../compiler/front/ExpressionVertex.java | 1 + .../compiler/front/FunctionValueVertex.java | 2 +- .../compiler/front/ImportTypeValue.java | 29 +++++ .../manifold/compiler/front/ImportValue.java | 37 ++++++ .../manifold/compiler/front/ImportVertex.java | 81 +++++++++++++ .../compiler/front/ImportVisitor.java | 27 ----- .../org/manifold/compiler/front/Main.java | 111 +----------------- .../compiler/front/NamedEntryTypeValue.java | 7 ++ .../compiler/front/NamedEntryValue.java | 7 ++ .../compiler/front/NodeValueVertex.java | 10 +- .../front/StaticAttributeAccessVertex.java | 41 +++++-- .../compiler/front/TupleTypeValue.java | 16 ++- .../manifold/compiler/front/TupleValue.java | 9 +- tests/acceptance/import.manifold | 4 +- tests/acceptance/import.manifold.schematic | 24 ++-- tests/acceptance/importSystem.manifold | 6 +- tests/acceptance/importTuple.manifold | 4 +- .../acceptance/importTuple.manifold.schematic | 16 +-- .../importFileWithError.manifold.error | 1 + tests/buildErrors/importRedefineVar.manifold | 3 - .../importRedefineVar.manifold.error | 1 - 25 files changed, 424 insertions(+), 208 deletions(-) create mode 100644 src/main/java/org/manifold/compiler/front/ExpressionGraphParser.java create mode 100644 src/main/java/org/manifold/compiler/front/ImportTypeValue.java create mode 100644 src/main/java/org/manifold/compiler/front/ImportValue.java create mode 100644 src/main/java/org/manifold/compiler/front/ImportVertex.java delete mode 100644 src/main/java/org/manifold/compiler/front/ImportVisitor.java create mode 100644 src/main/java/org/manifold/compiler/front/NamedEntryTypeValue.java create mode 100644 src/main/java/org/manifold/compiler/front/NamedEntryValue.java delete mode 100644 tests/buildErrors/importRedefineVar.manifold delete mode 100644 tests/buildErrors/importRedefineVar.manifold.error diff --git a/src/main/antlr4/Manifold.g4 b/src/main/antlr4/Manifold.g4 index f1f4594..432d38d 100644 --- a/src/main/antlr4/Manifold.g4 +++ b/src/main/antlr4/Manifold.g4 @@ -83,6 +83,7 @@ rvalue: | VISIBILITY_PUBLIC? lvalue '=' rvalue # AssignmentExpression | 'primitive' 'port' typevalue (':' tupleTypeValue)? # PrimitivePortDefinitionExpression | 'primitive' 'node' functionTypeValue # PrimitiveNodeDefinitionExpression + | 'import' STRING_VALUE #ImportExpr ; lvalue: @@ -97,11 +98,6 @@ expression: // | declaration ; -statement: - expression #ExpressionStatment - | 'import' STRING_VALUE #ImportStatement - ; - STATEMENT_TERMINATOR: ';'; @@ -111,4 +107,4 @@ STATEMENT_TERMINATOR: ';'; // // //////////////////////////////////////////////////////// -schematic: (statement STATEMENT_TERMINATOR)*; +schematic: (expression STATEMENT_TERMINATOR)*; diff --git a/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java b/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java index fb5c782..0704d98 100644 --- a/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java +++ b/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java @@ -14,13 +14,21 @@ import org.manifold.parser.ManifoldLexer; import org.manifold.parser.ManifoldParser.*; +import java.io.File; +import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.stream.Stream; class ExpressionContextVisitor extends ManifoldBaseVisitor { + private ExpressionGraphParser parser; private ExpressionGraph exprGraph; + private File inputFile; + private List errors; + public ExpressionGraph getExpressionGraph() { return this.exprGraph; } @@ -32,12 +40,27 @@ public ExpressionGraph getExpressionGraph() { private boolean isPublic = false; private int nextTmpVar = 0; - public ExpressionContextVisitor() { - this(new ExpressionGraph()); + public ExpressionContextVisitor(File inputFile) { + this(new ExpressionGraph(), inputFile); } - public ExpressionContextVisitor(ExpressionGraph exprGraph) { + public ExpressionContextVisitor(ExpressionGraph exprGraph, File inputFile) { + this.inputFile = inputFile; + this.parser = new ExpressionGraphParser(); this.exprGraph = exprGraph; + this.errors = new ArrayList<>(); + } + + public List getErrors() { + return errors; + } + + private File getLib(String libPath) { + URL url = this.getClass().getClassLoader().getResource("libraries/" + libPath); + if (url == null) { + return null; + } + return new File(url.getFile()); } @Override @@ -81,7 +104,7 @@ public ExpressionVertex visitFunctionInvocationExpression( public ExpressionVertex visitFunctionValue( FunctionValueContext ctx) { ExpressionContextVisitor functionGraphBuilder = - new ExpressionContextVisitor(); + new ExpressionContextVisitor(inputFile); ctx.expression().forEach(functionGraphBuilder::visit); ExpressionGraph fSubGraph = functionGraphBuilder.getExpressionGraph(); @@ -315,8 +338,46 @@ private ExpressionVertex createVariableVertex(VariableIdentifier id) { } @Override - public ExpressionVertex visitImportStatement(ImportStatementContext context) { - return null; + public ExpressionVertex visitImportExpr(ImportExprContext context) { + String importString = context.STRING_VALUE().getText() + .replaceAll("\\\"", "\""); + importString = importString.substring(1, importString.length() - 1); + + // Reassign to a new variable to satisfy the lambda requirement of "final" variables + String filePath = importString; + + File importedFile = Stream.of( + new File(inputFile.getParent(), filePath), + new File(inputFile.getParent(), filePath + ".manifold") + ).filter(f -> f.exists()) + .findFirst() + .orElseGet(() -> { + File lib = getLib(filePath); + if (lib == null) { + lib = getLib(filePath + ".manifold"); + } + if (lib != null) { + return lib; + } + errors.add("Import " + filePath + " not found"); + return null; + }); + if (importedFile == null) { + return null; + } + + ExpressionGraph g; + try { + g = parser.parseFile(importedFile); + } catch (Exception e) { + errors.add(e.getMessage().trim()); + errors.add("Error while parsing included file " + filePath); + return null; + } + + ExpressionVertex v = new ImportVertex(exprGraph, g); + exprGraph.addVertex(v); + return v; } @Override diff --git a/src/main/java/org/manifold/compiler/front/ExpressionGraph.java b/src/main/java/org/manifold/compiler/front/ExpressionGraph.java index c40079a..1e0da83 100644 --- a/src/main/java/org/manifold/compiler/front/ExpressionGraph.java +++ b/src/main/java/org/manifold/compiler/front/ExpressionGraph.java @@ -4,6 +4,7 @@ import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.antlr.v4.runtime.misc.Nullable; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.manifold.compiler.UndefinedBehaviourError; @@ -13,6 +14,8 @@ import java.io.FileWriter; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ExpressionGraph { @@ -29,9 +32,18 @@ public Map getVariableVertices() { /** * Copy everything from subGraph into this graph * @param subGraph the graph to copy - * @param importVars should the visibility modifiers in subGraph are respected */ - public void addSubGraph(ExpressionGraph subGraph, boolean importVars) { + public void addSubGraph(ExpressionGraph subGraph) { + addSubGraph(subGraph, null); + } + + /** + * Copy all vertices from subGraph into this graph. + * @param subGraph the graph to copy + * @param namespace The namespace for any exported variables. If this is null all variables will be exported under + * the same name. + */ + public void addSubGraph(ExpressionGraph subGraph, @Nullable NamespaceIdentifier namespace) { // map of subgraph edge -> new edge to be inserted Map exprEdgeMap = new HashMap<>(); subGraph.getEdges().forEach(e -> { @@ -42,6 +54,7 @@ public void addSubGraph(ExpressionGraph subGraph, boolean importVars) { // map of subgraph vertex -> new vertex Map exprVertexMap = new HashMap<>(); + List oldNs = namespace == null ? new ArrayList<>() : namespace.getName(); // do not add the input/output vertices since they are being replaced by the main graph's vertices subGraph.getVertices().stream() @@ -51,8 +64,13 @@ public void addSubGraph(ExpressionGraph subGraph, boolean importVars) { VariableReferenceVertex var = (VariableReferenceVertex) v; // Allow for ignoring the state of import, this is the case when this function // is used to copy the body of a FunctionValueVertex - if (var.getExported() || !importVars) { - VariableIdentifier ref = var.getId(); + if (namespace == null || var.getExported()) { + List newNs = + Stream.concat( + oldNs.stream(), + var.getId().getNamespaceIdentifier().getName().stream()) + .collect(Collectors.toList()); + VariableIdentifier ref = new VariableIdentifier(new NamespaceIdentifier(newNs), var.getId().getName()); try { this.addVertex(ref); newVertex = this.getVariableVertex(ref); @@ -61,6 +79,8 @@ public void addSubGraph(ExpressionGraph subGraph, boolean importVars) { } } else { newVertex = new VariableReferenceVertex(this, var.getId()); + // Uses the ExpressionVertex overload which will add this node to the non-variable vertices, + // instead of variable this.addVertex(newVertex); } } else { diff --git a/src/main/java/org/manifold/compiler/front/ExpressionGraphParser.java b/src/main/java/org/manifold/compiler/front/ExpressionGraphParser.java new file mode 100644 index 0000000..37f7b83 --- /dev/null +++ b/src/main/java/org/manifold/compiler/front/ExpressionGraphParser.java @@ -0,0 +1,86 @@ +package org.manifold.compiler.front; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.ATNConfigSet; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.NotNull; +import org.antlr.v4.runtime.misc.Nullable; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.manifold.parser.ManifoldLexer; +import org.manifold.parser.ManifoldParser; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.BitSet; +import java.util.List; + +public class ExpressionGraphParser { + + private static Logger log = LogManager.getLogger("ExpressionGraphParser"); + + public ExpressionGraph parseFile(File inputFile) throws IOException { + ManifoldLexer lexer = new ManifoldLexer(new ANTLRInputStream( + new FileInputStream(inputFile))); + + // Get a list of matched tokens + CommonTokenStream tokens = new CommonTokenStream(lexer); + + // Pass the tokens to the parser + ManifoldParser parser = new ManifoldParser(tokens); + + StringBuilder errors = new StringBuilder(); + parser.addErrorListener(new ANTLRErrorListener() { + + @Override + public void syntaxError(@NotNull Recognizer recognizer, @Nullable Object offendingSymbol, int line, + int charPositionInLine, @NotNull String msg, @Nullable RecognitionException e) { + errors.append("Error at line ").append(line).append(", char ") + .append(charPositionInLine).append(": ").append(msg).append("\n"); + } + + @Override + public void reportAmbiguity(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, + boolean exact, @Nullable BitSet ambigAlts, @NotNull ATNConfigSet configs) { + // Pass + } + + @Override + public void reportAttemptingFullContext(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, + int stopIndex, @Nullable BitSet conflictingAlts, + @NotNull ATNConfigSet configs) { + // Pass + } + + @Override + public void reportContextSensitivity(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, + int prediction, @NotNull ATNConfigSet configs) { + // Pass + } + }); + + // Specify our entry point + ManifoldParser.SchematicContext context = parser.schematic(); + + if (errors.length() != 0) { + throw new FrontendBuildException(errors.toString()); + } + + ExpressionContextVisitor graphBuilder = new ExpressionContextVisitor(inputFile); + List expressionContexts = context.expression(); + for (ManifoldParser.ExpressionContext expressionContext : expressionContexts) { + graphBuilder.visit(expressionContext); + } + if (graphBuilder.getErrors().size() > 0) { + throw new FrontendBuildException( + String.join("\n", graphBuilder.getErrors())); + } + ExpressionGraph exprGraph = graphBuilder.getExpressionGraph(); + + log.debug("writing out initial expression graph"); + File exprGraphDot = new File(inputFile.getName() + ".exprs.dot"); + exprGraph.writeDOTFile(exprGraphDot); + return exprGraph; + } +} diff --git a/src/main/java/org/manifold/compiler/front/ExpressionVertex.java b/src/main/java/org/manifold/compiler/front/ExpressionVertex.java index 50f2166..7ac1be1 100644 --- a/src/main/java/org/manifold/compiler/front/ExpressionVertex.java +++ b/src/main/java/org/manifold/compiler/front/ExpressionVertex.java @@ -10,6 +10,7 @@ public abstract class ExpressionVertex { private final ExpressionGraph exprGraph; + protected ExpressionGraph getExpressionGraph() { return this.exprGraph; } diff --git a/src/main/java/org/manifold/compiler/front/FunctionValueVertex.java b/src/main/java/org/manifold/compiler/front/FunctionValueVertex.java index 852dc0f..e77bad6 100644 --- a/src/main/java/org/manifold/compiler/front/FunctionValueVertex.java +++ b/src/main/java/org/manifold/compiler/front/FunctionValueVertex.java @@ -153,7 +153,7 @@ public ExpressionVertex copy(ExpressionGraph g, // Use a new expression graph for the body, just like when constructing a function initially. // This maintains proper scoping ExpressionGraph newBody = new ExpressionGraph(); - newBody.addSubGraph(functionBody, false); + newBody.addSubGraph(functionBody); return new FunctionValueVertex(g, edgeMap.get(functionTypeEdge), newBody); } diff --git a/src/main/java/org/manifold/compiler/front/ImportTypeValue.java b/src/main/java/org/manifold/compiler/front/ImportTypeValue.java new file mode 100644 index 0000000..33214fb --- /dev/null +++ b/src/main/java/org/manifold/compiler/front/ImportTypeValue.java @@ -0,0 +1,29 @@ +package org.manifold.compiler.front; + +import org.manifold.compiler.SchematicValueVisitor; +import org.manifold.compiler.TypeValue; +import org.manifold.compiler.UndefinedBehaviourError; + +public class ImportTypeValue extends TypeValue implements NamedEntryTypeValue { + + private NamespaceIdentifier namespace; + private ExpressionGraph exprGraph; + + public ImportTypeValue(ExpressionGraph exprGraph, NamespaceIdentifier namespace) { + this.exprGraph = exprGraph; + this.namespace = namespace; + } + + public TypeValue getEntry(String key) throws Exception { + VariableIdentifier id = new VariableIdentifier(namespace, key); + VariableReferenceVertex source = exprGraph.getVariableVertex(id); + source.elaborate(); + return source.getType(); + } + + @Override + public void accept(SchematicValueVisitor schematicValueVisitor) { + throw new UndefinedBehaviourError( + "cannot accept non-frontend ValueVisitor into a frontend Value"); + } +} diff --git a/src/main/java/org/manifold/compiler/front/ImportValue.java b/src/main/java/org/manifold/compiler/front/ImportValue.java new file mode 100644 index 0000000..b99883a --- /dev/null +++ b/src/main/java/org/manifold/compiler/front/ImportValue.java @@ -0,0 +1,37 @@ +package org.manifold.compiler.front; + +import org.manifold.compiler.SchematicValueVisitor; +import org.manifold.compiler.Value; + +public class ImportValue extends Value implements NamedEntryValue { + private ExpressionGraph exprGraph; + private NamespaceIdentifier namespace; + + public ImportValue(ExpressionGraph exprGraph, NamespaceIdentifier namespace) { + super(new ImportTypeValue(exprGraph, namespace)); + this.exprGraph = exprGraph; + this.namespace = namespace; + } + @Override + public boolean isElaborationtimeKnowable() { + return false; + } + + @Override + public boolean isRuntimeKnowable() { + return false; + } + + @Override + public void accept(SchematicValueVisitor schematicValueVisitor) { + return; + } + + @Override + public Value getEntry(String key) throws Exception { + VariableIdentifier id = new VariableIdentifier(namespace, key); + VariableReferenceVertex source = exprGraph.getVariableVertex(id); + source.elaborate(); + return source.getValue(); + } +} diff --git a/src/main/java/org/manifold/compiler/front/ImportVertex.java b/src/main/java/org/manifold/compiler/front/ImportVertex.java new file mode 100644 index 0000000..eed42db --- /dev/null +++ b/src/main/java/org/manifold/compiler/front/ImportVertex.java @@ -0,0 +1,81 @@ +package org.manifold.compiler.front; + +import org.manifold.compiler.TypeValue; +import org.manifold.compiler.UndefinedBehaviourError; +import org.manifold.compiler.Value; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class ImportVertex extends ExpressionVertex { + + private NamespaceIdentifier namespace; + private ExpressionGraph includedGraph; + private TypeValue type; + + public ImportVertex(ExpressionGraph exprGraph, ExpressionGraph includedGraph) { + super(exprGraph); + this.includedGraph = includedGraph; + } + + @Override + public TypeValue getType() { + return this.type; + } + + @Override + public Value getValue() { + return this.value; + } + + @Override + public void elaborate() throws Exception { + if (namespace != null) { + return; + } + + ExpressionGraph exprGraph = getExpressionGraph(); + List targets = exprGraph.getEdgesFromSource(this); + if (targets.size() != 1) { + throw new UndefinedBehaviourError("Multiple edges from import " + this.toString()); + } + ExpressionVertex target = targets.get(0).getTarget(); + if (!(target instanceof VariableReferenceVertex)) { + throw new UndefinedBehaviourError("Import " + this.toString() + " must be assigned to a variable"); + } + namespace = new NamespaceIdentifier(((VariableReferenceVertex) target).getId().getName()); + + exprGraph.addSubGraph(includedGraph, namespace); + this.value = new ImportValue(getExpressionGraph(), namespace); + this.type = this.value.getType(); + } + + @Override + public void verify() throws Exception { + return; + } + + @Override + public boolean isElaborationtimeKnowable() { + return false; + } + + @Override + public boolean isRuntimeKnowable() { + return false; + } + + @Override + public void writeToDOTFile(BufferedWriter writer) throws IOException { + return; + } + + @Override + public ExpressionVertex copy(ExpressionGraph g, Map edgeMap) { + ImportVertex v = new ImportVertex(g, includedGraph); + v.namespace = namespace; + return v; + } +} diff --git a/src/main/java/org/manifold/compiler/front/ImportVisitor.java b/src/main/java/org/manifold/compiler/front/ImportVisitor.java deleted file mode 100644 index 75935dc..0000000 --- a/src/main/java/org/manifold/compiler/front/ImportVisitor.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.manifold.compiler.front; - -import org.manifold.parser.ManifoldBaseVisitor; -import org.manifold.parser.ManifoldParser.ImportStatementContext; - -import java.util.ArrayList; -import java.util.List; - -class ImportVisitor extends ManifoldBaseVisitor { - - private List imports; - public List getImports() { - return this.imports; - } - - public ImportVisitor() { - this.imports = new ArrayList<>(); - } - - @Override - public Void visitImportStatement(ImportStatementContext context) { - String filePath = context.STRING_VALUE().getText(); - filePath = filePath.replaceAll("\\\"", "\""); - this.imports.add(filePath.substring(1, filePath.length() - 1)); - return null; - } -} diff --git a/src/main/java/org/manifold/compiler/front/Main.java b/src/main/java/org/manifold/compiler/front/Main.java index 102a8ff..0895f37 100644 --- a/src/main/java/org/manifold/compiler/front/Main.java +++ b/src/main/java/org/manifold/compiler/front/Main.java @@ -1,31 +1,15 @@ package org.manifold.compiler.front; -import com.google.common.base.Throwables; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATNConfigSet; -import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.misc.NotNull; -import org.antlr.v4.runtime.misc.Nullable; -import org.antlr.v4.runtime.misc.ParseCancellationException; -import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.manifold.compiler.*; import org.manifold.compiler.middle.Schematic; -import org.manifold.parser.ManifoldBaseVisitor; -import org.manifold.parser.ManifoldLexer; -import org.manifold.parser.ManifoldParser; -import org.manifold.parser.ManifoldParser.*; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.URL; import java.nio.file.Paths; import java.util.*; -import java.util.stream.Stream; public class Main implements Frontend { @@ -166,98 +150,6 @@ public static void elaborateNodes(ExpressionGraph g, Schematic s) } - private File getLib(String libPath) { - URL url = this.getClass().getClassLoader().getResource("libraries/" + libPath); - if (url == null) { - return null; - } - return new File(url.getFile()); - } - - public ExpressionGraph parseFile(File inputFile) throws IOException { - ManifoldLexer lexer = new ManifoldLexer(new ANTLRInputStream( - new FileInputStream(inputFile))); - - // Get a list of matched tokens - CommonTokenStream tokens = new CommonTokenStream(lexer); - - // Pass the tokens to the parser - ManifoldParser parser = new ManifoldParser(tokens); - - StringBuilder errors = new StringBuilder(); - parser.addErrorListener(new ANTLRErrorListener() { - - @Override - public void syntaxError(@NotNull Recognizer recognizer, @Nullable Object offendingSymbol, int line, - int charPositionInLine, @NotNull String msg, @Nullable RecognitionException e) { - errors.append("Error at line ").append(line).append(", char ") - .append(charPositionInLine).append(": ").append(msg).append("\n"); - } - - @Override - public void reportAmbiguity(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, - boolean exact, @Nullable BitSet ambigAlts, @NotNull ATNConfigSet configs) { - // Pass - } - - @Override - public void reportAttemptingFullContext(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, - int stopIndex, @Nullable BitSet conflictingAlts, - @NotNull ATNConfigSet configs) { - // Pass - } - - @Override - public void reportContextSensitivity(@NotNull Parser recognizer, @NotNull DFA dfa, int startIndex, int stopIndex, - int prediction, @NotNull ATNConfigSet configs) { - // Pass - } - }); - - // Specify our entry point - ManifoldParser.SchematicContext context = parser.schematic(); - - if (errors.length() != 0) { - throw new FrontendBuildException(errors.toString()); - } - - ExpressionGraph exprGraph = new ExpressionGraph(); - - ImportVisitor importVisitor = new ImportVisitor(); - importVisitor.visit(context); - for (String filePath : importVisitor.getImports()) { - File importedFile = Stream.of( - new File(inputFile.getParent(), filePath), - new File(inputFile.getParent(), filePath + ".manifold") - ).filter(f -> f.exists()) - .findFirst() - .orElseGet(() -> { - File lib = getLib(filePath); - if (lib == null) { - lib = getLib(filePath + ".manifold"); - } - if (lib != null) { - return lib; - } - throw new FrontendBuildException("Import " + filePath + " not found"); - }); - ExpressionGraph g = parseFile(importedFile); - exprGraph.addSubGraph(g, true); - } - - ExpressionContextVisitor graphBuilder = new ExpressionContextVisitor(exprGraph); - List statementContexts = context.statement(); - for (StatementContext statementContext : statementContexts) { - graphBuilder.visit(statementContext); - } - exprGraph = graphBuilder.getExpressionGraph(); - - log.debug("writing out initial expression graph"); - File exprGraphDot = new File(inputFile.getName() + ".exprs.dot"); - exprGraph.writeDOTFile(exprGraphDot); - return exprGraph; - } - @Override public Schematic invokeFrontend(CommandLine cmd) throws Exception { @@ -266,7 +158,8 @@ public Schematic invokeFrontend(CommandLine cmd) throws Exception { throw new FrontendBuildException(inputFile.getName() + " not found."); } - ExpressionGraph exprGraph = parseFile(inputFile); + ExpressionGraphParser parser = new ExpressionGraphParser(); + ExpressionGraph exprGraph = parser.parseFile(inputFile); exprGraph.verifyVariablesSingleAssignment(); Schematic schematic = new Schematic(inputFile.getName()); diff --git a/src/main/java/org/manifold/compiler/front/NamedEntryTypeValue.java b/src/main/java/org/manifold/compiler/front/NamedEntryTypeValue.java new file mode 100644 index 0000000..20441f0 --- /dev/null +++ b/src/main/java/org/manifold/compiler/front/NamedEntryTypeValue.java @@ -0,0 +1,7 @@ +package org.manifold.compiler.front; + +import org.manifold.compiler.TypeValue; + +public interface NamedEntryTypeValue { + TypeValue getEntry(String key) throws Exception; +} diff --git a/src/main/java/org/manifold/compiler/front/NamedEntryValue.java b/src/main/java/org/manifold/compiler/front/NamedEntryValue.java new file mode 100644 index 0000000..4f2a201 --- /dev/null +++ b/src/main/java/org/manifold/compiler/front/NamedEntryValue.java @@ -0,0 +1,7 @@ +package org.manifold.compiler.front; + +import org.manifold.compiler.Value; + +public interface NamedEntryValue { + Value getEntry(String key) throws Exception; +} diff --git a/src/main/java/org/manifold/compiler/front/NodeValueVertex.java b/src/main/java/org/manifold/compiler/front/NodeValueVertex.java index bacc918..bac7e34 100644 --- a/src/main/java/org/manifold/compiler/front/NodeValueVertex.java +++ b/src/main/java/org/manifold/compiler/front/NodeValueVertex.java @@ -105,7 +105,7 @@ public void elaborate() throws Exception { for (String inputPortName : inputPortNames) { PortTypeValue inputPortType = nodeType.getPorts().get(inputPortName); - Value inputPortValue = input.entry(inputPortName); + Value inputPortValue = input.getEntry(inputPortName); // if the port has attributes, this is a tuple // (0: FuturePortValue, 1: (attributes)) // otherwise, this is just a FuturePortValue @@ -120,8 +120,8 @@ public void elaborate() throws Exception { } else { TupleValue inputPortTuple = (TupleValue) inputPortValue; // same story here about unwrapping the port - futurePort = unwrapPort(inputPortTuple.atIndex(0)); - TupleValue attributesValue = (TupleValue) inputPortTuple.atIndex(1); + futurePort = unwrapPort(inputPortTuple.getEntry(0)); + TupleValue attributesValue = (TupleValue) inputPortTuple.getEntry(1); // TODO this can probably be done better, it assumes that all tuple values are named inputPortAttrs = MappedArray.toMap(attributesValue.getEntries()); } @@ -136,14 +136,14 @@ public void elaborate() throws Exception { if (outputPortType.getAttributes().isEmpty()) { outputPortAttrs = new HashMap<>(); // no attributes } else { - TupleValue attributesValue = (TupleValue) input.entry(outputPortName); + TupleValue attributesValue = (TupleValue) input.getEntry(outputPortName); outputPortAttrs = MappedArray.toMap(attributesValue.getEntries()); } portAttrs.put(outputPortName, outputPortAttrs); } for (String attrName : nodeType.getAttributes().keySet()) { - Value attrValue = input.entry(attrName); + Value attrValue = input.getEntry(attrName); nodeAttrs.put(attrName, attrValue); } diff --git a/src/main/java/org/manifold/compiler/front/StaticAttributeAccessVertex.java b/src/main/java/org/manifold/compiler/front/StaticAttributeAccessVertex.java index 2e51342..a4a7600 100644 --- a/src/main/java/org/manifold/compiler/front/StaticAttributeAccessVertex.java +++ b/src/main/java/org/manifold/compiler/front/StaticAttributeAccessVertex.java @@ -43,7 +43,9 @@ public Value getValue() { return this.value; } - protected abstract Value getVal(TupleValue tupleValue); + protected abstract Value getValEntry(Value v) throws Exception; + + protected abstract TypeValue getTypeEntry(TypeValue t) throws Exception; /** * The string representation of the value used to access this attribute @@ -57,9 +59,10 @@ public void elaborate() throws Exception { vExpr.elaborate(); Value val = vExpr.getValue(); - TupleValue tupleValue = (TupleValue) val; - this.value = getVal(tupleValue); - this.type = this.value.getType(); + this.value = getValEntry(val); + + TypeValue t = vExpr.getType(); + this.type = getTypeEntry(t); } @Override @@ -117,8 +120,19 @@ protected String attributeToString() { } @Override - protected final Value getVal(TupleValue tupleValue) { - return tupleValue.entry(attributeID); + protected final Value getValEntry(Value v) throws Exception { + if (!(v instanceof NamedEntryValue)) { + throw new RuntimeException("Cannot get entry by attribute of " + v.toString()); + } + return ((NamedEntryValue) v).getEntry(attributeID); + } + + @Override + protected final TypeValue getTypeEntry(TypeValue t) throws Exception { + if (!(t instanceof NamedEntryTypeValue)) { + throw new RuntimeException("Cannot get entry by attribute of " + t.toString()); + } + return ((NamedEntryTypeValue) t).getEntry(attributeID); } public StaticStringAttributeAccessVertex(ExpressionGraph exprGraph, @@ -151,8 +165,19 @@ protected String attributeToString() { } @Override - protected final Value getVal(TupleValue tupleValue) { - return tupleValue.atIndex(attributeIDX); + protected final Value getValEntry(Value v) { + if (!(v instanceof TupleValue)) { + throw new RuntimeException("Cannot get entry by index of " + v.toString()); + } + return ((TupleValue) v).getEntry(attributeIDX); + } + + @Override + protected final TypeValue getTypeEntry(TypeValue t) throws Exception { + if (!(t instanceof TupleTypeValue)) { + throw new RuntimeException("Cannot get entry by attribute of " + t.toString()); + } + return ((TupleTypeValue) t).getEntry(attributeIDX); } public StaticNumberAttributeAccessVertex(ExpressionGraph exprGraph, diff --git a/src/main/java/org/manifold/compiler/front/TupleTypeValue.java b/src/main/java/org/manifold/compiler/front/TupleTypeValue.java index 9052db2..0b10f2e 100644 --- a/src/main/java/org/manifold/compiler/front/TupleTypeValue.java +++ b/src/main/java/org/manifold/compiler/front/TupleTypeValue.java @@ -4,7 +4,7 @@ import org.manifold.compiler.TypeValue; import org.manifold.compiler.UndefinedBehaviourError; -public class TupleTypeValue extends TypeValue { +public class TupleTypeValue extends TypeValue implements NamedEntryTypeValue { private final MappedArray subtypes; // TODO default values @@ -17,7 +17,11 @@ public int getSize() { return subtypes.size(); } - public TypeValue entry(int i){ + public TypeValue getEntry(String key) { + return subtypes.get(key); + } + + public TypeValue getEntry(int i){ return subtypes.get(i); } @@ -58,8 +62,8 @@ public boolean equals(Object other) { } // type-check subexpressions for equality for (int i = 0; i < getSize(); ++i) { - TypeValue myType = entry(i).getType(); - TypeValue otherType = oTuple.entry(i).getType(); + TypeValue myType = getEntry(i).getType(); + TypeValue otherType = oTuple.getEntry(i).getType(); if (!myType.equals(otherType)) { return false; } @@ -84,8 +88,8 @@ public boolean isSubtypeOf(TypeValue other) { } // type-check subexpressions for (int i = 0; i < getSize(); ++i) { - TypeValue myType = entry(i).getType(); - TypeValue otherType = oTuple.entry(i).getType(); + TypeValue myType = getEntry(i).getType(); + TypeValue otherType = oTuple.getEntry(i).getType(); if (!myType.isSubtypeOf(otherType)) { return false; } diff --git a/src/main/java/org/manifold/compiler/front/TupleValue.java b/src/main/java/org/manifold/compiler/front/TupleValue.java index 461b2a6..4a7620d 100644 --- a/src/main/java/org/manifold/compiler/front/TupleValue.java +++ b/src/main/java/org/manifold/compiler/front/TupleValue.java @@ -4,7 +4,7 @@ import org.manifold.compiler.UndefinedBehaviourError; import org.manifold.compiler.Value; -public class TupleValue extends Value { +public class TupleValue extends Value implements NamedEntryValue { private final MappedArray entries; @@ -16,15 +16,15 @@ public int getSize() { return entries.size(); } - public Value entry(String key) { + public Value getEntry(String key) { if (!entries.containsKey(key)) { throw new IllegalArgumentException("No value for entry " + key); } return entries.get(key); } - public Value atIndex(int idx) { - return entries.get(idx); + public Value getEntry(int i) { + return entries.get(i); } public TupleValue(TupleTypeValue type, MappedArray entries) { @@ -68,5 +68,4 @@ public void accept(SchematicValueVisitor v) { throw new UndefinedBehaviourError( "cannot accept non-frontend ValueVisitor into a frontend Value"); } - } diff --git a/tests/acceptance/import.manifold b/tests/acceptance/import.manifold index 6c835cc..330e0f9 100644 --- a/tests/acceptance/import.manifold +++ b/tests/acceptance/import.manifold @@ -1,7 +1,7 @@ -import "../input_pin.manifold"; +pin = import "../input_pin.manifold"; digitalIn = primitive port Bool; outputPin = primitive node (in: digitalIn) -> (Nil); -v = myfunc(a=in, b=in); +v = pin.myfunc(a=pin.in, b=pin.in); outputPin(in=v); diff --git a/tests/acceptance/import.manifold.schematic b/tests/acceptance/import.manifold.schematic index ce4c775..e616e3e 100644 --- a/tests/acceptance/import.manifold.schematic +++ b/tests/acceptance/import.manifold.schematic @@ -2,26 +2,26 @@ "name": "import.manifold", "userDefinedTypes": {}, "portTypes": { - "digitalOut": { + "digitalIn": { "signalType": "Bool", "attributes": {} }, - "digitalIn": { + "digitalOut": { "signalType": "Bool", "attributes": {} } }, "nodeTypes": { - "inputPin": { + "outputPin": { "attributes": {}, "ports": { - "out": "digitalOut" + "in": "digitalIn" } }, - "outputPin": { + "inputPin": { "attributes": {}, "ports": { - "in": "digitalIn" + "out": "digitalOut" } } }, @@ -35,10 +35,10 @@ } }, "n2": { - "type": "inputPin", + "type": "outputPin", "attributes": {}, "portAttrs": { - "out": {} + "in": {} } }, "n3": { @@ -49,18 +49,18 @@ } }, "n4": { - "type": "outputPin", + "type": "inputPin", "attributes": {}, "portAttrs": { - "in": {} + "out": {} } } }, "connections": { "c1": { "attributes": {}, - "from": "n2:out", - "to": "n4:in" + "from": "n1:out", + "to": "n2:in" } }, "constraints": {} diff --git a/tests/acceptance/importSystem.manifold b/tests/acceptance/importSystem.manifold index 77e0f98..ec124e1 100644 --- a/tests/acceptance/importSystem.manifold +++ b/tests/acceptance/importSystem.manifold @@ -1,4 +1,4 @@ -import "circuits"; +c = import "circuits"; -x = inputPin(); -outputPin(in=x); \ No newline at end of file +x = c.inputPin(); +c.outputPin(in=x); \ No newline at end of file diff --git a/tests/acceptance/importTuple.manifold b/tests/acceptance/importTuple.manifold index 9a61c2b..d89b207 100644 --- a/tests/acceptance/importTuple.manifold +++ b/tests/acceptance/importTuple.manifold @@ -1,6 +1,6 @@ -import "../input_pin"; +pin = import "../input_pin"; digitalIn = primitive port Bool; outputPin = primitive node (in: digitalIn) -> (Nil); -outputPin(in=x); +outputPin(in=pin.x); diff --git a/tests/acceptance/importTuple.manifold.schematic b/tests/acceptance/importTuple.manifold.schematic index d039177..4f42505 100644 --- a/tests/acceptance/importTuple.manifold.schematic +++ b/tests/acceptance/importTuple.manifold.schematic @@ -2,11 +2,11 @@ "name": "importTuple.manifold", "userDefinedTypes": {}, "portTypes": { - "digitalOut": { + "digitalIn": { "signalType": "Bool", "attributes": {} }, - "digitalIn": { + "digitalOut": { "signalType": "Bool", "attributes": {} } @@ -42,25 +42,25 @@ } }, "n3": { - "type": "inputPin", + "type": "outputPin", "attributes": {}, "portAttrs": { - "out": {} + "in": {} } }, "n4": { - "type": "outputPin", + "type": "inputPin", "attributes": {}, "portAttrs": { - "in": {} + "out": {} } } }, "connections": { "c1": { "attributes": {}, - "from": "n3:out", - "to": "n4:in" + "from": "n1:out", + "to": "n3:in" } }, "constraints": {} diff --git a/tests/buildErrors/importFileWithError.manifold.error b/tests/buildErrors/importFileWithError.manifold.error index abd8f55..1cc9fb7 100644 --- a/tests/buildErrors/importFileWithError.manifold.error +++ b/tests/buildErrors/importFileWithError.manifold.error @@ -1 +1,2 @@ Error at line 2, char 0: no viable alternative at input 'compile.' +Error while parsing included file parseError.manifold \ No newline at end of file diff --git a/tests/buildErrors/importRedefineVar.manifold b/tests/buildErrors/importRedefineVar.manifold deleted file mode 100644 index 6af3a11..0000000 --- a/tests/buildErrors/importRedefineVar.manifold +++ /dev/null @@ -1,3 +0,0 @@ -import "../input_pin"; - -in = inputPin(); diff --git a/tests/buildErrors/importRedefineVar.manifold.error b/tests/buildErrors/importRedefineVar.manifold.error deleted file mode 100644 index a2ddc49..0000000 --- a/tests/buildErrors/importRedefineVar.manifold.error +++ /dev/null @@ -1 +0,0 @@ -[in is defined multiple times] \ No newline at end of file From 0bf3a7ff145d67eed88359acf438b9b3d81d8bee Mon Sep 17 00:00:00 2001 From: Nik Klassen Date: Mon, 13 Jun 2016 13:10:06 -0400 Subject: [PATCH 2/3] Fix build error --- src/main/java/org/manifold/compiler/front/ImportVertex.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/manifold/compiler/front/ImportVertex.java b/src/main/java/org/manifold/compiler/front/ImportVertex.java index eed42db..d3d0f89 100644 --- a/src/main/java/org/manifold/compiler/front/ImportVertex.java +++ b/src/main/java/org/manifold/compiler/front/ImportVertex.java @@ -14,6 +14,7 @@ public class ImportVertex extends ExpressionVertex { private NamespaceIdentifier namespace; private ExpressionGraph includedGraph; private TypeValue type; + private Value value; public ImportVertex(ExpressionGraph exprGraph, ExpressionGraph includedGraph) { super(exprGraph); From cede96a249b8bcb1542f88a38882d621de710c00 Mon Sep 17 00:00:00 2001 From: Nik Klassen Date: Wed, 15 Jun 2016 14:20:23 -0400 Subject: [PATCH 3/3] Make file parsing lazier --- src/main/antlr4/Manifold.g4 | 6 +++--- .../front/ExpressionContextVisitor.java | 13 +----------- .../manifold/compiler/front/ImportVertex.java | 21 ++++++++++++++----- .../buildErrors/importFileWithError.manifold | 8 ++++++- .../importFileWithError.manifold.error | 2 +- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/main/antlr4/Manifold.g4 b/src/main/antlr4/Manifold.g4 index 432d38d..77ea866 100644 --- a/src/main/antlr4/Manifold.g4 +++ b/src/main/antlr4/Manifold.g4 @@ -30,7 +30,7 @@ tupleValue: '(' ')'; functionTypeValue: tupleTypeValue '->' tupleTypeValue; -functionValue: functionTypeValue '{' (expression STATEMENT_TERMINATOR)* '}'; +functionValue: functionTypeValue '{' (expression EXPRESSION_TERMINATOR)* '}'; //////////////////////////////////////////////////////// // // @@ -98,7 +98,7 @@ expression: // | declaration ; -STATEMENT_TERMINATOR: ';'; +EXPRESSION_TERMINATOR: ';'; //////////////////////////////////////////////////////// @@ -107,4 +107,4 @@ STATEMENT_TERMINATOR: ';'; // // //////////////////////////////////////////////////////// -schematic: (expression STATEMENT_TERMINATOR)*; +schematic: (expression EXPRESSION_TERMINATOR)*; diff --git a/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java b/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java index 0704d98..a387341 100644 --- a/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java +++ b/src/main/java/org/manifold/compiler/front/ExpressionContextVisitor.java @@ -24,7 +24,6 @@ class ExpressionContextVisitor extends ManifoldBaseVisitor { - private ExpressionGraphParser parser; private ExpressionGraph exprGraph; private File inputFile; private List errors; @@ -46,7 +45,6 @@ public ExpressionContextVisitor(File inputFile) { public ExpressionContextVisitor(ExpressionGraph exprGraph, File inputFile) { this.inputFile = inputFile; - this.parser = new ExpressionGraphParser(); this.exprGraph = exprGraph; this.errors = new ArrayList<>(); } @@ -366,16 +364,7 @@ public ExpressionVertex visitImportExpr(ImportExprContext context) { return null; } - ExpressionGraph g; - try { - g = parser.parseFile(importedFile); - } catch (Exception e) { - errors.add(e.getMessage().trim()); - errors.add("Error while parsing included file " + filePath); - return null; - } - - ExpressionVertex v = new ImportVertex(exprGraph, g); + ExpressionVertex v = new ImportVertex(exprGraph, importedFile); exprGraph.addVertex(v); return v; } diff --git a/src/main/java/org/manifold/compiler/front/ImportVertex.java b/src/main/java/org/manifold/compiler/front/ImportVertex.java index d3d0f89..5d39cc0 100644 --- a/src/main/java/org/manifold/compiler/front/ImportVertex.java +++ b/src/main/java/org/manifold/compiler/front/ImportVertex.java @@ -5,20 +5,21 @@ import org.manifold.compiler.Value; import java.io.BufferedWriter; +import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; public class ImportVertex extends ExpressionVertex { + private File importedFile; private NamespaceIdentifier namespace; - private ExpressionGraph includedGraph; private TypeValue type; private Value value; - public ImportVertex(ExpressionGraph exprGraph, ExpressionGraph includedGraph) { + public ImportVertex(ExpressionGraph exprGraph, File importedFile) { super(exprGraph); - this.includedGraph = includedGraph; + this.importedFile = importedFile; } @Override @@ -37,6 +38,16 @@ public void elaborate() throws Exception { return; } + ExpressionGraphParser parser = new ExpressionGraphParser(); + ExpressionGraph importedGraph; + try { + importedGraph = parser.parseFile(importedFile); + } catch (FrontendBuildException e) { + throw new FrontendBuildException( + "Could not parse " + importedFile.getName() + "\n" + + e.getMessage()); + } + ExpressionGraph exprGraph = getExpressionGraph(); List targets = exprGraph.getEdgesFromSource(this); if (targets.size() != 1) { @@ -48,7 +59,7 @@ public void elaborate() throws Exception { } namespace = new NamespaceIdentifier(((VariableReferenceVertex) target).getId().getName()); - exprGraph.addSubGraph(includedGraph, namespace); + exprGraph.addSubGraph(importedGraph, namespace); this.value = new ImportValue(getExpressionGraph(), namespace); this.type = this.value.getType(); } @@ -75,7 +86,7 @@ public void writeToDOTFile(BufferedWriter writer) throws IOException { @Override public ExpressionVertex copy(ExpressionGraph g, Map edgeMap) { - ImportVertex v = new ImportVertex(g, includedGraph); + ImportVertex v = new ImportVertex(g, importedFile); v.namespace = namespace; return v; } diff --git a/tests/buildErrors/importFileWithError.manifold b/tests/buildErrors/importFileWithError.manifold index d4408b7..21d133c 100644 --- a/tests/buildErrors/importFileWithError.manifold +++ b/tests/buildErrors/importFileWithError.manifold @@ -1 +1,7 @@ -import "parseError.manifold"; \ No newline at end of file +error = import "parseError.manifold"; + +digitalIn = primitive port Bool; +outputPin = primitive node (in: digitalIn) -> (Nil); + +// error isn't parsed until usage, so force the elaboration here +outputPin(error.foo); diff --git a/tests/buildErrors/importFileWithError.manifold.error b/tests/buildErrors/importFileWithError.manifold.error index 1cc9fb7..57d5dd9 100644 --- a/tests/buildErrors/importFileWithError.manifold.error +++ b/tests/buildErrors/importFileWithError.manifold.error @@ -1,2 +1,2 @@ +Could not parse parseError.manifold Error at line 2, char 0: no viable alternative at input 'compile.' -Error while parsing included file parseError.manifold \ No newline at end of file