Added ability to order the execution of dictionary adapter behaviors.
[castle.git] / Experiments / Attic / Rook / Castle.Rook.Compiler / Parser / lang4.g
blobfef6db0c2ad0ab407f50b3dff4e817ae5af2f04a
1 header \r
2 {\r
3         using System.Text;\r
4         using System.Collections;\r
5 \r
6         using Castle.Rook.Compiler.AST;\r
7         using Castle.Rook.Compiler.Services;\r
8 }\r
9 options \r
10 {       \r
11         language = "CSharp";\r
12         namespace = "Castle.Rook.Compiler.Parser";\r
13 }\r
15 class RookBaseParser extends Parser;\r
16 options \r
17 {\r
18         k = 2;                           // two token lookahead\r
19         exportVocab=Rook;                \r
20         codeGenMakeSwitchThreshold = 2;  // Some optimizations\r
21         codeGenBitsetTestThreshold = 3;\r
22         defaultErrorHandler = false;     // Don't generate parser error handlers\r
23         // buildAST = true;\r
24         analyzerDebug = false;\r
25         codeGenDebug = false;\r
26 }\r
27 tokens\r
28 {\r
29         CLASS = "class";\r
30         DO = "do";\r
31         END = "end";\r
32         DEF = "def";\r
33         OPERATOR = "operator";\r
34         BEGIN = "begin";\r
35         WHILE = "while";        \r
36         TYPE; METHOD_CALL; SUPER_CTOR_CALL; POST_INC; POST_DEC; EXPR; ELIST; INDEX_OP; \r
37         UNARY_MINUS; UNARY_PLUS; TYPECAST; ARRAY_DECLARATOR; \r
38         NUM_INT; NUM_DOUBLE; NUM_FLOAT; NUM_LONG;\r
39         STATEMENT_END;\r
40 }\r
42 {\r
43         public IErrorReport ErrorReport;\r
44         \r
45         private bool withinStatic, withinFinal, withinAbstract, withinNew, withinOverride;\r
46         \r
47         private ISymbolTable topLevelScope;\r
49         AccessLevel currentAccessLevel = AccessLevel.Public;\r
50         \r
51         public override void reportError(RecognitionException ex)\r
52         {\r
53                 LexicalPosition lpos = new LexicalPosition( ex.getLine(), ex.getColumn() );\r
54                 \r
55                 ErrorReport.Error( ex.getFilename(), lpos, ex.Message );\r
56         }\r
58         // TODO: Research for a better way to set lexical information\r
59         // on our AST   \r
60         private void SetLexical(IASTNode node, IToken t)\r
61         {\r
62                 node.Position.Line = t.getLine();\r
63                 node.Position.Column = t.getColumn();\r
64         }\r
66         private Stack scopes = new Stack();\r
67         \r
68         private void PushScope(IASTNode node, ScopeType scopeType)\r
69         {\r
70                 if (node.DefiningSymbolTable != null)\r
71                 {\r
72                         throw new ArgumentException("We can't override a scope");\r
73                 }\r
74                 \r
75                 node.DefiningSymbolTable = new SymbolTable( GetCurrentScope(), scopeType );\r
76                 \r
77                 ISymbolTable scope = node.DefiningSymbolTable;\r
78                 \r
79                 if (scope == null) throw new ArgumentNullException("null scope?");\r
80                 \r
81                 scopes.Push(scope);\r
82         }\r
84         private void PopScope()\r
85         {\r
86                 scopes.Pop();\r
87         }\r
88         \r
89         private ISymbolTable GetCurrentScope()\r
90         {\r
91                 if (scopes.Count == 0) return topLevelScope;\r
92                         \r
93                 return scopes.Peek() as ISymbolTable;\r
94         }\r
95 }\r
97 qualified_name returns [String ident]\r
98         { String name = String.Empty; ident = null; }\r
99         :\r
100         t:IDENT { name = t.getText(); }\r
101         ( options{greedy=true;}:\r
102                 (\r
103                         DOT                     { name += "."; }\r
104                         | \r
105                         COLONCOLON      { name += "::"; }\r
106                 )\r
107                 t2:IDENT { name += t2.getText(); } \r
108         )*\r
109     { ident = name; }\r
110     ;\r
112 identifier returns [Identifier ident]\r
113         { ident = null; TypeReference tr = null; }\r
114         :\r
115         ident=name (tr=type { ident.TypeReference = tr; })? \r
116         ;\r
118 identifier_withtype returns [Identifier ident]\r
119         { ident = null; TypeReference tr = null; }\r
120         :\r
121         ident=name tr=type      { ident.TypeReference = tr; }\r
122         ;\r
124 type returns [ TypeReference tr ]\r
125         { tr = null; String n; }\r
126         :\r
127         COLON n=qualified_name  \r
128         { \r
129           tr = new TypeReference(n); \r
130         }\r
131         // (LBRACK RBRACK)? // We do not support multi-dimensional arrays yet\r
132         ;\r
134 name returns [Identifier ident]\r
135         { ident = null; }\r
136         :\r
137         t1:IDENT                { ident = new OpaqueIdentifier(t1.getText()); }\r
138         |\r
139         t2:STATICIDENT  { ident = new StaticVarIdentifier(t2.getText()); }\r
140         |\r
141         t3:INSTIDENT    { ident = new InstanceVarIdentifier(t3.getText()); }\r
142     ;\r
144 // qualified_symbol returns[String name]\r
145 //      { name = null; }\r
146 //      :\r
147 //      t:SYMBOL { name = t.getText().Substring(1); }\r
148 //     (options{greedy=true;}:DOT t2:IDENT { name += "." + t2.getText(); } )*\r
149 //     ;\r
151 protected \r
152 statement_term!\r
153     :\r
154     (options { greedy=true; }:(STATEMENT_END | SEMI | EOF))\r
155     ;\r
157 protected \r
158 nothing\r
159         :\r
160         (options { greedy=true; generateAmbigWarnings=false; }:(STATEMENT_END|EOF) )?\r
161         ;\r
163 sourceUnit[CompilationUnit cunit] returns[SourceUnit unit]\r
164         { \r
165           topLevelScope = cunit.DefiningSymbolTable;\r
166           unit = new SourceUnit(cunit, getFilename()); \r
167           PushScope(unit, ScopeType.SourceUnit); \r
168         }\r
169         :\r
170         nothing\r
171         (\r
172                 ("namespace" qualified_name) => namespace_declaration[unit.Namespaces]\r
173                 |\r
174                 suite[unit.Statements]\r
175         )\r
176         nothing\r
177         EOF\r
178         { \r
179           cunit.SourceUnits.Add(unit); \r
180           PopScope(); \r
181           if (!ErrorReport.HasErrors && scopes.Count != 0) \r
182             ErrorReport.Error("Invalid scope count. " + \r
183                         "Something seems to be very wrong. Contact Castle's team and report the " + \r
184                         "code that caused this error.");  \r
185         }\r
186         ;\r
188 namespace_declaration[IList namespaces]\r
189         options { defaultErrorHandler=true; }\r
190         { \r
191           NamespaceDescriptor nsdec = new NamespaceDescriptor(); \r
192           PushScope(nsdec, ScopeType.Namespace);\r
193           namespaces.Add(nsdec); String qn = null;\r
194           TypeDefinitionStatement typeDef = null;\r
195         }\r
196         :\r
197         t:"namespace" qn=qualified_name statement_term\r
198         { nsdec.Name = qn; }\r
199         (typeDef=type_def_statement { nsdec.TypeDefinitions.Add(typeDef); } )*\r
200         END     { PopScope(); }\r
201         ;\r
203 suite[IList stmts]\r
204         { IStatement stmt = null; }\r
205         :\r
206         (stmt=statement { if (stmt != null) stmts.Add(stmt); } )*\r
207         ;\r
209 type_suite[IList stmts]\r
210         { IStatement stmt = null; }\r
211         :\r
212         (access_level \r
213                 (\r
214                         stmt=statement { if (stmt != null) stmts.Add(stmt); } \r
215                         |\r
216                         method_scope[stmts]\r
217                 )\r
218         )*\r
219         ;\r
221 // class << self\r
222 //   def method <- will be static\r
223 // end\r
224 //\r
225 // class << override\r
226 //   def method <- will be override\r
227 // end\r
228 //\r
229 // class << new\r
230 //   def method <- will be new\r
231 // end\r
232 //\r
233 // class << final\r
234 //   def method <- will be final (not virtual or sealed)\r
235 // end\r
236 protected \r
237 method_scope[IList stmts]\r
238         { IStatement stmt = null; int index=0; }\r
239         :\r
240         CLASS SL \r
241         \r
242         (\r
243           "self"                { withinStatic = true; }\r
244           |\r
245           "override"    { index = 1; withinOverride = true; }\r
246           |\r
247           "abstract"    { index = 2; withinAbstract = true; }\r
248           |\r
249           "new"                 { index = 3; withinNew = true; }\r
250           |\r
251           "final"               { index = 4; withinFinal = true; }\r
252         )\r
254         statement_term\r
256     (access_level stmt=statement { if (stmt != null) stmts.Add(stmt); } )*\r
257         \r
258         END statement_term\r
259         { \r
260           if (index == 0)\r
261                 withinStatic = false;\r
262           else if (index == 1)\r
263                 withinOverride = false;\r
264           else if (index == 2)\r
265                 withinAbstract = false;\r
266           else if (index == 3)\r
267                 withinNew = false;\r
268           else if (index == 4)\r
269                 withinFinal = false;\r
270         }\r
271         ;\r
273 protected\r
274 access_level\r
275         :\r
276         (\r
277                 "public"^    { currentAccessLevel = AccessLevel.Public; }\r
278                 |\r
279                 "private"^   { currentAccessLevel = AccessLevel.Private; }\r
280                 |\r
281                 "protected"^ { currentAccessLevel = AccessLevel.Protected; }\r
282                 | \r
283                 "internal"^  { currentAccessLevel = AccessLevel.Internal; }\r
284                 |\r
285                         /* nothing - inherits the access level defined previously */  \r
286         )\r
287         ;\r
289 statement returns[IStatement stmt]\r
290         { stmt = null; }\r
291         :\r
292         (\r
293                 (declaration_statement) => stmt=declaration_statement\r
294                 // |\r
295                 // property_def_statement\r
296                 // |\r
297                 // operator_def_statement\r
298                 |\r
299                 stmt=type_def_statement\r
300                 // |\r
301                 // stmt=while_statement\r
302                 // |\r
303                 // stmt=until_statement\r
304                 // |\r
305                 // stmt=for_statement\r
306                 // |\r
307                 // stmt=if_statement\r
308                 // |\r
309                 // (unless_statement) => stmt=unless_statement\r
310                 |\r
311                 stmt=expression_statement\r
312                 // |\r
313                 // stmt=return_statement\r
314                 |\r
315                 stmt=require_statement\r
316         )\r
317         statement_term\r
318         ;\r
320 declaration_statement returns [MultipleVariableDeclarationStatement stmt]\r
321         { \r
322           stmt = new MultipleVariableDeclarationStatement(currentAccessLevel); \r
323           Identifier ident = null;\r
324           IExpression initExp = null; \r
325         }\r
326         :\r
327         ident=identifier_withtype                       { stmt.AddIdentifier(ident); }\r
328         (\r
329                 COMMA ident=identifier_withtype { stmt.AddIdentifier(ident); }\r
330         )* \r
331         (\r
332                 ASSIGN initExp=test { stmt.AddInitExp(initExp); } \r
333                 (COMMA initExp=test { stmt.AddInitExp(initExp); } )* \r
334         )?\r
335         ;\r
337 constructor_def_statement returns [ConstructorDefinitionStatement mdstmt]\r
338         { \r
339           mdstmt = new ConstructorDefinitionStatement( currentAccessLevel ); \r
340         }\r
341         :\r
342         DEF "initialize"\r
343         (\r
344                 LPAREN (methodParams[mdstmt])? RPAREN\r
345         )?\r
346         statement_term\r
347         suite[mdstmt.Statements]\r
348         END \r
349         ;\r
351 method_def_statement returns [MethodDefinitionStatement mdstmt]\r
352         { \r
353           mdstmt = new MethodDefinitionStatement( currentAccessLevel ); \r
354           String qn = null; TypeReference retType = null; \r
355         }\r
356         :\r
357         DEF^ modifier[mdstmt] qn=qualified_name \r
358         { \r
359             if (qn.StartsWith("self."))\r
360             {\r
361               mdstmt.IsStatic = true;\r
362               mdstmt.Name = qn.Substring( "self.".Length );\r
363             }\r
364             else\r
365             {\r
366                   mdstmt.Name = qn;\r
367             }\r
368                 PushScope(mdstmt, ScopeType.Method); \r
369         }\r
370         (\r
371                 LPAREN (methodParams[mdstmt])? RPAREN (retType=type)? \r
372         )?\r
373         statement_term\r
374         { mdstmt.ReturnType = retType; }\r
376         suite[mdstmt.Statements]\r
377         END \r
378         \r
379         { PopScope(); }\r
380         ;\r
382 protected\r
383 modifier[MethodDefinitionStatement mdstmt]\r
384         :\r
385         "override"                      { mdstmt.IsOverride = true; }\r
386         |\r
387         { withinOverride }? { mdstmt.IsOverride = true; }\r
388         |\r
389         "new"                           { mdstmt.IsNewSlot  = true; }\r
390         |\r
391         { withinNew }?          { mdstmt.IsNewSlot  = true; }\r
392         |\r
393         "abstract"                      { mdstmt.IsAbstract = true; }\r
394         |\r
395         { withinAbstract }?     { mdstmt.IsAbstract = true; }\r
396         |\r
397         "final"                         { mdstmt.IsFinal    = true; }\r
398         |\r
399         { withinFinal }?        { mdstmt.IsFinal    = true; }\r
400         |\r
401         { withinStatic }?       { mdstmt.IsStatic   = true; }\r
403         |\r
404         // nothing\r
405         ;\r
407 require_statement returns[RequireDirectiveStatement rd]\r
408         { rd = null; String ident = null; } \r
409         :\r
410         "require" ident=qualified_name { rd = new RequireDirectiveStatement(ident); }\r
411         ;\r
413 type_def_statement returns [TypeDefinitionStatement tdstmt]\r
414         { tdstmt = null; currentAccessLevel = AccessLevel.Public; }\r
415         :\r
416         tdstmt=class_def_statement\r
417         ;\r
419 class_def_statement returns [TypeDefinitionStatement tdstmt]\r
420         { tdstmt = null; String qn = null; }\r
421                                                 // TODO: Create ClassDefinitionStatement \r
422                                                 // and support modifiers like visibility and abstract etc\r
423         :\r
424         CLASS t:IDENT \r
425         { tdstmt = new TypeDefinitionStatement( currentAccessLevel, t.getText() );\r
426           PushScope(tdstmt, ScopeType.Type); \r
427         }\r
428         ( (LTHAN|SL) qn=qualified_name { tdstmt.BaseTypes.Add( new TypeReference(qn) ); }\r
429           (COMMA qn=qualified_name  { tdstmt.BaseTypes.Add( new TypeReference(qn) ); } )* \r
430         )? \r
431         statement_term\r
432         type_suite[tdstmt.Statements]\r
433         END { PopScope(); }\r
434         ;\r
436 methodParams[MethodDefinitionStatement mdstmt]\r
437         { ParameterVarIdentifier param = null; } \r
438         :\r
439         param=methodParam                       { mdstmt.AddFormalParameter( param ); } \r
440           (COMMA param=methodParam      { mdstmt.AddFormalParameter( param ); } )*\r
441         ;\r
443 methodParam returns [ParameterVarIdentifier param]\r
444         { IExpression exp = null; Identifier ident = null; param = null; }\r
445         :\r
446         (\r
447         ident=identifier                                { param = ParameterVarIdentifier.FromIdentifier(ParameterType.Ordinary, ident); } \r
448         |\r
449         (STAR identifier_withtype) => STAR ident=identifier_withtype    \r
450                                                                         { param = ParameterVarIdentifier.FromIdentifier(ParameterType.Params, ident); } \r
451         |\r
452         STAR ident=identifier                   { param = ParameterVarIdentifier.FromIdentifier(ParameterType.List, ident); } \r
453         |\r
454         BAND ident=identifier                   { param = ParameterVarIdentifier.FromIdentifier(ParameterType.Block, ident); } \r
455         )\r
456         (ASSIGN exp=expression  { param.InitExpression = exp; } )?\r
457         ;\r
459 expression_statement returns[IStatement stmt]\r
460         { stmt = null; PostfixCondition pfc = null; IExpression exp = null; IExpression rhs = null;\r
461           AugType rel = AugType.Undefined; }\r
462         :\r
463         (\r
464                 (compound) => exp=compound\r
465                 |\r
466                 exp=test\r
467                 (       \r
468                         rel=augassign rhs=test  { exp = new AugAssignmentExpression(exp, rhs, rel); }\r
469                         |\r
470                         (ASSIGN rhs=test                { exp = new AssignmentExpression(exp, rhs); } )+\r
471                 )?\r
472                 |\r
473                 exp=flow_expressions\r
474         )\r
475         (\r
476           pfc=postFixCondition \r
477           { exp.PostfixCondition = pfc; } \r
478         )?\r
479         { stmt = new ExpressionStatement(exp); }\r
480         |\r
481         stmt=method_def_statement\r
482         |\r
483         stmt=constructor_def_statement\r
484         ;\r
486 augassign returns [AugType rel]\r
487         { rel = AugType.Undefined; }\r
488     : PLUS_ASSIGN               { rel = AugType.PlusAssign; }\r
489         | MINUS_ASSIGN          { rel = AugType.MinusAssign; }\r
490         | STAR_ASSIGN           { rel = AugType.MultAssign; }\r
491         | DIV_ASSIGN            { rel = AugType.DivAssign; }\r
492         | MOD_ASSIGN            { rel = AugType.ModAssign; }\r
493         | BAND_ASSIGN           { rel = AugType.BitwiseAndAssign; }\r
494         | BOR_ASSIGN            { rel = AugType.BitwiseOrAssign; }\r
495         | BXOR_ASSIGN           { rel = AugType.BitwiseXorAssign; }\r
496 //      | LEFTSHIFTEQUAL\r
497 //      | RIGHTSHIFTEQUAL\r
498 //      | DOUBLESTAREQUAL\r
499 //      | DOUBLESLASHEQUAL\r
500         ;\r
502 postFixCondition returns[PostfixCondition pfc]\r
503         { pfc = null; IExpression exp; }\r
504         :\r
505         (\r
506                 ("if"                   { pfc = new PostfixCondition(PostfixConditionType.If); }\r
507                 |"unless"               { pfc = new PostfixCondition(PostfixConditionType.Unless); }\r
508                 |"while"                { pfc = new PostfixCondition(PostfixConditionType.While); }\r
509                 |"until"                { pfc = new PostfixCondition(PostfixConditionType.Until); }\r
510                 ) \r
511                 exp=test                { pfc.Condition = exp; }\r
512         )\r
513         ;\r
515 compound returns[CompoundExpression cexp]\r
516         { cexp = new CompoundExpression(); }\r
517         :\r
518         (DO^|BEGIN^) { PushScope(cexp, ScopeType.Compound); } \r
519         statement_term\r
520         suite[cexp.Statements]\r
521         END  { PopScope(); }\r
522         ;\r
524 flow_expressions returns[IExpression exp]\r
525         { exp = null; }\r
526         :\r
527         "redo"  { exp = new RedoExpression(); }\r
528         |\r
529         "break" { exp = new BreakExpression(); }\r
530         |\r
531         "next"  { exp = new NextExpression(); }\r
532         |\r
533         "retry" { exp = new RetryExpression(); }\r
534         ;\r
539 // Expressions\r
541 lambda returns [LambdaExpression lexp]\r
542         { BlockExpression bexp=null; lexp = null; }\r
543         :\r
544         "lambda"^ bexp=block\r
545         { lexp = new LambdaExpression(bexp); }\r
546         ;\r
548 block returns [BlockExpression bexp]\r
549         { bexp = new BlockExpression(); }\r
550         :\r
551         { PushScope(bexp, ScopeType.Block); }\r
552         (\r
553                 \r
554                 (DO nothing (blockargs[bexp])? (statement_term)? suite[bexp.Statements] END)\r
555                 |\r
556                 (LCURLY nothing (blockargs[bexp])? (statement_term)? suite[bexp.Statements] RCURLY)\r
557         )\r
558         { PopScope(); }\r
559         ;\r
561 raise returns [RaiseExpression rexp]\r
562         { rexp = null; IExpression exp; }\r
563         :\r
564         "raise" exp=expression  { rexp = new RaiseExpression(exp); }\r
565         ;\r
567 yield returns [YieldExpression rexp]\r
568         { rexp = new YieldExpression(); }\r
569         :\r
570         "yield" expressionList[rexp.ExpColl]\r
571         ;\r
573 blockargs[BlockExpression bexp]\r
574         { ParameterVarIdentifier ident = null; }\r
575         :\r
576         BOR ident=methodParam   \r
577         { bexp.AddBlockFormalParameter(ident); }\r
578         (options {greedy=true;}:COMMA ident=methodParam { bexp.AddBlockFormalParameter(ident); } )* \r
579         BOR\r
580         ;\r
583 test returns [IExpression exp]\r
584         { exp = null; IExpression rhs = null; }\r
585         : \r
586         // (block) => exp=block\r
587         // | \r
588         exp=and_test ("or" rhs=and_test { exp = new BinaryExpression(exp, rhs, BinaryOp.Or); })*\r
589         | \r
590         exp=lambda\r
591         |\r
592         exp=raise\r
593         | \r
594         exp=yield\r
595         ;\r
597 and_test returns [IExpression exp]\r
598         { exp = null; IExpression rhs = null; }\r
599         : \r
600         exp=not_test ("and" rhs=not_test { exp = new BinaryExpression(exp, rhs, BinaryOp.And); })*\r
601         ;\r
603 not_test returns [IExpression exp]\r
604         { exp = null; IExpression inner = null; }\r
605         : \r
606         ("not"|LNOT) inner=not_test { exp = new UnaryExpression(inner, UnaryOp.Not); }\r
607         | \r
608         exp=comparison\r
609         ;\r
611 comparison returns [IExpression exp]\r
612         { exp = null; IExpression rhs = null; BinaryOp op = BinaryOp.Undefined; }\r
613         : \r
614         exp=expression (op=comp_op rhs=expression { exp = new BinaryExpression(exp, rhs, op); } )*\r
615         ;\r
617 comp_op returns [BinaryOp op]\r
618         { op = BinaryOp.Undefined; }\r
619         : \r
620         LTHAN           { op = BinaryOp.LessThan; }\r
621         |\r
622         GT                      { op = BinaryOp.GreaterThan; }\r
623         |\r
624         EQUAL           { op = BinaryOp.Equal; }\r
625         |\r
626         GE                      { op = BinaryOp.GreaterEqual; }\r
627         |\r
628         LE                      { op = BinaryOp.LessEqual; }\r
629         |\r
630         NOT_EQUAL       { op = BinaryOp.NotEqual; }\r
631         |\r
632         "is"            { op = BinaryOp.IsA; }\r
633         \r
634 //      |ALT_NOTEQUAL\r
635 //      |"in"\r
636 //      |"not" "in"\r
637 //      |"is" "not"\r
638         ;\r
640 expressionList[IList expColl]\r
641         { IExpression exp = null; }\r
642         :\r
643         exp=expression { expColl.Add(exp); } \r
644         (options {greedy=true;}:COMMA exp=expression { expColl.Add(exp); } )*\r
645         ;       \r
647 expression returns [IExpression exp]\r
648         { exp = null; IExpression rhs = null; }\r
649         : \r
650         exp=xor_expr (BXOR rhs=xor_expr { exp = new BinaryExpression(exp, rhs, BinaryOp.Xor); })*\r
651         ;\r
653 xor_expr returns [IExpression exp]\r
654         { exp = null; IExpression rhs = null; }\r
655         : \r
656         exp=and_expr (options {greedy=true;}:BOR rhs=and_expr { exp = new BinaryExpression(exp, rhs, BinaryOp.Or2); })*\r
657         ;\r
659 and_expr returns [IExpression exp]\r
660         { exp = null; IExpression rhs = null; }\r
661         : \r
662         // shift_expr (BAND shift_expr)*\r
663         exp=arith_expr (BAND rhs=arith_expr { exp = new BinaryExpression(exp, rhs, BinaryOp.And2); })*\r
664         ;\r
666 // shift_expr: arith_expr ((LEFTSHIFT|RIGHTSHIFT) arith_expr)*\r
667 //      ;\r
669 arith_expr returns [IExpression exp]\r
670         { exp = null; IExpression rhs = null; }\r
671         : \r
672         exp=term ((t:PLUS|MINUS) rhs=term { exp = new BinaryExpression(exp, rhs, t != null ? BinaryOp.Plus : BinaryOp.Minus); })*\r
673         ;\r
675 term returns [IExpression exp]\r
676         { exp = null; IExpression rhs = null; BinaryOp op = BinaryOp.Undefined; }\r
677         : \r
678         exp=unary \r
679         (\r
680                 (\r
681                         STAR            { op = BinaryOp.Mult; }\r
682                         | SLASH         { op = BinaryOp.Div; }\r
683                         | PERCENT       { op = BinaryOp.Mod; }\r
684                 ) \r
685                 rhs=unary { exp = new BinaryExpression(exp, rhs, op); }\r
686         )*\r
687         ;\r
689 unary returns [IExpression exp]\r
690         { exp = null; IExpression inner = null; UnaryOp op = UnaryOp.Plus; }\r
691         : \r
692         (\r
693             PLUS        { op = UnaryOp.Plus; }\r
694           | MINUS       { op = UnaryOp.Minus; }\r
695           | BNOT        { op = UnaryOp.BitwiseNot; }\r
696         ) \r
697         inner=unary { exp = new UnaryExpression(inner, op); }\r
698         | \r
699         exp=primary\r
700         ;\r
702 primary returns [IExpression exp]\r
703         { exp = null; }\r
704         :\r
705         exp=atom (exp=trailer[exp])* \r
706         ;\r
708 atom returns [IExpression exp]\r
709         { exp = null; }\r
710         : \r
711         (range) => exp=range\r
712         | LPAREN (exp=test)? RPAREN // LPAREN (testlist)? RPAREN\r
713         | LBRACK (exp=listmaker)? RBRACK\r
714         | LCURLY (exp=dictmaker)? RCURLY\r
715         | exp=varref\r
716         | exp=constantref\r
717         | "self" { exp = SelfReferenceExpression.Instance; }\r
718         | "base" { exp = BaseReferenceExpression.Instance; }\r
719         ;\r
721 varref returns [VariableReferenceExpression vre]\r
722         { Identifier ident = null; vre = null; }\r
723         :\r
724         ident=name\r
725         { vre = new VariableReferenceExpression(ident); }\r
726         ;\r
728 constantref returns [ConstExpression lre]\r
729         { lre = null; }\r
730         :\r
731           t1:NUM_INT\r
732           { lre = new ConstExpression(t1.getText(), ConstExpressionType.IntLiteral); }\r
733         | t2:NUM_LONG\r
734           { lre = new ConstExpression(t2.getText(), ConstExpressionType.LongLiteral); }\r
735         | t3:NUM_FLOAT\r
736           { lre = new ConstExpression(t3.getText(), ConstExpressionType.FloatLiteral); }\r
737 //      | t4:SYMBOL\r
738 //        { lre = new ConstExpression(t4.getText(), ConstExpressionType.SymbolLiteral); }\r
739         | t5:STRING_LITERAL\r
740           { lre = new ConstExpression(t5.getText(), ConstExpressionType.StringLiteral); }\r
741         | t6:CHAR_LITERAL\r
742           { lre = new ConstExpression(t6.getText(), ConstExpressionType.CharLiteral); }\r
743         ;\r
745 trailer[IExpression inner] returns [IExpression exp]\r
746         { exp = null; BlockExpression temp = null; String qp = String.Empty; }\r
747         : \r
748         LPAREN \r
749         { exp = new MethodInvocationExpression(inner); } \r
750           (arglist[(exp as MethodInvocationExpression).Arguments])? \r
751         RPAREN \r
752         |\r
753         temp=block\r
754         {\r
755           exp = inner;\r
756           exp.Block = temp;\r
757         }\r
758         | \r
759 //      LBRACK subscriptlist RBRACK // TODO: Array/indexer access\r
760 //      | \r
761 //      (DOT|COLONCOLON) => qp=qualified_postfix        { exp = new MemberAccessExpression(inner, qp); }\r
762         COLONCOLON t1:IDENT     { exp = new MemberAccessExpression(inner, t1.getText()); }\r
763         |\r
764         DOT "nil?" { exp = new NullCheckExpression(inner); }\r
765         |\r
766         DOT t:IDENT { exp = new MemberAccessExpression(inner, t.getText()); }\r
767         ;\r
769 range returns[IExpression rex]\r
770         { rex = null; IExpression lhs = null; IExpression rhs = null; }\r
771         :\r
772         LPAREN lhs=expression (t:DOTDOT|DOTDOTDOT) rhs=expression RPAREN\r
773         { rex = new RangeExpression(lhs, rhs, t != null); }\r
774         ;\r
776 // subscriptlist\r
777 //     :   \r
778 //     subscript (options {greedy=true;}:COMMA subscript)*\r
779 //      ;\r
781 // subscript\r
782 //      : \r
783 //     expression\r
784 //     ;\r
786 arglist[IList expcoll]\r
787         { IExpression exp; }\r
788         : \r
789         exp=argument            { expcoll.Add(exp); }\r
790         (options {greedy=true;}:COMMA exp=argument { expcoll.Add(exp); } )*\r
791         /*\r
792         ( COMMA\r
793           ( STAR test (COMMA DOUBLESTAR test)?\r
794           | DOUBLESTAR test\r
795           )?\r
796         )?\r
797     |   STAR test (COMMA DOUBLESTAR test)?\r
798     |   DOUBLESTAR test\r
799     */\r
800     ;\r
802 argument returns [IExpression exp]\r
803         { exp = null; }\r
804         : \r
805         exp=test //(ASSIGN test)?\r
806         ;\r
808 listmaker returns [ListExpression exp]\r
809         { exp = new ListExpression(); IExpression item; }\r
810         : \r
811         item=test \r
812           { exp.Add(item); }\r
813         (options {greedy=true;}:COMMA item=test { exp.Add(item); } )* \r
814         ;\r
816 dictmaker returns [DictExpression exp]\r
817         { exp = new DictExpression(); IExpression key, value; }\r
818     :   \r
819     key=expression MAPASSIGN value=test\r
820       { exp.Add(key, value); }\r
821     (options {greedy=true;}:COMMA key=expression MAPASSIGN value=test \r
822       { exp.Add(key, value); } )* \r
823     ;\r
828 class RookLexer extends Lexer;\r
830 options \r
832         exportVocab=Rook;      \r
833         testLiterals=false;    // don't automatically test for literals\r
834         k=4;                   // four characters of lookahead\r
835         charVocabulary='\u0003'..'\uFFFF';\r
836         // without inlining some bitset tests, couldn't do unicode;\r
837         codeGenBitsetTestThreshold=20;\r
840     private int lastToken = 0;\r
842     private int getProperType() \r
843     {\r
844         int result;\r
845         if (lastToken == STATEMENT_END || lastToken == SEMI ) \r
846         {\r
847             result = Token.SKIP;\r
848         } \r
849         else \r
850         {\r
851             result = STATEMENT_END;\r
852         }\r
853         return result;\r
854     }\r
856         protected internal override IToken makeToken(int type) {\r
857                 lastToken = type;\r
858                 return base.makeToken(type);\r
859         }\r
862 // OPERATORS\r
863 QUESTION                :       '?'             ;\r
864 LPAREN                  :       '('             ;\r
865 RPAREN                  :       ')'             ;\r
866 LBRACK                  :       '['             ;\r
867 RBRACK                  :       ']'             ;\r
868 LCURLY                  :       '{'             ;\r
869 RCURLY                  :       '}'             ;\r
870 COMMA                   :       ','             ;\r
871 DOT                             :       '.'             ;\r
872 DOTDOT                  :       ".."    ;\r
873 DOTDOTDOT               :       "..."   ;\r
874 ASSIGN                  :       '='             ;\r
875 EQUAL                   :       "=="    ;\r
876 LNOT                    :       '!'             ;\r
877 BNOT                    :       '~'             ;\r
878 NOT_EQUAL               :       "!="    ;\r
879 DIV                             :       '/'             ;\r
880 DIV_ASSIGN              :       "/="    ;\r
881 PLUS                    :       '+'             ;\r
882 PLUS_ASSIGN             :       "+="    ;\r
883 INC                             :       "++"    ;\r
884 MINUS                   :       '-'             ;\r
885 MINUS_ASSIGN    :       "-="    ;\r
886 DEC                             :       "--"    ;\r
887 STAR                    :       '*'             ;\r
888 STAR_ASSIGN             :       "*="    ;\r
889 MOD                             :       '%'             ;\r
890 MOD_ASSIGN              :       "%="    ;\r
891 SR                              :       ">>"    ;\r
892 SR_ASSIGN               :       ">>="   ;\r
893 BSR                             :       ">>>"   ;\r
894 BSR_ASSIGN              :       ">>>="  ;\r
895 GE                              :       ">="    ;\r
896 GT                              :       ">"             ;\r
897 SL                              :       "<<"    ;\r
898 SL_ASSIGN               :       "<<="   ;\r
899 LE                              :       "<="    ;\r
900 LTHAN                   :       '<'             ;\r
901 BXOR                    :       '^'             ;\r
902 BXOR_ASSIGN             :       "^="    ;\r
903 BOR                             :       '|'             ;\r
904 BOR_ASSIGN              :       "|="    ;\r
905 LOR                             :       "||"    ;\r
906 BAND                    :       '&'             ;\r
907 BAND_ASSIGN             :       "&="    ;\r
908 LAND                    :       "&&"    ;\r
909 SEMI                    :       ';'             ;\r
910 MAPASSIGN               :       "=>"    ;\r
911 COLON                   :       ':'             ;\r
912 COLONCOLON              :       "::"    ;\r
914 NEWLINE\r
915         options { paraphrase = "a new line"; }\r
916         :\r
917         SL_NEWLINE \r
918         {\r
919                 newline();\r
920                 $setType(getProperType());\r
921         }\r
922         (   \r
923                 (SL_NEWLINE | WS | SL_COMMENT)+\r
924         )?\r
925         ;\r
927 /*\r
928         options { paraphrase = "a new line"; }\r
929         : \r
930         ( '\r' '\n' | '\n' | '\r') \r
931         {\r
932                 newline();\r
933                 $setType(getProperType());\r
934         }\r
935         (   (WS | SL_COMMENT)+   )?\r
936         ;\r
938 */\r
940 protected \r
941 SL_NEWLINE\r
942         :\r
943         (   options {generateAmbigWarnings=false;}:\r
944                 "\r\n"\r
945                 |   \r
946                 '\r'\r
947                 |   \r
948                 '\n'\r
949         )\r
950     ;\r
952 SL_COMMENT\r
953         options { paraphrase = "comments"; }\r
954         :       '#'\r
955                 ( options {  greedy = true;  }: ~('\n'|'\r'|'\uffff') )*\r
956                 {$setType(Token.SKIP); }\r
957         ;\r
959 WS\r
960         :       \r
961         ( options { greedy=true; }:' ' | '\t' | '\f' )+\r
962         { $setType(Token.SKIP); }\r
963         ;\r
965 // multiple-line comments\r
966 // \r
967 // ML_COMMENT\r
968 //      :       "/*"\r
969 //              (       /*      '\r' '\n' can be matched in one alternative or by matching\r
970 //                              '\r' in one iteration and '\n' in another.  I am trying to\r
971 //                              handle any flavor of newline that comes in, but the language\r
972 //                              that allows both "\r\n" and "\r" and "\n" to all be valid\r
973 //                              newline is ambiguous.  Consequently, the resulting grammar\r
974 //                              must be ambiguous.  I'm shutting this warning off.\r
975 //                       */\r
976 //                      options {\r
977 //                              generateAmbigWarnings=false;\r
978 //                      }\r
979 //              :\r
980 //                      { LA(2)!='/' }? '*'\r
981 //              |       '\r' '\n'               {newline();}\r
982 //              |       '\r'                    {newline();}\r
983 //              |       '\n'                    {newline();}\r
984 //              |       ~('*'|'\n'|'\r')\r
985 //              )*\r
986 //              "*/"\r
987 //              {$setType(Token.SKIP);}\r
988 //      ;\r
990 // character literals\r
991 CHAR_LITERAL\r
992         :       '\'' ( ESC | ~'\'' ) '\''\r
993         ;\r
995 // string literals\r
996 STRING_LITERAL\r
997         :       '"' (ESC|~('"'|'\\'))* '"'\r
998         ;\r
1000 // escape sequence -- note that this is protected; it can only be called\r
1001 //   from another lexer rule -- it will not ever directly return a token to\r
1002 //   the parser\r
1003 // There are various ambiguities hushed in this rule.  The optional\r
1004 // '0'...'9' digit matches should be matched here rather than letting\r
1005 // them go back to STRING_LITERAL to be matched.  ANTLR does the\r
1006 // right thing by matching immediately; hence, it's ok to shut off\r
1007 // the FOLLOW ambig warnings.\r
1008 protected\r
1009 ESC\r
1010         :       '\\'\r
1011                 (       'n'\r
1012                 |       'r'\r
1013                 |       't'\r
1014                 |       'b'\r
1015                 |       'f'\r
1016                 |       '"'\r
1017                 |       '\''\r
1018                 |       '\\'\r
1019                 |       ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT\r
1020                 |       '0'..'3'\r
1021                         (\r
1022                                 options {\r
1023                                         warnWhenFollowAmbig = false;\r
1024                                 }\r
1025                         :       '0'..'7'\r
1026                                 (\r
1027                                         options {\r
1028                                                 warnWhenFollowAmbig = false;\r
1029                                         }\r
1030                                 :       '0'..'7'\r
1031                                 )?\r
1032                         )?\r
1033                 |       '4'..'7'\r
1034                         (\r
1035                                 options {\r
1036                                         warnWhenFollowAmbig = false;\r
1037                                 }\r
1038                         :       '0'..'7'\r
1039                         )?\r
1040                 )\r
1041         ;\r
1043 // hexadecimal digit (again, note it's protected!)\r
1044 protected\r
1045 HEX_DIGIT\r
1046         :       ('0'..'9'|'A'..'F'|'a'..'f')\r
1047         ;\r
1049 // a dummy rule to force vocabulary to be all characters (except special\r
1050 //   ones that ANTLR uses internally (0 to 2)\r
1051 protected\r
1052 VOCAB\r
1053         :       '\3'..'\377'\r
1054         ;\r
1056 IDENT\r
1057         options {testLiterals=true;}\r
1058         :       ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')* ('?'|'!')?\r
1059         ;\r
1061 INSTIDENT\r
1062         :       \r
1063         '@' IDENT\r
1064         ;\r
1066 STATICIDENT\r
1067         :       \r
1068         "@@" IDENT\r
1069         ;\r
1071 // SYMBOL\r
1072 //      :\r
1073 //      COLON IDENT \r
1074 //      ;\r
1076 // a numeric literal\r
1077 /*\r
1078 NUM_INT\r
1079         {boolean isDecimal=false; Token t=null;}\r
1080     :   '.' {_ttype = DOT;}\r
1081             (   ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?\r
1082                 {\r
1083                                 if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {\r
1084                         _ttype = NUM_FLOAT;\r
1085                                 }\r
1086                                 else {\r
1087                         _ttype = NUM_DOUBLE; // assume double\r
1088                                 }\r
1089                                 }\r
1090             )?\r
1092         |       (       '0' {isDecimal = true;} // special case for just '0'\r
1093                         (       ('x'|'X')\r
1094                                 (                                                                                       // hex\r
1095                                         // the 'e'|'E' and float suffix stuff look\r
1096                                         // like hex digits, hence the (...)+ doesn't\r
1097                                         // know when to stop: ambig.  ANTLR resolves\r
1098                                         // it correctly by matching immediately.  It\r
1099                                         // is therefor ok to hush warning.\r
1100                                         options {\r
1101                                                 warnWhenFollowAmbig=false;\r
1102                                         }\r
1103                                 :       HEX_DIGIT\r
1104                                 )+\r
1105                         |       ('0'..'7')+                                                                     // octal\r
1106                         )?\r
1107                 |       ('1'..'9') ('0'..'9')*  {isDecimal=true;}               // non-zero decimal\r
1108                 )\r
1109                 (       ('l'|'L') { _ttype = NUM_LONG; }\r
1111                 // only check to see if it's a float if looks like decimal so far\r
1112                 |       {isDecimal}?\r
1113             (   '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?\r
1114             |   EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?\r
1115             |   f4:FLOAT_SUFFIX {t=f4;}\r
1116             )\r
1117             {\r
1118                         if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {\r
1119                 _ttype = NUM_FLOAT;\r
1120                         }\r
1121             else {\r
1122                         _ttype = NUM_DOUBLE; // assume double\r
1123                         }\r
1124                         }\r
1125         )?\r
1126         ;\r
1128 // a couple protected methods to assist in matching floating point numbers\r
1129 protected\r
1130 EXPONENT\r
1131         :       \r
1132         ('e'|'E') ('+'|'-')? ('0'..'9')+\r
1133         ;\r
1135 protected\r
1136 FLOAT_SUFFIX\r
1137         :       \r
1138         'f'|'F'|'d'|'D'\r
1139         ;\r
1140 */\r
1142 NUMBER\r
1143         :\r
1144         ( Int DOTDOT ) => Int {$setType(NUM_INT);}\r
1145         |\r
1146         ( Int DOTDOTDOT ) => Int {$setType(NUM_INT);}\r
1147         |\r
1148         // Hex\r
1149     '0' ('x' | 'X') ( '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' )+ {$setType(NUM_INT);} ('l' | 'L' {$setType(NUM_LONG);})?\r
1150 //    |   // Octal\r
1151 //        '0' Int {$setType(NUM_INT);}\r
1152 //              (   FloatTrailer\r
1153 //        |   ('l' | 'L')       {$setType(NUM_LONG);}\r
1154 //        )?\r
1155     |  \r
1156         Int {$setType(NUM_INT);}\r
1157         (   \r
1158                 FloatTrailer {$setType(NUM_FLOAT);}\r
1159         |   \r
1160         ('l' | 'L')     {$setType(NUM_LONG);}\r
1161     )?\r
1162 //    |   // Int or float\r
1163 //        (     NonZeroDigit (Int)?\r
1164 //                      (       ('l' | 'L')     {$setType(NUM_LONG);}\r
1165 //                      |       FloatTrailer {$setType(NUM_FLOAT);}\r
1166 //                      |       {$setType(NUM_INT);}\r
1167 //                      )\r
1168 //              )\r
1169 //      |       '.' Int (Exponent)? {$setType(FLOAT);}\r
1170 //    |   '.' {$setType(DOT);} // DOT (non number; e.g., field access)\r
1171         ;\r
1173 protected\r
1174 Int : ( '0' .. '9' )+ ;\r
1176 protected\r
1177 NonZeroDigit : '1' .. '9' ;\r
1179 protected\r
1180 FloatTrailer\r
1181         :       \r
1182 //      '.'\r
1183 //      |       \r
1184         '.' Int (Exponent)?\r
1185 //      |   \r
1186 //      Exponent\r
1187         ;\r
1189 protected\r
1190 Exponent\r
1191         :       ('e' | 'E') ( '+' | '-' )? Int\r
1192         ;\r
1194 /** Consume a newline and any whitespace at start of next line */\r
1195 CONTINUED_LINE\r
1196         :       \r
1197         '\\' ('\r')? '\n' (' '|'\t')* { newline(); $setType(Token.SKIP); }\r
1198         ;\r