/parser/branches/proteus_annotations/tags/at_local_mirrors/grammar/atgrammar.g

http://ambienttalk.googlecode.com/ · Unknown · 629 lines · 524 code · 105 blank · 0 comment · 0 complexity · ec28c95543052bf2e3fea06c2cb7f6e2 MD5 · raw file

  1. header { package edu.vub.at.parser; }
  2. class ParserImpl extends Parser;
  3. options {
  4. k = 2;
  5. buildAST = true;
  6. defaultErrorHandler = false;
  7. }
  8. { /* begin Parser class preamble */
  9. // The keywords2canonical auxiliary function transforms keyworded message sends or parameter lists into
  10. // their canonical equivalent.
  11. // EXAMPLE:
  12. // <foo: x bar: y> is parsed as:
  13. // p = ( foo: ( symbol x ) ) ( bar: ( symbol y ) )
  14. // where p.getText() = foo:
  15. // p.getFirstChild() = (symbol x)
  16. // p.getNextSibling() = (bar: (symbol y))
  17. // at each step in the algorithm, the current keyword is appended to the previously parsed keywords,
  18. // while the only child of the current tree (the argument variable) is added to the arguments
  19. // After processing all keywords, an APL tree is returned whose selector is the concatenation of the keywords and whose
  20. // argument table contains the argument variables, e.g.:
  21. // (apply (symbol foo:bar:) (table (symbol x) (symbol y)))
  22. AST keywords2canonical(AST keywordparameterlist) {
  23. AST currentKey = keywordparameterlist;
  24. AST arguments = currentKey.getFirstChild(); // a pointer to the very first argument to which subsequent arguments are attached as siblings
  25. AST lastArgument = arguments;
  26. AST composedSelectorToken = new antlr.CommonAST();
  27. composedSelectorToken.setType(NAM);
  28. java.lang.StringBuffer composedSelector = new java.lang.StringBuffer(currentKey.getText());
  29. while (currentKey.getNextSibling() != null) {
  30. currentKey = currentKey.getNextSibling();
  31. composedSelector.append(currentKey.getText());
  32. lastArgument.setNextSibling(currentKey.getFirstChild());
  33. lastArgument = lastArgument.getNextSibling();
  34. }
  35. composedSelectorToken.setText(composedSelector.toString());
  36. // return #([AGAPL, "apply"], #([AGSYM,"symbol"], composedSelectorToken), #([AGTAB,"table"], arguments));
  37. return (AST)astFactory.make( (new ASTArray(3)).add(astFactory.create(AGAPL,"apply")).add((AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(AGSYM,"symbol")).add(composedSelectorToken))).add((AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(AGTAB,"table")).add(arguments))));
  38. };
  39. } /* end Parser class preamble */
  40. // Ambienttalk/2 programs consist of statements separated by semicolons
  41. program : globalstatementlist;
  42. // TODO: refactor duplicated code by using an extra token parameter to abstract EOF and RBC tokens
  43. // an optional terminating semicolon is allowed
  44. // a global statementlist must always end with EOF
  45. globalstatementlist!: sts:globalstatements { #globalstatementlist = #([AGBEGIN,"begin"], #sts); };
  46. globalstatements!: stmt:statement stmts:moreglobalstatements[#stmt] { #globalstatements = #stmts; };
  47. moreglobalstatements![AST stmt]: (SMC EOF) => SMC EOF { #moreglobalstatements = #stmt; }
  48. | EOF { #moreglobalstatements = #stmt; }
  49. | SMC gsts:globalstatements { #stmt.setNextSibling(#gsts);
  50. #moreglobalstatements = #stmt; }
  51. ;
  52. // an optional terminating semicolon is allowed
  53. // a statementlist must always end with RBC
  54. statementlist!: sts:statements { #statementlist = #([AGBEGIN,"begin"], #sts); };
  55. statements!: stmt:statement stmts:morestatements[#stmt] { #statements = #stmts; };
  56. morestatements![AST stmt]: (SMC RBC) => SMC RBC { #morestatements = #stmt; }
  57. | RBC { #morestatements = #stmt; }
  58. | SMC msts:statements { #stmt.setNextSibling(#msts);
  59. #morestatements = #stmt; }
  60. ;
  61. // Statements can be either definitions assignments or ordinary expressions
  62. statement: ("def"! definition)
  63. | (variable EQL) => varassignment
  64. | (assignment) => assignment
  65. | expression;
  66. // Definitions start with ambienttalk/2's only reserved word def
  67. // def <name> := <expression> defines a variable which can be assigned later.
  68. // def <apl> { <body> } defines an immutable function.
  69. // def <name>[size-exp] { <init-expression> } defines and initializes a new table of a given size
  70. definition!: nam:variable EQL val:expression { #definition = #([AGDEFFIELD,"define-field"], nam, val); }
  71. | inv:signature LBC bdy:statementlist { #definition = #([AGDEFFUN,"define-function"], inv, bdy); }
  72. | tbl:variable LBR siz:expression RBR LBC init:expression RBC { #definition = #([AGDEFTABLE,"define-table"], tbl, siz, init); }
  73. | par:parametertable EQL vls:expression { #definition = #([AGMULTIDEF,"multi-def"], par, vls); };
  74. // A function signature can either be a canonical parameter list of the form <fun(a,b,c)>
  75. // or a keyworded list of the form <foo: a bar: b>
  76. signature: canonicalparameterlist
  77. | keywordparameterlist;
  78. canonicalparameterlist!: var:variable LPR pars:parameterlist RPR { #canonicalparameterlist = #([AGAPL,"apply"], var, pars); };
  79. // See the documentation at the keywordlist rule for more information. The difference between
  80. // keywordparameterlist and keywordlist lies in the ability to either parse a varlist or a commalist.
  81. keywordparameterlist: (keywordparam)+ {
  82. #keywordparameterlist = keywords2canonical(#keywordparameterlist);
  83. };
  84. keywordparam: KEY^ parameter;
  85. // Assignment of a variable is similar to its definition albeit without the word def.
  86. // TODO tabulation assignment requires the parser to look ahead arbitrarily far for a ':=' -> inefficient
  87. varassignment!: var:variable EQL val:expression { #varassignment = #([AGASSVAR, "var-set"], var, val); };
  88. // an assignment covers both table assignment t[i] := v and field assignment o.m := v
  89. assignment!: (parametertable EQL) => par:parametertable EQL val:expression { #assignment = #([AGMULTIASS,"multi-set"], par, val); }
  90. | o:operand a:assign_table_or_field[#o] { #assignment = #a; };
  91. assign_table_or_field![AST functor]: tbl:tabulation[functor] EQL tvl:expression { #assign_table_or_field = #([AGASSTAB,"table-set"], tbl, tvl); }
  92. | sel:selection[functor] EQL fvl:expression { #assign_table_or_field = #([AGASSFLD,"field-set"], sel, fvl); };
  93. // Expressions are split up according to precedence. Ambienttalk/2's keyworded message
  94. // sends have lowest priority and are therefore the highest applicable rule.
  95. expression: keywordlist
  96. | rcv:comparand (opr:CMP^ arg:comparand)*;
  97. // Comparands are expression types delimited by comparators so that they can
  98. // be composed of additive expressions or any higher ranking operations.
  99. comparand: term (ADD^ term)*;
  100. // Terms are expression types delimited by additive operators so that they can
  101. // be composed of multiplicative expressions or any higher ranking operations.
  102. term: factor (MUL^ factor)*;
  103. // Factors are expression types delimited by multiplicative operators so that they can
  104. // be composed of exponential expressions or any higher ranking operations.
  105. factor: invocation (POW^ invocation)*;
  106. // Terms are expression types delimited by exponential operators so that they can
  107. // be composed of curried invocations only. To allow them to intervene the result
  108. // of parsing the reference is passed to the curried invocation.
  109. invocation!: o:operand c:curried_invocation[#o] { #invocation = #c; };
  110. // Operands are the most fundamental elements of the language, namely primitive
  111. // values (numbers and strings), variables, blocks, inline tables and subexpressions
  112. // A reference can also be a quotation or a first-class message creation operation
  113. operand :! nbr:NBR { #operand = #([AGNBR,"number"],nbr); }
  114. |! frc:FRC { #operand = #([AGFRC,"fraction"],frc); }
  115. |! txt:TXT { #operand = #([AGTXT,"text"],txt); }
  116. | unary
  117. | pseudovariable
  118. | symbol
  119. | BQU! quotation
  120. | HSH! unquotation
  121. | DOT! message
  122. | ARW! asyncmessage
  123. | USD! universalmessage
  124. | LPR! subexpression
  125. | LBC! block
  126. | LBR! table;
  127. // tree cases for 'unary' operators:
  128. // +.m(1) => send the message m to + (first case)
  129. // -t[5] => negate the invocation t[5] (second case)
  130. // + => third case: operator as a variable
  131. unary! : (operator (LPR|LBR|DOT|ARW|USD)) => var:operator { #unary = #var; }
  132. | (operator invocation) => opr:operator arg:invocation { #unary = #([AGAPL,"apply"], opr, #([AGTAB,"table"], arg)); }
  133. | op:operator { #unary = #op; };
  134. // A quotation is a quoted piece of source code:
  135. // `{ statement }
  136. // or `operand
  137. // note that `{ x } parses x as a statement and returns `x
  138. // to quote a block literal, use `({ x }), which parses { x } as a subexpression
  139. // the rule is ambiguous as `{ x } can both be interpreted as `{ statement } or as `blockliteral
  140. quotation: (options { generateAmbigWarnings=false; } :
  141. statementquotation
  142. | invocationquotation);
  143. statementquotation!: LBC stmt:statement RBC { #statementquotation = #([AGQUO,"quote"],#stmt); };
  144. invocationquotation!: inv:invocation { #invocationquotation = #([AGQUO,"quote"],#inv); };
  145. // An unquotation is an unquoted or unquote-spliced piece of source code
  146. // #operand
  147. // #@operand
  148. unquotation!: uexp:invocation { #unquotation = #([AGUNQ,"unquote"], uexp); }
  149. | CAT usexp:invocation { #unquotation = #([AGUQS,"unquote-splice"], usexp); };
  150. // Curried invocations eagerly consume all subsequent ( [ . tokens. If such tokens are
  151. // available a single invocation is parsed passing on the received functor (which will
  152. // be applied, tabulated, or sent a message). The result of this parsing step is passed
  153. // to be curried even further. When no appropriate tokens are left, the passed functor
  154. // is returned.
  155. curried_invocation![AST functor]:
  156. (LPR|LBR|DOT|ARW|USD) => i:invoke_expression[functor] c:curried_invocation[#i] { #curried_invocation = #c; }
  157. | {#curried_invocation = #functor; };
  158. // Invocation expressions are a single curried expression whether to apply, tabulate or
  159. // invoke its functor.
  160. invoke_expression[AST functor]:
  161. ! LPR args:commalist RPR { #invoke_expression = #([AGAPL,"apply"], functor, args); }
  162. | tabulation[functor]
  163. |! (DOT variable LPR | DOT KEY) => DOT apl:application { #invoke_expression = #([AGSND,"send"], functor, #([AGMSG,"message"], apl)); }
  164. | selection[functor]
  165. |! (ARW variable LPR | ARW KEY) => ARW snd:application { #invoke_expression = #([AGSND,"send"], functor, #([AGAMS,"async-message"], snd)); }
  166. |! (USD expression) => USD exp:expression { #invoke_expression = #([AGSND,"send"], functor, #([AGUSD,"univ-message"], exp)); };
  167. tabulation![AST functor]: LBR idx:expression RBR { #tabulation = #([AGTBL,"table-get"], functor, idx); };
  168. selection![AST functor]: DOT var:variable { #selection = #([AGSEL,"select"], functor, var); };
  169. // Function application can be done using two distinct mechanisms, either using a
  170. // canonical format ( foobar( a1, a2 ) ) or using keywordlists (foo: a1 bar: a2).
  171. // The latter format is used often in conjunction with blocks.
  172. application: canonical
  173. | keywordlist;
  174. canonical!: var:variable LPR args:commalist RPR { #canonical = #([AGAPL,"apply"], var, args); };
  175. // Keyworded message sends are an alternation of keywords (names ending with a colon)
  176. // and ordinary expressions. They allow for elegant ways to write control structures
  177. // as well as custom language constructs. The keyworded messages suffer from a generalised
  178. // version of the dangling else problem. Keywords are chained by the parser to form the
  179. // longest possible chain. As a consequence, nested keyworded message consume all keywords
  180. // unless they are delimited using e.g. subexpressions.
  181. // TECH: The grammar is (inevitably?) ambiguous here, as we are aware of the problem, we
  182. // switch off the warning for this grammar rule.
  183. keywordlist: singlekeyword
  184. (options {
  185. warnWhenFollowAmbig = false;
  186. } : singlekeyword)* { #keywordlist = keywords2canonical(#keywordlist); };
  187. // This rule groups a keyword and the adjoined argument expression into a single tree element.
  188. singlekeyword: KEY^ argument;
  189. // First-class message creation syntax: .m() or .key:val
  190. message!: apl:application { #message = #([AGMSG,"message"], apl); };
  191. // First-class aynchronous message creation syntax: <-m() or <-key:val
  192. asyncmessage!: apl:application { #asyncmessage = #([AGAMS,"async-message"], apl); };
  193. // First-class universal message: <+ expression
  194. universalmessage!: exp:expression { #universalmessage = #([AGUSD,"univ-message"], exp); };
  195. // This rule unwraps an expression of its delimiter parentheses.
  196. subexpression!: e:expression RPR { #subexpression = #e; };
  197. // Inline syntax for nameless functions (lambdas or blocks)
  198. block!: PIP pars:parameterlist PIP body:statementlist
  199. { #block = #([AGCLO, "closure"], pars, body); }
  200. | no_args_body:statementlist
  201. { #block = #([AGCLO, "closure"], #([AGTAB,"table"], #([COM]) ), no_args_body); };
  202. // Inline syntax for table expressions
  203. table!: slots:commalist RBR { #table = #slots; };
  204. // syntax for tables that act as the left hand side of multi definitions and assignments
  205. parametertable!: LBR slots:parameterlist RBR { #parametertable = #slots; };
  206. // Parses a list of expressions separated by commas.
  207. // USAGE: canonical function application (arguments) and inline tables
  208. commalist: argument (COM! argument)*
  209. { #commalist = #([AGTAB,"table"], #commalist); }
  210. |! /* empty */ { #commalist = #([AGTAB,"table"], #([COM]));};
  211. argument:! CAT exp:expression { #argument = #([AGSPL,"splice"], exp); }
  212. | expression;
  213. // parses a list of variables that may act as formal parameters
  214. parameterlist: parameter (COM! parameter)* { #parameterlist = #([AGTAB, "table"], #parameterlist); }
  215. |! /* empty */ { #parameterlist = #([AGTAB,"table"], #([COM])); };
  216. parameter: variable_or_quotation
  217. |! CAT v:variable_or_quotation { #parameter = #([AGSPL,"splice"], v); };
  218. variable_or_quotation: variable
  219. | HSH! unquotation;
  220. // user-definable names for variables
  221. variable: symbol
  222. | operator;
  223. symbol!: var:NAM { #symbol = #([AGSYM,"symbol"], var); };
  224. pseudovariable!: "self" { #pseudovariable = #[AGSLF,"self"]; }
  225. | "super" { #pseudovariable = #([AGSUP, "super"]); };
  226. operator!: cmp:CMP { #operator = #([AGCMP, "symbol"], cmp); }
  227. | add:ADD { #operator = #([AGADD, "symbol"], add); }
  228. | mul:MUL { #operator = #([AGMUL, "symbol"], mul); }
  229. | pow:POW { #operator = #([AGPOW, "symbol"], pow); };
  230. class LexerImpl extends Lexer;
  231. options {
  232. k = 3;
  233. }
  234. // Protected Scanner Tokens
  235. // OUTPUT TOKENS
  236. // These tokens are never produced by the scanner itself as they are protected.
  237. // However they are used to annotate the resulting ANTLR tree, so that the walker
  238. // can easily produce the correct Java ATAbstractGrammar elements.
  239. // Each token definition aligns the token with its printed representation.
  240. // Statements
  241. protected AGBEGIN : "begin"; // AGBegin(TAB stmts)
  242. // Definitions
  243. protected AGDEFFIELD: "define-field"; // AGDefField(SYM nam, EXP val)
  244. protected AGDEFFUN : "define-function";// AGDefFunction(SYM sel, TAB arg, BGN bdy)
  245. protected AGDEFTABLE: "define-table"; // AGDefTable(SYM tbl, EXP siz, EXP ini)
  246. protected AGMULTIDEF: "multi-def"; // AGMultiDefinition(TAB par, EXP val)
  247. // Assignments
  248. protected AGASSVAR : "var-set"; // AGAssignField(SYM nam, EXP val)
  249. protected AGASSTAB : "table-set"; // AGAssignTable(EXP tbl, EXP idx, EXP val)
  250. protected AGASSFLD : "field-set"; // AGAssignField(EXP rcv, SYM fld, EXP val)
  251. protected AGMULTIASS: "multi-set"; // AGMultiAssignment(TAB par, EXP val)
  252. // Expressions
  253. protected AGSND : "send"; // AGMessageSend(EXP rcv, MSG msg)
  254. protected AGAPL : "apply"; // AGApplication(SYM sel, TAB arg)
  255. protected AGSEL : "select"; // AGSelection(EXP rcv, SYM sel)
  256. protected AGMSG : "message"; // AGMethodInvocation(SYM sel, TAB arg)
  257. protected AGAMS : "async-message"; // AGAsyncMessage(SYM sel, TAB arg)
  258. protected AGUSD : "univ-message"; // ATExpression(exp)
  259. protected AGTBL : "table-get"; // AGTabulation(EXP tbl, EXP idx)
  260. protected AGSYM : "symbol"; // AGSymbol(TXT nam)
  261. protected AGSLF : "self"; // AGSelf
  262. protected AGSUP : "super"; // AGSuper
  263. protected AGQUO : "quote"; // AGQuote(STMT stmt)
  264. protected AGUNQ : "unquote"; // AGUnquote(EXP exp)
  265. protected AGUQS : "unquote-splice";// AGUnquoteSplice(EXP exp)
  266. protected AGSPL : "splice"; // AGSplice(EXP exp)
  267. // Literals
  268. protected AGNBR : "number"; // NATNumber(<int>)
  269. protected AGFRC : "fraction"; // NATFraction(<double>)
  270. protected AGTXT : "text"; // NATText(<String>)
  271. protected AGTAB : "table"; // NATTable(<ATObject[]>)
  272. protected AGCLO : "closure"; // NATClosure(TAB arg, BGN bdy)
  273. // auxiliary tokens for operators
  274. protected AGCMP : "symbol";
  275. protected AGADD : "symbol";
  276. protected AGMUL : "symbol";
  277. protected AGPOW : "symbol";
  278. protected DIGIT: '0'..'9'
  279. ;
  280. protected LETTER: ('a'..'z'|'A'..'Z' )
  281. ;
  282. protected EXPONENT: ('e' | 'E')
  283. ;
  284. protected CMPCHAR: ('<' | '=' | '>' | '~' )
  285. ;
  286. protected ADDCHAR: ( '+' | '-')
  287. ;
  288. protected MULCHAR: ( '*' | '/' | '\\' | '&' )
  289. ;
  290. protected POWCHAR: ( '^' | '!' | '?' | '%' )
  291. ;
  292. protected OPRCHAR: CMPCHAR | ADDCHAR | MULCHAR | POWCHAR
  293. ;
  294. protected SIGN: ('+' | '-' )
  295. ;
  296. protected SCALE: EXPONENT (SIGN)? NBR
  297. ;
  298. protected COLON: ':'
  299. ;
  300. protected NBR: (DIGIT)+
  301. ;
  302. protected FRC: NBR (SCALE | DOT NBR (SCALE)?)
  303. ;
  304. NBR_OR_FRC options { paraphrase = "a number or fraction"; }: ( NBR EXPONENT ) => FRC { $setType(FRC); }
  305. | ( NBR DOT ) => FRC { $setType(FRC); }
  306. | NBR { $setType(NBR); }
  307. ;
  308. protected CMP: CMPCHAR (OPRCHAR)*
  309. ;
  310. ADD options { paraphrase = "an additive operator"; }: ADDCHAR (OPRCHAR)*
  311. ;
  312. MUL options { paraphrase = "a multiplicative operator"; }: MULCHAR (OPRCHAR)*
  313. ;
  314. POW options { paraphrase = "an exponential operator"; }: POWCHAR (OPRCHAR)*
  315. ;
  316. protected NAM: LETTER (DIGIT | LETTER)*
  317. ;
  318. protected KEY: NAM COLON
  319. ;
  320. NAM_OR_KEY options { paraphrase = "a name or a keyword"; }: ( NAM COLON ) => KEY { $setType(KEY); }
  321. | NAM { $setType(NAM); }
  322. ;
  323. WHITESPACE options { paraphrase = "whitespace"; }: ('\t' | ' ')
  324. { $setType(Token.SKIP); }
  325. ;
  326. NEWLINE options { paraphrase = "newline"; }: ( "\r\n" | '\r' | '\n')
  327. { newline();
  328. $setType(Token.SKIP); }
  329. ;
  330. LPR options { paraphrase = "a left parenthesis"; }: '(';
  331. RPR options { paraphrase = "a right parenthesis"; }: ')';
  332. LBR options { paraphrase = "a left bracket"; }: '[';
  333. RBR options { paraphrase = "a right bracket"; }: ']';
  334. LBC options { paraphrase = "a left brace"; }: '{';
  335. RBC options { paraphrase = "a right brace"; }: '}';
  336. COM options { paraphrase = "a comma"; }: ',';
  337. SMC options { paraphrase = "a semicolon"; }: ';';
  338. EQL options { paraphrase = "an assignment"; }: ":=";
  339. DOT options { paraphrase = "a selection"; }: '.';
  340. protected ARW: "<-"; // asynchronous send operator
  341. protected USD: "<+"; // universal send operator
  342. PIP options { paraphrase = "a block argument list"; }: '|';
  343. BQU options { paraphrase = "a quotation"; }: '`';
  344. HSH options { paraphrase = "an unquotation"; }: '#';
  345. CAT options { paraphrase = "a splice"; }: '@';
  346. CMP_OR_ARW options { paraphrase = "a comparator, asynchronous or universal send"; }
  347. : ( "<-" ) => ARW { $setType(ARW); }
  348. | ( "<+" ) => USD { $setType(USD); }
  349. | CMP { $setType(CMP); }
  350. ;
  351. TXT options { paraphrase = "a text string"; }: '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
  352. ;
  353. // Single-line comments
  354. SL_COMMENT options { paraphrase = "a single-line comment"; }
  355. : "//" WHITESPACE
  356. (~('\n'|'\r'))* ('\n'|'\r'('\n')?)
  357. {$setType(Token.SKIP); newline();}
  358. ;
  359. // multiple-line comments
  360. ML_COMMENT options { paraphrase = "a multi-line comment"; }
  361. : "/*"
  362. ( /* '\r' '\n' can be matched in one alternative or by matching
  363. '\r' in one iteration and '\n' in another. I am trying to
  364. handle any flavor of newline that comes in, but the language
  365. that allows both "\r\n" and "\r" and "\n" to all be valid
  366. newline is ambiguous. Consequently, the resulting grammar
  367. must be ambiguous. I'm shutting this warning off.
  368. */
  369. options {
  370. generateAmbigWarnings=false;
  371. }
  372. :
  373. { LA(2)!='/' }? '*'
  374. | '\r''\n' {newline();}
  375. | '\r' {newline();}
  376. | '\n' {newline();}
  377. | ~('*'|'\n'|'\r')
  378. )*
  379. "*/"
  380. {$setType(Token.SKIP);}
  381. ;
  382. protected ESC
  383. : '\\'
  384. ( 'n'
  385. | 'r'
  386. | 't'
  387. | 'b'
  388. | 'f'
  389. | '"'
  390. | '\''
  391. | '\\'
  392. | '0'..'3'
  393. (
  394. options {
  395. warnWhenFollowAmbig = false;
  396. }
  397. : '0'..'7'
  398. (
  399. options {
  400. warnWhenFollowAmbig = false;
  401. }
  402. : '0'..'7'
  403. )?
  404. )?
  405. | '4'..'7'
  406. (
  407. options {
  408. warnWhenFollowAmbig = false;
  409. }
  410. : '0'..'7'
  411. )?
  412. )
  413. ;
  414. { import edu.vub.at.objects.ATObject;
  415. import edu.vub.at.objects.natives.*;
  416. import edu.vub.at.objects.grammar.*;
  417. import edu.vub.at.objects.natives.grammar.*;
  418. import java.util.LinkedList; }
  419. class TreeWalkerImpl extends TreeParser;
  420. { // begin TreeWalker preamble
  421. // this auxiliary function converts operator syntax such as <a+b> into a message send of the form <a.+(b)>
  422. public AGMessageSend operatorToSend(AST opr, ATExpression receiver, ATExpression operand) {
  423. return new AGMessageSend(receiver,
  424. new AGMethodInvocationCreation(AGSymbol.alloc(NATText.atValue(opr.getText())),
  425. new NATTable(new ATObject[] { operand })));
  426. }
  427. } // end TreeWalker preamble
  428. program returns [NATAbstractGrammar ag] { ag = null; }
  429. : ag=begin
  430. ;
  431. statement returns [ATStatement stmt] { stmt = null; }
  432. : stmt=definition
  433. | stmt=assignment
  434. | stmt=expression
  435. ;
  436. definition returns [ATDefinition def]
  437. { def = null;
  438. ATSymbol nam;
  439. NATTable pars;
  440. ATExpression idx, val;
  441. ATBegin bdy; }
  442. : #(AGDEFFIELD nam=symbol val=expression) { def = new AGDefField(nam, val); }
  443. | #(AGDEFFUN #(AGAPL nam=symbol pars=table) bdy=begin) { def = new AGDefFunction(nam, pars, bdy); }
  444. | #(AGDEFTABLE nam=symbol idx=expression val=expression) { def = new AGDefTable(nam,idx,val); }
  445. | #(AGMULTIDEF pars=table val=expression) { def = new AGMultiDefinition(pars,val); }
  446. ;
  447. assignment returns [ATAssignment ass]
  448. { ass = null;
  449. ATSymbol nam;
  450. ATExpression rcv, val, idx;
  451. NATTable par; }
  452. : #(AGASSVAR nam=symbol val=expression) { ass = new AGAssignVariable(nam, val); }
  453. | #(AGASSTAB #(AGTBL rcv=expression idx=expression) val=expression) { ass = new AGAssignTable(rcv, idx, val); }
  454. | #(AGASSFLD #(AGSEL rcv=expression nam=symbol) val=expression) { ass = new AGAssignField(rcv, nam, val); }
  455. | #(AGMULTIASS par=table val=expression) { ass = new AGMultiAssignment(par, val); }
  456. ;
  457. expression returns [ATExpression exp]
  458. { exp = null;
  459. ATExpression rcv, idx, qexp, msg;
  460. ATStatement qstmt;
  461. ATSymbol sel;
  462. NATTable arg; }
  463. : #(AGSND rcv=expression msg=message) { exp = new AGMessageSend(rcv,msg); }
  464. | #(AGAPL rcv=expression arg=table) { exp = new AGApplication(rcv, arg); }
  465. | #(AGSEL rcv=expression sel=symbol) { exp = new AGSelection(rcv, sel); }
  466. | #(AGTBL rcv=expression idx=expression) { exp = new AGTabulation(rcv, idx); }
  467. | #(AGQUO qstmt=statement) { exp = new AGQuote(qstmt); }
  468. | #(AGUNQ qexp=expression) { exp = new AGUnquote(qexp); }
  469. | #(AGUQS qexp=expression) { exp = new AGUnquoteSplice(qexp); }
  470. | #(AGSPL qexp=expression) { exp = new AGSplice(qexp); }
  471. | exp=message
  472. | exp=symbol
  473. | exp=binop
  474. | exp=literal
  475. ;
  476. message returns [ATExpression msg]
  477. { msg = null;
  478. ATExpression exp;
  479. ATSymbol sel; NATTable arg; }
  480. : #(AGMSG #(AGAPL sel=symbol arg=table)) { msg = new AGMethodInvocationCreation(sel,arg); }
  481. | #(AGAMS #(AGAPL sel=symbol arg=table)) { msg = new AGAsyncMessageCreation(sel,arg); }
  482. | #(AGUSD exp=expression) { msg=exp; }
  483. ;
  484. binop returns [ATMessageSend snd]
  485. { snd = null;
  486. ATExpression exp1, exp2; }
  487. : #(cmp:CMP exp1=expression exp2=expression) { snd = operatorToSend(cmp, exp1, exp2); }
  488. | #(add:ADD exp1=expression exp2=expression) { snd = operatorToSend(add, exp1, exp2); }
  489. | #(mul:MUL exp1=expression exp2=expression) { snd = operatorToSend(mul, exp1, exp2); }
  490. | #(pow:POW exp1=expression exp2=expression) { snd = operatorToSend(pow, exp1, exp2); }
  491. ;
  492. literal returns[ATExpression lit]
  493. { lit = null;
  494. NATTable par;
  495. ATBegin body; }
  496. : #(AGNBR nbr:NBR) { lit = NATNumber.atValue(Integer.parseInt(nbr.getText())); }
  497. | #(AGFRC frc:FRC) { lit = NATFraction.atValue(Double.parseDouble(frc.getText())); }
  498. | #(AGTXT txt:TXT) { String text = txt.getText(); lit = NATText.atValue(text.substring(1, text.length() - 1)); }
  499. | lit=table
  500. | #(AGCLO par=table body=begin) { lit = new AGClosureLiteral(par, body); }
  501. ;
  502. symbol returns [AGSymbol sym] { sym = null; }
  503. : #(AGSYM txt:NAM) { sym = AGSymbol.alloc(NATText.atValue(txt.getText())); }
  504. | #(AGCMP cmp:CMP) { sym = AGSymbol.alloc(NATText.atValue(cmp.getText())); }
  505. | #(AGADD add:ADD) { sym = AGSymbol.alloc(NATText.atValue(add.getText())); }
  506. | #(AGMUL mul:MUL) { sym = AGSymbol.alloc(NATText.atValue(mul.getText())); }
  507. | #(AGPOW pow:POW) { sym = AGSymbol.alloc(NATText.atValue(pow.getText())); }
  508. | AGSLF { sym = AGSelf._INSTANCE_; }
  509. | AGSUP { sym = AGSuper._INSTANCE_; }
  510. ;
  511. table returns [NATTable tab]
  512. { tab = null;
  513. ATExpression expr;
  514. LinkedList list = new LinkedList(); }
  515. : #(AGTAB (expr=expression { list.add(expr); })* )
  516. { tab = (list.isEmpty()) ? NATTable.EMPTY : new NATTable((ATObject[]) list.toArray(new ATObject[list.size()])); }
  517. ;
  518. begin returns [AGBegin bgn]
  519. { bgn = null;
  520. ATStatement stmt;
  521. LinkedList list = new LinkedList(); }
  522. : #(AGBEGIN (stmt=statement { list.add(stmt); })+ )
  523. { bgn = new AGBegin(new NATTable((ATObject[]) list.toArray(new ATObject[list.size()]))); }
  524. ;