Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imports are now expressions #29

Merged
merged 3 commits into from
Jun 16, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/main/antlr4/Manifold.g4
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ rvalue:
| VISIBILITY_PUBLIC? lvalue '=' rvalue # AssignmentExpression
| 'primitive' 'port' typevalue (':' tupleTypeValue)? # PrimitivePortDefinitionExpression
| 'primitive' 'node' functionTypeValue # PrimitiveNodeDefinitionExpression
| 'import' STRING_VALUE #ImportExpr
;

lvalue:
Expand All @@ -97,11 +98,6 @@ expression:
// | declaration
;

statement:
expression #ExpressionStatment
| 'import' STRING_VALUE #ImportStatement
;

STATEMENT_TERMINATOR: ';';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was once called EXPRESSION_TERMINATOR. I don't see a need to change it now.



Expand All @@ -111,4 +107,4 @@ STATEMENT_TERMINATOR: ';';
// //
////////////////////////////////////////////////////////

schematic: (statement STATEMENT_TERMINATOR)*;
schematic: (expression STATEMENT_TERMINATOR)*;
Original file line number Diff line number Diff line change
Expand Up @@ -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<ExpressionVertex> {

private ExpressionGraphParser parser;
private ExpressionGraph exprGraph;
private File inputFile;
private List<String> errors;

public ExpressionGraph getExpressionGraph() {
return this.exprGraph;
}
Expand All @@ -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<String> 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
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the best place to put this, but I'm not really sure where it would make the most sense. The alternative that seems to make the most sense is during elaboration of the ImportVertex.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, it would make sense to me to have the import resolved during elaboration. I can see it being beneficial to keeping our simple graph views, well, simple. You know more about the process and performance so it's your call.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's no reason to parse a file if the import isn't used I'm going to move this in

} 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
Expand Down
28 changes: 24 additions & 4 deletions src/main/java/org/manifold/compiler/front/ExpressionGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

Expand All @@ -29,9 +32,18 @@ public Map<VariableIdentifier, VariableReferenceVertex> 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<ExpressionEdge, ExpressionEdge> exprEdgeMap = new HashMap<>();
subGraph.getEdges().forEach(e -> {
Expand All @@ -42,6 +54,7 @@ public void addSubGraph(ExpressionGraph subGraph, boolean importVars) {

// map of subgraph vertex -> new vertex
Map<ExpressionVertex, ExpressionVertex> exprVertexMap = new HashMap<>();
List<String> 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()
Expand All @@ -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<String> 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);
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ManifoldParser.ExpressionContext> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
public abstract class ExpressionVertex {

private final ExpressionGraph exprGraph;

protected ExpressionGraph getExpressionGraph() {
return this.exprGraph;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/org/manifold/compiler/front/ImportTypeValue.java
Original file line number Diff line number Diff line change
@@ -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");
}
}
37 changes: 37 additions & 0 deletions src/main/java/org/manifold/compiler/front/ImportValue.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
Loading