package com.babel17.interpreter.parser; import com.babel17.antlr.babel17Parser; import com.babel17.antlr.babel17Lexer; import org.antlr.runtime.*; import org.antlr.runtime.tree.*; import com.babel17.syntaxtree.*; import com.babel17.syntaxtree.patterns.*; import java.util.*; public class Parser { public static Collection<String> KEYWORDS = Collections.unmodifiableCollection(keywords()); private static TreeSet<String> keywords() { TreeSet<String> k = new TreeSet<String>(); k.add("begin"); k.add("end"); k.add("object"); k.add("with"); k.add("if"); k.add("then"); k.add("else"); k.add("elseif"); k.add("while"); k.add("for"); k.add("do"); k.add("yield"); k.add("match"); k.add("case"); k.add("as"); k.add("val"); k.add("def"); k.add("in"); k.add("exception"); k.add("to"); k.add("downto"); k.add("concurrent"); k.add("choose"); k.add("lazy"); k.add("force"); k.add("memoize"); k.add("true"); k.add("false"); k.add("this"); k.add("random"); k.add("nil"); k.add("div"); k.add("mod"); k.add("try"); k.add("catch"); k.add("module"); k.add("typedef"); k.add("typeof"); k.add("private"); k.add("import"); k.add("unittest"); k.add("not"); k.add("or"); k.add("and"); k.add("xor"); k.add("root"); k.add("native"); k.add("min"); k.add("max"); k.add("lens"); return k; } private static void printIndent(int depth) { for (int i = 0; i < depth; i++) { System.out.print(" "); } } private static void printTree(Tree tree, int depth) { printIndent(depth); System.out.println("" + tree); for (int i = 0; i < tree.getChildCount(); i++) { printTree(tree.getChild(i), depth + 2); } } private NodeList toNodeList(Tree tree) { NodeList l = new NodeList(); int count = tree.getChildCount(); for (int i = 0; i < count; i++) { l = l.cons(toNode(tree.getChild(i))); } return l.reverse(); } private NodeList toPatternList(Tree tree) { NodeList l = new NodeList(); int count = tree.getChildCount(); for (int i = 0; i < count; i++) { l = l.cons(toPattern(tree.getChild(i))); } return l.reverse(); } private Node rightassocBinary(NodeList l, int op) { if (l.tail().empty()) { return l.head(); } else { return new BinaryNode(new OperatorNode(op), l.head(), rightassocBinary(l.tail(), op)).mergeLocation(); } } private Node leftassocBinary(NodeList l, int op) { if (l.empty()) return BeginNode.empty(); Node result = l.head(); for (Node n : l.tail()) { result = new BinaryNode(new OperatorNode(op), result, n); result.mergeLocation(n.location()); } return result; } private BinaryNode toBinaryNode(Tree tree, int op) { Location loc = getLocation(tree); BinaryNode n = new BinaryNode( new OperatorNode(op), toNode(tree.getChild(0)), toNode(tree.getChild(1))); return (BinaryNode) n.mergeLocation(loc).mergeLocation(); } private UnaryNode toUnaryNode(Tree tree, int op) { Location loc = getLocation(tree); UnaryNode n = new UnaryNode( new OperatorNode(op), toNode(tree.getChild(0))); return (UnaryNode) n.mergeLocation(loc).mergeLocation(); } private Node toNullaryNode(int op) { return new NullaryNode(new OperatorNode(op)); } private Location getLocation(Tree tree) { int ti1 = tree.getTokenStartIndex(); int ti2 = tree.getTokenStopIndex(); return getLocation(tree, ti1, ti2); } private Location getLocation(Tree tree, int ti1, int ti2) { if (ti1 < 0) { if (ti2 < 0) { return lastKnownLocations.peek(); } else { ti1 = ti2; } } else if (ti2 < 0) { ti2 = ti1; } Token t1; Token t2; try { t1 = tokens.get(ti1); t2 = tokens.get(ti2); } catch (Exception e) { return lastKnownLocations.peek(); } Location l1 = new Location(source, t1.getLine(), t1.getCharPositionInLine() + 1); Location l2 = new Location(source, t2.getLine(), t2.getCharPositionInLine() + 1 + t2.getText().length() - 1); Location l = l1.add(l2); if (Location.invalid(l)) return lastKnownLocations.peek(); return l; } private Node emptyStatement(Location loc) { BlockNode b = new BlockNode(new NodeList()); b.mergeLocation(loc); BeginNode be = new BeginNode(b); be.mergeLocation(loc); return be; } private NodeList convertRootPrefix(NodeList ids) { if (!ids.empty() && ids.head() instanceof NullaryNode) { OperatorNode op = ((NullaryNode) ids.head()).operator(); if (op.operator() == OperatorNode.ROOT) { Node id = new IdentifierNode("root").mergeLocation(op.location()); return ids.tail().cons(id); } else throw new RuntimeException("invalid import prefix, code = "+op.operator()); } else return ids; } private OperatorNode modifycode(Tree tree) { int code = modifycode_(tree); OperatorNode n = new OperatorNode(code); n.mergeLocation(getLocation(tree)); return n; } private int modifycode_(Tree tree) { switch (tree.getType()) { case babel17Parser.ML_plus: return OperatorNode.PLUS; case babel17Parser.MR_plus: return OperatorNode.PLUS; case babel17Parser.ML_plusplus: return OperatorNode.PLUSPLUS; case babel17Parser.MR_plusplus: return OperatorNode.PLUSPLUS; case babel17Parser.ML_minus: return OperatorNode.MINUS; case babel17Parser.MR_minus: return OperatorNode.MINUS; case babel17Parser.ML_minusminus: return OperatorNode.MINUSMINUS; case babel17Parser.MR_minusminus: return OperatorNode.MINUSMINUS; case babel17Parser.ML_times: return OperatorNode.TIMES; case babel17Parser.MR_times: return OperatorNode.TIMES; case babel17Parser.ML_timestimes: return OperatorNode.TIMESTIMES; case babel17Parser.MR_timestimes: return OperatorNode.TIMESTIMES; case babel17Parser.ML_slash: return OperatorNode.QUOTIENT; case babel17Parser.MR_slash: return OperatorNode.QUOTIENT; case babel17Parser.ML_slashslash: return OperatorNode.QUOTIENTQUOTIENT; case babel17Parser.MR_slashslash: return OperatorNode.QUOTIENTQUOTIENT; case babel17Parser.ML_pow: return OperatorNode.POW; case babel17Parser.MR_pow: return OperatorNode.POW; case babel17Parser.L_and: return OperatorNode.AND; case babel17Parser.L_or: return OperatorNode.OR; case babel17Parser.L_xor: return OperatorNode.XOR; case babel17Parser.L_div: return OperatorNode.DIV; case babel17Parser.L_mod: return OperatorNode.MOD; case babel17Parser.L_min: return OperatorNode.MIN; case babel17Parser.L_max: return OperatorNode.MAX; } throw new RuntimeException("invalid modify code"); } private Node toNode(Tree tree) { Location loc = getLocation(tree); lastKnownLocations.push(loc); try { switch (tree.getType()) { case babel17Parser.PROG: return toNode(tree.getChild(0)); case babel17Parser.BLOCK: return new BlockNode(toNodeList(tree).suppressErrors()).mergeLocation(loc).mergeLocation(); case babel17Parser.LENS_ASSIGN: { Node leftSide = toNode(tree.getChild(0)); Node rightSide = toNode(tree.getChild(1)); return new LensAssignNode(leftSide, rightSide).mergeLocation(loc).mergeLocation(); } case babel17Parser.LENS_MODIFY_LEFT: { OperatorNode op = modifycode(tree.getChild(0)); Node leftSide = toNode(tree.getChild(1)); Node rightSide = toNode(tree.getChild(2)); return new LensModifyNode(true, op, leftSide, rightSide).mergeLocation(loc).mergeLocation(); } case babel17Parser.LENS_MODIFY_RIGHT: { OperatorNode op = modifycode(tree.getChild(0)); Node leftSide = toNode(tree.getChild(1)); Node rightSide = toNode(tree.getChild(2)); return new LensModifyNode(false, op, leftSide, rightSide).mergeLocation(loc).mergeLocation(); } case babel17Parser.ASSIGN: case babel17Parser.VAL: { boolean assign = tree.getType() == babel17Parser.ASSIGN; Tree left = tree.getChild(0); PatternNode pattern = toPattern(tree.getChild(0)); Node rightSide = toNode(tree.getChild(1)); return new ValNode(assign, pattern, rightSide).mergeLocation(loc). mergeLocation(); } case babel17Parser.Id: { String name = tree.getText(); if (KEYWORDS.contains(name.toLowerCase())) pe.addMessage(loc, "cannot use keyword as identifier"); return new IdentifierNode(name).mergeLocation(loc); } case babel17Parser.L_unittest: { return new IdentifierNode("unittest").mergeLocation(loc); } case babel17Parser.Constr: { return new ConstrNode(tree.getText(), loc, null).mergeLocation(loc); } case babel17Parser.DEF: { Node n = toNode(tree.getChild(0)); IdentifierNode id = (IdentifierNode) n; id = (IdentifierNode) n; PatternNode pattern = null; Node rightSide = null; Node returnType = null; int count = tree.getChildCount(); if (count == 2) { rightSide = toNode(tree.getChild(1)); } if (count == 4) { returnType = toNode(tree.getChild(1)); pattern = toPattern(tree.getChild(2)); rightSide = toNode(tree.getChild(3)); } else if (count == 3) { int k = tree.getChild(1).getType(); if (k == babel17Parser.TYPEID) returnType = toNode(tree.getChild(1)); else pattern = toPattern(tree.getChild(1)); rightSide = toNode(tree.getChild(2)); } if (returnType != null && !(returnType instanceof TypeIdNode)) returnType = null; return new DefNode(id, pattern, rightSide, (TypeIdNode) returnType).mergeLocation(loc). mergeLocation(); } case babel17Parser.COMPARE: { NodeList l = toNodeList(tree); if (l.tail().empty()) { return l.head(); } else { return new CompareNode(l).mergeLocation(); } } case babel17Parser.LIST_CONS: { NodeList l = toNodeList(tree); return rightassocBinary(l, OperatorNode.CONS). mergeLocation(loc); } case babel17Parser.POW: { NodeList l = toNodeList(tree); return leftassocBinary(l, OperatorNode.POW).mergeLocation(loc); } case babel17Parser.APPLY: { NodeList l = toNodeList(tree); if (l.head() instanceof ConstrNode) { ConstrNode c = (ConstrNode) l.head(); if (c.arg() == null && !l.tail().empty()) { c = (ConstrNode) new ConstrNode(c.name(), c.location(), l.tail().head()).mergeLocation(c.location()).mergeLocation(); l = l.tail().tail().cons(c); } } return leftassocBinary(l, OperatorNode.APPLY).mergeLocation(loc); } case babel17Parser.MESSAGE_SEND: { int count = tree.getChildCount(); if (count == 0) return BeginNode.empty(); Node result = toNode(tree.getChild(0)); for (int i=1; i<count; i++) { MessageNode m = null; Tree sub = tree.getChild(i); if (sub.getType() == babel17Parser.MESSAGE_ID) { Node n = toNode(sub.getChild(0)); if (n instanceof IdentifierNode) { IdentifierNode id = (IdentifierNode) n; m = new MessageNode(id.name()); m.mergeLocation(id.location()); } } else if (sub.getType() == babel17Parser.MESSAGE_LENS) { Node n = toNode(sub.getChild(0)); m = new MessageNode(n); m.mergeLocation(n.location()); } if (m != null) { result = new BinaryNode(new OperatorNode(OperatorNode.MESSAGE_SEND), result, m).mergeLocation(m.location()); } } return result.mergeLocation(loc); } case babel17Parser.L_or: return toBinaryNode(tree, OperatorNode.OR); case babel17Parser.L_and: return toBinaryNode(tree, OperatorNode.AND); case babel17Parser.L_xor: return toBinaryNode(tree, OperatorNode.XOR); case babel17Parser.L_not: return toUnaryNode(tree, OperatorNode.NOT); case babel17Parser.PLUSPLUS: return toBinaryNode(tree, OperatorNode.PLUSPLUS); case babel17Parser.MINUSMINUS: return toBinaryNode(tree, OperatorNode.MINUSMINUS); case babel17Parser.TIMESTIMES: return toBinaryNode(tree, OperatorNode.TIMESTIMES); case babel17Parser.QUOTIENTQUOTIENT: return toBinaryNode(tree, OperatorNode.QUOTIENTQUOTIENT); case babel17Parser.L_to: return toBinaryNode(tree, OperatorNode.TO); case babel17Parser.L_downto: return toBinaryNode(tree, OperatorNode.DOWNTO); case babel17Parser.PLUS: return toBinaryNode(tree, OperatorNode.PLUS); case babel17Parser.MINUS: return toBinaryNode(tree, OperatorNode.MINUS); case babel17Parser.UMINUS: return toUnaryNode(tree, OperatorNode.UMINUS); case babel17Parser.TIMES: return toBinaryNode(tree, OperatorNode.TIMES); case babel17Parser.QUOTIENT: return toBinaryNode(tree, OperatorNode.QUOTIENT); case babel17Parser.L_div: return toBinaryNode(tree, OperatorNode.DIV); case babel17Parser.L_mod: return toBinaryNode(tree, OperatorNode.MOD); case babel17Parser.RELATE: return leftassocBinary(toNodeList(tree).suppressErrors(), OperatorNode.RELATE); case babel17Parser.CONVERT: return leftassocBinary(toNodeList(tree).suppressErrors(), OperatorNode.CONVERT); case babel17Parser.INTERVAL: return toBinaryNode(tree, OperatorNode.INTERVAL); case babel17Parser.A_EQUAL: case babel17Parser.U_EQUAL: return new OperatorNode(OperatorNode.EQUAL); case babel17Parser.A_NOT_EQUAL: case babel17Parser.U_NOT_EQUAL: return new OperatorNode(OperatorNode.UNEQUAL); case babel17Parser.GREATER: return new OperatorNode(OperatorNode.GREATER); case babel17Parser.A_GREATER_EQ: case babel17Parser.U_GREATER_EQ: return new OperatorNode(OperatorNode.GREATER_EQ); case babel17Parser.LESS: return new OperatorNode(OperatorNode.LESS); case babel17Parser.A_LESS_EQ: case babel17Parser.U_LESS_EQ: return new OperatorNode(OperatorNode.LESS_EQ); case babel17Parser.Float: { java.math.BigInteger[] r = ConstParser.decimalFloat(tree.getText()); return new FloatNode(r[0], r[1]).mergeLocation(loc); } case babel17Parser.Num: return new IntegerNode(ConstParser.num(tree.getText())).mergeLocation(loc); case babel17Parser.String: { try { return new StringNode(ConstParser.string(source, tree.getText())).mergeLocation(loc); } catch (ParseException e) { Location l = e.location(); if (l != null) { l = l.shift(loc.startLine() - 1, loc.startColumn() - 1); } else { l = loc; } pe.addMessage(l, e.getMessage()); return new StringNode("").mergeLocation(loc); } } case babel17Parser.L_true: return toNullaryNode(OperatorNode.TRUE). mergeLocation(loc); case babel17Parser.L_false: return toNullaryNode(OperatorNode.FALSE). mergeLocation(loc); case babel17Parser.L_this: return toNullaryNode(OperatorNode.THIS). mergeLocation(loc); case babel17Parser.L_root: return toNullaryNode(OperatorNode.ROOT). mergeLocation(loc); case babel17Parser.L_lens: return toBinaryNode(tree, OperatorNode.LENS); case babel17Parser.FUNCTIONS_LENS: return toBinaryNode(tree, OperatorNode.FUNCTIONS_LENS); case babel17Parser.L_native: return toUnaryNode(tree, OperatorNode.NATIVE); case babel17Parser.L_random: return toUnaryNode(tree, OperatorNode.RANDOM); case babel17Parser.L_choose: return toUnaryNode(tree, OperatorNode.CHOOSE); case babel17Parser.L_exception: return toUnaryNode(tree, OperatorNode.EXCEPTION); case babel17Parser.L_lazy: return toUnaryNode(tree, OperatorNode.LAZY); case babel17Parser.L_concurrent: return toUnaryNode(tree, OperatorNode.CONCURRENT); case babel17Parser.L_force: return toUnaryNode(tree, OperatorNode.FORCE); case babel17Parser.L_typeof: return toUnaryNode(tree, OperatorNode.TYPEOF); case babel17Parser.L_min: return toUnaryNode(tree, OperatorNode.MIN); case babel17Parser.L_max: return toUnaryNode(tree, OperatorNode.MAX); case babel17Parser.EMPTY_MAP: return new MapNode(new NodeList()).mergeLocation(loc); case babel17Parser.L_nil: return new RecordNode(new NodeList()).mergeLocation(loc); case babel17Parser.SQUARE_LIST: return new ListNode(toNodeList(tree), false).mergeLocation(loc).mergeLocation(); case babel17Parser.ROUND_LIST: { int commas = tree.getChild(0).getChildCount(); NodeList l = toNodeList(tree.getChild(1)); int len = l.length(); if (len == 1 && commas == 0) { return l.head().mergeLocation(loc); } else { if (len == commas && len > 1) pe.addMessage(getLocation(tree.getChild(0).getChild(commas-1)), "trailing comma notation is only for vectors of length 1"); return new ListNode(l, true).mergeLocation(loc).mergeLocation(); } } case babel17Parser.MAP_OR_SET_OR_OBJ: { NodeList l = new NodeList(); int count = tree.getChildCount(); boolean is_set = false; boolean is_map = false; boolean is_obj = false; boolean error = false; for (int i = 0; i < count && !error; i++) { Tree t = tree.getChild(i); NodeList c = toNodeList(t.getChild(0)); if (c.length() == 1) { if (is_map || is_obj) { pe.addMessage(getLocation(t), "set element in map or object"); error = true; } else { is_set = true; l = l.cons(c.head().mergeLocation(getLocation(t))); } } else { int ty = t.getChild(1).getType(); if (ty == babel17Parser.ARROW) { if (is_set || is_obj) { pe.addMessage(getLocation(t), "map element in set or object"); error = true; } else { is_map = true; l = l.cons(new MapNode.KeyValue(c.head(), c.tail().head()).mergeLocation(getLocation(t))); } } else if (ty == babel17Parser.ASSIGN) { if (is_set || is_map) { pe.addMessage(getLocation(t), "object element in set or map"); error = true; } else { is_obj = true; Node m = c.head(); Node v = c.tail().head(); if (m instanceof IdentifierNode) { IdentifierNode message = (IdentifierNode)m; l = l.cons(new RecordNode.MessageValue(message, v).mergeLocation(getLocation(t))); } else { pe.addMessage(m.location(), "message identifier expected"); error = true; } } } else throw new RuntimeException("ARROW or ASSIGN expected, ty="+ty+" found"); } } if (is_map) { return new MapNode(l.reverse()).mergeLocation(loc).mergeLocation(); } else if (is_obj) { return new RecordNode(l.reverse()).mergeLocation(loc).mergeLocation(); } else { return new SetNode(l.reverse()).mergeLocation(loc).mergeLocation(); } } case babel17Parser.TYPEID: { NodeList children = toNodeList(tree); return new TypeIdNode(children).mergeLocation(loc); } case babel17Parser.TYPEVAL: { return toNode(tree.getChild(0)).mergeLocation(loc); } case babel17Parser.MODULEID: { NodeList children = toNodeList(tree); return new ModuleIdNode(children).mergeLocation(loc); } case babel17Parser.IMPORT_PLUS: { NodeList ids = toNodeList(tree); if (ids.hasErrors()) { return new ParseErrorNode().mergeLocation(loc); } IdentifierNode id1 = (IdentifierNode) ids.head(); IdentifierNode id2 = null; if (ids.length() == 2) id2 = (IdentifierNode) ids.tail().head(); int kind = id2 == null ? ImportNode.ENTRY_PLUS : ImportNode.ENTRY_MAP; return new ImportNode.Entry(kind, id1, id2).mergeLocation(loc); } case babel17Parser.IMPORT_MINUS: { NodeList ids = toNodeList(tree); if (ids.hasErrors()) { return new ParseErrorNode().mergeLocation(loc); } IdentifierNode id = (IdentifierNode) ids.head(); return new ImportNode.Entry(ImportNode.ENTRY_MINUS, id, null); } case babel17Parser.IMPORT_ALL: { Node e = new ImportNode.Entry(ImportNode.ENTRY_ALL, null, null); e.mergeLocation(loc); return e; } case babel17Parser.L_import: { NodeList prefix = toNodeList(tree.getChild(0)).suppressErrors(); if (prefix.empty()) return BeginNode.empty(); prefix = convertRootPrefix(prefix); if (tree.getChildCount() == 1) return ImportNode.simple(prefix).mergeLocation(loc); Tree arg = tree.getChild(1); ImportNode result = null; switch (arg.getType()) { case babel17Parser.IMPORT_ALL: result = ImportNode.wildcard(prefix); break; case babel17Parser.Id: result = ImportNode.rename(prefix, (IdentifierNode) toNode(arg)); break; case babel17Parser.IMPORT_SET: NodeList entries = toNodeList(arg).suppressErrors(); result = ImportNode.set(prefix, entries); break; } result.mergeLocation(loc); return result; } case babel17Parser.L_module: { ModuleIdNode m = (ModuleIdNode) toNode(tree.getChild(0)); BlockNode b = toNode(tree.getChild(1)).toBlock(); if (tree.getChildCount() > 2) { IdentifierNode id = new IdentifierNode("unittest"); id.mergeLocation(getLocation(tree.getChild(2))); BlockNode rightSide = toNode(tree.getChild(3)).toBlock(); Node u = new DefNode(id, null, rightSide, null).mergeLocation(loc).mergeLocation(); b = (BlockNode) new BlockNode(b.statements().reverse().cons(u).reverse()).mergeLocation().mergeLocation(b.location()); } return (new ModuleNode(m, b)).mergeLocation(loc); } case babel17Parser.IF: { NodeList children = toNodeList(tree); if (children.hasErrors()) return BeginNode.empty(); NodeList conditions = new NodeList(); NodeList blocks = new NodeList(); int len = children.length(); int i = 0; for (Node n : children) { if (i < len / 2) { conditions = conditions.cons(n); } else { blocks = blocks.cons(n); } i++; } return new IfNode(conditions.reverse(), blocks.reverse()).mergeLocation(loc); } case babel17Parser.BEGIN: return new BeginNode(toNode(tree.getChild(0)).toBlock()).mergeLocation(loc); case babel17Parser.OBJ: { BlockNode block = toNode(tree.getChild(0)).toBlock(); if (tree.getChildCount() > 1) { int t = tree.getChild(1).getType(); int combine_method; if (t == babel17Parser.PARENTS_PLUS) combine_method = ObjectNode.COMBINE_GLUE; else combine_method = ObjectNode.COMBINE_MERGE; Node parents = toNode(tree.getChild(1).getChild(0)); return new ObjectNode(block, combine_method, parents); } else return new ObjectNode(block).mergeLocation(loc); } case babel17Parser.WHILE_DO: return new WhileNode( toNode(tree.getChild(0)), toNode(tree.getChild(1)).toBlock()).mergeLocation(loc); case babel17Parser.FOR_EXPR: return new ForNode( toPattern(tree.getChild(0)), toNode(tree.getChild(1)), toNode(tree.getChild(2)).toBlock()).mergeLocation(loc); case babel17Parser.MATCH: { Node value = toNode(tree.getChild(0)); Tree t = tree.getChild(1); int count = t.getChildCount(); NodeList patterns = new NodeList(); NodeList blocks = new NodeList(); for (int i = 0; i < count; i++) { Tree s = t.getChild(i); PatternNode pattern = toPattern(s.getChild(0)); BlockNode block = toNode(s.getChild(1)).toBlock(); patterns = patterns.cons(pattern); blocks = blocks.cons(block); } return new MatchNode(value, patterns.reverse(), blocks.reverse()).mergeLocation(loc).mergeLocation(); } case babel17Parser.TRY: { Node mainblock = toNode(tree.getChild(0)); Tree t = tree.getChild(1); int count = t.getChildCount(); NodeList patterns = new NodeList(); NodeList blocks = new NodeList(); for (int i = 0; i < count; i++) { Tree s = t.getChild(i); PatternNode pattern = toPattern(s.getChild(0)); BlockNode block = toNode(s.getChild(1)).toBlock(); patterns = patterns.cons(pattern); blocks = blocks.cons(block); } return new TryNode(mainblock, patterns.reverse(), blocks.reverse()).mergeLocation(loc).mergeLocation(); } case babel17Parser.LAMBDA: { Tree t = tree.getChild(0); int count = t.getChildCount(); NodeList patterns = new NodeList(); NodeList blocks = new NodeList(); for (int i = 0; i < count; i++) { Tree s = t.getChild(i); PatternNode pattern = toPattern(s.getChild(0)); BlockNode block = toNode(s.getChild(1)).toBlock(); patterns = patterns.cons(pattern); blocks = blocks.cons(block); } return new LambdaNode(patterns.reverse(), blocks.reverse()).mergeLocation(loc).mergeLocation(); } case babel17Parser.WITH: { NodeList l = toNodeList(tree); if (l.hasErrors()) return BeginNode.empty(); return new WithNode( l.get(0), (ControlNode) l.get(1)).mergeLocation(loc).mergeLocation(); } case babel17Parser.TYPE_EXPR: return new TypeExprNode((TypeIdNode) toNode(tree.getChild(0))).mergeLocation(loc); case babel17Parser.TYPEDEF_CLAUSE: { int count = tree.getChildCount(); PatternNode p = toPattern(tree.getChild(0)); Node expr = null; if (count == 1) { return new TypedefClauseNode(p).mergeLocation(loc); } else if (count == 2) { expr = toNode(tree.getChild(1)); return new TypedefClauseNode(p, expr).mergeLocation(loc); } else { pe.addMessage(loc, "invalid typedef clause"); return BeginNode.empty(); } } case babel17Parser.TYPEDEF: { IdentifierNode id = (IdentifierNode) toNode(tree.getChild(0)); NodeList clauses = toNodeList(tree.getChild(1)); return new TypedefNode(id, clauses.suppressErrors()).mergeLocation(loc); } case babel17Parser.CONVERSION: { Node returnType = toNode(tree.getChild(0)); if (returnType instanceof TypeIdNode) { Node e = toNode(tree.getChild(1)); return new ConversionNode((TypeIdNode) returnType, e, false).mergeLocation(loc).mergeLocation(); } else { emptyStatement(loc); } } case babel17Parser.AUTOMATIC_CONVERSION: { Node returnType = toNode(tree.getChild(0)); if (returnType instanceof TypeIdNode) { Node e = toNode(tree.getChild(1)); return new ConversionNode((TypeIdNode) returnType, e, true).mergeLocation(loc).mergeLocation(); } else { emptyStatement(loc); } } case babel17Parser.MEMOID_STRONG: { Node n = toNode(tree.getChild(0)); if (n instanceof ParseErrorNode) return n; else return new MemoizeNode.MemoId(true, (IdentifierNode) n).mergeLocation(loc).mergeLocation(); } case babel17Parser.MEMOID_WEAK:{ Node n = toNode(tree.getChild(0)); if (n instanceof ParseErrorNode) return n; else return new MemoizeNode.MemoId(false, (IdentifierNode) n).mergeLocation(loc).mergeLocation(); } case babel17Parser.MEMOIZE: return new MemoizeNode(toNodeList(tree).suppressErrors()).mergeLocation(loc).mergeLocation(); /*case babel17Parser.PRIVATEID_STRONG: { Node n = toNode(tree.getChild(0)); if (n instanceof ParseErrorNode) return n; else return new PrivateNode.PrivateId(true, (IdentifierNode) n).mergeLocation(loc).mergeLocation(); } */ case babel17Parser.PRIVATEID: { Node n = toNode(tree.getChild(0)); if (n instanceof ParseErrorNode) return n; else return new PrivateNode.PrivateId((IdentifierNode) n).mergeLocation(loc).mergeLocation(); } case babel17Parser.PRIVATE: return new PrivateNode(toNodeList(tree).suppressErrors()).mergeLocation(loc).mergeLocation(); case babel17Parser.YIELD: return new YieldNode(toNode(tree.getChild(0))).mergeLocation(loc).mergeLocation(); case babel17Parser.PRAGMA_PRINT: return new PragmaNode(PragmaNode.PRAGMA_PRINT, toNode(tree.getChild(0))).mergeLocation(loc).mergeLocation(); case babel17Parser.PRAGMA_LOG: return new PragmaNode(PragmaNode.PRAGMA_LOG, toNode(tree.getChild(0))).mergeLocation(loc).mergeLocation(); case babel17Parser.PRAGMA_ASSERT: return new PragmaNode(PragmaNode.PRAGMA_ASSERT, toNode(tree.getChild(0))).mergeLocation(loc).mergeLocation(); case babel17Parser.PRAGMA_PROFILE: return new PragmaNode(PragmaNode.PRAGMA_PROFILE, toNode(tree.getChild(0))).mergeLocation(loc).mergeLocation(); case babel17Parser.PRAGMA_CATCH: return new PragmaNode(PragmaNode.PRAGMA_CATCH, toNode(tree.getChild(0)), toPattern(tree.getChild(1))).mergeLocation(loc).mergeLocation(); default: pe.addMessage(loc, "syntax error"); return new ParseErrorNode().mergeLocation(loc); } } finally { lastKnownLocations.pop(); } } private PatternNode makeConsPatterns(Tree tree, int i) { Location loc = getLocation(tree.getChild(i)); PatternNode p = (PatternNode) toPattern(tree.getChild(i)).mergeLocation(loc); if (i + 1 == tree.getChildCount()) { return p; } else { return (PatternNode) new ConsPattern(p, makeConsPatterns(tree, i + 1)).mergeLocation(); } } private PatternNode toPattern(Tree tree) { Location loc = getLocation(tree); lastKnownLocations.push(loc); try { switch (tree.getType()) { case babel17Parser.Id: { String name = tree.getText(); if (KEYWORDS.contains(name.toLowerCase())) pe.addMessage(loc, "cannot use keyword as identifier"); return (PatternNode) new IdentifierPattern(name).mergeLocation(loc); } case babel17Parser.Num: return (PatternNode) new IntegerPattern(ConstParser.num(tree.getText())).mergeLocation(loc); case babel17Parser.String: try { return (PatternNode) new StringPattern(ConstParser.string( source, tree.getText())).mergeLocation(loc); } catch (ParseException e) { Location l = e.location(); if (l != null) { l = l.shift(loc.startLine() - 1, loc.startColumn() - 1); } else { l = loc; } pe.addMessage(l, e.getMessage()); return (PatternNode) new StringPattern("").mergeLocation(loc); } case babel17Parser.ANY: return (PatternNode) new NullaryPattern(NullaryPattern.ANY).mergeLocation(loc); case babel17Parser.A_ELLIPSIS: case babel17Parser.U_ELLIPSIS: return (PatternNode) new NullaryPattern(NullaryPattern.ELLIPSIS).mergeLocation(loc); case babel17Parser.L_true: return (PatternNode) new NullaryPattern(NullaryPattern.TRUE).mergeLocation(loc); case babel17Parser.L_nil: return (PatternNode) new RecordPattern(new NodeList()).mergeLocation(loc); case babel17Parser.L_false: return (PatternNode) new NullaryPattern(NullaryPattern.FALSE).mergeLocation(loc); case babel17Parser.UMINUS: { PatternNode p = toPattern(tree.getChild(0)); if (p instanceof IntegerPattern) { return (PatternNode) new IntegerPattern( ((IntegerPattern) p).value().negate()).mergeLocation(loc); } else if (NullaryPattern.is(p, NullaryPattern.INFINITY)) { return (PatternNode) new NullaryPattern(NullaryPattern.NEGATIVE_INFINITY).mergeLocation(loc); } else { throw new RuntimeException("pattern cannot be used in negation"); } } case babel17Parser.L_as: return (PatternNode) new AsPattern((IdentifierPattern) toPattern(tree.getChild(0)), toPattern(tree.getChild(1))).mergeLocation(loc); case babel17Parser.IF_PATTERN: if (tree.getChildCount() == 2) { return (PatternNode) new IfPattern(toPattern(tree.getChild(0)), toNode(tree.getChild(1))).mergeLocation(loc); } else { return toPattern(tree.getChild(0)); } case babel17Parser.TYPE_PATTERN: { Tree ann = tree.getChild(0); Node typeAnnotation = null; if (ann.getType() == babel17Parser.TYPEVAL) typeAnnotation = toNode(ann.getChild(0)); else typeAnnotation = toNode(ann); return (PatternNode) new TypePattern(toPattern(tree.getChild(1)), typeAnnotation).mergeLocation(loc); } case babel17Parser.INNERVALUE_PATTERN: return (PatternNode) new InnerValuePattern((IdentifierNode)toNode(tree.getChild(0)), (PatternNode)toPattern(tree.getChild(1))).mergeLocation(loc); case babel17Parser.L_val: return (PatternNode) new ValPattern(toNode(tree.getChild(0))).mergeLocation(loc); case babel17Parser.L_exception: return (PatternNode) new ExceptionPattern(toPattern(tree.getChild(0))).mergeLocation(loc); case babel17Parser.EXCLAMATION_MARK: return (PatternNode) new PredicatePattern(toNode(tree.getChild(0)), tree.getChildCount() == 2 ? toPattern(tree.getChild(1)) : null, true); case babel17Parser.QUESTION_MARK: return (PatternNode) new PredicatePattern(toNode(tree.getChild(0)), tree.getChildCount() == 2 ? toPattern(tree.getChild(1)) : null, false); case babel17Parser.ROUND_LIST: { int commas = tree.getChild(0).getChildCount(); NodeList l = toPatternList(tree.getChild(1)); int len = l.length(); if (len == 1 && commas == 0) { return (PatternNode) l.head().mergeLocation(loc); } else { if (len == commas && len > 1) pe.addMessage(getLocation(tree.getChild(0).getChild(commas-1)), "trailing comma notation is only for vectors of length 1"); return (PatternNode) new ListPattern(l, true). mergeLocation(loc).mergeLocation(); } } case babel17Parser.L_for: { NodeList l = toPatternList(tree); return (PatternNode) new ForPattern(l).mergeLocation(loc).mergeLocation(); } case babel17Parser.SQUARE_LIST: { NodeList l = toPatternList(tree); return (PatternNode) new ListPattern(l, false).mergeLocation(loc).mergeLocation(); } case babel17Parser.MAP_OR_SET_OR_OBJ: { NodeList l = new NodeList(); int count = tree.getChildCount(); boolean is_set = false; boolean is_map = false; boolean is_obj = false; boolean error = false; for (int i = 0; i < count && !error; i++) { Tree t = tree.getChild(i); NodeList c = toPatternList(t.getChild(0)); if (c.length() == 1) { if (is_map || is_obj) { if (i != count - 1) { pe.addMessage(getLocation(t), "set element in map or object"); error = true; } else l = l.cons(c.head().mergeLocation(getLocation(t))); } else { is_set = true; l = l.cons(c.head().mergeLocation(getLocation(t))); } } else { int ty = t.getChild(1).getType(); if (ty == babel17Parser.ARROW) { if (is_set || is_obj) { pe.addMessage(getLocation(t), "map element in set or object"); error = true; } else { is_map = true; l = l.cons(new MapPattern.KeyValue((PatternNode) c.head(), (PatternNode) c.tail().head()).mergeLocation(getLocation(t))); } } else if (ty == babel17Parser.ASSIGN) { if (is_set || is_map) { pe.addMessage(getLocation(t), "object element in set or map"); error = true; } else { is_obj = true; Node m = c.head(); PatternNode v = (PatternNode) c.tail().head(); if (m instanceof IdentifierPattern) { IdentifierPattern message = (IdentifierPattern)m; l = l.cons(new RecordPattern.MessageValue(message, v).mergeLocation(getLocation(t))); } else { pe.addMessage(m.location(), "message identifier expected"); error = true; } } } else throw new RuntimeException("ARROW or ASSIGN expected, ty="+ty+" found"); } } if (is_map) { return (PatternNode) new MapPattern(l.reverse()).mergeLocation(loc).mergeLocation(); } else if (is_set) { return (PatternNode) new SetPattern(l.reverse()).mergeLocation(loc).mergeLocation(); } else if (is_obj) { return (PatternNode) new RecordPattern(l.reverse()).mergeLocation(loc).mergeLocation(); } } case babel17Parser.LIST_CONS: return makeConsPatterns(tree, 0); case babel17Parser.EMPTY_MAP: return (PatternNode) new MapPattern(new NodeList()).mergeLocation(loc); case babel17Parser.Constr: if (tree.getChildCount() == 0) { return (PatternNode) new ConstrPattern(tree.getText(), loc, null).mergeLocation(loc); } else { Location l = getLocation(tree, tree.getTokenStartIndex(), tree.getTokenStartIndex()); return (PatternNode) new ConstrPattern(tree.getText(), l, toPattern(tree.getChild(0))).mergeLocation(loc).mergeLocation(); } default: { pe.addMessage(loc, "pattern parse error: type="+tree.getType()); return (PatternNode) new ParseErrorNode().mergeLocation(loc); } } } finally { lastKnownLocations.pop(); } } private CommonTokenStream tokens; private Source source; private ParseException pe; private java.util.Stack<Location> lastKnownLocations; private Parser(Source source, CommonTokenStream tokens, ParseException pe) { this.tokens = tokens; this.pe = pe; this.source = source; lastKnownLocations = new java.util.Stack(); lastKnownLocations.push(new Location(source, 1, 1)); } public static class ParseResult { private Node node; private ParseException pe; public ParseResult(Node n, ParseException p) { node = n; pe = p; } public boolean hasErrors() { return pe != null; } public Node node() { return node; } public ParseException exception() { return pe; } } public static void lexit(String filename) throws java.io.IOException { ANTLRFileStream stream = new ANTLRFileStream(filename, "UTF-8"); babel17Lexer lexer = new babel17Lexer(stream); System.out.println("start lexing..."); do { Token t = lexer.nextToken(); if (t.getType() == lexer.EOF) { break; } System.out.println("token " + t.getType()); } while (true); System.out.println("... done lexing."); } public static ParseResult parse(String filename) throws java.io.IOException { ANTLRFileStream stream = new ANTLRFileStream(filename, "UTF-8"); return parse(new Source(filename), stream); } public static ParseResult parse(Source source, CharStream stream) throws java.io.IOException { babel17Lexer lexer = new babel17Lexer(stream); CommonTokenStream tokens = new CommonTokenStream(lexer); babel17Parser parser = new babel17Parser(tokens); ParseException pe = new ParseException(); CommonTree tree = null; try { tree = (CommonTree) parser.prog().getTree(); } catch (RecognitionException e) { int line = e.line; int pos = e.charPositionInLine; pe.addMessage(new Location(source, line, pos + 1), "syntax error"); } if (lexer.errorDuringLexing) { int numErrors = lexer.lexingErrors.size(); for (int i = 0; i < numErrors; i++) { RecognitionException e = lexer.lexingErrors.get(i); int line = e.line; int pos = e.charPositionInLine; pe.addMessage(new Location(source, line, pos + 1), "lexical error"); } } if (parser.errorDuringParsing) { int numErrors = parser.parsingErrors.size(); for (int i = 0; i < numErrors; i++) { RecognitionException e = parser.parsingErrors.get(i); int line = e.line; int pos = e.charPositionInLine; if (pos < 0 && pe.countMessages() > 0) continue; pe.addMessage(new Location(source, line, pos + 1), "syntax error"); } } if (tree != null) { Parser p = new Parser(source, tokens, pe); Node n = p.toNode(tree); n.mergeLocation(new Location(source, 1, 1)).distributeLocation(); return new ParseResult(n, pe.countMessages() == 0 ? null : pe); } return new ParseResult(null, pe); } }