/*
* xtc - The eXTensible Compiler
* Copyright (C) 2007 New York University
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.typical;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import xtc.tree.Comment;
import xtc.tree.GNode;
import xtc.tree.Visitor;
import xtc.tree.Node;
import xtc.util.SymbolTable;
import xtc.util.Runtime;
import xtc.util.Pair;
/**
* Visitor to translate Typical ASTs into Java ASTs.
*
* @author Laune Harris, Anh Le
* @version $Revision: 1.377 $
*/
public class Transformer extends Visitor {
/** A Typical attribute. */
static class Attribute {
/** The name. */
public String name;
/** The type (as a type expression node). */
public Node type;
/**
* Create a new attribute.
*
* @param name The name.
* @param type The type.
*/
Attribute(String name, Node type) {
this.name = name;
this.type = type;
}
}
// =========================================================================
/** A Typical equality definition. */
static class Equality {
/** The constructor name */
public String name;
/** The positions of the arguments to consider for equality. */
public List<Integer> positions;
/**
* Create a new equality definition.
*
* @param name The constructor name.
* @param positions The relevant positions.
*/
Equality(String name, List<Integer> positions) {
this.name = name;
this.positions = positions;
}
}
// =========================================================================
/** A primitive operation instance class. */
static class PrimitiveInstance {
/** The name of the operation. */
public String name;
/** The specific types of the instance. */
public List<String> types;
/** The name of the instance. */
public String instanceName;
/**
* Create a new primitive instance.
*
* @param name The name of the primitive operation
* @param types The types of the instance
*/
public PrimitiveInstance(String name, List<String> types, String instanceName) {
this.name = name;
this.types = types;
this.instanceName = instanceName;
}
}
// =========================================================================
/** Representation of a matching clause. */
static class Match {
/** The argument type. */
private Object type;
/** The condition on the argument. */
private Node condition;
/**
* Create a new match.
*
* @param type The argument type.
* @param condition The condition.
*/
public Match(Object type, Node condition) {
this.type = type;
this.condition = condition;
}
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Match)) return false;
Match other = (Match)o;
return (type.equals(other.type) && condition.equals(other.condition));
}
}
// =========================================================================
/** Representation of a variable binding in a let expression. */
static class LetBinding {
/** The name of the variable. */
public String name;
public Object typeObject;
/** The type node of the variable. */
public Node type;
/** The value node of the variable. */
public Node value;
/**
* Create a new let binding.
*
* @param name The name of the variable.
* @param type The type of the variable.
* @param value The value of the variable.
*/
public LetBinding(String name, Object typeObject, Node type, Node value){
this.name = name;
this.typeObject = typeObject;
this.type = type;
this.value = value;
}
}
// =========================================================================
/** The type annotation name. */
protected static final String TYPE = "__type";
/** The property indicating the top level of a pattern. */
protected static final String TOP = "top";
/** The property indicating the right hand side of a binding. */
protected static final String RHS = "rhs";
/** The property representing the match argument. */
protected static final String MATCHARG = "match_arg";
/** The property representing the block contains the bindings argument. */
protected static final String BINDINGS = "bindings";
/** The annotation name to remember it is currently in analyze function. */
protected static final String INANALYZE = "inAnalyze";
/** The annotation name to indicate it is needed to process scope. */
protected static final String SCOPE = "process_scope";
/** The annotation name to indicate it is needed to annotate the node. */
protected static final String ANNOTATE = "annotate_node";
/** The property indicating the variables from upper levels of binding. */
protected static final String UPVARS = "up_variables";
/** The property indicating the variable bindings from an expression. */
protected static final String LETBINDINGS = "let_bindings";
/** The property indicating the body of a function definition. */
protected static final String BODY = "body";
/** The property indicating a new instance of Let must be created. */
protected static final String NEWLET = "new_let";
/** The tree factory. */
protected final TreeFactory factory;
/** The symbol table for this typical file. */
protected final SymbolTable table;
/** The root of the incoming typical abstract syntax tree. */
protected final Node typical;
/** The name of the node type. */
protected final String nodeTypeName;
/** The name of the checker to be output. */
protected final String output;
/** The root of the generated java ast for the type checker. */
protected GNode transformed;
/** The root of the types file. */
protected GNode typesAST;
/** The root of the support file. */
protected GNode supportAST;
/** The class body of the generated typechecker. */
protected Node cbody;
/** The class body of the types file. */
protected Node tbody;
/** The class body of the support file. */
protected Node sbody;
/** The type enumerations. */
protected Node tags;
/** This Transformers runtime. */
protected final Runtime runtime;
/** The cached variables. */
protected final
HashMap<Integer, String> typicalVars = new HashMap<Integer,String>();
/** The Type mapper. */
protected TypeMapper mapper;
/** Flag indicating that a scope definition has been seen. */
protected boolean seenScope = false;
/** The set of seen match conditions */
protected HashMap<Match, String> matches =
new HashMap<Match, String>();
/** The set of seen match conditions */
protected HashMap<Node, String> nodeMatches =
new HashMap<Node, String>();
/** Empty modifier node. */
final protected Node mod = GNode.create("Modifiers");
/** Final modifier node. */
final protected Node fmod = toModifiers("final");
/** Public modifier node. */
final protected Node pmod = toModifiers("public");
/** Nullliteral node. */
final protected Node nullNode = GNode.create("NullLiteral");
/** Node type. */
final protected Node nodeType = GNode.create("Type",
GNode.create("QualifiedIdentifier", "Node"),
null);
/** GNode type. */
final protected Node gnodeType = GNode.create("Type",
GNode.create("QualifiedIdentifier", "GNode"),
null);
/** The list of field that go into the. */
final protected List<Node> staticFields = new ArrayList<Node>();
/** The list of function definitions. */
final protected List<Node> functionDefinitions = new ArrayList<Node>();
/** A spare variable used in binding to a wildcard. */
final protected String spareVar;
/** Flag indicating that a namespace declaration has been seen. */
protected boolean seenNameSpace = false;
/** A list to store all node names in scope definition. */
protected ArrayList<String> processScopeNodes = new ArrayList<String>();
/** List of equal structure. */
protected ArrayList<Equality> equalities = new ArrayList<Equality>();
/** The package name. */
protected String packageName;
/** The package node. */
protected Node packageNode;
/** A list to store all defined attributes. */
protected List<Attribute> attributeList = new ArrayList<Attribute>();
/** A list to store all defined equal attributes. */
protected List<Attribute> eqAttributeList = new ArrayList<Attribute>();
/** A variable to remember if type is optimized. */
protected boolean replaceType;
/** A variable to remember if let is optimized. */
protected boolean optimizeLet;
/** A variable to check if List is used. */
private boolean isListUsed;
/** A variable to check if ArrayList is used. */
private boolean isArrayListUsed;
/** A variable to check if BigInteger is used. */
private boolean isBigIntegerUsed;
/** A variable to check if Pair is used. */
private boolean isPairUsed;
/** A variable to check if Node is used. */
private boolean isNodeUsed;
/** A variable to check if GNode is used. */
private boolean isGNodeUsed;
/** A variable to check if Primitives is used. */
private boolean isPrimitivesUsed;
/** A variable to check if Record is used. */
private boolean isRecordUsed;
/** A variable to check if Variant is used. */
private boolean isVariantUsed;
/** A variable to check if Tuple is used. */
private boolean isTupleUsed;
/** A variable to check if Reduction is used. */
private boolean isReductionUsed;
/** A variable to check if Name is used. */
private boolean isNameUsed;
/** A variable to check if Scope is used. */
private boolean isScopeUsed;
/** A variable to check if ScopeKind is used. */
private boolean isScopeKindUsed;
/** A variable to check if Analyzer is used. */
private boolean isAnalyzerUsed;
/**
* A list to store all declarations of
* instances of primitive list operations.
*/
protected List<Node> primitiveDeclList = new ArrayList<Node>();
/** A list to store all primitive instances. */
protected List<PrimitiveInstance> primitiveInsList =
new ArrayList<PrimitiveInstance>();
/** A list of types that are nodes. */
protected Pair<String> nodeTypes = null;
/**
* Initialise this transformer.
*
* @param ast the root of the typical ast
* @param s the name of the checker to be generated
* @param runt the runtime
*/
public Transformer(GNode ast, SymbolTable st, String s, Runtime runt) {
factory = new TreeFactory();
typical = ast;
output = s;
table = st;
runtime = runt;
// Set replaceType
if (runtime.test("optimizeType")) replaceType = true;
// Set optimizeLet
if (runtime.test("optimizeLet")) optimizeLet = true;
else optimizeLet = false;
spareVar = table.freshJavaId("spareVar");
// Get the name of the node type
String tempName = (String)runtime.getValue("optionNodeType");
if (null == tempName) nodeTypeName = "node";
else nodeTypeName = tempName;
/* Process the module declaration. */
dispatch(typical.getGeneric(0));
cbody = makeClassBody();
cbody = GNode.ensureVariable((GNode)cbody);
// Add spare variable declaration
if (optimizeLet) cbody.add(factory.fieldDecl3(spareVar));
tbody = GNode.create("ClassBody");
tbody = GNode.ensureVariable((GNode)tbody);
sbody = GNode.create("ClassBody");
sbody = GNode.ensureVariable((GNode)sbody);
}
/**
* Process the module.
*
* @param n The module node.
*/
public void visitModule(GNode n) {
boolean hasAttributes = false;
final int size = n.size();
for (int i = 0; i < size; i++) {
Node node = n.getGeneric(i);
if (node.hasName("AttributeDefinition") ||
node.hasName("EqualAttributeDefinition")) {
hasAttributes = true;
new TypeCollector().dispatch(node);
} else if (node.hasName("NameSpaceDefinition") ||
(node.hasName("TypeDefinition") &&
"raw_type".equals(node.getString(1)))) {
new TypeCollector().dispatch(node);
}
}
if (hasAttributes && replaceType) {
replaceType = false;
}
// Get the list of types that are nodes
@SuppressWarnings("unchecked")
Object ob = n.getProperty("__node_types");
Pair<String> nodeTypes = TypeMapper.getAnnotatedStringList(ob);
mapper = new TypeMapper(runtime, output + "Types", replaceType, nodeTypes);
/* Process attribute, equality, and namespaced definitions first. */
for (int j = 0; j < size; j++) {
Node node = n.getGeneric(j);
if(node.hasName("AttributeDefinition") ||
node.hasName("EqualAttributeDefinition") ||
node.hasName("EqualityDefinition") ||
node.hasName("NameSpaceDefinition")) {
dispatch(node);
}
}
for (int i = 0; i < size; i++) {
Node node = n.getGeneric(i);
/* Skip the node, attribute, equality and namespace declarations. */
if ((node.hasName("TypeDefinition") &&
nodeTypes.contains(node.getString(1))) ||
node.hasName("AttributeDefinition") ||
node.hasName("EqualAttributeDefinition") ||
node.hasName("EqualityDefinition") ||
node.hasName("NameSpaceDefinition")) {
continue;
}
dispatch(node);
if (node.hasName("TypeDefinition") &&
"raw_type".equals(node.getString(1))) {
dispatch(processRawTypeDefinition());
}
}
/* Add code to process scopes. */
processScopeSpace();
cbody.addAll(functionDefinitions);
sbody.addAll(primitiveDeclList);
sbody.addAll(staticFields);
tbody.add(factory.typesConstr(output + "Types"));
sbody.add(factory.typesConstr(output + "Support"));
// Make skeletons of generated files
transformed = GNode.cast(makeSkeleton());
typesAST = GNode.cast(makeTypesSkeleton());
supportAST = GNode.cast(makeSupportSkeleton());
}
/**
* Process a module declaration.
*
* @param n The ModuleDeclaration node.
*/
public void visitModuleDeclaration(GNode n) {
Node qid = GNode.create("QualifiedIdentifier");
StringBuilder buf = new StringBuilder();
for (int i = 0; i < n.size() - 1; i++) {
qid.add(n.getString(i));
buf.append(n.getString(i));
if (i < n.size() - 2) buf.append('.');
}
packageName = buf.toString();
packageNode = GNode.create("PackageDeclaration", null, qid);
}
/**
* Process a fun expression.
*
* @param n The fun expression node.
* @return The java code for the fun expression.
*/
public Node visitFunExpression(GNode n) {
Object t = n.getProperty(TYPE);
if (null == t) throw new AssertionError("Null type");
if (mapper.isFunctionType(t)) {
Node params = n.getGeneric(0);
Node value = n.getGeneric(1);
if (n.hasProperty(INANALYZE)) {
params.setProperty(INANALYZE, Boolean.TRUE);
value.setProperty(INANALYZE, Boolean.TRUE);
}
final String scopename = (String)n.getProperty("enterScope");
boolean didEnter = false;
if (n.hasProperty("enterScope")) {
if (!table.current().getName().equals(scopename)) {
enterScope(scopename);
didEnter = true;
}
}
// Get the number of type variables from the function type
final int typeVarNumber = mapper.processTypeVariables(t, 0);
// Check if this function is generic
final boolean isGeneric = typeVarNumber > 0;
Node returnTypeNode = mapper.getReturnTypeNode(t);
List<Node> paramTypeNodes = mapper.getParameterTypeNodes(t);
Node functionTypeNode = mapper.toTypeNode(t,false);
value.setProperty(TYPE, returnTypeNode);
//populate the formal parameters for the "apply" method
Node formalParameters = GNode.create("FormalParameters", params.size());
for (int i = 0; i < params.size(); i++) {
formalParameters.add(GNode.create("FormalParameter", fmod,
paramTypeNodes.get(i), null,
params.getGeneric(i).getString(0), null));
}
// Type parameters node
Node typeParas = null;
if (isGeneric) {
typeParas = GNode.create("TypeParameters");
for (int i = 0; i < typeVarNumber; i ++) {
typeParas.add(GNode.create("TypeParameter", "T" + i, null));
}
}
// Make a new let for the body if necessary
Object returnType = mapper.getReturnTypeObject(t);
Node valueExpr = (Node)dispatch(value);
valueExpr = checkToLet(valueExpr, returnType);
Node classBody = GNode.create("ClassBody",
GNode.create("MethodDeclaration", pmod, typeParas,
returnTypeNode, "apply", formalParameters, null, null,
GNode.create("Block", factory.ret(valueExpr))));
if (didEnter) exitScope(scopename);
return toNewExpression2(functionTypeNode,null,classBody);
} else throw new AssertionError("Function type is required");
}
/**
* Process a value definition.
*
* @param n The value binding node.
* @return The java code for the funciton
*/
public Node visitValueDefinition(GNode n) {
String name = n.getString(0);
Node params = n.getGeneric(1);
Node value = n.getGeneric(2);
String nsname = SymbolTable.toNameSpace(name, "value");
Object t = n.getProperty(TYPE);
if (null == t) t = table.current().lookup(nsname);
if (mapper.isFunctionType(t)) {
// Get the number of type variables from the function type
final int typeVarNumber = mapper.processTypeVariables(t, 0);
// Check if this function is generic
final boolean isGeneric = typeVarNumber > 0;
Node returnTypeNode = mapper.getReturnTypeNode(t);
List<Node> paramTypeNodes = mapper.getParameterTypeNodes(t);
Node functionTypeNode = mapper.toTypeNode(t, false);
//desugar function expressions
if (value.hasName("FunctionExpression")) {
String arg = table.freshJavaId("arg");
value = GNode.create("MatchExpression",
GNode.create("LowerID", arg), value.get(0));
value.setProperty("__arg_type",paramTypeNodes.get(0));
n.set(1, GNode.create("Parameters",
GNode.create("Parameter", arg , null)));
params = n.getGeneric(1);
} else if (value.hasName("ReduceExpression")) {
String arg = "lst";
n.set(1, GNode.create("Parameters",
GNode.create("Parameter", arg , null)));
params = n.getGeneric(1);
}
// Set property to remember value is in analyze function
if ("analyze".equals(name)) value.setProperty(INANALYZE, Boolean.TRUE);
value.setProperty(TYPE, returnTypeNode);
//populate the formal parameters for the "apply" method
Node formalParameters = GNode.create("FormalParameters", params.size());
for (int i = 0; i < params.size(); i++) {
formalParameters.add(GNode.create("FormalParameter", fmod,
paramTypeNodes.get(i), null,
params.getGeneric(i).getString(0), null));
}
//enter the scope and process this bindings value
if (!"getNameSpace".equals(name)) enterScope(name);
// Type parameters node
Node typeParas = null;
if (isGeneric) {
typeParas = GNode.create("TypeParameters");
for (int i = 0; i < typeVarNumber; i ++) {
typeParas.add(GNode.create("TypeParameter", "T" + i, null));
}
}
// The body of the function
Node block;
if (!optimizeLet) {
block = GNode.create("Block", factory.ret((Node)dispatch(value)));
} else {
block = GNode.create("Block");
block = GNode.ensureVariable(GNode.cast(block));
Node valueExpr = (Node)dispatch(value);
List<LetBinding> bindList = getBindings(valueExpr);
if (null != bindList) {
for (LetBinding bind : bindList) {
if (!bind.name.equals(spareVar)) {
if (mapper.hasTypeVariables(bind.typeObject)) {
block.add(factory.fieldDecl2(bind.type, bind.name, bind.value));
} else {
block.add(factory.fieldDecl2(bind.type, bind.name,
factory.cast(bind.value)));
}
} else {
if (mapper.hasTypeVariables(bind.typeObject)) {
block.add(factory.assign(toIdentifier(bind.name), bind.value));
} else {
block.add(factory.assign(toIdentifier(bind.name),
factory.cast(bind.value)));
}
}
}
}
block.add(factory.castReturn(valueExpr));
}
Node classBody = GNode.create("ClassBody",
GNode.create("MethodDeclaration", pmod, typeParas,
returnTypeNode, "apply", formalParameters, null, null, block));
if (!"getNameSpace".equals(name)) exitScope(name);
//create and add the fielddeclaration to the typechecker
if ("getNameSpace".equals(name) || "getScope".equals(name)) {
return makeVarDec2(name,functionTypeNode,
toNewExpression2(functionTypeNode,null,classBody));
} else {
// If not a generic function, create a field declaration
if (!isGeneric){
functionDefinitions.add(makeVarDec2(name,functionTypeNode,
toNewExpression2(functionTypeNode,null,classBody)));
} else { // create a class
Node classNode = factory.classDecl3(name);
classNode.set(5, classBody);
functionDefinitions.add(classNode);
functionDefinitions.add(
factory.instanceDecl(GNode.create("Type",
GNode.create("QualifiedIdentifier",name),null),
name,
GNode.create("QualifiedIdentifier",name)));
}
}
} else {
//no function needed, just field declaration
//value.setProperty(NEWLET, Boolean.TRUE);
Node valueExpr = (Node)dispatch(value);
valueExpr = checkToLet(valueExpr, t);
// fix cast here
if (mapper.hasTypeVariables(t)) {
functionDefinitions.add(makeVarDec2(name, mapper.toTypeNode(t, false),
valueExpr));
} else {
functionDefinitions.add(makeVarDec2(name, mapper.toTypeNode(t, false),
factory.cast(valueExpr)));
}
}
// Note: in general, we modify the AST in place and are done. For
// getNameSpace() and getScope(), however, we need to do further
// processing; so they are returned above.
return null;
}
/**
* Process a function expression
*
* @param n The function expression node
* @return The translated node
*/
public Node visitFunctionExpression(GNode n) {
// Get the function type
final Object t = n.getProperty(TYPE);
final Node returnTypeNode = mapper.getReturnTypeNode(t);
final List<Node> paramTypeNodes = mapper.getParameterTypeNodes(t);
// Get the return type from the pattern match type
final Object retType =
mapper.getPatternMatchRightType(n.getGeneric(0).getProperty(TYPE));
// Create a Typical match expression node
Node value = GNode.create("MatchExpression",
GNode.create("LowerID", "var"), n.getGeneric(0));
value.setProperty("__arg_type", paramTypeNodes.get(0));
value.setProperty(TYPE, retType);
return factory.functionExpression(
returnTypeNode, paramTypeNodes.get(0), (Node)dispatch(value));
}
/**
* Process a type definition.
*
* @param n The type definition node.
*/
public void visitTypeDefinition(GNode n) {
n.getGeneric(2).setProperty("name", n.getString(1));
dispatch(n.getGeneric(2));
}
/**
* Process a string literal.
*
* @param n The string literal node.
* @return n.
*/
public GNode visitStringLiteral(GNode n) {
return n;
}
/**
* Process an integer literal.
*
* @param n the integer literal node.
* @return The BigInteger node.
*/
public Node visitIntegerLiteral(GNode n) {
return factory.createInteger(toLiteral("IntegerLiteral", n.getString(0)));
}
/**
* Process a float literal.
*
* @param n the float literal node.
* @return The 'new Double' node.
*/
public Node visitFloatingLiteral(GNode n) {
return
factory.createFloat(toLiteral("FloatingPointLiteral", n.getString(0)));
}
/**
* Process a bottom node.
*
* @param n The bottom node.
* @return A null literal.
*/
public Node visitBottom(GNode n) {
return GNode.create("NullLiteral");
}
/**
* Process a bottom pattern.
*
* @param n The bottom pattern node.
* @return A null literal.
*/
public Node visitBottomPattern(GNode n) {
return
factory.equalsBottom(toIdentifier((String)n.getProperty(MATCHARG)));
}
/**
* Process a boolean literal.
*
* @param n the boolean literal node.
*/
public Node visitBooleanLiteral(GNode n) {
return ("true".equals(n.getString(0))) ? toIdentifier("Boolean.TRUE")
: toIdentifier("Boolean.FALSE");
}
/**
* Process a cons expression.
*
* @param n The cons expression node.
* @return The java equivalent.
*/
public Node visitConsExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
if (!optimizeLet) {
return factory.consWrapper((Node)dispatch(n.getGeneric(0)),
(Node)dispatch(n.getGeneric(1)));
} else {
List<String> upVars = getUpVariables(n);
Node left = n.getGeneric(0);
Node right = n.getGeneric(1);
if (null != upVars) left.setProperty(UPVARS, upVars);
Node leftExpr = (Node)dispatch(left);
List<LetBinding> bl1 = getBindings(leftExpr);
List<String> leftVars = extractVariables(bl1);
List<String> upVars2 = groupList(upVars,leftVars);
if (null != upVars2) right.setProperty(UPVARS, upVars2);
Node rightExpr = (Node)dispatch(right);
List<LetBinding> bl2 = getBindings(rightExpr);
List<LetBinding> bl = groupList(bl1,bl2);
Node ret = factory.consWrapper(leftExpr, rightExpr);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
/**
* Transform a wildcard.
*
* @param n The wildcard node.
* @return A wildcard primary identifier.
*/
public Node visitWildCard(GNode n) {
return toLiteral("BooleanLiteral", "true");
}
/**
* Process a field expression.
*
* @param n The field expression node.
* @return A java field access node (with null pointer checks inserted).
*/
public Node visitFieldExpression(GNode n) {
Node expr = n.getGeneric(0);
if (n.hasProperty(INANALYZE)) {
expr.setProperty(INANALYZE, Boolean.TRUE);
}
if ("TupleConstructor".equals(expr.getName())) {
String convertedName = Primitives.convertName(n.getString(1));
if ("Limits".equals(expr.getString(0))) {
if (Primitives.hasIntegerType(convertedName)) {
return factory.createInteger(toIdentifier(
"xtc.Limits." + convertedName));
}
return toIdentifier("xtc.Limits." + convertedName);
}
return toIdentifier("Primitives." + convertedName);
}
passVariables(n, expr);
// Check replaceType and the field name
if (replaceType && "type".equals(n.getString(1))) {
return (Node)dispatch(expr);
}
Node exprNode = (Node)dispatch(expr);
Node ret = factory.fieldExpression(exprNode, n.getString(1));
passBindings(exprNode, ret);
return ret;
}
/**
* Process a tuple literal.
*
* @param n The tuple literal node.
* @return The java equivalent.
*/
public Node visitTupleLiteral(GNode n) {
return makeTuple(n);
}
/**
* Process a tuple pattern.
*
* @param n The tuple pattern node.
* @return The java equivalent.
*/
public Node visitTuplePattern(GNode n) {
String matchArg = (String)n.getProperty(MATCHARG);
Node condition =
factory.jand(factory.notEqualsBottom(toIdentifier(matchArg)),
factory.sizeEqual(toIdentifier(matchArg), toLiteral("IntegerLiteral",
Integer.toString(n.size()))));
for (int i = 0; i < n.size(); i++) {
Node node = n.getGeneric(i);
if (node.hasName("WildCard")) continue;
if (node.hasName("Variable")) {
//make the binding
node.setProperty(RHS, matchArg + ".get" + (i + 1) + "()");
node.setProperty(BINDINGS, n.getProperty(BINDINGS));
dispatch(node);
continue;
}
if (isLiteral(node)) {
condition = factory.jand(condition,
factory.jequals2((Node)dispatch(node),
toIdentifier(matchArg + ".get" + (i + 1) + "()")));
continue;
}
node.setProperty(RHS, matchArg + ".get" + (i + 1) + "()");
node.setProperty(BINDINGS, (n.getProperty(BINDINGS)));
node.setProperty(MATCHARG, (String)n.getProperty(MATCHARG) +
".get" + (i + 1) + "()");
condition = factory.jand(condition, (Node)dispatch(node));
}
if (n.hasProperty(TOP)) {
String matchName = table.freshJavaId("match");
condition = replaceMatchArg(condition, matchArg);
Match ms = new Match(mapper.toTypeNode(n.getProperty(TYPE), false),
condition);
if (matches.containsKey(ms)) {
matchName = matches.get(ms);
} else {
matches.put(ms, matchName);
Object t = n.getProperty(TYPE);
Node tNode = null;
if (mapper.hasTypeVariables(t)) {
tNode = mapper.toTypeNode(t, true);
} else {
tNode = mapper.toTypeNode(t, false);
}
Node matchFunction =
factory.matchFunction(matchName, tNode, condition);
matchFunction.getGeneric(4).getGeneric(0).set(3, "m");
staticFields.add(matchFunction);
}
return factory.matchCall(toIdentifier(output + "Support"), matchName,
toIdentifier((String)n.getProperty(MATCHARG)));
} else {
return condition;
}
}
/**
* Process a List literal.
*
* @param n The list literal node.
* @return The java equivalent.
*/
public Node visitListLiteral(GNode n) {
return makeList(n);
}
/**
* Make conditions identical with respect to argument name so we can generate
* unique match functions;
*
* @param n The node to process.
* @param id The name of the id to replace.
* @return The processed node.
*/
private Node replaceMatchArg(Node n, String id) {
for (int i = 0; i < n.size(); i++) {
Object o = n.get(i);
if (o instanceof Node) {
Node node = (Node)o;
if (node.hasName("PrimaryIdentifier") &&
node.getString(0).equals(id)) {
node.set(0, node.getString(0).replace(id,"m"));
} else if (node.hasName("PrimaryIdentifier") &&
node.getString(0).startsWith(id + ".")) {
node.set(0, node.getString(0).replace(id + ".", "m."));
} else {
replaceMatchArg(node, id);
}
} else if ((o instanceof String) && id.equals(o)) {
n.set(i, id);
}
}
return n;
}
/**
* Process a List pattern.
*
* @param n The list pattern node.
* @return The java equivalent.
*/
public Node visitListPattern(GNode n) {
checkTypeAnnotation(n);
String matchArg = (String)n.getProperty(MATCHARG);
Node condition = (0 == n.size())
? factory.isEmptyCall(toIdentifier(matchArg))
: factory.sizeEqual(toIdentifier(matchArg),
toLiteral("IntegerLiteral", Integer.toString(n.size())));
for (int i = 0; i < n.size(); i++) {
Node node = n.getGeneric(i);
if (node.hasName("WildCard")) continue;
if (node.hasName("Variable")) {
// fix cast here
Object t = n.getProperty(TYPE);
if (mapper.hasTypeVariables(t)) {
((Node)n.getProperty(BINDINGS)).add(makeVarDec2(node.getString(0),
mapper.toTypeNode(mapper.getBase(t), false),
toIdentifier(matchArg + ".get(" + i + ")")));
} else {
((Node)n.getProperty(BINDINGS)).add(makeVarDec2(node.getString(0),
mapper.toTypeNode(mapper.getBase(t), false),
factory.cast(toIdentifier(matchArg + ".get(" + i + ")"))));
}
continue;
}
if (isLiteral(node)) {
condition = factory.jand(condition,
factory.jequals2((Node)dispatch(node),
toIdentifier(matchArg + ".get(" + i + ")")));
continue;
}
node.setProperty(BINDINGS, n.getProperty(BINDINGS));
node.setProperty(MATCHARG, matchArg + ".get(" + i + ")");
condition = factory.jand(condition, (Node)dispatch(node));
}
if (n.hasProperty(TOP)) {
Object t = n.getProperty(TYPE);
Node listTypeNode = null;
if (mapper.hasTypeVariables(t)) {
listTypeNode = mapper.toTypeNode(t, true);
} else {
listTypeNode = mapper.toTypeNode(t, false);
}
condition = replaceMatchArg(condition, matchArg);
String matchName = table.freshJavaId("match");
Match ms = null;
ms = new Match(listTypeNode, condition);
if (matches.containsKey(ms)) {
matchName = matches.get(ms);
} else {
matches.put(ms, matchName);
Node matchFunction =
factory.matchFunction(matchName, listTypeNode, condition);
matchFunction.getGeneric(4).getGeneric(0).set(3, "m");
staticFields.add(matchFunction);
}
return factory.matchCall(toIdentifier(output + "Support"), matchName,
toIdentifier((String)n.getProperty(MATCHARG)));
} else {
return condition;
}
}
/**
* Transform a predicate expression.
*
* @param n The predicate expression.
* @return The java equivalent.
*/
public Node visitPredicateExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
Node arg = n.getGeneric(0).getGeneric(0);
for (int i = 0; i < arg.size(); i++) {
Node node = arg.getGeneric(i);
node.setProperty(RHS, RHS);
node.setProperty(BINDINGS, GNode.create("Block"));
node.setProperty("enterScope", "scope" + i);
}
Node wild = GNode.create("WildCard");
wild.setProperty("enterScope", "ihavenoscope");
Node last = GNode.create("PatternMatch",
GNode.create("Patterns",wild),GNode.create("BooleanLiteral", "false"));
Node first = GNode.create("PatternMatch", n.getGeneric(0).getGeneric(0),
GNode.create("BooleanLiteral", "true"));
Node pmatching = GNode.create("PatternMatching", first, last);
Object pt = mapper.makePatternMatchType(arg.getProperty(TYPE),
n.getProperty(TYPE));
first.setProperty(TYPE, pt);
last.setProperty(TYPE, pt);
pmatching.setProperty(TYPE, pt);
first.setProperty("enterScope", "predicatescope");
last.setProperty("enterScope", "predicatescope");
Node match = GNode.create("MatchExpression", n.getGeneric(1), pmatching);
match.setProperty("__arg_type", n.getProperty("__arg_type"));
match.setProperty(TYPE, n.getProperty(TYPE));
return
factory.jequals2((Node)dispatch(match),toLiteral("BooleanLiteral","true"));
}
/**
* Transform a guard expression.
*
* @param n
*/
public Node visitGuardExpression(GNode n) {
//we need to collect all the variables and test for nullity
Set<String> variables = new FreeVariableCollector(n).getIdentifiers();
List<Node> statements = new ArrayList<Node>();
Object t = n.getGeneric(0).getProperty(TYPE);
Node typeNode = mapper.toTypeNode(t, false);
String name = table.freshJavaId("result");
for (String variable : variables) {
statements.add(factory.
ifStatement(factory.isNull(toIdentifier(variable)),
factory.ret(toIdentifier("null"))));
}
Node no = n.getGeneric(0);
if (n.hasProperty(INANALYZE)) {
no.setProperty(INANALYZE, Boolean.TRUE);
}
passVariables(n, no);
Node expr = (Node)dispatch(no);
statements.add(factory.fieldDecl2(typeNode, name,expr));
// fix cast here
if (mapper.hasTypeVariables(t)) {
statements.add(factory.ifStatement(factory.isNull(toIdentifier(name)),
factory.ret((Node)dispatch(n.getGeneric(1)))));
} else {
statements.add(factory.ifStatement(factory.isNull(toIdentifier(name)),
factory.ret(factory.cast((Node)dispatch(n.getGeneric(1))))));
}
statements.add(factory.ret(toIdentifier(name)));
Node ret = factory.guardExpression(typeNode, statements);
passBindings(expr, ret);
return ret;
}
/**
* Transform a reduce expression.
*
* @param n The predicate expression.
* @return The java equivalent.
*/
public Node visitReduceExpression(GNode n) {
Node arg = toIdentifier("lst");
Node runtimeNode = toIdentifier("runtime");
List<Node> initList = new ArrayList<Node>();
Node options = n.getGeneric(0);
for (int i = 0; i < options.size(); i++) {
String opt = options.getString(i);
if ("required".equals(opt)) {
initList.add(factory.reduceReq());
} else if ("optional".equals(opt)) {
initList.add(factory.reduceOpt());
} else if ("list".equals(opt)) {
initList.add(factory.reduceList());
} else if ("set".equals(opt)) {
initList.add(factory.reduceSet());
} else if ("dup".equals(opt)) {
initList.add(factory.reduceDup());
} else if ("nodup".equals(opt)) {
initList.add(factory.reduceNodup());
} else if ("singleton".equals(opt)) {
initList.add(factory.reduceSing());
}
}
//set the tag
initList.add(factory.reduceTag(n.getGeneric(1)));
Node patternMatching = n.getGeneric(2);
for (int i = 0; i < patternMatching.size(); i++) {
Node patternMatch = patternMatching.getGeneric(i);
ArrayList<Node> addArgs = new ArrayList<Node>();
ArrayList<Node> block = new ArrayList<Node>();
addArgs.add((Node)dispatch(patternMatch.getGeneric(1)));
Node lpatterns = patternMatch.getGeneric(0).getGeneric(0);
for (int j = 0; j < lpatterns.size(); j++) {
Node node = lpatterns.getGeneric(j);
if (node.hasName("AsPattern")) {
String binding = node.getString(1);
node = node.getGeneric(0);
node.setProperty("ancestor", true);
node.setProperty("top", true);
node.setProperty(MATCHARG, table.freshJavaId("arg"));
block.add(factory.reduceGetMatch(binding, (Node)dispatch(node)));
}
node.setProperty("ancestor", true);
node.setProperty("top", true);
node.setProperty(MATCHARG, table.freshJavaId("arg"));
addArgs.add((Node)dispatch(node));
}
block.add(factory.reduceAddPatterns(addArgs));
initList.add(factory.block(block));
}
return factory.cast(factory.reduceExpression(arg, runtimeNode, initList));
}
/**
* Process a function application.
*
* @param n The function application node.
* @return The java equivalent of the function application node.
*/
public Node visitFunctionApplication(GNode n) {
// Get function arguments
Node funcArgs = n.getGeneric(n.size() - 1);
Node id = n.getGeneric(0);
if ("ancestor".equals(id.getString(0)) ||
"parent".equals(id.getString(0))) {
Node arg = funcArgs.getGeneric(0);
arg.setProperty("ancestor", true);
arg.setProperty(MATCHARG, table.freshJavaId("arg"));
arg = (Node)dispatch(arg);
List<Node> nlist = new ArrayList<Node>(1);
nlist.add(arg);
return factory.apply(toIdentifier(id.getString(0)),nlist);
}
//special case
// Annotate if this function application is in analyze function
if (n.hasProperty(INANALYZE)) {
for (int i = 0; i < funcArgs.size(); i++) {
funcArgs.getGeneric(i).setProperty(INANALYZE, Boolean.TRUE);
}
}
//process arguments
Node args = GNode.create("Arguments");
List<LetBinding> bl = null;
List<String> upVars = getUpVariables(n);
for (int i = 0; i < funcArgs.size(); i++) {
Node arg = funcArgs.getGeneric(i);
if (null != upVars) arg.setProperty(UPVARS, upVars);
Node expr = (Node)dispatch(arg);
List<LetBinding> l = getBindings(expr);
List<String> vars = extractVariables(l);
upVars = groupList(upVars, vars);
bl = groupList(bl,l);
args.add(expr);
}
// Name of this function
final String funcName;
// Name is this function in Java's style
final String newName;
// Type of this function
final Object funcType;
// Parameter types of this function
final List<String> paramTypes;
final List<Node> paramTypeNodes;
// Return type of this function
final Node retTypeNode;
Node ret = null;
// Process function application of the form Name.name ...
if (3 == n.size()) {
// All functions here are in Primitives
// Module name
String moduleName = n.getGeneric(0).getString(0);
if ("Prelude".equals(moduleName)) {
// Functions of this form: Prelude.name
funcName = n.getGeneric(1).getString(0);
} else {
funcName = moduleName + "." + n.getGeneric(1).getString(0);
}
// Get type of this function
funcType = table.current().lookup("value(" + funcName + ")");
// Get parameter type list
paramTypes = mapper.getParameterTypes(funcType);
paramTypeNodes = mapper.getParameterTypeNodes(funcType);
// Get return type
retTypeNode = mapper.getReturnTypeNode(funcType);
// Java's style of the function name
newName = Primitives.convertName(n.getGeneric(1).getString(0));
// Process get and put here
if ("Map".equals(moduleName)) {
List<Node> args1 = new ArrayList<Node>();
if ("get".equals(newName)) {
// This must be a complete function application
args1.add(args.getGeneric(0));
args1.add(toIdentifier("hashTable"));
ret = factory.castInvocation(toIdentifier("Primitives.get"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
if (2 == args.size()) {
// complete application
args1.add(args.getGeneric(0));
args1.add(args.getGeneric(1));
args1.add(toIdentifier("hashTable"));
ret = factory.castInvocation(toIdentifier("Primitives.put"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
// incomplete application
String tempVar = table.freshJavaId("var");
ret = factory.curryingPut(toIdentifier(tempVar), args.getGeneric(0));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
}
//check if this is a complete or imcomplete function application
if (args.size() == paramTypes.size()) {
// This is a complete function application
// Special case the pair ops are generic
final String newInstance;
Node newIns = null;
// Instances with one type parameter
if ("head".equals(newName) || "tail".equals(newName) ||
"append".equals(newName) || "union".equals(newName) ||
"cons".equals(newName) || "nth".equals(newName) ||
"intersection".equals(newName) || "subtraction".equals(newName)) {
final Object t =
mapper.getBase(funcArgs.getGeneric(0).getProperty(TYPE));
final String typeName = mapper.toTypeString(t);
final Node typeNode = mapper.toTypeNode(t, false);
// Check for type variables
if (mapper.hasTypeVariables(t)) {
if ("head".equals(newName)) {
ret = factory.newApplyHead(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("tail".equals(newName)) {
ret = factory.newApplyHead(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("append".equals(newName)) {
ret = factory.newApplyAppend(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("union".equals(newName)) {
ret = factory.newApplyUnion(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("cons".equals(newName)) {
ret = factory.newApplyCons(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("nth".equals(newName)) {
ret = factory.newApplyNth(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("intersection".equals(newName)) {
ret = factory.newApplyIntersection(typeNode,
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("subtraction".equals(newName)) {
ret = factory.newApplySubtraction(typeNode,
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
List<String> instanceTypes = new ArrayList<String>();
instanceTypes.add(typeName);
String instanceName = getInstanceName(newName, instanceTypes);
if (null == instanceName) {
newInstance = table.freshJavaId(newName);
primitiveInsList.add(new PrimitiveInstance(newName, instanceTypes,
newInstance));
} else {
newInstance = instanceName;
}
// Create a new instances with one type parameter
if (null == instanceName && "head".equals(newName)) {
newIns = factory.newHead(typeNode, newInstance);
} else if (null == instanceName && "tail".equals(newName)) {
newIns = factory.newTail(typeNode, newInstance);
} else if (null == instanceName && "append".equals(newName)){
newIns = factory.newAppend(typeNode, newInstance);
} else if (null == instanceName && "union".equals(newName)) {
newIns = factory.newUnion(typeNode, newInstance);
} else if (null == instanceName && "cons".equals(newName)) {
newIns = factory.newCons(typeNode, newInstance);
} else if (null == instanceName && "nth".equals(newName)) {
newIns = factory.newNth(typeNode, newInstance);
} else if (null == instanceName && "intersection".equals(newName)) {
newIns = factory.newIntersection(typeNode, newInstance);
} else if (null == instanceName && "subtraction".equals(newName)) {
newIns = factory.newSubtraction(typeNode, newInstance);
}
if (null == instanceName) primitiveDeclList.add(newIns);
ret = factory.apply(toIdentifier(output + "Support." + newInstance),
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
if ("exists".equals(newName)) {
final Object t =
mapper.getBase(funcArgs.getGeneric(1).getProperty(TYPE));
final String typeName = mapper.toTypeString(t);
final Node typeNode = mapper.toTypeNode(t, false);
// check for type variables
if (mapper.hasTypeVariables(t)) {
ret = factory.newApplyExists(typeNode, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
List<String> instanceTypes = new ArrayList<String>();
instanceTypes.add(typeName);
String instanceName = getInstanceName(newName, instanceTypes);
if (null == instanceName) {
newInstance = table.freshJavaId(newName);
primitiveInsList.add(new PrimitiveInstance(newName, instanceTypes,
newInstance));
newIns = factory.newExists(typeNode, newInstance);
primitiveDeclList.add(newIns);
} else {
newInstance = instanceName;
}
ret = factory.apply(toIdentifier(output + "Support." + newInstance),
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
// Instances with two type parameters
if ("map".equals(newName) || "iter".equals(newName)) {
final Object t1 = funcArgs.getGeneric(0).getProperty(TYPE);
final String typeName1 = mapper.getReturnType(t1);
final Node typeNode1 = mapper.getReturnTypeNode(t1);
final Object t2 =
mapper.getBase(funcArgs.getGeneric(1).getProperty(TYPE));
final String typeName2 = mapper.toTypeString(t2);
final Node typeNode2 = mapper.toTypeNode(t2, false);
// Check for type variables
if (mapper.hasTypeVariables(t1) || mapper.hasTypeVariables(t2)) {
if ("map".equals(newName)) {
ret = factory.newApplyMap(typeNode1, typeNode2,
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if ("iter".equals(newName)) {
ret = factory.newApplyIter(typeNode1, typeNode2,
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
List<String> instanceTypes = new ArrayList<String>();
instanceTypes.add(typeName1);
instanceTypes.add(typeName2);
String instanceName = getInstanceName(newName, instanceTypes);
if (null == instanceName) {
newInstance = table.freshJavaId(newName);
primitiveInsList.add(new PrimitiveInstance(newName, instanceTypes,
newInstance));
} else {
newInstance = instanceName;
}
if (null == instanceName && "map".equals(newName)) {
newIns = factory.newMap(typeNode1, typeNode2, newInstance);
} else if (null == instanceName && "iter".equals(newName)) {
newIns = factory.newIter(typeNode1, typeNode2, newInstance);
}
if (null == instanceName) primitiveDeclList.add(newIns);
ret = factory.apply(toIdentifier(output + "Support." + newInstance),
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
if ("foldl".equals(newName)) {
final Object t1 = funcArgs.getGeneric(2).getProperty(TYPE);
final String typeName1 = mapper.toTypeString(t1);
final Node typeNode1 = mapper.toTypeNode(t1, false);
final Object t2 =
mapper.getBase(funcArgs.getGeneric(1).getProperty(TYPE));
final String typeName2 = mapper.toTypeString(t2);
final Node typeNode2 = mapper.toTypeNode(t2, false);
// Check for type variables
if (mapper.hasTypeVariables(t1) || mapper.hasTypeVariables(t2)) {
ret = factory.newApplyFoldl(typeNode1, typeNode2,
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
List<String> instanceTypes = new ArrayList<String>();
instanceTypes.add(typeName1);
instanceTypes.add(typeName2);
String instanceName = getInstanceName(newName, instanceTypes);
if (null == instanceName) {
newInstance = table.freshJavaId(newName);
primitiveInsList.add(new PrimitiveInstance(newName, instanceTypes,
newInstance));
newIns = factory.newFoldl(typeNode1, typeNode2, newInstance);
primitiveDeclList.add(newIns);
} else {
newInstance = instanceName;
}
ret = factory.apply(toIdentifier(output + "Support." + newInstance),
makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
// Other primitive functions
ret = factory.applyPrimitive(newName, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
// This is an incomplete function application, process currying
ret = makeCurry("Primitives." + newName, args,
paramTypeNodes, retTypeNode, funcType);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
} else { // Process function application of this form: name ...
funcName = n.getGeneric(0).getString(0);
// Java's style of the function name
newName = Primitives.convertName(n.getGeneric(0).getString(0));
List<Node> args1 = new ArrayList<Node>();
// Process symbol table function applications, they must be complete.
if ("lookup".equals(newName)||"lookupLocally".equals(newName)) {
if (1 == funcArgs.size()) {
// If it has only one child, that must be a node
args1.add((Node)dispatch(funcArgs.getGeneric(0)));
args1.add(toIdentifier("getNameSpace"));
ret = factory.castInvocation(toIdentifier(newName + "2"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else if(2 == funcArgs.size()) {
Node arg = (Node)dispatch(funcArgs.getGeneric(0));
if ("ErrorClause".equals(funcArgs.getGeneric(1).getName())) {
// If the second child is a error clause.
String tag = funcArgs.getGeneric(1).getGeneric(0).getString(0);
args1.add(arg);
args1.add(toLiteral("StringLiteral", "\"" + tag + "\""));
args1.add((Node)dispatch(funcArgs.getGeneric(1).getGeneric(1)));
args1.add(toIdentifier("getNameSpace"));
ret = factory.castInvocation(toIdentifier(newName + "4"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
// The second child is a tag.
args1.add(arg);
args1.add(toIdentifier("getNameSpace"));
ret = factory.castInvocation(toIdentifier(newName + "2"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
} else {
// The arguments include: node, tag and error clause in that order.
String tag = funcArgs.getGeneric(2).getGeneric(0).getString(0);
args1.add((Node)dispatch(funcArgs.getGeneric(0)));
args1.add(toLiteral("StringLiteral", "\"" + tag + "\""));
args1.add((Node)dispatch(funcArgs.getGeneric(2).getGeneric(1)));
args1.add(toIdentifier("getNameSpace"));
ret = factory.castInvocation(toIdentifier(newName + "4"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
// Process define.
if ("define".equals(newName)) {
if (2 == funcArgs.size()) {
// It is has 2 children, they must be a node and a type.
args1.add((Node)dispatch(funcArgs.getGeneric(0)));
args1.add((Node)dispatch(funcArgs.getGeneric(1)));
args1.add(toIdentifier("getNameSpace"));
ret = factory.apply(toIdentifier("define3"), args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
// It has 3 children: node, type and and error clause in that order.
String tag = funcArgs.getGeneric(2).getGeneric(0).getString(0);
args1.add((Node)dispatch(funcArgs.getGeneric(0)));
args1.add((Node)dispatch(funcArgs.getGeneric(1)));
args1.add(toLiteral("StringLiteral", "\"" + tag + "\""));
args1.add((Node)dispatch(funcArgs.getGeneric(2).getGeneric(1)));
args1.add(toIdentifier("getNameSpace"));
ret = factory.invocation(toIdentifier("define5"),
"apply", args1);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
//process redefine, isDefined, and isDefinedLocally
if ("isDefined".equals(newName) || "isDefinedLocally".equals(newName)
|| "redefine".equals(newName)) {
args.add(toIdentifier("getNameSpace"));
ret = factory.apply(toIdentifier(newName),makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
// Get the type of this function
funcType = table.current().lookup("value(" + funcName + ")");
// Get parameter type
paramTypes = mapper.getParameterTypes(funcType);
paramTypeNodes = mapper.getParameterTypeNodes(funcType);
// Get return type
retTypeNode = mapper.getReturnTypeNode(funcType);
// check for complete and incomplete function applications
if (args.size() == paramTypes.size()) {
// Complete function application
if (Primitives.isPrimitive(newName)) {
ret = factory.applyPrimitive(newName, makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
ret = factory.apply(toIdentifier(newName),makeArgumentList(args));
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
} else {
// incomplete function application
if (Primitives.isPrimitive(newName)) {
ret = makeCurry("Primitives." + newName, args,
paramTypeNodes, retTypeNode, funcType);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
} else {
ret = makeCurry(newName, args, paramTypeNodes,
retTypeNode, funcType);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
}
}
}
/**
* Make a java expresson to represent a tuple.
*
* @param n The typical tuple node.
* @return The java representation.
*/
private Node makeTuple(GNode n) {
GNode args = GNode.create("Arguments");
List<String> upVars = getUpVariables(n);
List<LetBinding> bl = null;
for (int i = 0; i < n.size(); i++) {
Node no = n.getGeneric(i);
if (n.hasProperty(INANALYZE)) {
no.setProperty(INANALYZE, Boolean.TRUE);
}
if (null != upVars) no.setProperty(UPVARS,upVars);
Node expr = (Node)dispatch(no);
args.add(expr);
List<LetBinding> l = getBindings(expr);
List<String> vars = extractVariables(l);
upVars = groupList(upVars, vars);
bl = groupList(bl,l);
}
final List<Node> members = mapper.getMemberNodes(n.getProperty(TYPE));
// Make type arguments
Node typeArgs = GNode.create("TypeArguments");
final Node typeNode;
for (Node ob : members) typeArgs.add(ob);
if (!members.isEmpty()) {
typeNode = GNode.create("Type",
GNode.create("InstantiatedType",
GNode.create("TypeInstantiation", "Tuple", null),
GNode.create("TypeInstantiation", "T" + members.size(),
typeArgs)),
null);
} else {
typeNode = GNode.create("Type",
GNode.create("QualifiedIdentifier", "Tuple", "T0"),
null);
}
Node ret = toNewExpression2(typeNode, args,null);
if (null != bl) ret.setProperty(LETBINDINGS,bl);
return ret;
}
/**
* Create java code for a list literal.
*
* @param n The list expression or pattern node.
* @return A Pair representing this list.
*/
private Node makeList(GNode n) {
List<Node> arguments = new ArrayList<Node>(n.size());
List<LetBinding> bl = null;
List<String> upVars = getUpVariables(n);
//process each list element
for (int i = 0; i < n.size(); i++) {
Node no = n.getGeneric(i);
if (n.hasProperty(INANALYZE)) {
no.setProperty(INANALYZE, Boolean.TRUE);
}
if (null != upVars) no.setProperty(UPVARS, upVars);
Node expr = (Node)dispatch(no);
arguments.add(expr);
List<LetBinding> l = getBindings(expr);
List<String> vars = extractVariables(l);
upVars = groupList(upVars, vars);
bl = groupList(bl,l);
}
if (arguments.isEmpty()) {
final String typeName = getType(mapper.getBase(n.getProperty(TYPE)));
final Node typeNode = mapper.toTypeNode(
mapper.getBase(n.getProperty(TYPE)), false);
if ("Object".equals(typeName)) {
return factory.invocation(toIdentifier("Pair"), "empty", arguments);
} else {
return factory.pairEmpty(typeNode);
}
}
//cons up the list
Node newPair = factory.newPair(
mapper.toTypeNode(n.getProperty(TYPE), false), arguments.get(0));
for (int i = 1; i < arguments.size(); i++) {
newPair = factory.appendPair(newPair,
toNewExpression2(mapper.toTypeNode(n.getProperty(TYPE), false),
GNode.create("Arguments", arguments.get(i)), null));
}
if (null != bl) newPair.setProperty(LETBINDINGS, bl);
return newPair;
}
/**
* Process a cons pattern.
*
* @param n The cons pattern node.
* @return The java equivalent.
*/
public Node visitConsPattern(GNode n) {
String name = table.freshJavaId("list");
String rhs = (String)n.getProperty(RHS);
String matchArg = (String)n.getProperty(MATCHARG);
// fix cast here
Object t = n.getProperty(TYPE);
if (mapper.hasTypeVariables(t)) {
((Node)n.getProperty(BINDINGS)).add(makeVarDec2(name,
mapper.toTypeNode(t, false),
toIdentifier(rhs)));
} else {
((Node)n.getProperty(BINDINGS)).add(makeVarDec2(name,
mapper.toTypeNode(t, false),
factory.cast(toIdentifier(rhs))));
}
Node head = n.getGeneric(0);
head.setProperty(MATCHARG, "Primitives.wrapHead(" + matchArg + ")");
head.setProperty(RHS, "Primitives.wrapHead(" + name + ")");
head.setProperty(BINDINGS, n.getProperty(BINDINGS));
Node tail = n.getGeneric(1);
tail.setProperty(MATCHARG,"Primitives.wrapTail(" + matchArg + ".tail()");
tail.setProperty(RHS, "Primitives.wrapTail(" + name + ")");
tail.setProperty(BINDINGS, n.getProperty(BINDINGS));
if ((head.hasName("WildCard") || head.hasName("Variable")) &&
(tail.hasName("WildCard") || tail.hasName("Variable"))) {
dispatch(head);
dispatch(tail);
return factory.isNotEmptyCall(toIdentifier(matchArg));
} else if (tail.hasName("WildCard") || tail.hasName("Variable")) {
head = (Node)dispatch(head);
dispatch(tail);
return factory.jequals(head,factory.headWrapper(toIdentifier(matchArg)));
} else if (head.hasName("WildCard") || head.hasName("Variable")) {
tail = (Node)dispatch(tail);
dispatch(head);
return factory.jequals(tail,factory.tailWrapper(toIdentifier(matchArg)));
}
return factory.jand(factory.jequals((Node)dispatch(head),
factory.headWrapper(toIdentifier(matchArg))),
factory.jequals((Node)dispatch(tail),
factory.tailWrapper(toIdentifier(matchArg))));
}
/**
* Process a match expression type.
*
* @param n The match expression node.
* @return The java equivalent.
*/
public Node visitMatchExpression(GNode n) {
Object argType =
mapper.getPatternMatchLeftType(n.getGeneric(1).getProperty(TYPE));
String matchArg = table.freshJavaId("arg");
n.getGeneric(1).setProperty(TOP, null);
n.getGeneric(1).setProperty(MATCHARG, matchArg);
n.getGeneric(1).setProperty(RHS, matchArg);
List<Node> nodes = new ArrayList<Node>();
final Node argTypeNode = mapper.toTypeNode(argType, false);
if (nodeType.equals(argTypeNode) ||
gnodeType.equals(argTypeNode)) {
nodes.add(makeVarDec2(matchArg, argTypeNode,
factory.gnodeCast((Node)dispatch(n.getGeneric(0)))));
if (n.hasProperty(INANALYZE)) {
n.getGeneric(1).setProperty(ANNOTATE, Boolean.TRUE);
} else {
n.getGeneric(1).setProperty(SCOPE, Boolean.TRUE);
}
} else {
// fix cast here
if (mapper.hasTypeVariables(argType)) {
nodes.add(makeVarDec2(matchArg, argTypeNode,
(Node)dispatch(n.getGeneric(0))));
} else {
nodes.add(makeVarDec2(matchArg, argTypeNode,
factory.cast((Node)dispatch(n.getGeneric(0)))));
}
}
// Checking and return null
if (!containsBottomMatch(n.getGeneric(1))) {
nodes.add(factory.ifStatement4(toIdentifier(matchArg)));
}
@SuppressWarnings("unchecked")
List<Node> matches = (List<Node>)dispatch(n.getGeneric(1));
nodes.addAll(matches);
nodes.add(factory.ret(nullNode));
Node match = factory.matchExpression(
mapper.toTypeNode(n.getProperty(TYPE), false), nodes);
return match;
}
/**
* Check if a pattern matching contains an explicit match for bottom.
*
* @param n The pattern matching node.
* @return <code> true </code> if it contains a match for bottom pattern.
* <code> false</code> otherwise.
*/
private boolean containsBottomMatch(Node n) {
for (int i = 0; i < n.size(); i++) {
Node patterns = n.getGeneric(i).getGeneric(0);
for(int j= 0; j < patterns.size(); j++) {
Node pat = patterns.getGeneric(j);
if (pat.hasName("BottomPattern")) return true;
}
}
return false;
}
/**
* Check if this pattern match is on non-node type constructors.
*
* @param n the pattern match node.
* @return <code> true </code> if type constructor match. <code> false</code>
* otherwise.
*/
private boolean isTypeConstructorMatch(Node n) {
for (int i = 0; i < n.size(); i++) {
if (n.getGeneric(i).getGeneric(0).getGeneric(0)
.hasName("TypeConstructorPattern") &&
!mapper.isNode(n.getGeneric(i).getGeneric(0).getGeneric(0).
getProperty(TYPE))) {
return true;
}
}
return false;
}
/**
* Process a pattern matching expression.
*
* @param n The pattern matching node.
* @return A list with the unified types of the left and right sides
* of the pattern matching.
*/
public List<Node> visitPatternMatching(GNode n) {
int size = n.size();
ArrayList<Node> nodes = new ArrayList<Node>();
boolean tcmatch = isTypeConstructorMatch(n);
for (int i = 0; i < size; i++) {
Node patterns = n.getGeneric(i).getGeneric(0);
for(int j= 0; j < patterns.size(); j++) {
String foo = (String)n.getGeneric(i).getProperty("enterScope");
if (null== foo) foo = (String)n.getGeneric(i).getProperty("enterScope");
enterScope(foo);
Node pmatch2 = GNode.create("PatternMatch",
GNode.create("Patterns",patterns.getGeneric(j)),
n.getGeneric(i).getGeneric(1));
pmatch2.setProperty(TOP, null);
pmatch2.setProperty(MATCHARG, n.getProperty(MATCHARG));
pmatch2.setProperty(RHS, n.getProperty(MATCHARG));
pmatch2.setProperty(TYPE,n.getProperty(TYPE));
if (n.hasProperty(ANNOTATE)) {
pmatch2.setProperty(ANNOTATE, Boolean.TRUE);
}
if (n.hasProperty(SCOPE)) {
pmatch2.setProperty(SCOPE, Boolean.TRUE);
}
if (tcmatch) pmatch2.setProperty("TCMatch", null);
nodes.add((Node)dispatch(pmatch2));
exitScope(foo);
}
}
if (runtime.test("optimizeMatch")) {
HashMap<String, ArrayList<Node>> bins =
new HashMap<String, ArrayList<Node>>();
bins.put("default", new ArrayList<Node>());
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
if (node.hasProperty("TName")) {
String name = (String)node.getProperty("TName");
if (bins.containsKey(name)) {
bins.get(name).add(node);
} else {
ArrayList<Node> temp = new ArrayList<Node>();
temp.add(node);
bins.put(name, temp);
}
} else {
bins.get("default").add(node);
}
}
ArrayList<Node> nodes2 = new ArrayList<Node>();
Node switchn =
factory.switchStmnt(toIdentifier((String)n.getProperty(MATCHARG)));
switchn = GNode.ensureVariable(GNode.cast(switchn));
String defname = table.freshJavaId("default");
for (String key : bins.keySet()) {
if ("default".equals(key)) continue;
switchn.add(makeCase(GNode.create("PrimaryIdentifier", key),
bins.get(key),defname));
}
switchn.add(GNode.create("DefaultClause",
GNode.create("BreakStatement", null)));
nodes2.add(factory.switchWrap(
toIdentifier((String)n.getProperty(MATCHARG)),switchn));
if (bins.get("default").size() > 0) {
nodes2.addAll(bins.get("default"));
}
if (tcmatch) {
return nodes2;
}
}
return nodes;
}
/**
* Transform a typed pattern.
*
* @param n The typed pattern node.
* @return The java code for the typed pattern.
*/
public Node visitTypedPattern(GNode n) {
return (Node)dispatch(n.getGeneric(0));
}
/**
* Generate an as pattern.
*
* @param n The as pattern node.
* @return The java as pattern node.
*/
public Node visitAsPattern(GNode n) {
Node pat = n.getGeneric(0);
String rhs = (String)n.getProperty(RHS);
String matchArg = (String)n.getProperty(MATCHARG);
if (n.hasProperty(TOP)) pat.setProperty(TOP, null);
pat.setProperty(MATCHARG, n.getProperty(MATCHARG));
pat.setProperty(RHS, rhs);
pat.setProperty(BINDINGS, n.getProperty(BINDINGS));
pat.setProperty(TYPE,pat.getProperty(TYPE));
// fix cast here
Object t = pat.getProperty(TYPE);
if (mapper.hasTypeVariables(t)) {
((Node)n.getProperty(BINDINGS)).add(makeVarDec2(n.getString(1),
mapper.toTypeNode(t, false),
toIdentifier(matchArg)));
} else {
((Node)n.getProperty(BINDINGS)).add(makeVarDec2(n.getString(1),
mapper.toTypeNode(t, false),
factory.cast(toIdentifier(matchArg))));
}
if (isLiteral(n))
return factory.jequals((Node)dispatch(pat),toIdentifier(matchArg));
return (Node)dispatch(pat);
}
/**
* Generate a when pattern.
*
* @param n The when pattern node.
* @return An if statement represeing the when expression.
*/
public Node visitWhenPattern(GNode n) {
Node pat = n.getGeneric(0);
pat.setProperty(TOP, null);
pat.setProperty(RHS, n.getProperty(RHS));
pat.setProperty(BINDINGS, n.getProperty(BINDINGS));
pat.setProperty(TYPE, n.getProperty(TYPE));
pat.setProperty(MATCHARG, n.getProperty(MATCHARG));
if (n.hasProperty(TOP)) pat.setProperty(TOP, null);
//n.getGeneric(1).setProperty(NEWLET, Boolean.TRUE);
Node expr = (Node)dispatch(n.getGeneric(1));
expr = checkToLet(expr, n.getGeneric(1).getProperty(TYPE));
return factory.ifStatement(expr,(Node)dispatch(pat));
}
//additional conditions that need to be met after the basic pattern
//is matched and bound.
//For example, in the pattern Foo(a, a) -> e, both a's are wildcards.
//however the expression is only executed if the a's are equal.
//we therefor translate that pattern match as follows
// if ( Constructor.make("Foo", wild1, wild2).equals(arg)) {
// a = arg.get(1);
// if (a.equals(arg.get(2))) { ***conditions***
// return e;
// }
// }
Node conditions = null;
/**
* Process a pattern match.
*
* @param n The pattern match node.
* @return The if statement representing this pattern match.
*/
public Node visitPatternMatch(GNode n) {
Node savedConditions = conditions;
String rhs = (String)n.getProperty(RHS);
Node pattern = n.getGeneric(0);
Node expr = n.getGeneric(1);
String matchArg = (String)n.getProperty(MATCHARG);
Node ifStmnt = toIfStatement(null, null);
if (n.hasProperty(INANALYZE)) expr.setProperty(INANALYZE, Boolean.TRUE);
pattern.setProperty(TOP, null);
pattern.setProperty(BINDINGS, ifStmnt.getGeneric(1));
pattern.setProperty(MATCHARG, matchArg);
pattern.setProperty(RHS, rhs);
if ("WhenPattern".equals(pattern.getGeneric(0).getName())) {
Node when = (GNode)dispatch(pattern);
if (pattern.getGeneric(0).getGeneric(0).hasName("WildCard") ||
pattern.getGeneric(0).getGeneric(0).hasName("Variable")) {
ifStmnt.set(0, toLiteral("BooleanLiteral", "true"));
} else {
ifStmnt.set(0, GNode.create(when.getGeneric(1).getGeneric(0)));
}
if (optimizeLet) {
List<String> vars = getPatternVariables(pattern.getGeneric(0));
if (null != vars && !vars.isEmpty()) expr.setProperty(UPVARS, vars);
}
Node exprNode = (Node)dispatch(expr);
when.getGeneric(1).set(0, factory.ret(exprNode));
ifStmnt.getGeneric(1).add(when);
if (n.hasProperty(ANNOTATE) || n.hasProperty(SCOPE)) {
return augmentIfStatement(ifStmnt, matchArg, n, exprNode);
}
return addToIf(ifStmnt, exprNode);
}
if (pattern.hasName("WildCard") || pattern.hasName("Variable")) {
ifStmnt.set(0, toLiteral("BooleanLiteral", "true"));
dispatch(pattern);
} else {
ifStmnt.set(0, dispatch(pattern));
}
if (optimizeLet) {
List<String> vars = getPatternVariables(pattern.getGeneric(0));
if (null != vars && !vars.isEmpty()) expr.setProperty(UPVARS, vars);
}
Node res = (Node)dispatch(expr);
// fix cast
Object t = mapper.getPatternMatchRightType(n.getProperty(TYPE));
if(res.hasName("Block")) {
ifStmnt.getGeneric(1).add(res);
} else {
if(conditions == null) {
if (mapper.hasTypeVariables(t)) {
ifStmnt.getGeneric(1).
add(factory.ret(res));
} else {
ifStmnt.getGeneric(1).
add(factory.ret(factory.cast(res)));
}
} else {
Node b = GNode.create("Block");
Node newIf = toIfStatement(conditions, b);
if (mapper.hasTypeVariables(t)) {
b.add(factory.ret(res));
} else {
b.add(factory.ret(factory.cast(res)));
}
ifStmnt.getGeneric(1).add(newIf);
}
}
conditions = savedConditions;
if (n.hasProperty(ANNOTATE) || n.hasProperty(SCOPE)) {
return augmentIfStatement(ifStmnt, matchArg, n, res);
}
if (n.hasProperty("TCMatch")) {
if (n.getGeneric(0).getGeneric(0).hasName("TypeConstructorPattern")) {
ifStmnt.setProperty("TName",
n.getGeneric(0).getGeneric(0).getString(0));
}
if (n.getGeneric(0).getGeneric(0).hasName("AsPattern") &&
n.getGeneric(0).getGeneric(0).getGeneric(0).hasName("TypeConstructorPattern")) {
ifStmnt.setProperty("TName",
n.getGeneric(0).getGeneric(0).getGeneric(0).getString(0));
}
}
return addToIf(ifStmnt, res);
}
/**
* Process a type constructor pattern.
*
* @param n The type constructor node.
* @return The java equivalent.
*/
public Node visitTypeConstructorPattern(GNode n) {
final String typeName = n.getString(0);
final Object type = n.getProperty(TYPE);
final Node typeNode = mapper.toTypeNode(type, false);
String matchArg = (String)n.getProperty(MATCHARG);
Node matchArgNode = toIdentifier(matchArg);
Node condition = null;
Node inner = (Node)n.getProperty(BINDINGS);
final int size = n.size();
if (nodeType.equals(typeNode) || gnodeType.equals(typeNode)) {
condition = factory.hasNameCall(toIdentifier(matchArg),
toLiteral("StringLiteral", "\"" + typeName + "\""));
if ((size == 1) || n.getGeneric(1).hasName("WildCard")) {
//do nothing since the initial condition is sufficient
} else {
Node params = n.getGeneric(1);
List<String> members = mapper.getMembers(type);
List<Object> memberObjects = mapper.getMemberObjects(type);
List<Node> memberNodes = mapper.getMemberNodes(type);
boolean hasVar = false;
for (Object o : memberObjects) {
if (mapper.isVariable(o)) hasVar = true;
}
//check the last item to see if it's a list variable
//need to also check the last item to see if it's a node var
if (members.get(members.size() -1).startsWith("Pair") || hasVar) {
condition = factory.jand(condition,
factory.sizeGreaterEqual(matchArgNode,
toLiteral("IntegerLiteral", Integer.toString((params.size()- 1)))));
} else {
condition = factory.jand(condition,
factory.sizeEqual(matchArgNode,
toLiteral("IntegerLiteral", Integer.toString(params.size()))));
}
for (int i = 0; i < params.size(); i++) {
String tname = members.get(i);
Node tNode = memberNodes.get(i);
Node node = params.getGeneric(i);
if (node.hasName("Variable")) {
if ("String".equals(tname)) {
inner.add(factory.makeNodeBinding2(node.getString(0),
toIdentifier(matchArg),
toLiteral("IntegerLiteral", Integer.toString(i))));
} else if ( "Node".equals(members.get(i)) ||
"GNode".equals(members.get(i))) {
inner.add(factory.makeNodeBinding(node.getString(0),
toIdentifier(matchArg),
toLiteral("IntegerLiteral", Integer.toString(i))));
} else if (tname.startsWith("Pair")) {
inner.add(makeVarDec2(node.getString(0), tNode,
factory.cast(toIdentifier("Primitives.getChildren(" + matchArg +
", " + i + ", " + matchArg + ".size())"))));
}
continue;
}
if (node.hasName("WildCard")) continue;
if (isLiteral(node)) {
condition = factory.jand(condition,
factory.jequals2((Node)dispatch(node),
toIdentifier(matchArg + ".getString(" + i + ")")));
continue;
}
node.setProperty(BINDINGS, inner);
if ("String".equals(members.get(i))) {
node.setProperty(MATCHARG, matchArg + ".getString(" + i + ")");
} else if ( "Node".equals(members.get(i)) ||
"GNode".equals(members.get(i))) {
node.setProperty(MATCHARG, matchArg + ".getGeneric(" + i + ")");
} else if (members.get(i).startsWith("Pair")) {
node.setProperty(MATCHARG, "Primitives.getChildren(" + matchArg +
", " + i + ", " + matchArg + ".size())");
}
condition = factory.jand(condition,(Node)dispatch(node));
}
}
} else {
condition =
factory.isMethodCall(matchArgNode, "is" + typeName);
if (n.size() == 1 || n.getGeneric(1).hasName("WildCard")) {
//do nothing since the initial condition is sufficient
} else {
Node params = n.getGeneric(1);
List<Node> memberNodes = mapper.getMemberNodes(type);
for (int i = 0; i < params.size(); i++) {
Node node = params.getGeneric(i);
if (node.hasName("WildCard")) {
continue;
}
if (node.hasName("Variable")) {
inner.add(makeVarDec2(node.getString(0), memberNodes.get(i),
factory.cast(toIdentifier(matchArg + ".getTuple().get" +
(i + 1) + "()"))));
continue;
}
if (isLiteral(node)) {
condition = factory.jand(condition,
factory.jequals2((Node)dispatch(node),
toIdentifier(matchArg + ".getTuple().get" + (i + 1) + "()")));
continue;
}
node.setProperty(MATCHARG, matchArg + ".getTuple().get" + (i + 1) +
"()");
condition = factory.jand(condition,(Node)dispatch(node));
}
}
}
if (n.hasProperty(TOP) || n.hasProperty("ancestor")) {
condition = replaceMatchArg(condition, matchArg);
if (n.hasProperty("ancestor")) {
Node node = factory.ancestorExpression(factory.ret(condition));
if (nodeMatches.containsKey(node)) {
return factory.support(toIdentifier(output + "Support"),
nodeMatches.get(node));
} else {
String arg = table.freshJavaId("nodeMatch");
staticFields.add(factory.supportNodeMatch(arg, node));
nodeMatches.put(node, arg);
return factory.support(toIdentifier(output + "Support"),arg);
}
}
String matchName = table.freshJavaId("match");
Match ms = new Match(mapper.toTypeNode(n.getProperty(TYPE), false),
condition);
if (matches.containsKey(ms)) {
matchName = matches.get(ms);
} else {
matches.put(ms, matchName);
Node tNode = null;
if (mapper.hasTypeVariables(type)) {
tNode = mapper.toTypeNode(type, true);
} else {
tNode = mapper.toTypeNode(type, false);
}
Node matchFunction =
factory.matchFunction(matchName, tNode ,
condition);
matchFunction.getGeneric(4).getGeneric(0).set(3, "m");
staticFields.add(matchFunction);
}
return factory.matchCall(toIdentifier(output + "Support"), matchName,
toIdentifier((String)n.getProperty(MATCHARG)));
} else {
return condition;
}
}
/**
* Process pattern parameters.
*
* @param n The pattern parameters node.
* @return A new tuple expression.
*/
public Node visitPatternParameters(GNode n) {
return makeTuple(n);
}
/**
* Process a variant type definition.
*
* @param n The variant type node.
*/
public void visitVariantDeclaration(GNode n) {
String baseName = (String)n.getProperty("name");
Node baseBody = GNode.create("ClassBody");
Node enums = GNode.create("EnumConstants");
Node tag = GNode.create("EnumDeclaration", GNode.create("Modifiers",
GNode.create("Modifier", "public"), GNode.create("Modifier", "static")),
"Tag", null, enums, null);
baseBody.add(tag);
baseBody.add(factory.defaultConstr(baseName));
baseBody.add(factory.getTagAbstract());
for (int i = 0; i < n.size(); i++) {
Node tc = n.getGeneric(i);
addEnum(enums, tc.getString(0));
Object tcType = tc.getProperty(TYPE);
List<String> types = mapper.getMembers(tcType);
List<Node> typeNodes = mapper.getMemberNodes(tcType);
int size = types.size();
Node fparams = GNode.create("FormalParameters");
Node classBody = GNode.create("ClassBody");
//create a constructor
Node createArgs = GNode.create("Arguments");
for (int j = 0; j < size; j++) {
Node fptype = typeNodes.get(j);
String fpname = "member" + (j + 1);
createArgs.add(toIdentifier(fpname));
fparams.add(GNode.create("FormalParameter", null, fptype, null,
fpname, null));
}
Node constrblock1 = GNode.create("Block");
Node constr1 = GNode.create("ConstructorDeclaration", pmod, null,
tc.getString(0), fparams, null, constrblock1);
// Make type arguments
Node typeArgs = GNode.create("TypeArguments");
final Node typeNode;
for (Node ob : typeNodes) typeArgs.add(ob);
if (!typeNodes.isEmpty()) {
typeNode = GNode.create("Type",
GNode.create("InstantiatedType",
GNode.create("TypeInstantiation", "Tuple", null),
GNode.create("TypeInstantiation", "T" + typeNodes.size(),
typeArgs)),
null);
} else {
typeNode = GNode.create("Type",
GNode.create("QualifiedIdentifier", "Tuple", "T0"),
null);
}
constrblock1.add(factory.assign(toIdentifier("tuple"),
factory.newExpr(typeNode, makeArgumentList(createArgs))));
classBody.add(constr1);
classBody.add(factory.getTag(tc.getString(0)));
//add an isXXX method to the base class
Node isBase = factory.isMethod();
isBase.set(3, "is" + tc.getString(0));
baseBody.add(isBase);
//add an isXXX method to the variant type class
Node isVariant = factory.isMethod();
isVariant.set(3, "is" + tc.getString(0));
isVariant.getGeneric(7).getGeneric(0).getGeneric(0).set(0, "true");
classBody.add(isVariant);
// Add getName() method
classBody.add(factory.getNameMethod(GNode.create("StringLiteral","\"" +
tc.getString(0)+ "\"")));
// ADD equals methods
for (Equality e : equalities) {
if (e.name.equals(tc.getString(0))) {
classBody.add(createVariantEqualsMethod(tc.getString(0)));
break;
}
}
// Add toString()
String toString = "\"" + tc.getString(0);
if (size > 0) {
toString += " of \" + tuple.toString()";
} else {
toString += "\"";
}
Node toStringNode = factory.toStringMethod();
toStringNode.set(7, GNode.create("Block",
factory.ret(toLiteral("StringLiteral", toString))));
classBody.add(toStringNode);
final Node baseNameNode = GNode.create("Type",
GNode.create("InstantiatedType",
GNode.create("TypeInstantiation", baseName,
GNode.create("TypeArguments", typeNode))),
null);
tbody.add(comment(makeExtendedClassDecl(tc.getString(0),
baseNameNode, classBody),
"Implementation of constructor '"+ tc.getString(0) +
"' in variant '"+ baseName + "'."));
}
final String typeName = baseName + "<T extends Tuple>";
final Node vNode = GNode.create("Type",
GNode.create("InstantiatedType",
GNode.create("TypeInstantiation", "Variant",
GNode.create("TypeArguments",
GNode.create("Type",
GNode.create("QualifiedIdentifier", "T"),
null)))),
null);
tbody.add(comment(makeExtendedClassDecl2(typeName, vNode, baseBody),
"Superclass of all constructors in variant '" +
baseName + "'."));
}
/**
* Create an extends class declaration.
*
* @param n The name of the class.
* @param b The base name node (the class that is extended).
* @param classBody The class body.
*/
private Node makeExtendedClassDecl(String n, Node b, Node classBody) {
Node foo = factory.extendsDecl();
foo.set(1, n);
foo.getGeneric(3).set(0, b);
foo.set(5, classBody);
return foo;
}
/**
* Create an abstract extends class declaration.
*
* @param n The name of the class.
* @param b The base name node (the class that is extended).
* @param classBody The class body.
*/
private Node makeExtendedClassDecl2(String n, Node b, Node classBody) {
Node foo = factory.extendsDecl2();
foo.set(1, n);
foo.getGeneric(3).set(0, b);
foo.set(5, classBody);
return foo;
}
/**
* Create an implements class declaration.
*
* @param n The name of the class.
* @param b The base name (the interface that is implemented).
* @param classBody The class body.
*/
private Node makeImplementedClassDecl(String n, String b, Node classBody) {
Node foo = factory.implementsDecl();
foo.set(1, n);
foo.getGeneric(4).set(0, toType(b));
foo.set(5, classBody);
return foo;
}
/**
* Process a record type definition.
*
* @param n The type information.
*/
public void visitRecordDeclaration(GNode n) {
String name = (String)n.getProperty("name");
Object t = n.getProperty(TYPE);
List<Node> fieldTypeNodes = mapper.getFieldTypeNodes(t);
List<String> fieldNames = mapper.getFieldNames(t);
Node classBody = GNode.create("ClassBody");
StringBuilder toString = new StringBuilder("\"{\"");
//ADD equals method for type record
Node equals = null;
Node eqBlock = GNode.create("Block");
if("type".equals(name)) {
equals = createTypeRecordEquals();
} else {
equals = factory.equalsMethod();
equals.set(7, eqBlock);
eqBlock.add(toIfStatement(factory.jnot(toInstanceOf(toIdentifier("o"),
toType(name))), factory.ret(toLiteral("BooleanLiteral", "true"))));
eqBlock.add(makeVarDec("r", name, factory.cast(toIdentifier("o"))));
}
Node constrblk = GNode.create("Block");
Node constr = GNode.create("ConstructorDeclaration", pmod, null, name,
GNode.create("FormalParameters"), null, constrblk);
Node fps = constr.getGeneric(3);
for (int i = 0; i < fieldNames.size(); i++) {
String fname = fieldNames.get(i);
Node ftype = fieldTypeNodes.get(i);
toString.append(" + (null == "+fname+ " ? \"?\" : " +fname
+ ".toString())");
fps.add(GNode.create("FormalParameter", null, ftype,
null, fname, null));
constrblk.add(factory.assign(factory.thisExpr(fname),
toIdentifier(fname)));
if (i < fieldNames.size() - 1) toString.append(" + \",\" ");
classBody.add(factory.publicFieldDecl(ftype, fname));
eqBlock.add(toIfStatement(
factory.jnot(factory.jequals(toIdentifier(fname),
factory.fieldExpression(toIdentifier("r"),
fname))),
factory.ret(toLiteral("BooleanLiteral", "false"))));
}
eqBlock.add(factory.ret(toLiteral("BooleanLiteral", "true")));
toString.append(" + " + "\"}\"");
//create the toString method for this record
Node toStringNode = factory.toStringMethod();
toStringNode.getGeneric(7).set(0,
factory.ret(toLiteral("StringLiteral",toString.toString())));
classBody.add(constr);
classBody.add(equals);
classBody.add(toStringNode);
tbody.add(comment(makeImplementedClassDecl(name, "Record", classBody),
"Implementation of record '" + name + "'."));
}
/**
* Create a new named tuple.
*
* @param n The tuple constructor node.
* @return The java equivalent.
*/
public Node visitTupleConstructor(GNode n) {
Node args = GNode.create("Arguments");
if (n.hasProperty(INANALYZE)) {
for (int j = 1; j < n.size(); j++) {
n.getGeneric(j).setProperty(INANALYZE, Boolean.TRUE);
}
}
List<LetBinding> bl = null;
List<String> upVars = getUpVariables(n);
Node ret;
if (n.getProperty(TYPE) != null &&
gnodeType.equals(mapper.toTypeNode(n.getProperty(TYPE),false)) ||
nodeType.equals(mapper.toTypeNode(n.getProperty(TYPE), false))) {
List<Node> args2 = new ArrayList<Node>(n.size());
args2.add(toLiteral("StringLiteral", "\"" + n.getString(0) + "\"" ));
for (int i = 1; i < n.size(); i++) {
Node no = n.getGeneric(i);
if (null != upVars) no.setProperty(UPVARS, upVars);
Node expr = (Node)dispatch(no);
List<LetBinding> l = getBindings(expr);
List<String> vars = extractVariables(l);
upVars = groupList(upVars, vars);
bl = groupList(bl,l);
args2.add(expr);
}
ret = factory.gnodeCreate(args2);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
for (int i = 1; i < n.size(); i++) {
Node no = n.getGeneric(i);
if (null != upVars) no.setProperty(UPVARS, upVars);
Node expr = (Node)dispatch(no);
List<LetBinding> l = getBindings(expr);
List<String> vars = extractVariables(l);
upVars = groupList(upVars, vars);
bl = groupList(bl,l);
args.add(expr);
}
ret = toNewExpression2(mapper.toTypeNode(n.getString(0), false),
args,null);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
/**
* Create an instanceof node.
*
* @param n1 The object node.
* @param n2 The type node.
* @return The instanceof expression
*/
private Node toInstanceOf(Node n1, Node n2) {
return GNode.create("InstanceOfExpression", n1, n2);
}
/**
* Process a LowerID node.
*
* @return The primary identifier corresponding to this node.
*/
public Node visitLowerID(GNode n) {
final String newName = Primitives.convertName(n.getString(0));
if (Primitives.isPrimitive(newName)) {
if ("nonce".equals(newName)) {
return factory.apply2(toIdentifier("Primitives." + newName));
}
return toIdentifier("Primitives." + newName);
}
else return toIdentifier(newName);
}
/**
* Process a variable.
*
* @param n The variable node.
*/
public void visitVariable(GNode n) {
String name = n.getString(0);
//make bindings for this variable if necessary
Object type = n.getProperty(TYPE);
final Node typeNode = mapper.toTypeNode(type, false);
String rhs = (String)n.getProperty(RHS);
if (table.current().isDefinedLocally(
SymbolTable.toNameSpace(name, "value"))) {
if (nodeType.equals(typeNode) || gnodeType.equals(typeNode)) {
((GNode)n.getProperty(BINDINGS)).add(makeVarDec2(name, typeNode,
factory.gnodeCast(toIdentifier(rhs))));
} else {
// fix cast here
if (mapper.hasTypeVariables(type)) {
((GNode)n.getProperty(BINDINGS)).add(makeVarDec2(name, typeNode,
toIdentifier(rhs)));
} else {
((GNode)n.getProperty(BINDINGS)).add(makeVarDec2(name, typeNode,
factory.cast(toIdentifier(rhs))));
}
}
} else {
Node cond = factory.jequals(toIdentifier(rhs),toIdentifier(name));
if (conditions == null) {
conditions = cond;
} else {
conditions = factory.jand(conditions, cond);
}
}
}
/**
* Transform a record expression.
*
* @param n The record expression node.
* @return A java equivalent.
*/
public Node visitRecordExpression(GNode n) {
boolean bottomWith = (null != n.getGeneric(0)) &&
n.getGeneric(0).getGeneric(0).hasName("Bottom");
if (n.hasProperty(INANALYZE)) {
for (int j = 0; j < n.size(); j++) {
n.getGeneric(j).setProperty(INANALYZE, Boolean.TRUE);
}
}
// Check the first field assign, field name and replaceType variable
if (replaceType && "type".equals(n.getGeneric(1).getString(0))) {
return (Node)dispatch(n.getGeneric(1).getGeneric(1));
}
Object rt = n.getProperty(TYPE);
List<String> fieldNames = mapper.getFieldNames(rt);
Node firstNode = n.getGeneric(0);
Node args = GNode.create("Arguments");
List<LetBinding> bl = null;
List<String> upVars = getUpVariables(n);
for (String s : fieldNames) {
boolean found = false;
for (int i = 1; i < n.size(); i++) {
if (s.equals(n.getGeneric(i).getString(0))) {
found = true;
Node no = n.getGeneric(i).getNode(1);
if (null != upVars) no.setProperty(UPVARS, upVars);
Node expr = (Node)dispatch(no);
List<LetBinding> l = getBindings(expr);
List<String> vars = extractVariables(l);
upVars = groupList(upVars, vars);
bl = groupList(bl,l);
args.add(expr);
}
}
if (!found && ("WithExpression".equals(firstNode.getName()))) {
if (!bottomWith) {
// expression with
//firstNode.getGeneric(0).setProperty(NEWLET, Boolean.TRUE);
Node letNode = (Node)dispatch(firstNode.getGeneric(0));
letNode = checkToLet(letNode, firstNode.getGeneric(0).getProperty(TYPE));
args.add(factory.fieldExpression(letNode, s));
} else {
args.add(GNode.create("NullLiteral"));
}
} else if (!found) {
assert found : "cannot determine field value";
}
}
Node ret = toNewExpression2(mapper.toTypeNode(rt,false), args, null);
if (null != bl) ret.setProperty(LETBINDINGS, bl);
return ret;
}
/**
* Transform a field assignment.
*
* @param n The field assignment node.
* @return The java assignment expression.
*/
public Node visitFieldAssign(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
if (!optimizeLet) {
return factory.assignField(toIdentifier(n.getString(0)),
(Node)dispatch(n.getNode(1)));
} else {
passVariables(n, n.getGeneric(1));
Node expr = (Node)dispatch(n.getNode(1));
Node ret = factory.assignField(toIdentifier(n.getString(0)), expr);
passBindings(expr, ret);
return ret;
}
}
/**
* Process a let expression.
*
* @param n The let expression node.
* @return An anonymous Let instance
*/
public Node visitLetExpression(GNode n) {
if (runtime.test("optimizeFoldLet")) {
new LetFolder().collapseLet(n, table);
}
if (n.hasProperty(INANALYZE)) {
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
final String scopename = (String)n.getProperty("enterScope");
boolean didEnter = false;
if (n.hasProperty("enterScope")) {
if (!table.current().getName().equals(scopename)) {
enterScope(scopename);
didEnter = true;
}
}
Node bindings = n.getGeneric(0);
Node value = n.getGeneric(1);
Object resultType = n.getProperty(TYPE);
int size = bindings.size();
Node block = null;
Node res = null;
Object t = value.getProperty(TYPE);
if (!optimizeLet) {
res = (GNode)dispatch(value);
if ("Block".equals(res.getName())) {
block = GNode.create("Block", res);
} else {
// fix cast here
if (mapper.hasTypeVariables(t)) {
block = GNode.create("Block", factory.ret(res));
} else {
block = GNode.create("Block", factory.ret(factory.cast(res)));
}
}
Node letclass = GNode.create("ClassBody");
letclass = GNode.ensureVariable((GNode)letclass);
GNode letbody = GNode.create("Block");
for (int i = 0; i < size; i++) {
Node binding = bindings.getGeneric(i);
Node left = binding.getGeneric(0);
Node right = binding.getGeneric(1);
if (n.hasProperty(INANALYZE)) right.setProperty(INANALYZE, Boolean.TRUE);
String bname;
Object btype;
right = (Node)dispatch(right);
if (left.hasName("Variable")) {
bname = left.getString(0);
btype = left.getProperty(TYPE);
letclass.add(makeVarDec2(bname, mapper.toTypeNode(btype, false) , null));
// fix cast here
if (mapper.hasTypeVariables(btype)) {
letbody.add(factory.assign(toIdentifier(bname), right));
} else {
letbody.add(factory.assign(toIdentifier(bname), factory.cast(right)));
}
} else if ("TypedPattern".equals(left.getName()) &&
"Variable".equals(left.getGeneric(0).getName())) {
bname = left.getGeneric(0).getString(0);
btype = left.getProperty(TYPE);
letclass.add(makeVarDec2(bname, mapper.toTypeNode(btype, false), null));
// fix cast here
if (mapper.hasTypeVariables(btype)) {
letbody.add(factory.assign(toIdentifier(bname),right));
} else {
letbody.add(factory.assign(toIdentifier(bname),factory.cast(right)));
}
} else {
if (right.hasName("ConditionalExpression")) {
letbody.add(factory.discard(right));
} else {
letbody.add(factory.expressionStmnt(right));
}
}
}
if (letbody.size() > 0) {
letclass.add(letbody);
}
letclass.add(GNode.create("MethodDeclaration",
toModifiers("public"),null, mapper.toTypeNode(resultType, false),
"apply", GNode.create("FormalParameters"), null, null, block));
Node let = factory.letExpression(mapper.toTypeNode(resultType, false));
let.getGeneric(0).set(4, letclass);
if (didEnter) exitScope(scopename);
return let;
} else { // optimizing Let
List<String> upVars = getUpVariables(n);
List<LetBinding> bl = null;
// Get variables in let bindings
List<String> vars = new ArrayList<String>();
for (int i = 0; i < size; i++) {
Node binding = bindings.getGeneric(i);
Node left = binding.getGeneric(0);
if (left.hasName("Variable")) {
vars.add(left.getString(0));
} else if ("TypedPattern".equals(left.getName()) &&
"Variable".equals(left.getGeneric(0).getName())) {
vars.add(left.getGeneric(0).getString(0));
}
}
// check for redefinitions
boolean check = false;
for (String v : vars) {
if (null != upVars && upVars.contains(v)) {
check = true;
continue;
}
}
if (check) upVars = vars;
else upVars = groupList(upVars, vars);
for (int i = 0; i < size; i++) {
Node binding = bindings.getGeneric(i);
Node left = binding.getGeneric(0);
Node right = binding.getGeneric(1);
String name;
Object type;
if (left.hasName("Variable")) {
name = left.getString(0);
type = left.getProperty(TYPE);
} else if ("TypedPattern".equals(left.getName()) &&
"Variable".equals(left.getGeneric(0).getName())) {
name = left.getGeneric(0).getString(0);
type = left.getProperty(TYPE);
} else {
name = spareVar;
type = right.getProperty(TYPE);
}
// process the value of a binding
right.setProperty(UPVARS, upVars);
Node expr = (Node)dispatch(right);
List<LetBinding> l = getBindings(expr);
List<String> vs = extractVariables(l);
bl = groupList(bl,l);
if (null == bl) {
bl = new ArrayList<LetBinding>();
bl.add(new LetBinding(name, type, mapper.toTypeNode(type, false), expr));
} else {
bl.add(new LetBinding(name, type, mapper.toTypeNode(type, false), expr));
}
upVars = groupList(upVars, vs);
}
// Process the expression
value.setProperty(UPVARS, upVars);
res = (Node)dispatch(value);
List<LetBinding> l = getBindings(res);
bl = groupList(bl,l);
Node let = null;
if (check || n.hasProperty(NEWLET)) {
let = convertToLet(res, bl, t);
} else {
res.setProperty(LETBINDINGS, bl);
let = res;
}
if (didEnter) exitScope(scopename);
return let;
}
}
/**
* Check and convert an expression to let expression if it contains bindings.
*
* @param n The expression node.
* @param retType The type of that expression.
* @return the converted node.
*/
private Node checkToLet(Node n, Object retType) {
List<LetBinding> bl = getBindings(n);
if (null == bl || bl.isEmpty()) return n;
Node block = null;
if ("Block".equals(n.getName())) {
block = GNode.create("Block", n);
} else {
// fix cast here
if (mapper.hasTypeVariables(retType)) {
block = GNode.create("Block", factory.ret(n));
} else {
block = GNode.create("Block", factory.ret(factory.cast(n)));
}
}
Node letclass = GNode.create("ClassBody");
letclass = GNode.ensureVariable((GNode)letclass);
GNode letbody = GNode.create("Block");
for (LetBinding bind : bl) {
if (!bind.name.equals(spareVar)) {
letclass.add(makeVarDec2(bind.name, bind.type , null));
}
if (mapper.hasTypeVariables(bind.typeObject)) {
letbody.add(factory.assign(toIdentifier(bind.name), bind.value));
} else {
letbody.add(factory.assign(toIdentifier(bind.name),
factory.cast(bind.value)));
}
}
if (letbody.size() > 0) {
letclass.add(letbody);
}
letclass.add(GNode.create("MethodDeclaration",
toModifiers("public"),null, mapper.toTypeNode(retType, false),
"apply", GNode.create("FormalParameters"), null, null, block));
Node let = factory.letExpression(mapper.toTypeNode(retType, false));
let.getGeneric(0).set(4, letclass);
return let;
}
/**
* Convert an expression to let expression if it contains bindings.
*
* @param n The expression node.
* @param bl The list of variable bindings.
* @param retType The type of that expression.
* @return the converted node.
*/
private Node convertToLet(Node n, List<LetBinding> bl, Object retType) {
Node block = null;
if ("Block".equals(n.getName())) {
block = GNode.create("Block", n);
} else {
// fix cast here
if (mapper.hasTypeVariables(retType)) {
block = GNode.create("Block", factory.ret(n));
} else {
block = GNode.create("Block", factory.ret(factory.cast(n)));
}
}
Node letclass = GNode.create("ClassBody");
letclass = GNode.ensureVariable((GNode)letclass);
GNode letbody = GNode.create("Block");
for (LetBinding bind : bl) {
if (!bind.name.equals(spareVar)) {
letclass.add(makeVarDec2(bind.name, bind.type , null));
}
if (mapper.hasTypeVariables(bind.typeObject)) {
letbody.add(factory.assign(toIdentifier(bind.name), bind.value));
} else {
letbody.add(factory.assign(toIdentifier(bind.name),
factory.cast(bind.value)));
}
}
if (letbody.size() > 0) {
letclass.add(letbody);
}
letclass.add(GNode.create("MethodDeclaration",
toModifiers("public"),null, mapper.toTypeNode(retType, false),
"apply", GNode.create("FormalParameters"), null, null, block));
Node let = factory.letExpression(mapper.toTypeNode(retType, false));
let.getGeneric(0).set(4, letclass);
return let;
}
/**
* Process a Patterns node.
*
* @return The patterns node corresponding to this node.
*/
public Node visitPatterns(GNode n) {
Node pat = n.getGeneric(0);
if (n.hasProperty(TOP)) pat.setProperty(TOP, null);
if (isLiteral(pat)) {
return factory.jequals((Node)dispatch(pat),
toIdentifier((String)n.getProperty(MATCHARG)));
} else {
pat.setProperty(MATCHARG, n.getProperty(MATCHARG));
pat.setProperty(BINDINGS, n.getProperty(BINDINGS));
pat.setProperty(RHS, n.getProperty(RHS));
return (GNode)dispatch(pat);
}
}
/**
* Test if a node is a literal.
*
* @param n The node to test.
* @return True if literal false otherwise.
*/
private boolean isLiteral(Node n) {
if (null == n) {
runtime.error("Calling isLiteral on null node", n);
} else {
String name = n.getName();
return ("StringLiteral".equals(name) || "BooleanLiteral".equals(name) ||
"FloatingLiteral".equals(name) || "IntegerLiteral".equals(name));
}
return false;
}
/**
* Process an additive expression.
*
* @param n The additive expression node.
* @return The java additive expression.
*/
public Node visitAdditiveExpression(GNode n) {
String op = n.getString(1);
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(2).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(2).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(2));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret;
if ("+".equals(op)) ret = factory.addInt(left, right);
else if ("-".equals(op)) ret = factory.subtractInt(left, right);
else if ("+.".equals(op)) ret = factory.addFloat64(left, right);
else ret = factory.subtractFloat64(left, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process a concatenation expression.
*
* @param n The concatenation expression node.
* @return The java equivalent.
*/
public Node visitConcatenationExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(2).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(2).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(2));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret;
if ("^".equals(n.getString(1))) ret = factory.concatStrings(left, right);
else ret = factory.concatLists(left, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process a multiplicative expression.
*
* @param n The multiplicative expression node.
* @return The java multiplicatiee expression.
*/
public Node visitMultiplicativeExpression(GNode n) {
String op = n.getString(1);
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(2).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(2).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(2));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret;
if ("*".equals(op)) ret = factory.multiplyInt(left, right);
else if ("/".equals(op)) ret = factory.divideInt(left, right);
else if ("%".equals(op)) ret = factory.modInt(left, right);
else if ("*.".equals(op)) ret = factory.multiplyFloat64(left, right);
else ret = factory.divideFloat64(left, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process a relational expression.
*
* @param n The relational expression node.
* @return The java relational expression
*/
public Node visitRelationalExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(2).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(2).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(2));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret;
String op = n.getString(1);
String internal = null;
if ("<".equals(op)) internal = "lessInt";
if ("<=".equals(op)) internal = "lessEqualInt";
if (">".equals(op)) internal = "greaterInt";
if (">=".equals(op)) internal = "greaterEqualInt";
if ("<.".equals(op)) internal = "lessFloat64";
if ("<=.".equals(op)) internal = "lessEqualFloat64";
if (">.".equals(op)) internal = "greaterFloat64";
if (">=.".equals(op)) internal = "greaterEqualFloat64";
assert null != internal : "undefined relational operator " + op;
ret =
factory.relationalExpr(toIdentifier("Primitives." + internal),left,right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process a logical or expression.
*
* @param n The logical or expression node.
* @return The java expression.
*/
public Node visitLogicalOrExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(1).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(1));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret = factory.or(left, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process a logical and expression.
*
* @param n The logical and expression node.
* @return The java expression.
*/
public Node visitLogicalAndExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(1).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(1));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret = factory.and(left, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process a logical negation expression.
*
* @param n The logical negation expression node.
* @return n The java equivalent.
*/
public Node visitLogicalNegationExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
}
passVariables(n, n.getGeneric(0));
Node expr = (Node)dispatch(n.getGeneric(0));
Node ret = factory.not(expr);
passBindings(expr, ret);
return ret;
}
/**
* Process an equality expression.
*
* @param n The equality expression node.
* @return The java equivalent.
*/
public Node visitEqualityExpression(GNode n) {
String op = n.getString(1);
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(2).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
List<String> vars = extractVariables(bl1);
upVars = groupList(upVars,vars);
if (null != upVars) n.getGeneric(2).setProperty(UPVARS, upVars);
Node right = (Node)dispatch(n.getGeneric(2));
List<LetBinding> bl2 = getBindings(right);
bl1 = groupList(bl1, bl2);
Node ret;
if ("=".equals(op)) {
if ("Bottom".equals(n.getGeneric(0).getName())) {
ret = factory.equalsBottom(right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
} else if ("Bottom".equals(n.getGeneric(2).getName())) {
ret = factory.equalsBottom(left);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
} else {
if ("Bottom".equals(n.getGeneric(0).getName())) {
ret = factory.notEqualsBottom(right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
} else if ("Bottom".equals(n.getGeneric(2).getName())) {
ret = factory.notEqualsBottom(left);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
}
ret =
("=".equals(n.getString(1))) ? factory.equal(left, right)
: factory.not(factory.equal(left, right));
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process an attribute declaration.
*
* @param n the attribute declaration node to process.
*/
public void visitAttributeDefinition(GNode n) {
Node typeNode = n.getGeneric(1);
if ("ConstraintType".equals(typeNode.getName())) {
typeNode = GNode.create("UserDefinedType","Node");
}
attributeList.add(new Attribute(n.getString(0), typeNode));
}
/**
* Process an equal attribute definition.
*
* @param n the equal attribute definition node to process.
*/
public void visitEqualAttributeDefinition(GNode n) {
Node typeNode = n.getGeneric(1);
if ("ConstraintType".equals(typeNode.getName())) {
typeNode = GNode.create("UserDefinedType","Node");
}
eqAttributeList.add(new Attribute(n.getString(0), typeNode));
}
/**
* Process raw_type definition to create "type" record.
*
* @return The node of generated code for "type" record definition.
*/
public Node processRawTypeDefinition() {
//Create type
Node typeInfo =
GNode.create("RecordDeclaration",GNode.create("FieldType", "type",
GNode.create("UserDefinedType", "raw_type<?>")));
typeInfo = GNode.ensureVariable((GNode)typeInfo);
typeInfo.setProperty(TYPE, table.current().lookup("type(type)"));
//Create equal attributes
for (Attribute att : eqAttributeList) {
typeInfo.add(GNode.create("FieldType", att.name, att.type));
}
//Create attributes
for (Attribute att : attributeList) {
typeInfo.add(GNode.create("FieldType", att.name, att.type));
}
return GNode.create("TypeDefinition", null, "type", typeInfo);
}
/**
* Process an equality definition.
*
* @param n The equality definition node.
*/
public void visitEqualityDefinition(GNode n) {
// process equal structure
for (int index = 1; index < n.size(); index ++) {
boolean seenLowerID = false;
Node child = (GNode)n.get(index);
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 1; i < child.size(); i++) {
if (!("WildCard".equals(child.getGeneric(i).getName()))) {
list.add(i);
seenLowerID = true;
}
}
if (!seenLowerID) {
throw new AssertionError("At least one identifier required");
}
equalities.add(new Equality((child.getGeneric(0)).getString(0),list));
}
}
/**
* Get node name from a pattern
*
* @param n The pattern node
*/
protected String getNodeName(Node n) {
return ("TypeConstructorPattern".equals(n.getName()))
? n.getString(0) : getNodeName(n.getGeneric(0));
}
/**
* Process scope definition
*
* @param n The scope definition node
*/
public void visitScopeDefinition(GNode n) {
// Adding code to build the list of node names that need to process scope
Node pat = n.getGeneric(0);
for (int i = 0; i < pat.size(); i++) {
Node patterns = pat.getGeneric(i).getGeneric(0);
for (int j = 0; j < patterns.size(); j++) {
processScopeNodes.add(getNodeName(patterns.getGeneric(j)));
}
}
Node match = GNode.create("MatchExpression",
GNode.create("LowerID","n"), n.getGeneric(0));
match.setProperty("__arg_type", n.getProperty("__arg_type"));
match.setProperty(TYPE,
mapper.getPatternMatchRightType(n.getProperty(TYPE)));
seenScope = true;
Node pmatch = n.getGeneric(0);
pmatch.setProperty(MATCHARG, "n");
@SuppressWarnings("unchecked")
List<Node> nodes = (List<Node>)dispatch(pmatch);
nodes.add(factory.ret(GNode.create("NullLiteral")));
// Create typical AST
Node top = GNode.create("ValueDefinition",
"getScope",
GNode.create("Parameters",
GNode.create("Parameter",
"n",
GNode.create("UserDefinedType",
"node")
)
),
GNode.create("BooleanLiteral", "true")
);
top.setProperty(TYPE, table.current().lookup("value(getScope)"));
top.setProperty("__isfunction", null);
Node block = GNode.create("Block");
for (Node node : nodes) block.add(node);
Node scopefunc = (Node)dispatch(top);
scopefunc.getGeneric(2).getGeneric(0).getGeneric(2).getGeneric(4).
getGeneric(0).set(7, block);
functionDefinitions.add(scopefunc);
return;
}
/**
* Process namespace definition.
*
* @param n The name space definition node.
*/
public void visitNameSpaceDefinition(GNode n) {
seenNameSpace = true;
Node pat = GNode.create("PatternMatching");
pat.setProperty(TYPE, n.getProperty(TYPE));
pat.setProperty(MATCHARG, "n");
// Create the pattern matching node
for(int i = 0; i < n.size(); i++) {
Node child = n.getGeneric(i);
for(int j = 0; j < child.getGeneric(2).size(); j++) {
Node grand = child.getGeneric(2).getGeneric(j);
Node pattern = GNode.create("PatternMatch");
pattern.add(grand.getGeneric(0));
// Create Typical tuple
Node tup = GNode.create("TupleLiteral", grand.getGeneric(1),
GNode.create("StringLiteral", "\"" + child.getString(0) + "\""),
GNode.create("StringLiteral", "\"" + child.getString(1) + "\""));
tup.setProperty(TYPE, TypeMapper.nameTupleT);
pattern.add(tup);
pattern.setProperty("enterScope",grand.getProperty("enterScope"));
Node thepatterns = pattern.getGeneric(0);
for (int k = 0; k < thepatterns.size(); k++) {
thepatterns.getGeneric(k).setProperty("enterScope",
pattern.getProperty("enterScope"));
}
pat.add(pattern);
}
}
pat.setProperty(MATCHARG, "n");
Node match =
GNode.create("MatchExpression", GNode.create("LowerID","n"),pat);
// create the value definition node
Node top = GNode.create("ValueDefinition",
"getNameSpace", GNode.create("Parameters", GNode.create("Parameter", "n",
GNode.create("UserDefinedType", "node"))), match);
top.setProperty("__isfunction", null);
match.setProperty("__arg_type", table.current().lookup("type(node)"));
match.setProperty(TYPE, TypeMapper.nameTupleT);
top.setProperty("__arg_type", n.getProperty("__arg_type"));
top.setProperty(TYPE, table.current().lookup("value(getNameSpace)"));
functionDefinitions.add((Node)dispatch(top));
}
/**
* Transform an error clause into a function call to either or warning.
*
* @param n The expression node.
* @return The function call java node.
*/
public Node visitErrorClause(GNode n) {
Node loc = (Node)dispatch(n.getGeneric(2));
if (null == loc) loc = nullNode;
//n.getGeneric(1).setProperty(NEWLET, Boolean.TRUE);
Node letNode = (Node)dispatch(n.getGeneric(1));
letNode = checkToLet(letNode, n.getGeneric(1).getProperty(TYPE));
return factory.errorClause(n.getGeneric(0).getString(0), letNode,loc);
}
/**
* Transform an assert clause into a function call to assert.
*
* @param n The assert clause node.
* @return The function call java node.
*/
public Node visitAssertClause(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
if (null != n.getGeneric(1)) {
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
}
//n.getGeneric(0).setProperty(NEWLET, Boolean.TRUE);
//n.getGeneric(1).setProperty(NEWLET, Boolean.TRUE);
Node exp0 = (Node)dispatch(n.getGeneric(0));
exp0 = checkToLet(exp0, n.getGeneric(0).getProperty(TYPE));
Node exp1 = (Node)dispatch(n.getGeneric(1));
exp1 = checkToLet(exp1, n.getGeneric(1).getProperty(TYPE));
return (null == n.getGeneric(1))
? GNode.create("PostfixExpression", toIdentifier("assertion"),
GNode.create("Arguments", exp0))
: GNode.create("PostfixExpression", toIdentifier("assertion"),
GNode.create("Arguments", exp0, exp1));
}
/**
* Transform an if expression into a java conditional expression.
*
* @param n The if expression node.
* @return The java conditional expression.
*/
public Node visitIfExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
Node right = (Node)dispatch(n.getGeneric(1));
right = checkToLet(right, n.getGeneric(1).getProperty(TYPE));
Node ret = factory.ifExpression(left, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Transform an if expression into a java conditional expression.
*
* @param n The if expression node.
* @return The java conditional expression.
*/
public Node visitIfElseExpression(GNode n) {
if (n.hasProperty(INANALYZE)) {
n.getGeneric(0).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(1).setProperty(INANALYZE, Boolean.TRUE);
n.getGeneric(2).setProperty(INANALYZE, Boolean.TRUE);
}
List<String> upVars = getUpVariables(n);
if (null != upVars) n.getGeneric(0).setProperty(UPVARS, upVars);
Node left = (Node)dispatch(n.getGeneric(0));
List<LetBinding> bl1 = getBindings(left);
Node middle = (Node)dispatch(n.getGeneric(1));
middle = checkToLet(middle, n.getGeneric(1).getProperty(TYPE));
Node right = (Node)dispatch(n.getGeneric(2));
right = checkToLet(right, n.getGeneric(2).getProperty(TYPE));
Node ret = factory.ifElseExpression(left, middle, right);
if (null != bl1) ret.setProperty(LETBINDINGS, bl1);
return ret;
}
/**
* Process require expression.
*
* @param n the require expression node
* @return The java code for the require expression.
*/
public Node visitRequireExpression(GNode n) {
int nodeSize = n.size();
// get the expression
Node expr = n.getGeneric(nodeSize -1);
passVariables(n, expr);
if (n.hasProperty(INANALYZE)) expr.setProperty(INANALYZE, Boolean.TRUE);
//dispatch this node to translate
Node valExpr = (Node)dispatch(expr);
final Node genericType;
if (expr.hasProperty(TYPE)) {
genericType = mapper.toTypeNode(expr.getProperty(TYPE), false);
} else {
genericType = GNode.create("Type",
GNode.create("QualifiedIdentifier", "Object"),
null);
}
ArrayList<Node> list = new ArrayList<Node>();
for (int id = 0; id < nodeSize - 1; id++) {
Node no = n.getGeneric(id);
list.add(no);
}
// Create require block
List<Node> requireBlock = new ArrayList<Node>();
/* A list of translated expressions */
ArrayList<Node> listExpr = new ArrayList<Node>();
// Add statement
for (Node node: list) {
Node boolNode = node.getGeneric(0);
//boolNode.setProperty(NEWLET, Boolean.TRUE);
if (n.hasProperty(INANALYZE)) {
boolNode.setProperty(INANALYZE, Boolean.TRUE);
}
Node boolExpr = (Node)dispatch(boolNode);
boolExpr = checkToLet(boolExpr, boolNode.getProperty(TYPE));
final String newVar = table.freshJavaId("var");
requireBlock.add(factory.boolVar(newVar, boolExpr));
listExpr.add(toIdentifier(newVar));
Node tagNode = node.getGeneric(1);
String tag = tagNode.getString(0);
Node msgNode = node.getGeneric(2);
Node msgExpr = (Node)dispatch(msgNode);
Node atNode = node.getGeneric(3);
Node atExpr;
if (null == atNode) {
atExpr = nullNode;
} else {
atExpr = (Node)dispatch(atNode);
}
Node ifNode = factory.ifStatement3(toIdentifier(newVar),
GNode.create("StringLiteral",
"\"" + tag + "\""), msgExpr,atExpr);
requireBlock.add(ifNode);
}
// check for returning null (bottom)
if (1 == listExpr.size()) {
Node checkNode = factory.ifStatement4(listExpr.get(0));
requireBlock.add(checkNode);
} else {
Node logicalOr = GNode.create("LogicalOrExpression");
logicalOr.add(factory.isNull(listExpr.get(0)));
logicalOr.add(factory.isNull(listExpr.get(1)));
for (int i = 2; i < listExpr.size(); i++ ) {
logicalOr = GNode.create("LogicalOrExpression", logicalOr,
factory.isNull(listExpr.get(i)));
}
Node checkNode = factory.ifStatement5(logicalOr);
requireBlock.add(checkNode);
}
// Check to return expr
if (1 == listExpr.size()) {
Node checkNode;
if(!"Block".equals(valExpr.getName())) {
checkNode = factory.ifStatement(listExpr.get(0), factory.ret(valExpr));
} else {
checkNode = toIfStatement(listExpr.get(0), valExpr);
}
requireBlock.add(checkNode);
} else {
Node logicalAnd = GNode.create("LogicalAndExpression");
logicalAnd.add(listExpr.get(0));
logicalAnd.add(listExpr.get(1));
for(int i = 2; i < listExpr.size(); i++) {
logicalAnd = GNode.create("LogicalAndExpression", logicalAnd,
listExpr.get(i));
}
Node checkNode;
if (!"Block".equals(valExpr.getName())) {
checkNode = factory.ifStatement(logicalAnd, factory.ret(valExpr));
} else {
checkNode = toIfStatement(logicalAnd, valExpr);
}
requireBlock.add(checkNode);
}
// return null at the end
requireBlock.add(factory.ret(nullNode));
Node ret = factory.requireExpression(genericType, requireBlock);
passBindings(valExpr, ret);
return ret;
}
/** Store nodes that need to process scopes. */
public void processScopeSpace() {
Node block = GNode.create("Block");
for (int i = 0; i < processScopeNodes.size(); i++) {
Node add = factory.addScopeNode(toIdentifier(
"\"" + processScopeNodes.get(i) + "\""));
block.add(add);
}
Node getNodes = factory.getScopeNodesMethod();
getNodes.set(7, block);
cbody.add(getNodes);
// if scope definition is not used
if(!seenScope) {
cbody.add(factory.getScopeClass());
cbody.add(factory.getScopeObject());
}
if(!seenNameSpace) {
throw new AssertionError("Name space must be defined");
}
}
/**
* Create equals method for the record "type".
*
* @return The equals method for the type record.
*/
public Node createTypeRecordEquals() {
Node block = GNode.create("Block");
block.add(toIfStatement(factory.equality(toIdentifier("o"), nullNode),
factory.ret(GNode.create("BooleanLiteral","false"))));
block.add(toIfStatement(GNode.create("LogicalNegationExpression",
GNode.create("InstanceOfExpression", toIdentifier("o"), toType("type"))),
factory.ret(toLiteral("BooleanLiteral","false"))) );
block.add(factory.recordFieldEqual());
block.add(factory.recordEqualReturn());
block.add(factory.compareTypes());
// Add equal attribute comparisons.
for (Attribute att : eqAttributeList) {
block.add(factory.compareAttributes(toIdentifier(att.name)));
}
block.add(factory.ret(toIdentifier("res")));
Node retNode = factory.equalsMethod();
retNode.set(7, block);
return retNode;
}
/**
* Create equals method for a constructor that is in equality definition.
*
* @param variantName The name of the contructor.
* @return The equals method for the variant.
*/
public Node createVariantEqualsMethod(String variantName) {
Equality constr = null;
for (Equality e : equalities) {
if (variantName.equals(e.name)) {
constr = e;
break;
}
}
assert null != constr : "null value for constr";
Node block = GNode.create("Block");
block.add(factory.ifStatement1(toIdentifier("o")));
Node secondIf = factory.ifStatement2(toIdentifier("o"));
secondIf.getGeneric(0).getGeneric(0).set(1, toType(variantName));
block.add(secondIf);
block.add(makeDec("other", variantName, GNode.create("CastExpression",
toType(variantName), toIdentifier("o"))));
block.add(makeDec("res", "boolean", toLiteral("BooleanLiteral","true")));
for (Integer pos : constr.positions) {
block.add(factory.compareMembers(
"getTuple().get" + pos + "()"));
}
block.add(factory.ret(toIdentifier("res")));
Node foo = factory.equalsMethod();
foo.set(7, block);
return foo;
}
/**
* Augment a translated IfStatement of a pattern match to process scope.
*
* @param n The IfStatement node.
* @param matchArg The argument of the match expression.
* @param no The pattern match node.
* @param bn The node to get bindings from (if exists).
* @return The augmented IfStatement.
*/
public Node augmentIfStatement(Node n, String matchArg, GNode no, Node bn) {
Node block = n.getGeneric(1);
GNode pattern = no.getGeneric(0).getGeneric(0);
List<Integer> indexList = getIndexList(pattern);
int size = block.size();
// Get the last return statement of the block
Node retNode = block.getGeneric(size - 1);
assert ("ReturnStatement" == retNode.getName()) :
"The last statement of the if block is not a return statement";
// Update matching_nodes.
block.set(size - 1, factory.matchingNodesAdd(toIdentifier(matchArg)));
// Check if this node needs to process scope
block.add(factory.processScope(toIdentifier(matchArg)));
// Check if enter a new scope
block.add(factory.checkEnterScope(toIdentifier(matchArg)));
// Check if needed to process scope of the offsprings
String nodeName = table.freshJavaId("nodeName");
String listName = table.freshJavaId("listName");
if (null != indexList && indexList.size() > 1) {
block.add(factory.spOffspringList(listName));
block.add(factory.spRunNode(nodeName, toIdentifier(matchArg)));
int index;
for (int ind = 0; ind < indexList.size() - 1; ind++){
index = indexList.get(ind);
block.add(factory.spGetGeneric(toIdentifier(nodeName),
toLiteral("IntegerLiteral", "" + index)));
block.add(factory.processScope(toIdentifier(nodeName)));
block.add(factory.checkEnterScope(toIdentifier(nodeName)));
block.add(factory.spOffspringListAdd(toIdentifier(listName),
toIdentifier(nodeName)));
}
}
// Add bindings if exists
List<LetBinding> bl = getBindings(bn);
if (null != bl) {
for (LetBinding bind : bl) {
if (!bind.name.equals(spareVar)) {
if (mapper.hasTypeVariables(bind.typeObject)) {
block.add(factory.fieldDecl2(bind.type, bind.name, bind.value));
} else {
block.add(factory.fieldDecl2(bind.type, bind.name,
factory.cast(bind.value)));
}
} else {
if (mapper.hasTypeVariables(bind.typeObject)) {
block.add(factory.assign(toIdentifier(bind.name), bind.value));
} else {
block.add(factory.assign(toIdentifier(bind.name),
factory.cast(bind.value)));
}
}
}
}
// Store the return value
String freshId = table.freshJavaId("retValue");
block.add(factory.storeValue(freshId, retNode.getGeneric(0)));
// Check to exit scope
if (null != indexList && indexList.size() > 1) {
block.add(factory.spForLoop(toIdentifier(listName)));
}
block.add(factory.checkExitScope(toIdentifier(matchArg)));
// Update matching_nodes
block.add(factory.matchingNodesRemove());
// Annotate this node with the type
if (no.hasProperty(ANNOTATE)) {
block.add(factory.annotateType(toIdentifier(matchArg),
toIdentifier(freshId)));
}
// return
Object t = mapper.getPatternMatchRightType(no.getProperty(TYPE));
if (mapper.hasTypeVariables(t)) {
block.add(factory.castReturn(toIdentifier(freshId)));
} else {
block.add(factory.castReturn(toIdentifier(freshId)));
}
return n;
}
/**
* Add bindings to an if statement
*
* @param n The if statement node
* @param no The node annotated with bindings
* @return The if statement with bindings added
*/
public Node addToIf(Node n, Node no) {
Node block = n.getGeneric(1);
int size = block.size();
// Get the last return statement of the block
Node retNode = block.getGeneric(size - 1);
block.set(size - 1, null);
List<LetBinding> bl = getBindings(no);
if (null != bl) {
for (LetBinding bind : bl) {
if (!bind.name.equals(spareVar)) {
if (mapper.hasTypeVariables(bind.typeObject)) {
block.add(factory.fieldDecl2(bind.type, bind.name, bind.value));
} else {
block.add(factory.fieldDecl2(bind.type, bind.name,
factory.cast(bind.value)));
}
} else {
if (mapper.hasTypeVariables(bind.typeObject)) {
block.add(factory.assign(toIdentifier(bind.name), bind.value));
} else {
block.add(factory.assign(toIdentifier(bind.name),
factory.cast(bind.value)));
}
}
}
}
block.add(retNode);
return n;
}
/**
* Get a list of indice that corresspond to nodes needed to process scope
*
* @param node The pattern node
* @return The list of indice
*/
public static List<Integer> getIndexList(GNode node){
List<Integer> res;
final String nodeName = node.getName();
if ("WhenPattern".equals(nodeName) ||
"AsPattern".equals(nodeName) ||
"TypedPattern".equals(nodeName)) {
return getIndexList(node.getGeneric(0));
} else if ("TypeConstructorPattern".equals(nodeName)) {
if (1 == node.size() || "WidlCard".equals(node.getGeneric(1).getName())) {
return null;
} else {
Node paras = node.getGeneric(1);
boolean hasBinding = false;
for (int index = 0; index < paras.size(); index++) {
res = getIndexList(paras.getGeneric(index));
if (null != res && !res.isEmpty()) {
if ("ConsPattern".equals(paras.getGeneric(index).getName())||
"ListPattern".equals(paras.getGeneric(index).getName())) {
int pos = res.remove(0);
res.add(0, pos + index);
return res;
} else {
res.add(0, index);
return res;
}
} else if (null != res) {
hasBinding = true;
}
}
if (hasBinding) {
res = new ArrayList<Integer>();
res.add(0);
return res;
} else return null;
}
} else if ("ConsPattern".equals(nodeName)) {
res = getIndexList(node.getGeneric(0));
if (null == res) {
res = getIndexList(node.getGeneric(1));
if (null == res || res.isEmpty()) return res;
else {
int pos = res.remove(0);
res.add(0, pos + 1);
return res;
}
} else if (res.isEmpty()) {
return res;
} else {
res.add(0,0);
return res;
}
} else if ("ListPattern".equals(nodeName)) {
boolean hasBinding = false;
for (int index = 0; index < node.size(); index++){
res = getIndexList(node.getGeneric(index));
if (null != res && !res.isEmpty()) {
res.add(0, index);
return res;
} else if (null != res){
hasBinding = true;
}
}
return hasBinding? new ArrayList<Integer>() : null;
} else if ("Variable".equals(nodeName)) {
return new ArrayList<Integer>();
} else if ("WildCard".equals(nodeName) ||
"BottomPattern".equals(nodeName)) {
return null;
}
return null;
}
/**
* Process currying in function applications
*
* @param funcName The name of the function
* @param args The node that contains all arguments
* @param paramTypes The list of parameter type nodes of the function
* @param retType The return type node of the function
* @param funcType The whole function type
* @return A node that is a new function
*/
public Node makeCurry(String funcName, Node args,
List<Node> paramTypes, Node retType, Object funcType) {
//create the function name and parameterise it with the return type
//and the argument types
final int paraSize = paramTypes.size() - args.size();
Node typeArgs = GNode.create("TypeArguments");
typeArgs.add(retType);
for (int i = args.size(); i < paramTypes.size(); i++) {
typeArgs.add(paramTypes.get(i));
}
Node functionTypeNode = GNode.create("Type",
GNode.create("InstantiatedType",
GNode.create("TypeInstantiation", "Function", null),
GNode.create("TypeInstantiation", "F" + paraSize,
typeArgs)),
null);
// Populate the formal parameters for the "apply" method
Node formalParameters = GNode.create("FormalParameters", paraSize);
// Names of formal parameters
List<String> formalParams = new ArrayList<String>();
for (int i = args.size(); i < paramTypes.size(); i++) {
String newPara = table.freshJavaId("para");
formalParams.add(newPara);
formalParameters.add(GNode.create("FormalParameter", fmod,
paramTypes.get(i), null, newPara, null));
}
// Create block for apply method
Node block = GNode.create("Block");
// Names of temporary variables
List<String> tempVars = new ArrayList<String>();
for (int i = 0; i < args.size(); i++) {
// Assign to a temporary variable
String tempVar = table.freshJavaId("var");
tempVars.add(tempVar);
block.add(factory.fieldDecl2(paramTypes.get(i),
tempVar, args.getGeneric(i)));
}
// Node of new arguments
Node newArgs = GNode.create("Arguments");
for (String s : tempVars) newArgs.add(toIdentifier(s));
for (String s : formalParams) newArgs.add(toIdentifier(s));
// Create return statement
Node ret = factory.ret(factory.apply(toIdentifier(funcName),
makeArgumentList(newArgs)));
block.add(ret);
// Create body of the class
Node classBody = GNode.create("ClassBody",
GNode.create("MethodDeclaration", pmod, null,
retType, "apply", formalParameters, null, null,
block));
return toNewExpression2(functionTypeNode,null,classBody);
}
/**
* Get the index of a primitive instance in the list
*
* @param name The name of the instance
* @param types The types of the instance
* @return The index of the instance, -1 if not exists
*/
public String getInstanceName(String name, List<String> types) {
for (PrimitiveInstance ins : primitiveInsList) {
if (!name.equals(ins.name) || types.size() != ins.types.size()) continue;
boolean check = true;
for (int j = 0; j < types.size(); j++) {
if (!types.get(j).equals(ins.types.get(j))) {
check = false;
break;
}
}
if (check) return ins.instanceName;
}
return null;
}
/**
* Make a variable declaration.
*
* @param s The variable name.
* @param t The type.
* @param d The declarator value.
* @return The variable declaration node.
*/
private Node makeVarDec(String s, String t, Node d) {
Node decl = factory.fieldDecl(toType(t), d);
//set the name
decl.getGeneric(2).getGeneric(0).set(0, s);
return decl;
}
/**
* Make a variable declaration with type is a node.
*
* @param s The variable name.
* @param t The type node.
* @param d The declarator value.
* @return The variable declaration node.
*/
private Node makeVarDec2(String s, Node t, Node d) {
Node decl = factory.fieldDecl(t, d);
//set the name
decl.getGeneric(2).getGeneric(0).set(0, s);
return decl;
}
/**
* Make a variable declaration.
*
* @param s The variable name.
* @param t The type.
* @param d The declarator value.
* @return The variable declaration node.
*/
@SuppressWarnings ("unused")
private Node makeStaticVarDec(String s, String t, Node d) {
Node decl = factory.staticFieldDecl(toType(t), d);
//set the name
decl.getGeneric(2).getGeneric(0).set(0, s);
return decl;
}
/**
* Make a variable declaration.
*
* @param s The variable name.
* @param t The type.
* @param d The declarator value.
* @return The variable declaration node.
*/
private Node makeDec(String s, String t, Node d) {
Node decl = factory.fieldDecl1(toType(t), d);
//set the name
decl.getGeneric(2).getGeneric(0).set(0, s);
return decl;
}
/**
* Get variale bindings from a node.
*
* @param n The node to get variable bindings.
* @return A list of bindings.
*/
@SuppressWarnings("unchecked")
private List<LetBinding> getBindings(Node n) {
return (List<LetBinding>)n.getProperty(LETBINDINGS);
}
/**
* Get annotated variales from a node.
*
* @param n The node to get variables bindings.
* @return A list of variables (string).
*/
@SuppressWarnings("unchecked")
private List<String> getUpVariables(Node n) {
return (List<String>)n.getProperty(UPVARS);
}
/**
* Get variables from a list of bindings.
*
* @param l The list of bindings.
* @return A list of variables.
*/
private List<String> extractVariables(List<LetBinding> l) {
if (null == l) return null;
List<String> ret = new ArrayList<String>();
for (LetBinding bind : l) {
ret.add(bind.name);
}
return ret;
}
/**
* Group variables from 2 lists of variables.
* @param l1 The first list.
* @param l2 The second list.
* @return The resulted list.
*/
private <T0> List<T0> groupList(List<T0> l1, List<T0> l2) {
if (null == l1) return l2;
if (null == l2) return l1;
List<T0> ret = l1;
ret.addAll(l2);
return ret;
}
/**
* Pass annotated variables from a node to another.
*
* @param from The node to get annotated variables.
* @param to The node to pass variables to.
*/
private void passVariables(Node from, Node to) {
List<String> vars = getUpVariables(from);
if (null != vars) to.setProperty(UPVARS, vars);
}
/**
* Pass annotated bindings from a node to another.
*
* @param from The node to get annotated bindings.
* @param to The node to pass bindings to.
*/
private void passBindings(Node from, Node to) {
List<LetBinding> bl = getBindings(from);
if (null != bl) to.setProperty(LETBINDINGS, bl);
}
/**
* Get variables from a pattern.
*
* @param n The pattern node.
* @return A list of variables.
*/
private List<String> getPatternVariables(Node n) {
String name = n.getName();
if ("TuplePattern".equals(name)) {
List<String> res = new ArrayList<String>();
for (int i = 0; i < n.size(); i++) {
List<String> vars = getPatternVariables(n.getGeneric(i));
if (null != vars) res.addAll(vars);
}
return res;
} else if ("WhenPattern".equals(name)) {
return getPatternVariables(n.getGeneric(0));
} else if ("AsPattern".equals(name)) {
List<String> vars = getPatternVariables(n.getGeneric(0));
vars.add(n.getString(1));
return vars;
} else if ("TypedPattern".equals(name)) {
return getPatternVariables(n.getGeneric(0));
} else if ("ConsPattern".equals(name)) {
List<String> res = getPatternVariables(n.getGeneric(0));
res.addAll(getPatternVariables(n.getGeneric(1)));
return res;
} else if ("Variable".equals(name)) {
List<String> res = new ArrayList<String>();
res.add(n.getString(0));
return res;
} else if ("TypeConstructorPattern".equals(name)) {
if (1 < n.size()) return getPatternVariables(n.getGeneric(1));
else return new ArrayList<String>();
} else if ("PatternParameters".equals(name)) {
List<String> res = new ArrayList<String>();
for (int i = 0; i < n.size(); i++) {
List<String> vars = getPatternVariables(n.getGeneric(i));
if (null != vars) res.addAll(vars);
}
return res;
} else if ("ListPattern".equals(name)) {
List<String> res = new ArrayList<String>();
for (int i = 0; i < n.size(); i++) {
List<String> vars = getPatternVariables(n.getGeneric(i));
if (null != vars) res.addAll(vars);
}
return res;
} else if ("RecordPattern".equals(name)) {
List<String> res = new ArrayList<String>();
for (int i = 0; i < n.size(); i++) {
List<String> vars = getPatternVariables(n.getGeneric(i));
if (null != vars) res.addAll(vars);
}
return res;
} else if ("FieldPattern".equals(name)) {
return getPatternVariables(n.getGeneric(1));
} else return new ArrayList<String>();
}
/** Run this transformer. */
public void run() {
dispatch(typical);
}
/**
* Return the ast of the generated program.
*
* @return The ast of the output type checker.
*/
public GNode getCheckerAST() {
return transformed;
}
/**
* Return the ast of the generated types file.
*
* @return The ast of the output types file.
*/
public GNode getTypesAST() {
return typesAST;
}
/**
* Return the ast of the generated support file.
*
* @return The ast of the output support file.
*/
public GNode getSupportAST() {
return supportAST;
}
/**
* Check which libraries are used, set the corresponding flag variables.
*
* @param n The root of the generated code to check.
*/
private void setFlagVariables(Node n) {
FlagSetter set = new FlagSetter((GNode)n);
isListUsed = set.isListUsed;
isArrayListUsed = set.isArrayListUsed;
isBigIntegerUsed = set.isBigIntegerUsed;
isPairUsed = set.isPairUsed;
isNodeUsed = set.isNodeUsed;
isGNodeUsed = set.isGNodeUsed;
isPrimitivesUsed = set.isPrimitivesUsed;
isRecordUsed = set.isRecordUsed;
isVariantUsed = set.isVariantUsed;
isTupleUsed = set.isTupleUsed;
isReductionUsed = set.isReductionUsed;
isNameUsed = set.isNameUsed;
isScopeUsed = set.isScopeUsed;
isScopeKindUsed = set.isScopeKindUsed;
isAnalyzerUsed = set.isAnalyzerUsed;
}
/**
* Import libraries that are used.
*
* @param compUnit The CompilationUnit node.
* @param n The node to check which libraries are used.
* @param fileName The importing file, XXXAnalyzer, XXXTypes or XXXSuppport
*/
private void addImports(Node compUnit, Node n, String fileName) {
setFlagVariables(n);
Node importNode;
if (isBigIntegerUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "java", "math", "BigInteger"),
null);
compUnit.add(importNode);
}
if (isListUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "java", "util", "List"),null);
compUnit.add(importNode);
}
if (isArrayListUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "java", "util", "ArrayList"),
null);
compUnit.add(importNode);
}
if (isPairUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "util", "Pair"), null);
compUnit.add(importNode);
}
if ("Analyzer".equals(fileName)) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "util", "Runtime"), null);
compUnit.add(importNode);
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "util", "Function"), null);
compUnit.add(importNode);
}
if (isNodeUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "tree", "Node"), null);
compUnit.add(importNode);
}
if (isGNodeUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "tree", "GNode"), null);
compUnit.add(importNode);
}
// Check and import xtc.typical.XXX
if (!"xtc.typical".equals(packageName)) {
if ("Analyzer".equals(fileName) || isAnalyzerUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Analyzer"),
(GNode)null);
compUnit.add(importNode);
}
if (isPrimitivesUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Primitives"),
(GNode)null);
compUnit.add(importNode);
}
if (isRecordUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Record"),
(GNode)null);
compUnit.add(importNode);
}
if (isVariantUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Variant"),
(GNode)null);
compUnit.add(importNode);
}
if (isTupleUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Tuple"),
(GNode)null);
compUnit.add(importNode);
}
if (isReductionUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Reduction"),
(GNode)null);
compUnit.add(importNode);
}
if (isNameUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Name"),
(GNode)null);
compUnit.add(importNode);
}
if (isScopeUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "Scope"),
(GNode)null);
compUnit.add(importNode);
}
if (isScopeKindUsed) {
importNode = GNode.create("ImportDeclaration", null,
GNode.create("QualifiedIdentifier", "xtc", "typical", "ScopeKind"),
(GNode)null);
compUnit.add(importNode);
}
}
}
/**
* Make the class body for the XXXAnalyzer
*
* @return The node of the class body
*/
private Node makeClassBody() {
// Make the constructor
Node constructor;
if ("Typical".equals(output)) {
constructor = factory.makeConstructor(output + "Analyzer");
Node fieldDecl = factory.nodeTypeDecl();
// return the class body node
return GNode.create("ClassBody", fieldDecl, constructor);
} else {
constructor = factory.makeConstructor2(output + "Analyzer");
// return the class body node
return GNode.create("ClassBody", constructor);
}
}
/**
* Create the typechecker skeleton.
*
* @return The root of the type checker ast.
*/
private Node makeSkeleton() {
Node classDec = GNode.create("ClassDeclaration",
toModifiers("public"),
output + "Analyzer",
null,
GNode.create("Extension", GNode.create("Type",
GNode.create("QualifiedIdentifier", "Analyzer"),null)),null,
cbody);
Node compUnit = GNode.create("CompilationUnit", 8);
compUnit.add(packageNode);
addImports(compUnit, cbody, "Analyzer");
compUnit.add(comment(classDec,
"Type checker for " + output + "."));
return compUnit;
}
/**
* Create the skeleton for the xxxTypes.java file.
*
* @return The root of the XXXTypes.java ast.
*/
private Node makeTypesSkeleton() {
Node compUnit = GNode.create("CompilationUnit", 8);
compUnit.add(packageNode);
addImports(compUnit, tbody, "Types");
Node classDecl = factory.classDecl2(output + "Types");
classDecl.set(5, tbody);
compUnit.add(comment(classDecl,
"Types for " + output + "."));
return compUnit;
}
/**
* Create the skeleton for the xxxSupport.java file.
*
* @return The root of the XXXSupport.java ast.
*/
private Node makeSupportSkeleton() {
Node compUnit = GNode.create("CompilationUnit", 8);
compUnit.add(packageNode);
addImports(compUnit, sbody, "Support");
Node classDecl = factory.classDecl2(output + "Support");
classDecl.set(5, sbody);
compUnit.add(comment(classDecl,
"Helper functionality for " + output + "."));
return compUnit;
}
/**
* Add an enumeration constant.
*
* @param s The name of the enum.
*/
private void addEnum(Node enums, String s) {
enums.add(GNode.create("EnumConstant", null, s, null, null));
}
/**
* Enter the scoped named.
*
* @param n The scope name.
*/
private void enterScope(String n) {
table.enter(n);
}
/**
* Exit the scope named n.
*
* @param n The scope name.
*/
private void exitScope(String n) {
if (!(n.equals(table.current().getName()))) {
throw new AssertionError("mismatched scope exit " + n);
} else {
table.exit();
}
}
/**
* Debug function to check for type annotations.
*
* @param n The node to check.
*/
private void checkTypeAnnotation(GNode n) {
if (!n.hasProperty(TYPE)) {
throw new AssertionError("no type annotation for " + n.getName());
} else if (n.getProperty(TYPE) == null) {
throw new AssertionError(n.getName() + " has null type");
}
}
/**
* Utility function to print a nicely formatted ast for debugging.
*
* @param n The ast root.
*/
@SuppressWarnings("unused")
private final void printAST(Node n) {
runtime.console().pln().format(n).pln().flush();
}
/** Print the symbol table. */
@SuppressWarnings("unused")
private final void printSymbolTable() {
if (null != table) {
Visitor visitor = runtime.console().visitor();
try {
table.root().dump(runtime.console());
} finally {
runtime.console().register(visitor);
}
runtime.console().flush();
} else {
throw new AssertionError("Symbol table not initialized");
}
}
/**
* Return the qualified name of a type object.
*
* @param o The type object.
* @return The (possibly prefixed) type.
*/
private String getType(Object o) {
return mapper.toTypeString(o);
}
/**
* Wrap the specified node in a documentation comment.
*
* @param node The node.
* @param text The comment's text.
* @return The commented node.
*/
public static Node comment(Node node, String... text) {
final List<String> l = new ArrayList<String>(text.length);
for (String s : text) l.add(s);
return new Comment(Comment.Kind.DOCUMENTATION, l, node);
}
/**
* Convert the specified string to a modifier in a list of modifiers.
*
* @param mod The modifier
* @return The corresponding node.
*/
public static Node toModifiers(String mod) {
return GNode.create("Modifiers", GNode.create("Modifier", mod));
}
/**
* Convert the specified string to a literal node.
*
* @param name The node name.
* @param literal The literal as a string.
* @return The corresponding literal node.
*/
public static Node toLiteral(String name, String literal) {
return GNode.create(name, literal);
}
/**
* Create an identifier node with the specified name.
*
* @param name The name.
* @return The corresponding identifier node.
*/
public static Node toIdentifier(String name) {
if (null == name) throw new AssertionError("null name in toIdentifier");
return GNode.create("PrimaryIdentifier", name);
}
/**
* Create a conditional statement node.
*
* @param condition The condition node.
* @param action The action statement or block.
* @return The conditional node.
*/
public Node toIfStatement(Node condition, Node action) {
action = (null == action) ? GNode.create("Block") : action;
Node block = (action.hasName("Block"))
? GNode.ensureVariable(GNode.cast(action))
: GNode.ensureVariable(GNode.create("Block", action));
return GNode.create("ConditionalStatement", condition, block, null);
}
/**
* Create a case statemnt
*
* @param clause
* @param action
*/
private Node makeCase(Node clause, List<Node> actions, String s) {
Node c = factory.caseStmnt(clause, actions).getGeneric(1);
return c;
}
/**
* Create a type node.
*
* @param s The name of the type.
* @return The type node.
*/
private static Node toType(String s) {
assert null != s :"null string";
return
GNode.create("Type",GNode.create("QualifiedIdentifier",s), null);
}
/**
* Create new expression with type is a node.
* If args is null empty arguments will be used.
*
* @param name The type node.
* @param args The arguments.
* @param body The option anonymous class body.
*/
private Node toNewExpression2(Node name, Node args, Node body) {
if (null == args) args = GNode.create("Arguments");
List<Object> arglisto = new ArrayList<Object>(args.size());
args.addAllTo(arglisto);
Object o = arglisto; // Hack to enable cast from List<Object> to
// List<Node>.
@SuppressWarnings("unchecked")
List<Node> arglistn = (List<Node>)o;
Node newNode = factory.newExpr(name, arglistn);
newNode.set(4, body);
return newNode;
}
/**
* Extract the list of arguments from an Arguments node.
*
* @param args The arguments node.
* @return The list of arguments.
*/
@SuppressWarnings("unchecked")
private static List<Node> makeArgumentList(Node args) {
if (null == args) args = GNode.create("Arguments");
List<Object> arguments = new ArrayList<Object>(args.size());
args.addAllTo(arguments);
Object o = arguments; // Hack to enable cast from List<Object> to
// List<Node>.
return (List<Node>)(o);
}
}