package sizzle.compiler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import sizzle.aggregators.AggregatorSpec;
import sizzle.parser.syntaxtree.ArrayType;
import sizzle.parser.syntaxtree.Assignment;
import sizzle.parser.syntaxtree.Block;
import sizzle.parser.syntaxtree.BreakStatement;
import sizzle.parser.syntaxtree.BytesLiteral;
import sizzle.parser.syntaxtree.Call;
import sizzle.parser.syntaxtree.CharLiteral;
import sizzle.parser.syntaxtree.Comparison;
import sizzle.parser.syntaxtree.Component;
import sizzle.parser.syntaxtree.Composite;
import sizzle.parser.syntaxtree.Conjunction;
import sizzle.parser.syntaxtree.ContinueStatement;
import sizzle.parser.syntaxtree.Declaration;
import sizzle.parser.syntaxtree.DoStatement;
import sizzle.parser.syntaxtree.EmitStatement;
import sizzle.parser.syntaxtree.ExprList;
import sizzle.parser.syntaxtree.ExprStatement;
import sizzle.parser.syntaxtree.Expression;
import sizzle.parser.syntaxtree.Factor;
import sizzle.parser.syntaxtree.FingerprintLiteral;
import sizzle.parser.syntaxtree.FloatingPointLiteral;
import sizzle.parser.syntaxtree.ForExprStatement;
import sizzle.parser.syntaxtree.ForStatement;
import sizzle.parser.syntaxtree.ForVarDecl;
import sizzle.parser.syntaxtree.Function;
import sizzle.parser.syntaxtree.FunctionType;
import sizzle.parser.syntaxtree.Identifier;
import sizzle.parser.syntaxtree.IdentifierList;
import sizzle.parser.syntaxtree.IfStatement;
import sizzle.parser.syntaxtree.Index;
import sizzle.parser.syntaxtree.IntegerLiteral;
import sizzle.parser.syntaxtree.MapType;
import sizzle.parser.syntaxtree.Node;
import sizzle.parser.syntaxtree.NodeChoice;
import sizzle.parser.syntaxtree.NodeSequence;
import sizzle.parser.syntaxtree.NodeToken;
import sizzle.parser.syntaxtree.Operand;
import sizzle.parser.syntaxtree.OutputType;
import sizzle.parser.syntaxtree.Pair;
import sizzle.parser.syntaxtree.PairList;
import sizzle.parser.syntaxtree.Program;
import sizzle.parser.syntaxtree.Proto;
import sizzle.parser.syntaxtree.ProtoFieldDecl;
import sizzle.parser.syntaxtree.ProtoMember;
import sizzle.parser.syntaxtree.ProtoMemberList;
import sizzle.parser.syntaxtree.ProtoTupleType;
import sizzle.parser.syntaxtree.Regexp;
import sizzle.parser.syntaxtree.RegexpList;
import sizzle.parser.syntaxtree.ResultStatement;
import sizzle.parser.syntaxtree.ReturnStatement;
import sizzle.parser.syntaxtree.Selector;
import sizzle.parser.syntaxtree.SimpleExpr;
import sizzle.parser.syntaxtree.SimpleMember;
import sizzle.parser.syntaxtree.SimpleMemberList;
import sizzle.parser.syntaxtree.SimpleTupleType;
import sizzle.parser.syntaxtree.Start;
import sizzle.parser.syntaxtree.Statement;
import sizzle.parser.syntaxtree.StatementExpr;
import sizzle.parser.syntaxtree.StaticVarDecl;
import sizzle.parser.syntaxtree.StringLiteral;
import sizzle.parser.syntaxtree.SwitchStatement;
import sizzle.parser.syntaxtree.Term;
import sizzle.parser.syntaxtree.TimeLiteral;
import sizzle.parser.syntaxtree.TupleType;
import sizzle.parser.syntaxtree.Type;
import sizzle.parser.syntaxtree.TypeDecl;
import sizzle.parser.syntaxtree.VarDecl;
import sizzle.parser.syntaxtree.WhenStatement;
import sizzle.parser.syntaxtree.WhileStatement;
import sizzle.parser.visitor.GJDepthFirst;
import sizzle.types.SizzleArray;
import sizzle.types.SizzleBool;
import sizzle.types.SizzleBytes;
import sizzle.types.SizzleFingerprint;
import sizzle.types.SizzleFloat;
import sizzle.types.SizzleFunction;
import sizzle.types.SizzleInt;
import sizzle.types.SizzleMap;
import sizzle.types.SizzleName;
import sizzle.types.SizzleScalar;
import sizzle.types.SizzleString;
import sizzle.types.SizzleTable;
import sizzle.types.SizzleTime;
import sizzle.types.SizzleTuple;
import sizzle.types.SizzleType;
/**
* Prescan the Sizzle program and check that all variables are consistently
* typed.
*
* @author anthonyu
*
*/
public class TypeCheckingVisitor extends GJDepthFirst<SizzleType, SymbolTable> {
/** {@inheritDoc} */
@Override
public SizzleType visit(final Start n, final SymbolTable argu) {
return n.f0.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Program n, final SymbolTable argu) {
for (final Node node : n.f0.nodes)
node.accept(this, argu);
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Declaration n, final SymbolTable argu) {
switch (n.f0.which) {
case 0: // type declaration
case 1: // static variable declaration
case 2: // variable declaration
return n.f0.choice.accept(this, argu);
default:
throw new RuntimeException("unexpected choice " + n.f0.which + " is " + n.f0.choice.getClass());
}
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final TypeDecl n, final SymbolTable argu) {
final String id = n.f1.f0.tokenImage;
if (argu.hasType(id))
throw new TypeException(id + " already defined as " + argu.getType(id));
argu.setType(id, new SizzleName(n.f3.accept(this, argu)));
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final StaticVarDecl n, final SymbolTable argu) {
return n.f1.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final VarDecl n, final SymbolTable argu) {
final String id = n.f0.f0.tokenImage;
if (argu.contains(id))
throw new TypeException("variable " + id + " already declared as " + argu.get(id));
SizzleType rhs = null;
if (n.f3.present()) {
final NodeChoice nodeChoice = (NodeChoice) n.f3.node;
switch (nodeChoice.which) {
case 0: // initializer
rhs = ((NodeSequence) nodeChoice.choice).elementAt(1).accept(this, argu);
break;
default:
throw new RuntimeException("unexpected choice " + nodeChoice.which + " is " + nodeChoice.choice.getClass());
}
}
SizzleType lhs;
if (n.f2.present()) {
lhs = n.f2.node.accept(this, argu);
if (rhs != null && !lhs.assigns(rhs) && !argu.hasCast(lhs, rhs))
throw new TypeException("incorrect type " + rhs + " for assignment to " + id + ':' + lhs);
} else {
if (rhs == null)
throw new TypeException("variable declaration requires a type or an initializer");
lhs = rhs;
}
argu.set(id, lhs);
// switch (n.f2.which) {
// case 0: // identifier
// final SizzleType ittype = argu.getType(((Identifier)
// n.f2.choice).f0.tokenImage);
//
// if (n.f3.present()) {
// final SizzleType ietype = ((Initializer) ((NodeSequence)
// n.f3.node).nodes.get(1)).accept(this, argu);
//
// if (!ittype.assigns(ietype) && !argu.hasCast(ittype, ietype))
// throw new TypeException("incorrect type " + ietype +
// " for assignment to " + id + ':' + ittype);
//
// argu.set(id, ittype, false);
// } else
// argu.set(id, ittype);
// break;
// case 1: // map
// final NodeSequence seq = (NodeSequence) n.f2.choice;
// final SizzleType mvtype = new SizzleMap((SizzleScalar)
// argu.getType(((Identifier) seq.elementAt(2)).f0.tokenImage),
// (SizzleScalar) argu.getType(((Identifier)
// seq.elementAt(5)).f0.tokenImage));
//
// if (n.f3.present()) {
// final SizzleType mitype = ((Initializer) ((NodeSequence)
// n.f3.node).nodes.get(1)).accept(this, argu);
//
// if (!mvtype.assigns(mitype))
// throw new TypeException("incorrect type " + mitype +
// " for assignment to " + id + ':' + mvtype);
// }
//
// argu.set(id, mvtype);
// break;
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Type n, final SymbolTable argu) {
switch (n.f0.which) {
case 0: // identifier
case 1: // array
case 2: // map
case 3: // tuple
case 4: // table
return n.f0.choice.accept(this, argu);
default:
throw new RuntimeException("unexpected choice " + n.f0.which + " is " + n.f0.choice.getClass());
}
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Component n, final SymbolTable argu) {
return n.f1.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ArrayType n, final SymbolTable argu) {
return new SizzleArray(n.f2.accept(this, argu));
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final TupleType n, final SymbolTable argu) {
return n.f0.choice.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final SimpleTupleType n, final SymbolTable argu) {
if (n.f1.present())
return new SizzleTuple(this.check((SimpleMemberList) n.f1.node, argu));
else
return new SizzleTuple(new ArrayList<SizzleType>());
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final SimpleMemberList n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final SimpleMember n, final SymbolTable argu) {
return n.f0.choice.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ProtoTupleType n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ProtoMemberList n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ProtoMember n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ProtoFieldDecl n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final MapType n, final SymbolTable argu) {
return new SizzleMap(n.f2.accept(this, argu), n.f5.accept(this, argu));
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final OutputType n, final SymbolTable argu) {
List<SizzleScalar> indexTypes = null;
if (n.f3.present()) {
indexTypes = new ArrayList<SizzleScalar>();
for (final Node node : n.f3.nodes) {
final SizzleType sizzleType = ((NodeSequence) node).elementAt(1).accept(this, argu);
if (!(sizzleType instanceof SizzleScalar))
throw new TypeException("incorrect type " + sizzleType + " for index");
indexTypes.add((SizzleScalar) sizzleType);
}
}
final SizzleType type = n.f5.accept(this, argu);
final AggregatorSpec annotation = argu.getAggregators(n.f1.f0.tokenImage, type).get(0).getAnnotation(AggregatorSpec.class);
SizzleScalar tweight = null;
if (n.f6.present()) {
if (annotation.weightType().equals("none"))
throw new TypeException("unexpected weight for table declaration");
final SizzleType aweight = argu.getType(annotation.weightType());
tweight = (SizzleScalar) ((NodeSequence) n.f6.node).nodes.get(1).accept(this, argu);
if (!aweight.assigns(tweight))
throw new TypeException("incorrect weight type for table declaration");
} else if (!annotation.weightType().equals("none"))
throw new TypeException("missing weight for table declaration");
if (n.f2.present())
if (annotation.formalParameters().length == 0)
throw new TypeException("no arguments for table " + n.f1.f0.tokenImage);
return new SizzleTable(type, indexTypes, tweight);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ExprList n, final SymbolTable argu) {
final List<SizzleType> types = this.check(n, argu);
final SizzleType t = types.get(0);
for (int i = 1; i < types.size(); i++)
if (!t.assigns(types.get(i)))
return new SizzleTuple(types);
return new SizzleArray(t);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final FunctionType n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Statement n, final SymbolTable argu) {
return n.f0.choice.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Assignment n, final SymbolTable argu) {
final SizzleType lhs = n.f0.accept(this, argu);
final SizzleType rhs = n.f2.accept(this, argu);
if (!lhs.assigns(rhs))
throw new TypeException("invalid type " + rhs + " for assignment to " + lhs);
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Block n, final SymbolTable argu) {
if (n.f1.present())
for (final Node node : n.f1.nodes)
node.accept(this, argu);
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final BreakStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ContinueStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final DoStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final EmitStatement n, final SymbolTable argu) {
final String id = n.f1.f0.tokenImage;
final SizzleTable t = (SizzleTable) argu.get(id);
if (t == null)
throw new TypeException("emitting to undeclared table " + id);
if (n.f2.present()) {
final List<SizzleType> indices = new ArrayList<SizzleType>();
for (final Node node : n.f2.nodes)
indices.add(((NodeSequence) node).nodes.get(1).accept(this, argu));
if (indices.size() != t.countIndices())
throw new TypeException("incorrect number of indices for " + id);
for (int i = 0; i < t.countIndices(); i++)
if (!t.getIndex(i).assigns(indices.get(i)))
throw new TypeException("incorrect type " + indices.get(i) + " for index " + i);
} else if (t.countIndices() > 0)
throw new TypeException("indices missing from emit");
final SizzleType expression = n.f4.accept(this, argu);
if (!t.accepts(expression))
throw new TypeException("incorrect type " + expression + " for " + id + ":" + t);
if (n.f5.present()) {
if (t.getWeightType() == null)
throw new TypeException("unexpected weight specified by emit");
final SizzleType wtype = ((NodeSequence) n.f5.node).nodes.get(1).accept(this, argu);
if (!t.acceptsWeight(wtype))
throw new TypeException("incorrect type " + wtype + " for weight of " + id + ":" + t.getWeightType());
} else if (t.getWeightType() != null)
throw new TypeException("no weight specified by emit");
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ExprStatement n, final SymbolTable argu) {
final SizzleType type = n.f0.accept(this, argu);
if (n.f1.present() && !(type instanceof SizzleInt))
throw new TypeException(type + " not valid for operator " + n.f1.toString());
return type;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ForStatement n, final SymbolTable argu) {
SymbolTable st;
try {
st = argu.cloneNonLocals();
} catch (final IOException e) {
throw new RuntimeException(e.getClass().getSimpleName() + " caught", e);
}
if (n.f2.present())
((NodeChoice) n.f2.node).choice.accept(this, st);
if (n.f4.present())
n.f4.accept(this, st);
if (n.f6.present())
((NodeChoice) n.f6.node).choice.accept(this, st);
n.f8.accept(this, st);
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ForVarDecl n, final SymbolTable argu) {
final VarDecl varDecl = new VarDecl(n.f0, n.f1, n.f2, n.f3, new NodeToken(";"));
return varDecl.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ForExprStatement n, final SymbolTable argu) {
final ExprStatement exprStatement = new ExprStatement(n.f0, n.f1, new NodeToken(";"));
return exprStatement.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final IfStatement n, final SymbolTable argu) {
final SizzleType test = n.f2.accept(this, argu);
if (!(test instanceof SizzleBool) && !(test instanceof SizzleFunction && ((SizzleFunction) test).getType() instanceof SizzleBool))
throw new TypeException("invalid type " + test + " for if test");
n.f4.accept(this, argu);
if (n.f5.present())
((Statement) ((NodeSequence) n.f5.node).elementAt(1)).accept(this, argu);
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ResultStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final ReturnStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final SwitchStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final WhenStatement n, final SymbolTable argu) {
SymbolTable st;
try {
st = argu.cloneNonLocals();
} catch (final IOException e) {
throw new RuntimeException(e.getClass().getSimpleName() + " caught", e);
}
for (final Node node : n.f2.nodes) {
final SizzleType type = ((NodeSequence) node).nodes.get(3).accept(this, argu);
final IdentifierList identifierList = (IdentifierList) ((NodeSequence) node).nodes.get(0);
st.set(identifierList.f0.f0.tokenImage, type);
if (identifierList.f1.present())
for (final Node nod : identifierList.f1.nodes)
st.set(((Identifier) ((NodeSequence) nod).elementAt(1)).f0.tokenImage, type);
}
n.f3.accept(this, st);
n.f5.accept(this, st);
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final IdentifierList n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final WhileStatement n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Expression n, final SymbolTable argu) {
final SizzleType ltype = n.f0.accept(this, argu);
if (n.f1.present()) {
if (!(ltype instanceof SizzleBool))
throw new TypeException("invalid type " + ltype + " for disjunction");
final SizzleType rtype = n.f0.accept(this, argu);
if (!(rtype instanceof SizzleBool))
throw new TypeException("invalid type " + rtype + " for disjunction");
return new SizzleBool();
}
return ltype;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Conjunction n, final SymbolTable argu) {
final SizzleType lhs = n.f0.accept(this, argu);
if (n.f1.present()) {
final SizzleType rhs = n.f0.accept(this, argu);
if (!rhs.compares(lhs))
throw new TypeException("invalid type " + rhs + " for conjunction with " + lhs);
return new SizzleBool();
}
return lhs;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Comparison n, final SymbolTable argu) {
final SizzleType lhs = n.f0.accept(this, argu);
if (n.f1.present()) {
final SizzleType rhs = ((NodeSequence) n.f1.node).nodes.get(1).accept(this, argu);
if (!rhs.compares(lhs))
throw new TypeException("invalid type " + rhs + " for comparison with " + lhs);
return new SizzleBool();
}
return lhs;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final SimpleExpr n, final SymbolTable argu) {
SizzleType type = n.f0.accept(this, argu);
if (n.f1.present()) {
for (final Node node : n.f1.nodes) {
final SizzleType accept = ((NodeSequence) node).nodes.get(1).accept(this, argu);
type = type.arithmetics(accept);
}
}
return type;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Term n, final SymbolTable argu) {
final SizzleType accepts = n.f0.accept(this, argu);
if (n.f1.present()) {
SizzleScalar type;
if (accepts instanceof SizzleFunction)
type = (SizzleScalar) ((SizzleFunction) accepts).getType();
else
type = (SizzleScalar) accepts;
for (final Node node : n.f1.nodes) {
final SizzleType accept = ((NodeSequence) node).nodes.get(1).accept(this, argu);
type = type.arithmetics(accept);
}
return type;
}
return accepts;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Factor n, final SymbolTable argu) {
if (n.f1.present()) {
for (final Node node : n.f1.nodes) {
final NodeChoice nodeChoice = (NodeChoice) node;
switch (nodeChoice.which) {
case 0: // member
final SizzleType soperand = n.f0.accept(this, argu);
if (!(soperand instanceof SizzleTuple))
throw new TypeException("invalid operand type " + soperand + " for member selection");
// final SizzleType selector = ((Selector)
// nodeChoice.choice).accept(this, argu);
return ((SizzleTuple) soperand).getMember(((Selector) nodeChoice.choice).f1.f0.tokenImage);
case 1: // index
final SizzleType ioperand = n.f0.accept(this, argu);
final SizzleType index = ((Index) nodeChoice.choice).accept(this, argu);
if (ioperand instanceof SizzleArray) {
if (!(index instanceof SizzleInt))
throw new TypeException("invalid operand type " + index + " for indexing into array");
return ((SizzleArray) ioperand).getType();
} else if (ioperand instanceof SizzleMap) {
if (!((SizzleMap) ioperand).getIndexType().assigns(index))
throw new TypeException("invalid operand type " + index + " for indexing into " + ioperand);
return ((SizzleMap) ioperand).getType();
} else {
throw new TypeException("invalid operand type " + ioperand + " for indexing expression");
}
case 2: // call
final List<SizzleType> formalParameters = this.check((Call) nodeChoice.choice, argu);
final SizzleFunction f = new FunctionFindingVisitor(formalParameters).visit(n.f0, argu);
// if (f.countParameters() != formalParameters.size())
// for (int i = 0; i < formalParameters.size(); i++)
// if (!f.getParameter(i).assigns(formalParameters.get(i)))
// throw new TypeException("invalid args " +
// formalParameters + " for call to " + f);
return f;
default:
throw new RuntimeException("unexpected choice " + nodeChoice.which + " is " + nodeChoice.choice.getClass());
}
}
}
return n.f0.accept(this, argu);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Selector n, final SymbolTable argu) {
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Index n, final SymbolTable argu) {
final SizzleType index = n.f1.accept(this, argu);
if (index == null)
throw new RuntimeException();
if (n.f2.present()) {
if (!(index instanceof SizzleInt))
throw new RuntimeException("invalid type " + index + " for slice expression");
final SizzleType slice = ((NodeSequence) n.f2.node).elementAt(1).accept(this, argu);
if (!(slice instanceof SizzleInt))
throw new RuntimeException("invalid type " + slice + " for slice expression");
}
return index;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Call n, final SymbolTable argu) {
if (n.f1.present())
return n.f1.node.accept(this, argu);
return new SizzleArray();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final RegexpList n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Regexp n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Operand n, final SymbolTable argu) {
switch (n.f0.which) {
case 0: // identifier
case 1: // string literal
case 2: // integer literal
case 3: // floating point literal
case 4: // composite
return n.f0.choice.accept(this, argu);
case 9: // parenthetical
return ((NodeSequence) n.f0.choice).nodes.elementAt(1).accept(this, argu);
default:
throw new RuntimeException("unexpected choice " + n.f0.which + " is " + n.f0.choice.getClass());
}
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Composite n, final SymbolTable argu) {
if (n.f1.present()) {
final NodeChoice nodeChoice = (NodeChoice) n.f1.node;
switch (nodeChoice.which) {
case 0: // pair list
case 1: // expression list
return nodeChoice.choice.accept(this, argu);
case 2: // empty map
return new SizzleMap();
default:
throw new RuntimeException("unexpected choice " + nodeChoice.which + " is " + nodeChoice.choice.getClass());
}
}
return new SizzleArray();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final PairList n, final SymbolTable argu) {
final SizzleMap sizzleMap = (SizzleMap) n.f0.accept(this, argu);
if (n.f1.present())
for (final Node node : n.f1.nodes)
if (!sizzleMap.assigns(((NodeSequence) node).elementAt(1).accept(this, argu)))
throw new TypeException("incorrect type " + node + " for " + sizzleMap);
return sizzleMap;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Pair n, final SymbolTable argu) {
return new SizzleMap(n.f0.accept(this, argu), n.f2.accept(this, argu));
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Function n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final StatementExpr n, final SymbolTable argu) {
throw new RuntimeException("unimplemented");
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Proto n, final SymbolTable argu) {
final String tokenImage = n.f1.f0.tokenImage;
argu.importProto(tokenImage.substring(1, tokenImage.length() - 1));
return null;
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final Identifier n, final SymbolTable argu) {
final String id = n.f0.tokenImage;
if (argu.hasType(id))
return argu.getType(id);
return argu.get(id);
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final IntegerLiteral n, final SymbolTable argu) {
return new SizzleInt();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final FingerprintLiteral n, final SymbolTable argu) {
return new SizzleFingerprint();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final FloatingPointLiteral n, final SymbolTable argu) {
return new SizzleFloat();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final CharLiteral n, final SymbolTable argu) {
return new SizzleInt();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final StringLiteral n, final SymbolTable argu) {
return new SizzleString();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final BytesLiteral n, final SymbolTable argu) {
return new SizzleBytes();
}
/** {@inheritDoc} */
@Override
public SizzleType visit(final TimeLiteral n, final SymbolTable argu) {
return new SizzleTime();
}
List<SizzleType> check(final Call c, final SymbolTable argu) {
if (c.f1.present())
return this.check((ExprList) c.f1.node, argu);
return new ArrayList<SizzleType>();
}
private List<SizzleType> check(final ExprList e, final SymbolTable argu) {
final List<SizzleType> types = new ArrayList<SizzleType>();
types.add(e.f0.accept(this, argu));
if (e.f1.present())
for (final Node node : e.f1.nodes)
types.add(((NodeSequence) node).elementAt(1).accept(this, argu));
return types;
}
private List<SizzleType> check(final SimpleMemberList e, final SymbolTable argu) {
final List<SizzleType> types = new ArrayList<SizzleType>();
types.add(e.f0.accept(this, argu));
if (e.f1.present())
for (final Node node : e.f1.nodes)
types.add(((NodeSequence) node).elementAt(1).accept(this, argu));
return types;
}
// private final NameFindingVisitor namefinder;
//
// /**
// * Construct a TypeCheckingVisitor.
// *
// * @param namefinder
// * A {@link NameFindingVisitor} used to find names.
// */
// public TypeCheckingVisitor(final NameFindingVisitor namefinder) {
// this.namefinder = namefinder;
// }
//
// public List<SizzleType> check(final ExpressionRest e, final SymbolTable
// argu) {
// final List<SizzleType> types = new ArrayList<SizzleType>();
//
// types.add(e.f1.accept(this, argu));
//
// return types;
// }
//
// public List<SizzleScalar> check(final TypleList t, final SymbolTable
// argu) {
// final List<SizzleScalar> types = new ArrayList<SizzleScalar>();
//
// final SizzleType type = t.f0.accept(this, argu);
// if (type instanceof SizzleScalar)
// types.add((SizzleScalar) type);
// else
// throw new TypeException("unexpected type " + type + " in a typle list");
//
// if (t.f1.present())
// for (final Node i : t.f1.nodes)
// types.addAll(this.check((TypleRest) i, argu));
//
// return types;
// }
//
// public List<SizzleScalar> check(final TypleRest t, final SymbolTable
// argu) {
// final List<SizzleScalar> types = new ArrayList<SizzleScalar>();
//
// final SizzleType type = t.f1.accept(this, argu);
// if (type instanceof SizzleScalar)
// types.add((SizzleScalar) type);
// else
// throw new TypeException("unexpected type " + type + " in a typle list");
//
// return types;
// }
//
// // FIXME: really support implicit cast on assignment?
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Assignment n, final SymbolTable argu) {
// final String id = n.f0.f0.tokenImage;
// final SizzleType t = argu.get(id);
// final SizzleType u = n.f2.accept(this, argu);
//
// if (t.assigns(u))
// return t;
//
// if (argu.hasCast(u, t))
// return t;
//
// throw new TypeException("incorrect type " + u + " for assignment to " +
// id + ':' + t);
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final AssignmentList n, final SymbolTable argu) {
// n.f0.accept(this, argu);
// if (n.f1.present())
// for (final Node node : n.f1.nodes)
// ((EmitStatement) node).accept(this, argu);
//
// return null;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final AssignmentRest n, final SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final AssignmentStatement n, final SymbolTable
// argu) {
// return n.f0.accept(this, argu);
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Block n, final SymbolTable argu) {
//
// if (n.f1.present()) {
// SymbolTable st;
// try {
// st = argu.cloneNonLocals();
// } catch (final IOException e) {
// throw new RuntimeException(e.getClass().getSimpleName() + " caught", e);
// }
//
// for (final Node node : n.f1.nodes)
// ((Statement) node).accept(this, st);
// }
//
// return null;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final CallExpression n, final SymbolTable argu) {
// final String name = n.f0.f0.tokenImage;
//
// if (n.f2.present())
// return argu.getFunction(name, this.check((ExpressionList) n.f2.node,
// argu));
// else
// return argu.getFunction(name);
// }
//
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final ExpressionList n, final SymbolTable argu) {
// final SizzleType type = n.f0.accept(this, argu);
//
// if (n.f1.present())
// for (final Node node : n.f1.nodes)
// if (!type.assigns(((ExpressionRest) node).accept(this, argu)))
// throw new TypeException("invalid expression list");
//
// return new SizzleArray((SizzleScalar) type);
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final ExpressionRest n, final SymbolTable argu) {
// return n.f1.accept(this, argu);
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final FloatingPointLiteral n, final SymbolTable
// argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final ForStatement n, final SymbolTable argu) {
// SymbolTable st;
// try {
// st = argu.cloneNonLocals();
// } catch (final IOException e) {
// throw new RuntimeException(e.getClass().getSimpleName() + " caught", e);
// }
//
// if (n.f2.present())
// ((AssignmentList) n.f2.node).accept(this, st);
// if (n.f4.present())
// ((ExpressionList) n.f4.node).accept(this, st);
// if (n.f6.present())
// ((ExpressionList) n.f6.node).accept(this, st);
//
// n.f8.accept(this, st);
//
// return null;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final IdentifierList n, final SymbolTable argu) {
// for (final String id : this.namefinder.visit(n))
// if (argu.contains(id))
// throw new TypeException(id + " already declared as " + argu.get(id));
//
// return null;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final IdentifierRest n, final SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final IndexExpression n, final SymbolTable argu)
// {
// final SizzleType type = n.f0.accept(this, argu);
//
// if (n.f1.present()) {
// final SizzleType itype = ((NodeSequence)
// n.f1.node).nodes.get(1).accept(this, argu);
// if (type instanceof SizzleArray) {
// if (!new SizzleInt().assigns(itype))
// throw new TypeException("incorrect type " + itype +
// " for indexing into array");
//
// return ((SizzleArray) type).getType();
// } else if (type instanceof SizzleMap) {
// final SizzleScalar ktype = ((SizzleMap) type).getIndexType();
//
// if (!ktype.assigns(itype))
// throw new TypeException("incorrect type " + itype + " for indexing into "
// + type);
//
// return ((SizzleMap) type).getType();
// } else
// throw new TypeException("type " + type + " cannot be indexed into");
// }
//
// return type;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Initializer n, final SymbolTable argu) {
// switch (n.f0.which) {
// case 0: // expression
// return n.f0.accept(this, argu);
// case 1:
// return ((NodeSequence) n.f0.choice).nodes.get(1).accept(this, argu);
// default:
// throw new RuntimeException("unexpected choice " + n.f0.which + " is " +
// n.f0.choice.getClass());
// }
//
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final IntegerLiteral n, final SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final MemberExpression n, final SymbolTable argu)
// {
// final String id = n.f0.f0.tokenImage;
// final String member = n.f2.f0.tokenImage;
//
// final SizzleType stype = argu.get(id);
//
// if (!(stype instanceof SizzleTuple))
// throw new TypeException(id + " is not a tuple" +
// stype.getClass().getName());
//
// final SizzleType mtype = ((SizzleTuple) stype).getMember(member);
//
// if (mtype == null)
// throw new TypeException("no such member " + member + " in " + id);
//
// return mtype;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Pair n, final SymbolTable argu) {
// final SizzleType vtype = n.f0.accept(this, argu);
// if (!vtype.getClass().getSuperclass().equals(SizzleScalar.class))
// throw new TypeException("invalid type " + vtype + " for map value");
//
// final SizzleType ktype = n.f2.accept(this, argu);
// if (!ktype.getClass().getSuperclass().equals(SizzleScalar.class))
// throw new TypeException("invalid type " + ktype + " for map key");
//
// return new SizzleMap((SizzleScalar) vtype, (SizzleScalar) ktype);
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final PairList n, final SymbolTable argu) {
// final SizzleMap mtype = (SizzleMap) n.f0.accept(this, argu);
//
// if (n.f1.present())
// for (final Node node : n.f1.nodes) {
// final SizzleType rtype = node.accept(this, argu);
// if (!mtype.assigns(rtype))
// throw new TypeException("invalid type " + rtype + " for entry in " +
// mtype);
// }
//
// return mtype;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final ParentheticalExpression n, final
// SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final SliceExpression n, final SymbolTable argu)
// {
// final String id = n.f0.f0.tokenImage;
// final SizzleType type = argu.get(id);
//
// if (n.f1.present())
// for (final Node node : n.f1.nodes) {
// final SizzleType slicetype = ((NodeSequence)
// node).nodes.get(1).accept(this, argu);
// if (slicetype.getClass() != SizzleInt.class)
// throw new TypeException("invalid type " + slicetype +
// " for indexing into an array");
// final SizzleType slicetype2 = ((NodeSequence)
// node).nodes.get(3).accept(this, argu);
// if (slicetype2.getClass() != SizzleInt.class)
// throw new TypeException("invalid type " + slicetype2 +
// " for indexing into an array");
// }
//
// return type;
// }
//
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Statement n, final SymbolTable argu) {
// switch (n.f0.which) {
// case 0: // block
// ((Block) n.f0.choice).accept(this, argu);
// break;
// case 4: // assignment statement
// ((Block) n.f0.choice).accept(this, argu);
// break;
// case 5: // emit statement
// ((AssignmentStatement) n.f0.choice).accept(this, argu);
// break;
// case 6: // emit statement
// ((EmitStatement) n.f0.choice).accept(this, argu);
// break;
// case 7: // emit statement
// ((IfStatement) n.f0.choice).accept(this, argu);
// break;
// case 9: // for statement
// ((ForStatement) n.f0.choice).accept(this, argu);
// break;
// case 10: // when statement
// ((WhenStatement) n.f0.choice).accept(this, argu);
// break;
// case 11: // when statement
// ((ProtoStatement) n.f0.choice).accept(this, argu);
// break;
// default:
// throw new RuntimeException("unexpected choice " + n.f0.which + " is " +
// n.f0.choice.getClass());
// }
//
// return null;
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final StringLiteral n, final SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Term n, final SymbolTable argu) {
// switch (n.f0.which) {
// case 0: // call
// return n.f0.choice.accept(this, argu);
// case 1: // member
// return n.f0.choice.accept(this, argu);
// case 2: // slice
// return n.f0.choice.accept(this, argu);
// case 3: // index
// return n.f0.choice.accept(this, argu);
// case 4: // parenthetical
// return ((ParentheticalExpression) n.f0.choice).f1.accept(this, argu);
// case 5: // atom
// return n.f0.choice.accept(this, argu);
// default:
// throw new RuntimeException("unexpected choice " + n.f0.which + " is " +
// n.f0.choice.getClass());
// }
// }
//
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final Type n, final SymbolTable argu) {
// switch (n.f0.which) {
// case 0: // identifier
// return argu.getType(((Identifier) n.f0.choice).f0.tokenImage);
// case 2: // tuple
// return new SizzleTuple(new LinkedHashMap<String, SizzleType>());
// default:
// throw new RuntimeException("unexpected choice " + n.f0.which + " is " +
// n.f0.choice.getClass());
// }
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final TypeDeclaration n, final SymbolTable argu)
// {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final TypleList n, final SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final TypleRest n, final SymbolTable argu) {
// throw new RuntimeException("unimplemented");
// }
//
// /** {@inheritDoc} */
// /** {@inheritDoc} */ @Override
// public SizzleType visit(final UnaryExpression n, final SymbolTable argu)
// {
// final SizzleType type = n.f0.accept(this, argu);
//
// if (n.f1.present())
// if (!type.getClass().equals(SizzleInt.class))
// throw new TypeException("unary arithmetic on non-integer " +
// type.toString());
//
// return type;
// }
//
}