Skip to content

Commit

Permalink
Merge pull request #69 from mtrberzi/non-primitive-elaboration
Browse files Browse the repository at this point in the history
Non-primitive function elaboration
  • Loading branch information
mtrberzi committed Mar 19, 2015
2 parents 6d637b9 + e101973 commit 03a9184
Show file tree
Hide file tree
Showing 11 changed files with 513 additions and 55 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ targetCompatibility = 1.8

group = "org.manifold"
// name = "manifold-frontend"
version = '0.3.1-SNAPSHOT'
version = '0.4.0-SNAPSHOT'

mainClassName = "org.manifold.compiler.front.Main"

Expand Down
8 changes: 5 additions & 3 deletions src/main/java/org/manifold/compiler/front/ExpressionEdge.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.manifold.compiler.front;

import org.manifold.compiler.UndefinedBehaviourError;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class ExpressionEdge {

private static Logger log = LogManager.getLogger(ExpressionEdge.class);

private String name = "";
public String getName() {
return name;
Expand All @@ -30,8 +33,7 @@ public void setTarget(ExpressionVertex newTarget) {

public ExpressionEdge(ExpressionVertex from, ExpressionVertex to) {
if (from == null && to == null) {
throw new UndefinedBehaviourError(
"attempt to create a totally disconnected ExpressionEdge");
log.warn("attempt to create a totally disconnected ExpressionEdge");
}
source = from;
target = to;
Expand Down
57 changes: 34 additions & 23 deletions src/main/java/org/manifold/compiler/front/ExpressionGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
import java.util.Map;
import java.util.Set;

import com.google.common.base.Throwables;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.manifold.compiler.UndefinedBehaviourError;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

Expand All @@ -32,11 +33,11 @@ public class ExpressionGraph {
public Map<VariableIdentifier, VariableReferenceVertex> getVariableVertices() {
return ImmutableMap.copyOf(variableVertices);
}

public boolean containsVariable(VariableIdentifier vID) {
return variableVertices.containsKey(vID);
}

public VariableReferenceVertex getVariableVertex(VariableIdentifier vID)
throws VariableNotDefinedException {
if (variableVertices.containsKey(vID)) {
Expand All @@ -62,6 +63,9 @@ public List<ExpressionVertex> getNonVariableVertices() {
return ImmutableList.copyOf(nonVariableVertices);
}
public void addVertex(ExpressionVertex v) {
if (v == null) {
throw new UndefinedBehaviourError("attempt to add null vertex to graph");
}
nonVariableVertices.add(v);
allVertices.add(v);
}
Expand All @@ -75,12 +79,13 @@ public void removeVertex(ExpressionVertex v) {
while (variableVertices.values().remove(v)) { }
// simple removal from nonVariableVertices
nonVariableVertices.remove(v);
allVertices.remove(v);
}

private List<ExpressionEdge> edges = new ArrayList<>();
public void addEdge(ExpressionEdge e) {
Preconditions.checkArgument(
getVertices().contains(e.getSource())
(e.getSource() == null || getVertices().contains(e.getSource()))
&& (e.getTarget() == null || getVertices().contains(e.getTarget())),
"Edge had unexpected vertices " + e.toString());
edges.add(e);
Expand Down Expand Up @@ -142,7 +147,8 @@ public ExpressionGraph() {
*/
public void addSubExpressionGraph(ExpressionGraph subGraph,
ExpressionEdge mainGraphInput, ExpressionVertex subGraphInput,
ExpressionEdge mainGraphOutput, ExpressionVertex subGraphOutput) {
ExpressionEdge mainGraphOutput, ExpressionVertex subGraphOutput,
Map<VariableReferenceVertex, VariableReferenceVertex> variableRenamingMap) {

// Sanity checks
// input/output vertices exist in mainGraph and subGraph
Expand All @@ -158,15 +164,11 @@ public void addSubExpressionGraph(ExpressionGraph subGraph,
this.allVertices.remove(mainGraphInput.getTarget());
this.edges.removeAll(ImmutableList.of(mainGraphInput, mainGraphOutput));

ExpressionVertex inputVertex = mainGraphInput.getSource();
ExpressionVertex outputVertex = mainGraphOutput.getTarget();

// map of subgraph edge -> new edge to be inserted
Map<ExpressionEdge, ExpressionEdge> exprEdgeMap = new HashMap<>();
subGraph.getEdges().forEach(e -> {
// copy source/target for now since ExpressionEdge doesn't like creating with null on both
// they will be replaced with the correct vertices later
ExpressionEdge newEdge = new ExpressionEdge(e.getSource(), e.getTarget());
// replace these with the correct vertices later
ExpressionEdge newEdge = new ExpressionEdge(null, null);
exprEdgeMap.put(e, newEdge);
});

Expand All @@ -179,14 +181,17 @@ public void addSubExpressionGraph(ExpressionGraph subGraph,
.forEach(v -> {
ExpressionVertex newVertex;
if (v instanceof VariableReferenceVertex) {
// special case
// TODO: probably can handle renaming here?
VariableIdentifier ref = ((VariableReferenceVertex) v).getId();
try {
this.addVertex(ref);
newVertex = this.getVariableVertex(ref);
} catch (MultipleDefinitionException | VariableNotDefinedException e) {
throw Throwables.propagate(e);
// special case; handle renaming here
if (variableRenamingMap.containsKey(v)) {
newVertex = variableRenamingMap.get(v);
} else {
VariableIdentifier ref = ((VariableReferenceVertex) v).getId();
try {
this.addVertex(ref);
newVertex = this.getVariableVertex(ref);
} catch (MultipleDefinitionException | VariableNotDefinedException e) {
throw Throwables.propagate(e);
}
}
} else {
newVertex = v.copy(this, exprEdgeMap);
Expand All @@ -196,13 +201,19 @@ public void addSubExpressionGraph(ExpressionGraph subGraph,
});

// input/output vertex
ExpressionVertex inputVertex = mainGraphInput.getSource();
ExpressionVertex outputVertex = mainGraphOutput.getTarget();
exprVertexMap.put(subGraphInput, inputVertex);
exprVertexMap.put(subGraphOutput, outputVertex);

// each edge in subgraph -> edge in main graph should refer to the same source/target
subGraph.getEdges().forEach(edge -> {
exprEdgeMap.get(edge).setSource(exprVertexMap.get(edge.getSource()));
exprEdgeMap.get(edge).setTarget(exprVertexMap.get(edge.getTarget()));
if (edge.getSource() != null) {
exprEdgeMap.get(edge).setSource(exprVertexMap.get(edge.getSource()));
}
if (edge.getTarget() != null) {
exprEdgeMap.get(edge).setTarget(exprVertexMap.get(edge.getTarget()));
}
});

this.edges.addAll(exprEdgeMap.values());
Expand Down Expand Up @@ -275,5 +286,5 @@ public void verifyVariablesSingleAssignment() {
throw new RuntimeException(errors.toString());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import com.google.common.base.Preconditions;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.manifold.compiler.NodeTypeValue;
import org.manifold.compiler.TypeValue;
import org.manifold.compiler.UndefinedBehaviourError;
import org.manifold.compiler.Value;

import com.google.common.base.Preconditions;

public class FunctionInvocationVertex extends ExpressionVertex {

private static Logger log = LogManager.getLogger("FunctionInvocationVertex");
Expand Down Expand Up @@ -107,9 +113,74 @@ private void elaborateNodeInstantiation(Value function,
// now remove this vertex from the graph
getExpressionGraph().removeVertex(this);
}

private void elaborateNonPrimitiveFunction(Value f,
ExpressionVertex input) throws Exception {
log.debug("function invocation is non-primitive elaboration");
FunctionValue function = (FunctionValue) f;
FunctionTypeValue signature = (FunctionTypeValue) f.getType();
TupleTypeValue inputType = (TupleTypeValue) signature.getInputType();
TupleTypeValue outputType = (TupleTypeValue) signature.getOutputType();
// calculate renaming map (body -> this.exprGraph)
Map<VariableReferenceVertex, VariableReferenceVertex> renamingMap =
new HashMap<>();
for (Entry<VariableIdentifier, VariableReferenceVertex> entry
: function.getBody().getVariableVertices().entrySet()) {
VariableReferenceVertex varTarget;
if (getExpressionGraph().containsVariable(entry.getKey())) {
// if the main graph contains this variable, don't rename; use existing
log.debug("preserving variable " + entry.getKey());
varTarget = getExpressionGraph().getVariableVertex(entry.getKey());
} else {
// otherwise, create a fresh variable in the main graph and map to that
String oldName = entry.getKey().getName();
Random rng = new Random();
while (true) {
// choose a random suffix and mangle
Integer i = rng.nextInt(Integer.MAX_VALUE);
String newName = oldName + "_" + i.toString();
List<String> newNames = new ArrayList<>();
newNames.add(newName);
VariableIdentifier newID = new VariableIdentifier(newNames);
if (!getExpressionGraph().containsVariable(newID)) {
log.debug("renaming local variable " + entry.getKey()
+ " to " + newID);
getExpressionGraph().addVertex(newID);
varTarget = getExpressionGraph().getVariableVertex(newID);
break;
}
}
}
renamingMap.put(entry.getValue(), varTarget);
}
// identify main graph input and output edges
// we assume there's exactly one of each
ExpressionEdge mainGraphInput = inputEdge;
log.debug("main graph input is " + mainGraphInput);
ExpressionEdge mainGraphOutput = null;
for (ExpressionEdge e : getExpressionGraph().getEdgesFromSource(this)) {
mainGraphOutput = e;
break;
}
log.debug("main graph output is " + mainGraphOutput);
// identify subgraph (body) input and output vertices
ExpressionVertex subGraphInput = function.getInputVertex();
ExpressionVertex subGraphOutput = function.getOutputVertex();
// perform copy
getExpressionGraph().addSubExpressionGraph(function.getBody(),
mainGraphInput, subGraphInput, mainGraphOutput, subGraphOutput,
renamingMap);
// destroy the function edge
getExpressionGraph().removeEdge(functionEdge);
// now remove this vertex from the graph
getExpressionGraph().removeVertex(this);
}

private boolean elaborated = false;

@Override
public void elaborate() throws Exception {
if (elaborated) return;
// Elaborate argument
ExpressionVertex vInput = inputEdge.getSource();
vInput.elaborate();
Expand All @@ -121,10 +192,14 @@ public void elaborate() throws Exception {
if (function instanceof NodeTypeValue) {
// we're not calling a function; we're instantiating a node!
elaborateNodeInstantiation(function, vFunction);
} else if (function instanceof FunctionValue) {
// non-primitive function elaboration
elaborateNonPrimitiveFunction(function, vInput);
} else {
throw new UndefinedBehaviourError("don't know how to invoke '"
+ function.toString() + "'");
}
elaborated = true;
}

}
31 changes: 21 additions & 10 deletions src/main/java/org/manifold/compiler/front/FunctionValue.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package org.manifold.compiler.front;

import java.util.List;

import org.manifold.compiler.SchematicValueVisitor;
import org.manifold.compiler.UndefinedBehaviourError;
import org.manifold.compiler.Value;

public class FunctionValue extends Value {

private ExpressionGraph body;

public FunctionValue(FunctionTypeValue type, ExpressionGraph body) {
private TupleValueVertex vInput;
private TupleValueVertex vOutput;

public FunctionValue(FunctionTypeValue type, ExpressionGraph body,
TupleValueVertex vInput, TupleValueVertex vOutput) {
super(type);
this.body = body;
this.vInput = vInput;
this.vOutput = vOutput;
}

@Override
public void verify() throws Exception {
// TODO introspect body to make sure it treats input and output values
Expand All @@ -24,21 +27,29 @@ public void verify() throws Exception {
public ExpressionGraph getBody() {
return body;
}


public TupleValueVertex getInputVertex() {
return vInput;
}

public TupleValueVertex getOutputVertex() {
return vOutput;
}

@Override
public boolean isRuntimeKnowable() {
return false;
}

@Override
public boolean isElaborationtimeKnowable() {
return true;
}

@Override
public void accept(SchematicValueVisitor v) {
throw new UndefinedBehaviourError(
"cannot accept non-frontend ValueVisitor into a frontend Value");
}

}
Loading

0 comments on commit 03a9184

Please sign in to comment.