00001
00005 package edu.mit.csail.sdg.squander.spec;
00006
00007 import static edu.mit.csail.sdg.squander.parser.JFSLParser.AMBIGUOUS;
00008 import static edu.mit.csail.sdg.squander.parser.JFSLParser.ARGUMENT;
00009 import static edu.mit.csail.sdg.squander.parser.JFSLParser.BINARY;
00010 import static edu.mit.csail.sdg.squander.parser.JFSLParser.BRACKET;
00011 import static edu.mit.csail.sdg.squander.parser.JFSLParser.CALL;
00012 import static edu.mit.csail.sdg.squander.parser.JFSLParser.CAST;
00013 import static edu.mit.csail.sdg.squander.parser.JFSLParser.CHAIN;
00014 import static edu.mit.csail.sdg.squander.parser.JFSLParser.CLASS_DESIGNATOR;
00015 import static edu.mit.csail.sdg.squander.parser.JFSLParser.CONDITIONAL;
00016 import static edu.mit.csail.sdg.squander.parser.JFSLParser.DECLARATION;
00017 import static edu.mit.csail.sdg.squander.parser.JFSLParser.DecimalLiteral;
00018 import static edu.mit.csail.sdg.squander.parser.JFSLParser.FIELD;
00019 import static edu.mit.csail.sdg.squander.parser.JFSLParser.FRAME;
00020 import static edu.mit.csail.sdg.squander.parser.JFSLParser.FRAME_ALL;
00021 import static edu.mit.csail.sdg.squander.parser.JFSLParser.FRAME_LOCATION;
00022 import static edu.mit.csail.sdg.squander.parser.JFSLParser.IDENTIFIER;
00023 import static edu.mit.csail.sdg.squander.parser.JFSLParser.JOIN;
00024 import static edu.mit.csail.sdg.squander.parser.JFSLParser.JOIN_REFLEXIVE;
00025 import static edu.mit.csail.sdg.squander.parser.JFSLParser.LIT_FALSE;
00026 import static edu.mit.csail.sdg.squander.parser.JFSLParser.LIT_NULL;
00027 import static edu.mit.csail.sdg.squander.parser.JFSLParser.LIT_TRUE;
00028 import static edu.mit.csail.sdg.squander.parser.JFSLParser.OLD;
00029 import static edu.mit.csail.sdg.squander.parser.JFSLParser.QUANTIFY;
00030 import static edu.mit.csail.sdg.squander.parser.JFSLParser.RETURN_VAR;
00031 import static edu.mit.csail.sdg.squander.parser.JFSLParser.SUPER_VAR;
00032 import static edu.mit.csail.sdg.squander.parser.JFSLParser.StringLiteral;
00033 import static edu.mit.csail.sdg.squander.parser.JFSLParser.THIS_VAR;
00034 import static edu.mit.csail.sdg.squander.parser.JFSLParser.THROW_VAR;
00035 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_ARRAY;
00036 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_BOOLEAN;
00037 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_BYTE;
00038 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_CHAR;
00039 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_INT;
00040 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_LONG;
00041 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_REF;
00042 import static edu.mit.csail.sdg.squander.parser.JFSLParser.TYPE_SHORT;
00043 import static edu.mit.csail.sdg.squander.parser.JFSLParser.UNARY;
00044
00045 import java.util.ArrayList;
00046 import java.util.LinkedList;
00047 import java.util.List;
00048
00049 import org.antlr.runtime.tree.Tree;
00050
00051 import edu.mit.csail.sdg.squander.parser.JFSLParser;
00052 import edu.mit.csail.sdg.squander.parser.JFSLParserException;
00053 import edu.mit.csail.sdg.squander.parser.JFSLParser.Node;
00054
00055
00066 public
00067 abstract class Visitor<N, M> {
00068
00072 public
00073 final N visit(M env, Tree tree) {
00074 try {
00075 final Node source = cast(tree);
00076
00077 if (source.token == null)
00078 throw new JFSLParserException("missing token type in the AST node; failed to parse correctly");
00079
00080 final N result;
00081
00082 switch (source.token.getType()) {
00084 case DECLARATION:
00085 assert source.getChildCount() >= 3;
00086 Node frame = source.getChildCount() >= 4 ? cast(source.getChild(3)) : null;
00087 if (frame.getType() == JFSLParser.NULL)
00088 frame = null;
00089 Node constraint = source.getChildCount() >= 5 ? cast(source.getChild(4)) : null;
00090 result = visitFieldDeclaration(env, cast(source.getChild(0)), source.getChild(1).getType(), cast(source.getChild(2)), frame, constraint);
00091 break;
00092 case FRAME:
00093 final List<N> locations = new ArrayList<N>();
00094 final List<Node> fields = new ArrayList<Node>();
00095 final List<N> selectors = new ArrayList<N>();
00096 final List<N> lowers = new ArrayList<N>();
00097 final List<N> uppers = new ArrayList<N>();
00098
00099 for (int i = 0; i < source.getChildCount(); i++) {
00100 final Tree child = source.getChild(i);
00101 assert child.getType() == FRAME_LOCATION;
00102 int nChildren = child.getChildCount();
00103
00104 List<Node> trailingBrackets = new LinkedList<Node>();
00105 for (int idx = nChildren - 1; idx > 0; idx--) {
00106 Node node = cast(child.getChild(idx));
00107 if (node.getType() != BRACKET)
00108 break;
00109 trailingBrackets.add(0, node);
00110 }
00111
00112 nChildren -= trailingBrackets.size();
00113
00114 N sel = null;
00115 N lower = null;
00116 N upper = null;
00117
00118 if (!trailingBrackets.isEmpty()) {
00119 Node selNode = trailingBrackets.remove(0);
00120 if (selNode.getChildCount() > 0)
00121 sel = visit(env, child(selNode));
00122 }
00123
00124
00125 if (!trailingBrackets.isEmpty()) {
00126 Node low = trailingBrackets.remove(0);
00127 if (low.getChildCount() > 0)
00128 lower = visit(env, child(low));
00129 }
00130
00131
00132 if (!trailingBrackets.isEmpty()) {
00133 Node up = trailingBrackets.remove(0);
00134 if (up.getChildCount() > 0)
00135 upper = visit(env, child(up));
00136 }
00137
00138 if (!trailingBrackets.isEmpty())
00139 throw new JFSLParserException("too many trailing brackets");
00140
00141 selectors.add(sel);
00142 lowers.add(lower);
00143 uppers.add(upper);
00144
00145 List<Node> join = new ArrayList<Node>();
00146 for (int j = 0; j < nChildren - 1; j++)
00147 join.add(cast(child.getChild(j)));
00148
00149 locations.add(visitChain(env, join));
00150 Node relation = cast(child.getChild(nChildren - 1));
00151 if (relation.getType() == FRAME_ALL)
00152 fields.add(relation);
00153 else if (relation.getType() == JOIN)
00154 fields.add(child(relation));
00155 else
00156 throw new JFSLParserException("wrong selector in frame condition");
00157 }
00158
00159 result = visitFrame(env, locations, fields, selectors, lowers, uppers);
00160 break;
00161
00163 case BINARY:
00164 result = visitBinary(env, source, source.getChild(0).getType(), cast(source.getChild(1)),
00165 cast(source.getChild(2)));
00166 break;
00167 case UNARY:
00168 result = visitUnary(env, source, source.getChild(0).getType(), cast(source.getChild(1)));
00169 break;
00170 case QUANTIFY:
00171
00172 final int num = source.getChild(1).getChildCount();
00173 assert num % 3 == 0;
00174 int count = num / 3;
00175 assert count > 0;
00176
00177 final List<String> names = new ArrayList<String>();
00178 final List<String> mults = new ArrayList<String>();
00179 final List<Node> sets = new ArrayList<Node>();
00180
00181
00182 for (int i = 0; i < count; i++) {
00183 names.add(source.getChild(1).getChild(2 * i).getText());
00184 mults.add(source.getChild(1).getChild(2 * i + 1).getText());
00185 sets.add(cast(source.getChild(1).getChild(2 * i + 2)));
00186 }
00187
00188 result = visitQuantification(env, source.getChild(0).getType(), names, mults, sets, cast(source.getChild(2)));
00189 break;
00190 case CONDITIONAL:
00191 result = visitConditional(env,
00192 cast(source.getChild(0)),
00193 cast(source.getChild(1)),
00194 cast(source.getChild(2)));
00195 break;
00196 case CHAIN:
00197 result = visitChain(env, children(source));
00198 break;
00199 case OLD:
00200 result = visitOld(env, child(source));
00201 break;
00202 case AMBIGUOUS:
00203 result = visitAmbiguous(env, children(source));
00204 break;
00205 case IDENTIFIER:
00206 result = visitName(env, source);
00207 break;
00208 case CAST:
00209 result = visitCastExpression(env, cast(source.getChild(0)), cast(source.getChild(1)));
00210 break;
00211 case FIELD:
00212 result = visitFieldRelation(env, cast(source.getChild(0)), cast(source.getChild(1)));
00213 break;
00214 case TYPE_INT: case TYPE_BYTE: case TYPE_SHORT: case TYPE_LONG: case TYPE_CHAR:
00215 result = visitIntegralType(env);
00216 break;
00217 case TYPE_BOOLEAN:
00218 result = visitBooleanType(env);
00219 break;
00220 case TYPE_ARRAY:
00221 result = visitArrayType(env, child(source));
00222 break;
00223 case TYPE_REF:
00224 result = visitRefType(env, source, children(source));
00225 break;
00226 case CLASS_DESIGNATOR:
00227 assert false;
00228 case CALL:
00229
00230 result = visitMethodCall(env, null, source.getChild(0).getText(), cast(source.getChild(1)));
00231 break;
00232 case ARGUMENT:
00233 result = visitArgument(env, parseInt(source.getChild(0)));
00234 break;
00235
00237 case THIS_VAR:
00238 result = visitThis(env);
00239 break;
00240 case SUPER_VAR:
00241 result = visitSuper(env);
00242 break;
00243 case RETURN_VAR:
00244 result = visitReturn(env);
00245 break;
00246 case THROW_VAR:
00247 result = visitThrow(env);
00248 break;
00249
00250 case LIT_TRUE:
00251 result = visitTrue(env);
00252 break;
00253 case LIT_FALSE:
00254 result = visitFalse(env);
00255 break;
00256 case LIT_NULL:
00257 result = visitNull(env);
00258 break;
00259 case DecimalLiteral:
00260 result = visitDecimal(env, parseInt(source));
00261 break;
00262 case StringLiteral:
00263 result = visitString(env, source.getText());
00264 break;
00265 default:
00266 result = null;
00267 }
00268
00269
00270 validate(source, result);
00271 return result;
00272 } catch (JFSLParserException e) {
00273
00274 if (e.token() == null) e.setToken(tree);
00275 throw e;
00276 } catch (RuntimeException e) {
00277
00278 throw new JFSLParserException(e, tree);
00279 }
00280
00281 }
00282
00284 private final N visitChain(M env, List<Node> children) {
00285
00286 N result = visit(env, children.get(0));
00287
00288
00289 for (int i = 1; i < children.size(); i++) {
00290 Node child = children.get(i);
00291
00292 switch (child.getType()) {
00293 case BRACKET:
00294 result = visitBracket(env, result, child);
00295 break;
00296 case JOIN:
00297 result = visitJoin(env, result, child);
00298 break;
00299 case JOIN_REFLEXIVE:
00300 result = visitJoinReflexive(env, result, child);
00301 break;
00302 case CALL:
00303 result = visitMethodCall(env, result, child.getChild(0).getText(), cast(child.getChild(1)));
00304 break;
00305 default:
00306 return null;
00307 }
00308 }
00309
00310 return result;
00311 }
00312
00314 protected void validate(Node node, N result) {
00315 if (result == null)
00316 throw new TypeCheckException("not implemented or failed to resolve: " + node.toStringTree());
00317 }
00318
00319
00320
00321 protected N visitFieldDeclaration(M env, Node ident, int op, Node set, Node frame, Node constraint) {return null;}
00322
00323 protected N visitFrame(M env, List<N> joins, List<Node> fields, List<N> selectors, List<N> lowers, List<N> uppers) {return null;}
00324
00325
00326
00327 protected N visitBinary(M env, Node tree, int op, Node leftTree, Node rightTree) {return null;}
00328
00329 protected N visitUnary(M env, Node tree, int op, Node expr) {return null;}
00330
00331 protected N visitQuantification(M env, int op, List<String> names, List<String> mults, List<Node> sets, Node expr) {return null;}
00332
00333 protected N visitConditional(M env, Node condTree, Node leftTree, Node rightTree) {return null;}
00334
00335 protected N visitOld(M env, Node sub) {return null;}
00336
00337 protected N visitName(M env, Node tree) {return null;}
00338
00339 protected N visitAmbiguous(M env, List<Node> idents) {return null;}
00340
00341 protected N visitCastExpression(M env, Node type, Node sub) {return null;}
00342
00343 protected N visitFieldRelation(M env, Node type, Node ident) {return null;}
00344
00345
00346
00347 protected N visitBracket(M env, N primary, Node selector) {return null;}
00348
00349 protected N visitJoin(M env, N primary, Node selector) {return null;}
00350
00351 protected N visitJoinReflexive(M env, N primary, Node selector) {return null;}
00352
00353 protected N visitMethodCall(M env, N receiver, String id, Node arguments) {return null;}
00354
00355
00356
00357 protected N visitThis(M env) {return null;}
00358
00359 protected N visitSuper(M env) {return null;}
00360
00361 protected N visitReturn(M env) {return null;}
00362
00363 protected N visitThrow(M env) {return null;}
00364
00365 protected N visitDecimal(M env, int i) {return null;}
00366
00367 protected N visitString(M env, String s) {return null;}
00368
00369 protected N visitTrue(M env) {return null;}
00370
00371 protected N visitFalse(M env) {return null;}
00372
00373 protected N visitNull(M env) {return null;}
00374
00375 protected N visitArgument(M env, int i) {return null;}
00376
00377
00378
00379 protected N visitIntegralType(M env) {return null;}
00380
00381 protected N visitBooleanType(M env) {return null;}
00382
00383 protected N visitArrayType(M env, Node base) {return null;}
00384
00385 protected N visitRefType(M env, Node source, List<Node> idents) {return null;}
00386
00387
00388
00389 protected List<Node> children(Tree node) {
00390 List<Node> lst = new ArrayList<Node>();
00391 for (int i = 0; i < node.getChildCount(); i++) {
00392 lst.add(cast(node.getChild(i)));
00393 }
00394 return lst;
00395 }
00396
00398 private Node cast(Tree tree) {
00399 if (!(tree instanceof Node))
00400 throw new JFSLParserException("malformed node in the AST");
00401 return (Node) tree;
00402 }
00403
00405 protected Node child(Node parent) {
00406 return cast(parent.getChild(0));
00407 }
00408
00410 protected String asText(Tree node) {
00411 if (node.getChildCount() != 1)
00412 throw new JFSLParserException("node cannot be viewed as a text");
00413 return node.getChild(0).getText();
00414 }
00415
00417 public static int parseInt(Tree tree) {
00418 try {
00419 return Integer.parseInt(tree.getText());
00420 } catch (NumberFormatException e) {
00421 throw new JFSLParserException("malformed decimal expression: " + tree.toStringTree());
00422 }
00423 }
00424 }