1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 15 Sep 05 Brian Frank Creation
7 // 6 Jun 06 Brian Frank Ported from Java to Fan
8 //
9
10 **
11 ** Parser is responsible for parsing a list of tokens into the
12 ** abstract syntax tree. At this point the CompilationUnit, Usings,
13 ** and TypeDefs are already populated by the ScanForUsingAndTypes
14 ** step.
15 **
16 public class Parser : CompilerSupport
17 {
18
19 //////////////////////////////////////////////////////////////////////////
20 // Construction
21 //////////////////////////////////////////////////////////////////////////
22
23 **
24 ** Construct the parser for the specified compilation unit.
25 **
26 new make(Compiler compiler, CompilationUnit unit, ClosureExpr[] closures)
27 : super(compiler)
28 {
29 this.unit = unit
30 this.tokens = unit.tokens
31 this.numTokens = unit.tokens.size
32 this.closures = closures
33 this.suppressErr = false
34 if (compiler != null) this.isSys = compiler.isSys
35 reset(0)
36 }
37
38 //////////////////////////////////////////////////////////////////////////
39 // Access
40 //////////////////////////////////////////////////////////////////////////
41
42 **
43 ** Top level parse a compilation unit:
44 **
45 ** <compilationUnit> := [<usings>] <typeDef>*
46 **
47 Void parse()
48 {
49 usings
50 while (curt !== Token.eof) typeDef
51 }
52
53 //////////////////////////////////////////////////////////////////////////
54 // Usings
55 //////////////////////////////////////////////////////////////////////////
56
57 **
58 ** Parse <using>* - note that we are just skipping them because
59 ** they are already parsed by ScanForUsingsAndTypes.
60 **
61 ** <using> := <usingPod> | <usingType> | <usingAs>
62 ** <usingPod> := "using" <id> <eos>
63 ** <usingType> := "using" <id> "::" <id> <eos>
64 ** <usingAs> := "using" <id> "::" <id> "as" <id> <eos>
65 **
66 private Void usings()
67 {
68 while (curt == Token.usingKeyword)
69 {
70 consume
71 consumeId
72 if (curt === Token.doubleColon)
73 {
74 consume
75 consumeId
76 if (curt === Token.asKeyword)
77 {
78 consume
79 consumeId
80 }
81 }
82 endOfStmt
83 }
84 }
85
86 //////////////////////////////////////////////////////////////////////////
87 // TypeDef
88 //////////////////////////////////////////////////////////////////////////
89
90 **
91 ** TypeDef:
92 ** <typeDef> := <classDef> | <mixinDef> | <enumDef>
93 **
94 ** <classDef> := <classHeader> <classBody>
95 ** <classHeader> := [<doc>] <facets> <typeFlags> "class" [<inheritance>]
96 ** <classFlags> := [<protection>] ["abstract"] ["final"]
97 ** <classBody> := "{" <slotDefs> "}"
98 **
99 ** <enumDef> := <enumHeader> <enumBody>
100 ** <enumHeader> := [<doc>] <facets> <protection> "enum" [<inheritance>]
101 ** <enumBody> := "{" <enumDefs> <slotDefs> "}"
102 **
103 ** <mixinDef> := <enumHeader> <enumBody>
104 ** <mixinHeader> := [<doc>] <facets> <protection> "mixin" [<inheritance>]
105 ** <mixinBody> := "{" <slotDefs> "}"
106 **
107 ** <protection> := "public" | "protected" | "private" | "internal"
108 ** <inheritance> := ":" <typeList>
109 **
110 Void typeDef()
111 {
112 // [<doc>]
113 doc := doc()
114 if (curt === Token.eof) return
115
116 // <facets>
117 facets := facets()
118
119 // <flags>
120 flags := flags(false)
121 if (flags & ~ProtectionMask == 0) flags |= FConst.Public
122
123 // local working variables
124 loc := cur
125 isMixin := false
126 isEnum := false
127
128 // mixin, enum, or class
129 if (curt === Token.mixinKeyword)
130 {
131 if (flags & FConst.Abstract != 0) err("The 'abstract' modifier is implied on mixin", loc)
132 if (flags & FConst.Const != 0) err("Cannot use 'const' modifier on mixin", loc)
133 if (flags & FConst.Final != 0) err("Cannot use 'final' modifier on mixin", loc)
134 flags |= FConst.Mixin | FConst.Abstract
135 isMixin = true
136 consume
137 }
138 else if (curt === Token.enumKeyword)
139 {
140 if (flags & FConst.Const != 0) err("The 'const' modifier is implied on enum", loc)
141 if (flags & FConst.Final != 0) err("The 'final' modifier is implied on enum", loc)
142 if (flags & FConst.Abstract != 0) err("Cannot use 'abstract' modifier on enum", loc)
143 flags |= FConst.Enum | FConst.Const | FConst.Final
144 isEnum = true
145 consume
146 }
147 else
148 {
149 consume(Token.classKeyword)
150 }
151
152 // name
153 name := consumeId
154 // lookup TypeDef
155 def := unit.types.find |TypeDef def->Bool| { return def.name == name }
156 if (def == null) throw err("Invalid class definition", cur)
157
158 // populate it's doc, facets, and flags
159 def.doc = doc
160 def.facets = facets
161 def.flags = flags
162
163 // inheritance
164 if (curt === Token.colon)
165 {
166 // first inheritance type can be extends or mixin
167 consume
168 first := typeRef
169 if (!first.isMixin)
170 def.base = first
171 else
172 def.mixins.add(first)
173
174 // additional mixins
175 while (curt === Token.comma)
176 {
177 consume
178 def.mixins.add(typeRef)
179 }
180 }
181
182 // if no inheritance specified then apply default base class
183 if (def.base == null)
184 {
185 def.baseSpecified = false
186 if (isEnum)
187 def.base = ns.enumType
188 else if (def.qname != "sys::Obj")
189 def.base = ns.objType
190 }
191
192 // start class body
193 consume(Token.lbrace)
194
195 // if enum, parse values
196 if (isEnum) enumDefs(def)
197
198 // slots
199 curType = def
200 closureCount = 0
201 while (true)
202 {
203 doc = this.doc
204 if (curt === Token.rbrace) break
205 slot := slotDef(def, doc)
206
207 // do duplicate name error checking here
208 if (def.hasSlotDef(slot.name))
209 {
210 err("Duplicate slot name '$slot.name'", slot.location)
211 }
212 else
213 {
214 def.addSlot(slot)
215 }
216 }
217 closureCount = null
218 curType = null
219
220 // end of class body
221 consume(Token.rbrace)
222 }
223
224 private Void mixins(TypeDef def)
225 {
226 consume // extends or mixin
227 def.mixins.add(typeRef)
228 while (curt === Token.comma)
229 {
230 consume
231 def.mixins.add(typeRef)
232 }
233 }
234
235 //////////////////////////////////////////////////////////////////////////
236 // Flags
237 //////////////////////////////////////////////////////////////////////////
238
239 **
240 ** Parse any list of flags in any order, we will check invalid
241 ** combinations in the CheckErrors step.
242 **
243 private Int flags(Bool normalize := true)
244 {
245 loc := cur
246 flags := 0
247 protection := false
248 for (done := false; !done; )
249 {
250 oldFlags := flags
251 switch (curt)
252 {
253 case Token.abstractKeyword: flags |= FConst.Abstract
254 case Token.constKeyword: flags |= FConst.Const
255 case Token.finalKeyword: flags |= FConst.Final
256 case Token.internalKeyword: flags |= FConst.Internal; protection = true
257 case Token.nativeKeyword: flags |= FConst.Native
258 case Token.newKeyword: flags |= FConst.Ctor
259 case Token.overrideKeyword: flags |= FConst.Override
260 case Token.privateKeyword: flags |= FConst.Private; protection = true
261 case Token.protectedKeyword: flags |= FConst.Protected; protection = true
262 case Token.publicKeyword: flags |= FConst.Public; protection = true
263 case Token.readonlyKeyword: flags |= Readonly // Parser only flag
264 case Token.staticKeyword: flags |= FConst.Static
265 case Token.virtualKeyword: flags |= FConst.Virtual
266 default: done = true
267 }
268 if (done) break
269 if (oldFlags == flags) err("Repeated modifier")
270 oldFlags = flags
271 consume
272 }
273
274 if ((flags & FConst.Abstract !== 0) && (flags & FConst.Virtual !== 0))
275 err("Abstract implies virtual", loc)
276 if ((flags & FConst.Override !== 0) && (flags & FConst.Virtual !== 0))
277 err("Override implies virtual", loc)
278
279 if (normalize)
280 {
281 if (!protection) flags |= FConst.Public
282 if (flags & FConst.Abstract !== 0) flags |= FConst.Virtual
283 if (flags & FConst.Override !== 0)
284 {
285 if (flags & FConst.Final !== 0)
286 flags &= ~FConst.Final
287 else
288 flags |= FConst.Virtual
289 }
290 }
291
292 return flags
293 }
294
295 //////////////////////////////////////////////////////////////////////////
296 // Enum
297 //////////////////////////////////////////////////////////////////////////
298
299 **
300 ** Enum definition list:
301 ** <enumDefs> := <enumDef> ("," <enumDef>)* <eos>
302 **
303 private Void enumDefs(TypeDef def)
304 {
305 ordinal := 0
306 def.enumDefs.add(enumDef(ordinal++))
307 while (curt === Token.comma)
308 {
309 consume
310 def.enumDefs.add(enumDef(ordinal++))
311 }
312 endOfStmt
313 }
314
315 **
316 ** Enum definition:
317 ** <enumDef> := <id> ["(" <args> ")"]
318 **
319 private EnumDef enumDef(Int ordinal)
320 {
321 doc := doc()
322
323 def := EnumDef.make(cur)
324 def.doc = doc
325 def.ordinal = ordinal
326 def.name = consumeId
327
328 // optional ctor args
329 if (curt === Token.lparen)
330 {
331 consume(Token.lparen)
332 if (curt != Token.rparen)
333 {
334 while (true)
335 {
336 def.ctorArgs.add( expr )
337 if (curt === Token.rparen) break
338 consume(Token.comma);
339 }
340 }
341 consume(Token.rparen)
342 }
343
344 return def
345 }
346
347 //////////////////////////////////////////////////////////////////////////
348 // Slots
349 //////////////////////////////////////////////////////////////////////////
350
351 **
352 ** Slot definition:
353 ** <slotDef> := <fieldDef> | <methodDef> | <ctorDef>
354 **
355 private SlotDef slotDef(TypeDef parent, Str[] doc)
356 {
357 // check for static {} class initialization
358 if (curt === Token.staticKeyword && peekt === Token.lbrace)
359 {
360 location := cur
361 consume
362 curMethod = MethodDef.makeStaticInit(location, parent, null)
363 curMethod.code = block(true)
364 return curMethod
365 }
366
367 // all members start with facets, flags
368 loc := cur
369 facets := facets()
370 flags := flags()
371
372 // check if this is a Java style constructor, log error and parse like Fan sytle ctor
373 if (curt === Token.identifier && cur.val == parent.name && peekt == Token.lparen)
374 {
375 err("Invalid constructor syntax - use new keyword")
376 return methodDef(loc, parent, doc, facets, flags|FConst.Ctor, TypeRef.make(loc, ns.voidType), consumeId)
377 }
378
379 // check for inferred typed field
380 // if = used rather than := then fieldDef() will log error
381 if (curt === Token.identifier && (peekt === Token.defAssign || peekt === Token.assign))
382 {
383 name := consumeId
384 return fieldDef(loc, parent, doc, facets, flags, null, name)
385 }
386
387 // check for constructor
388 if (flags & FConst.Ctor !== 0)
389 {
390 name := consumeId
391 return methodDef(loc, parent, doc, facets, flags, TypeRef.make(loc, ns.voidType), name)
392 }
393
394 // otherwise must be field or method
395 type := typeRef
396 name := consumeId
397 if (curt === Token.lparen)
398 {
399 return methodDef(loc, parent, doc, facets, flags, type, name)
400 }
401 else
402 {
403 return fieldDef(loc, parent, doc, facets, flags, type, name)
404 }
405 }
406
407 //////////////////////////////////////////////////////////////////////////
408 // FieldDef
409 //////////////////////////////////////////////////////////////////////////
410
411 **
412 ** Field definition:
413 ** <fieldDef> := <facets> <fieldFlags> [<type>] <id> [":=" <expr>]
414 ** [ "{" [<fieldGetter>] [<fieldSetter>] "}" ] <eos>
415 ** <fieldFlags> := [<protection>] ["readonly"] ["static"]
416 ** <fieldGetter> := "get" (<eos> | <block>)
417 ** <fieldSetter> := <protection> "set" (<eos> | <block>)
418 **
419 private FieldDef fieldDef(Location loc, TypeDef parent, Str[] doc, Str:FacetDef facets, Int flags, TypeRef type, Str name)
420 {
421 // define field itself
422 field := FieldDef.make(loc, parent)
423 field.doc = doc
424 field.facets = facets
425 field.flags = flags & ~ParserFlagsMask
426 field.fieldType = type
427 field.name = name
428
429 // const always has storage, otherwise assume no storage
430 // until proved otherwise in ResolveExpr step or we
431 // auto-generate getters/setters
432 if (field.isConst)
433 field.flags |= FConst.Storage
434
435 // field initializer
436 if (curt === Token.defAssign || curt === Token.assign)
437 {
438 if (curt === Token.assign) err("Must use := for field initialization")
439 consume
440 inFieldInit = true
441 field.init = expr
442 inFieldInit = false
443 }
444
445 // disable type inference for now - doing inference for literals is
446 // pretty trivial, but other types is tricky; I'm not sure it is such
447 // a hot idea anyways so it may just stay disabled forever
448 if (type == null)
449 err("Type inference not supported for fields", loc)
450
451 // if not const, define getter/setter methods
452 if (!field.isConst) defGetAndSet(field)
453
454 // explicit getter or setter
455 if (curt === Token.lbrace)
456 {
457 consume(Token.lbrace)
458 getOrSet(field)
459 getOrSet(field)
460 consume(Token.rbrace)
461 }
462
463 // generate synthetic getter or setter code if necessary
464 if (!field.isConst)
465 {
466 if (field.get.code == null) genSyntheticGet(field)
467 if (field.set.code == null) genSyntheticSet(field)
468 }
469
470 // readonly is syntatic sugar for { private set }
471 if (flags & Readonly !== 0)
472 {
473 field.set.flags = (field.set.flags & ProtectionMask) | FConst.Private
474 }
475
476 endOfStmt
477 return field
478 }
479
480 private Void defGetAndSet(FieldDef f)
481 {
482 loc := f.location
483
484 // getter MethodDef
485 get := MethodDef.make(loc, f.parentDef)
486 get.accessorFor = f
487 get.flags = f.flags | FConst.Getter
488 get.name = f.name
489 get.ret = f.fieldType
490 f.get = get
491
492 // setter MethodDef
493 set := MethodDef.make(loc, f.parentDef)
494 set.accessorFor = f
495 set.flags = f.flags | FConst.Setter
496 set.name = f.name
497 set.ret = ns.voidType
498 set.params.add(ParamDef.make(loc, f.fieldType, "val"))
499 f.set = set
500 }
501
502 private Void genSyntheticGet(FieldDef f)
503 {
504 loc := f.location
505 f.get.flags |= FConst.Synthetic
506 if (!f.isAbstract)
507 {
508 f.flags |= FConst.Storage
509 f.get.code = Block.make(loc)
510 f.get.code.add(ReturnStmt.make(loc, f.makeAccessorExpr(loc, false)))
511 }
512 }
513
514 private Void genSyntheticSet(FieldDef f)
515 {
516 loc := f.location
517 f.set.flags |= FConst.Synthetic
518 if (!f.isAbstract)
519 {
520 f.flags |= FConst.Storage
521 lhs := f.makeAccessorExpr(loc, false)
522 rhs := UnknownVarExpr.make(loc, null, "val")
523 f.set.code = Block.make(loc)
524 f.set.code.add(BinaryExpr.makeAssign(lhs, rhs).toStmt)
525 f.set.code.add(ReturnStmt.make(loc))
526 }
527 }
528
529 private Void getOrSet(FieldDef f)
530 {
531 loc := cur
532 accessorFlags := flags(false)
533 if (curt === Token.identifier)
534 {
535 // get or set
536 idLoc := cur
537 id := consumeId
538
539 if (id == "get")
540 curMethod = f.get
541 else
542 curMethod = f.set
543
544 // { ...block... }
545 Block block := null
546 if (curt === Token.lbrace)
547 block = this.block(id != "get")
548 else
549 endOfStmt
550
551 // const field cannot have getter/setter
552 if (f.isConst)
553 {
554 err("Const field '$f.name' cannot have ${id}ter", idLoc)
555 return
556 }
557
558 // map to get or set on FieldDef
559 if (id == "get")
560 {
561 if (accessorFlags != 0) err("Cannot use modifiers on field getter", loc)
562 f.get.code = block
563 }
564 else if (id.equals("set"))
565 {
566 if (accessorFlags != 0)
567 {
568 if (accessorFlags & ProtectionMask != 0)
569 err("Cannot use modifiers on field setter except to narrow protection", loc)
570 f.set.flags = (f.set.flags & ProtectionMask) | accessorFlags
571 }
572 f.set.code = block
573 }
574 else
575 {
576 err("Expected 'get' or 'set', not '$id'", idLoc)
577 }
578 }
579 }
580
581 //////////////////////////////////////////////////////////////////////////
582 // MethodDef
583 //////////////////////////////////////////////////////////////////////////
584
585 **
586 ** Method definition:
587 ** <methodDef> := <facets> <methodFlags> <type> <id> "(" <params> ")" <methodBody>
588 ** <methodFlags> := [<protection>] ["virtual"] ["override"] ["abstract"] ["static"]
589 ** <params> := [<param> ("," <param>)*]
590 ** <param> := <type> <id> [":=" <expr>]
591 ** <methodBody> := <eos> | ( "{" <stmts> "}" )
592 **
593 private MethodDef methodDef(Location loc, TypeDef parent, Str[] doc, Str:FacetDef facets, Int flags, TypeRef ret, Str name)
594 {
595 method := MethodDef.make(loc, parent)
596 method.doc = doc
597 method.facets = facets
598 method.flags = flags
599 method.ret = ret
600 method.name = name
601
602 // enter scope
603 curMethod = method
604
605 // parameters
606 consume(Token.lparen)
607 if (curt !== Token.rparen)
608 {
609 while (true)
610 {
611 method.params.add(paramDef)
612 if (curt === Token.rparen) break
613 consume(Token.comma)
614 }
615 }
616 consume(Token.rparen)
617
618 // if no body expected
619 if (flags & FConst.Abstract !== 0 || flags & FConst.Native !== 0 || isSys)
620 {
621 if (curt === Token.lbrace)
622 {
623 err("Abstract and native methods cannot have method body")
624 block(ret.isVoid) // keep parsing
625 }
626 else
627 {
628 endOfStmt
629 }
630 return method
631 }
632
633 // ctor chain
634 if ((flags & FConst.Ctor !== 0) && (curt === Token.colon))
635 method.ctorChain = ctorChain(method);
636
637 // body
638 if (curt != Token.lbrace)
639 err("Expecting method body")
640 else
641 method.code = block(ret.isVoid)
642
643 // exit scope
644 curMethod = null
645
646 return method
647 }
648
649 private ParamDef paramDef()
650 {
651 param := ParamDef.make(cur)
652 param.paramType = typeRef
653 param.name = consumeId
654 if (curt === Token.defAssign || curt === Token.assign)
655 {
656 if (curt === Token.assign) err("Must use := for parameter default");
657 consume
658 param.def = expr
659 }
660 return param
661 }
662
663 private CallExpr ctorChain(MethodDef method)
664 {
665 consume(Token.colon)
666 loc := cur
667
668 call := CallExpr.make(loc)
669 call.isCtorChain = true
670 switch (curt)
671 {
672 case Token.superKeyword: consume; call.target = SuperExpr.make(loc)
673 case Token.thisKeyword: consume; call.target = ThisExpr.make(loc)
674 default: throw err("Expecting this or super for constructor chaining", loc);
675 }
676
677 // we can omit name if super
678 if (call.target.id === ExprId.superExpr && curt != Token.dot)
679 {
680 call.name = method.name
681 }
682 else
683 {
684 consume(Token.dot)
685 call.name = consumeId
686 }
687
688 // TODO: omit args if pass thru?
689 callArgs(call)
690 return call
691 }
692
693 //////////////////////////////////////////////////////////////////////////
694 // Facets
695 //////////////////////////////////////////////////////////////////////////
696
697 private Str:FacetDef facets()
698 {
699 if (curt !== Token.at) return null
700
701 facets := Str:FacetDef[:]
702 while (curt === Token.at)
703 {
704 consume
705 loc := cur
706 name := consumeId
707 Expr val
708 if (curt === Token.assign)
709 {
710 consume()
711 val = expr
712 }
713 else
714 {
715 val = LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true)
716 }
717 if (facets[name] != null) err("Duplicate facet '$name'", loc)
718 facets[name] = FacetDef.make(loc, name, val)
719 }
720 return facets
721 }
722
723 //////////////////////////////////////////////////////////////////////////
724 // Block
725 //////////////////////////////////////////////////////////////////////////
726
727 **
728 ** Top level for blocks which must be surrounded by braces
729 **
730 private Block block(Bool inVoid)
731 {
732 this.inVoid = inVoid
733 verify(Token.lbrace)
734 return stmtOrBlock
735 }
736
737 **
738 ** <block> := <stmt> | ( "{" <stmts> "}" )
739 ** <stmts> := <stmt>*
740 **
741 private Block stmtOrBlock()
742 {
743 block := Block.make(cur)
744
745 if (curt !== Token.lbrace)
746 {
747 block.stmts.add( stmt )
748 }
749 else
750 {
751 consume(Token.lbrace)
752 while (curt != Token.rbrace)
753 block.stmts.add( stmt )
754 consume(Token.rbrace)
755 }
756
757 return block
758 }
759
760 //////////////////////////////////////////////////////////////////////////
761 // Statements
762 //////////////////////////////////////////////////////////////////////////
763
764 **
765 ** Statement:
766 ** <stmt> := <break> | <continue> | <for> | <if> | <return> | <switch> |
767 ** <throw> | <while> | <try> | <exprStmt> | <localDef>
768 **
769 private Stmt stmt()
770 {
771 // check for statement keywords
772 switch (curt)
773 {
774 case Token.breakKeyword: return breakStmt
775 case Token.continueKeyword: return continueStmt
776 case Token.forKeyword: return forStmt
777 case Token.ifKeyword: return ifStmt
778 case Token.returnKeyword: return returnStmt
779 case Token.switchKeyword: return switchStmt
780 case Token.throwKeyword: return throwStmt
781 case Token.tryKeyword: return tryStmt
782 case Token.whileKeyword: return whileStmt
783 }
784
785 // at this point we either have an expr or local var declaration
786 return exprOrLocalDefStmt(true)
787 }
788
789 **
790 ** Expression or local variable declaration:
791 ** <exprStmt> := <expr> <eos>
792 ** <localDef> := [<type>] <id> [":=" <expr>] <eos>
793 **
794 private Stmt exprOrLocalDefStmt(Bool isEndOfStmt)
795 {
796 // see if this statement begins with a type literal
797 loc := cur
798 mark := pos
799 localType := tryType
800
801 // type followed by identifier must be local variable declaration
802 if (localType != null && curt === Token.identifier)
803 {
804 return localDefStmt(loc, localType, isEndOfStmt)
805 }
806 reset(mark)
807
808 // identifier followed by def assign is inferred typed local var declaration
809 if (curt === Token.identifier && peekt === Token.defAssign)
810 {
811 return localDefStmt(loc, null, isEndOfStmt)
812 }
813
814 // if current is an identifer, save for special error handling
815 Str id := (curt === Token.identifier) ? (Str)cur.val : null
816
817 // otherwise assume it's a stand alone expression statement
818 stmt := ExprStmt.make(expr)
819 if (!isEndOfStmt) return stmt
820 if (endOfStmt(null)) return stmt
821
822 // report error
823 if (id != null && curt === Token.identifier && (peekt === Token.defAssign || peekt === Token.assign))
824 throw err("Unknown type '$id' for local declaration", loc)
825 else
826 throw err("Expected expression statement", loc)
827 }
828
829 **
830 ** Parse local variable declaration, the current token must be
831 ** the identifier of the local variable.
832 **
833 private LocalDefStmt localDefStmt(Location loc, CType localType, Bool isEndOfStmt)
834 {
835 stmt := LocalDefStmt.make(loc)
836 stmt.ctype = localType
837 stmt.name = consumeId
838
839 if (curt === Token.defAssign || curt === Token.assign)
840 {
841 if (curt === Token.assign) err("Must use := for declaration assignments")
842 consume
843 stmt.init = expr
844 }
845
846 if (isEndOfStmt) endOfStmt
847 return stmt
848 }
849
850 **
851 ** If/else statement:
852 ** <if> := "if" "(" <expr> ")" <block> [ "else" <block> ]
853 **
854 private IfStmt ifStmt()
855 {
856 stmt := IfStmt.make(cur)
857 consume(Token.ifKeyword)
858 consume(Token.lparen)
859 stmt.condition = expr
860 consume(Token.rparen)
861 stmt.trueBlock = stmtOrBlock
862 if (curt === Token.elseKeyword)
863 {
864 consume(Token.elseKeyword)
865 stmt.falseBlock = stmtOrBlock
866 }
867 return stmt
868 }
869
870 **
871 ** Return statement:
872 ** <return> := "return" [<expr>] <eos>
873 **
874 private ReturnStmt returnStmt()
875 {
876 stmt := ReturnStmt.make(cur)
877 consume(Token.returnKeyword)
878 if (inVoid)
879 {
880 endOfStmt("Expected end of statement after return in Void method")
881 }
882 else
883 {
884 stmt.expr = expr
885 endOfStmt
886 }
887 return stmt
888 }
889
890 **
891 ** Throw statement:
892 ** <throw> := "throw" <expr> <eos>
893 **
894 private ThrowStmt throwStmt()
895 {
896 stmt := ThrowStmt.make(cur)
897 consume(Token.throwKeyword)
898 stmt.exception = expr
899 endOfStmt
900 return stmt
901 }
902
903 **
904 ** While statement:
905 ** <while> := "while" "(" <expr> ")" <block>
906 **
907 private WhileStmt whileStmt()
908 {
909 stmt := WhileStmt.make(cur)
910 consume(Token.whileKeyword)
911 consume(Token.lparen)
912 stmt.condition = expr
913 consume(Token.rparen)
914 stmt.block = stmtOrBlock
915 return stmt
916 }
917
918 **
919 ** For statement:
920 ** <for> := "for" "(" [<forInit>] ";" <expr> ";" <expr> ")" <block>
921 ** <forInit> := <expr> | <localDef>
922 **
923 private ForStmt forStmt()
924 {
925 stmt := ForStmt.make(cur)
926 consume(Token.forKeyword)
927 consume(Token.lparen)
928
929 if (curt !== Token.semicolon) stmt.init = exprOrLocalDefStmt(false)
930 consume(Token.semicolon)
931
932 if (curt != Token.semicolon) stmt.condition = expr
933 consume(Token.semicolon)
934
935 if (curt != Token.rparen) stmt.update = expr
936 consume(Token.rparen)
937
938 stmt.block = stmtOrBlock
939 return stmt
940 }
941
942 **
943 ** Break statement:
944 ** <break> := "break" <eos>
945 **
946 private BreakStmt breakStmt()
947 {
948 stmt := BreakStmt.make(cur)
949 consume(Token.breakKeyword)
950 endOfStmt
951 return stmt
952 }
953
954 **
955 ** Continue statement:
956 ** <continue> := "continue" <eos>
957 **
958 private ContinueStmt continueStmt()
959 {
960 stmt := ContinueStmt.make(cur)
961 consume(Token.continueKeyword)
962 endOfStmt
963 return stmt
964 }
965
966 **
967 ** Try-catch-finally statement:
968 ** <try> := "try" "{" <stmt>* "}" <catch>* [<finally>]
969 ** <catch> := "catch" [<catchDef>] "{" <stmt>* "}"
970 ** <catchDef> := "(" <type> <id> ")"
971 ** <finally> := "finally" "{" <stmt>* "}"
972 **
973 private TryStmt tryStmt()
974 {
975 stmt := TryStmt.make(cur)
976 consume(Token.tryKeyword)
977 verify(Token.lbrace)
978 stmt.block = block(inVoid)
979 if (curt !== Token.catchKeyword && curt !== Token.finallyKeyword)
980 throw err("Expecting catch or finally block")
981 while (curt === Token.catchKeyword)
982 {
983 stmt.catches.add(tryCatch)
984 }
985 if (curt === Token.finallyKeyword)
986 {
987 consume
988 verify(Token.lbrace)
989 stmt.finallyBlock = block(inVoid)
990 }
991 return stmt
992 }
993
994 private Catch tryCatch()
995 {
996 c := Catch.make(cur)
997 consume(Token.catchKeyword)
998
999 if (curt === Token.lparen)
1000 {
1001 consume(Token.lparen)
1002 c.errType = typeRef
1003 c.errVariable = consumeId
1004 consume(Token.rparen)
1005 }
1006
1007 c.block = block(inVoid)
1008
1009 // insert implicit local variable declaration
1010 if (c.errVariable != null)
1011 c.block.stmts.insert(0, LocalDefStmt.makeCatchVar(c))
1012
1013 return c
1014 }
1015
1016 **
1017 ** Switch statement:
1018 ** <switch> := "switch" "(" <expr> ")" "{" <case>* [<default>] "}"
1019 ** <case> := "case" <expr> ":" <stmts>
1020 ** <default> := "default" ":" <stmts>
1021 **
1022 private SwitchStmt switchStmt()
1023 {
1024 stmt := SwitchStmt.make(cur)
1025 consume(Token.switchKeyword)
1026 consume(Token.lparen)
1027 stmt.condition = expr
1028 consume(Token.rparen)
1029 consume(Token.lbrace)
1030 while (curt != Token.rbrace)
1031 {
1032 if (curt === Token.caseKeyword)
1033 {
1034 c := Case.make(cur)
1035 while (curt === Token.caseKeyword)
1036 {
1037 consume
1038 c.cases.add(expr)
1039 consume(Token.colon)
1040 }
1041 if (curt !== Token.defaultKeyword) // optimize away case fall-thru to default
1042 {
1043 c.block = switchBlock
1044 stmt.cases.add(c)
1045 }
1046 }
1047 else if (curt === Token.defaultKeyword)
1048 {
1049 if (stmt.defaultBlock != null) err("Duplicate default blocks")
1050 consume
1051 consume(Token.colon)
1052 stmt.defaultBlock = switchBlock
1053 }
1054 else
1055 {
1056 throw err("Expected case or default statement")
1057 }
1058 }
1059 consume(Token.rbrace)
1060 endOfStmt
1061 return stmt
1062 }
1063
1064 private Block switchBlock()
1065 {
1066 Block block := null
1067 while (curt !== Token.caseKeyword && curt != Token.defaultKeyword && curt !== Token.rbrace)
1068 {
1069 if (block == null) block = Block.make(cur)
1070 block.stmts.add(stmt)
1071 }
1072 return block;
1073 }
1074
1075 //////////////////////////////////////////////////////////////////////////
1076 // Expr
1077 //////////////////////////////////////////////////////////////////////////
1078
1079 **
1080 ** Expression:
1081 ** <expr> := <assignExpr>
1082 **
1083 private Expr expr()
1084 {
1085 return assignExpr
1086 }
1087
1088 **
1089 ** Assignment expression:
1090 ** <assignExpr> := <condOrExpr> [<assignOp> <assignExpr>]
1091 ** <assignOp> := "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|="
1092 **
1093 private Expr assignExpr(Expr expr := null)
1094 {
1095 // this is tree if built to the right (others to the left)
1096 if (expr == null) expr = ternary
1097 if (curt.isAssign)
1098 {
1099 if (curt === Token.assign)
1100 return BinaryExpr.make(expr, consume.kind, assignExpr)
1101 else
1102 return ShortcutExpr.makeBinary(expr, consume.kind, assignExpr)
1103 }
1104 return expr
1105 }
1106
1107 **
1108 ** Ternary expression:
1109 ** <ternaryExpr> := <condOrExpr> "?" <condOrExpr> ":" <condOrExpr>
1110 **
1111 private Expr ternary()
1112 {
1113 expr := condOrExpr
1114 if (curt === Token.question)
1115 {
1116 condition := expr
1117 consume(Token.question);
1118 trueExpr := condOrExpr
1119 consume(Token.colon)
1120 falseExpr := condOrExpr
1121 expr = TernaryExpr.make(condition, trueExpr, falseExpr)
1122 }
1123 return expr
1124 }
1125
1126 **
1127 ** Conditional or expression:
1128 ** <condOrExpr> := <condAndExpr> ("||" <condAndExpr>)*
1129 **
1130 private Expr condOrExpr()
1131 {
1132 expr := condAndExpr
1133 if (curt === Token.doublePipe)
1134 {
1135 cond := CondExpr.make(expr, cur.kind)
1136 while (curt === Token.doublePipe)
1137 {
1138 consume
1139 cond.operands.add(condAndExpr)
1140 }
1141 expr = cond
1142 }
1143 return expr
1144 }
1145
1146 **
1147 ** Conditional and expression:
1148 ** <condAndExpr> := <equalityExpr> ("&&" <equalityExpr>)*
1149 **
1150 private Expr condAndExpr()
1151 {
1152 expr := equalityExpr
1153 if (curt === Token.doubleAmp)
1154 {
1155 cond := CondExpr.make(expr, cur.kind)
1156 while (curt === Token.doubleAmp)
1157 {
1158 consume
1159 cond.operands.add(equalityExpr)
1160 }
1161 expr = cond
1162 }
1163 return expr
1164 }
1165
1166 **
1167 ** Equality expression:
1168 ** <equalityExpr> := <relationalExpr> (("==" | "!=" | "===" | "!==") <relationalExpr>)*
1169 **
1170 private Expr equalityExpr()
1171 {
1172 expr := relationalExpr
1173 while (curt === Token.eq || curt === Token.notEq ||
1174 curt === Token.same || curt === Token.notSame)
1175 {
1176 lhs := expr
1177 tok := consume.kind
1178 rhs := relationalExpr
1179
1180 // optimize for null literal
1181 if (lhs.id === ExprId.nullLiteral || rhs.id === ExprId.nullLiteral)
1182 {
1183 id := (tok === Token.eq || tok === Token.same) ? ExprId.cmpNull : ExprId.cmpNotNull
1184 operand := (lhs.id === ExprId.nullLiteral) ? rhs : lhs
1185 expr = UnaryExpr.make(lhs.location, id, tok, operand)
1186 }
1187 else
1188 {
1189 if (tok === Token.same || tok === Token.notSame)
1190 expr = BinaryExpr.make(lhs, tok, rhs)
1191 else
1192 expr = ShortcutExpr.makeBinary(lhs, tok, rhs)
1193 }
1194 }
1195 return expr
1196 }
1197
1198 **
1199 ** Relational expression:
1200 ** <relationalExpr> := <rangeExpr> (("is" | "as" | "<" | "<=" | ">" | ">=" | "<=>") <rangeExpr>)*
1201 **
1202 private Expr relationalExpr()
1203 {
1204 expr := rangeExpr
1205 while (curt === Token.isKeyword || curt === Token.asKeyword ||
1206 curt === Token.lt || curt === Token.ltEq ||
1207 curt === Token.gt || curt === Token.gtEq ||
1208 curt === Token.cmp)
1209 {
1210 if (curt === Token.isKeyword)
1211 {
1212 consume
1213 expr = TypeCheckExpr.make(expr.location, ExprId.isExpr, expr, ctype)
1214 }
1215 else if (curt === Token.asKeyword)
1216 {
1217 consume
1218 expr = TypeCheckExpr.make(expr.location, ExprId.asExpr, expr, ctype)
1219 }
1220 else
1221 {
1222 expr = ShortcutExpr.makeBinary(expr, consume.kind, rangeExpr)
1223 }
1224 }
1225 return expr
1226 }
1227
1228 **
1229 ** Range expression:
1230 ** <rangeExpr> := <bitOrExpr> ((".." | "...") <bitOrExpr>)*
1231 **
1232 private Expr rangeExpr()
1233 {
1234 expr := bitOrExpr
1235 if (curt === Token.dotDot || curt === Token.dotDotDot)
1236 {
1237 range := RangeLiteralExpr.make(expr.location, ns.rangeType)
1238 range.start = expr
1239 range.exclusive = consume.kind === Token.dotDotDot
1240 range.end = bitOrExpr
1241 return range
1242 }
1243 return expr
1244 }
1245
1246 **
1247 ** Bitwise or expression:
1248 ** <bitOrExpr> := <bitAndExpr> (("^" | "|") <bitAndExpr>)*
1249 **
1250 private Expr bitOrExpr()
1251 {
1252 expr := bitAndExpr
1253 while (curt === Token.caret || curt === Token.pipe)
1254 expr = ShortcutExpr.makeBinary(expr, consume.kind, bitAndExpr)
1255 return expr
1256 }
1257
1258 **
1259 ** Bitwise and expression:
1260 ** <bitAndExpr> := <shiftExpr> (("&" <shiftExpr>)*
1261 **
1262 private Expr bitAndExpr()
1263 {
1264 expr := shiftExpr
1265 while (curt === Token.amp)
1266 expr = ShortcutExpr.makeBinary(expr, consume.kind, shiftExpr)
1267 return expr
1268 }
1269
1270 **
1271 ** Bitwise shift expression:
1272 ** <shiftExpr> := <addExpr> (("<<" | ">>") <addExpr>)*
1273 **
1274 private Expr shiftExpr()
1275 {
1276 expr := additiveExpr
1277 while (curt === Token.lshift || curt === Token.rshift)
1278 expr = ShortcutExpr.makeBinary(expr, consume.kind, additiveExpr)
1279 return expr
1280 }
1281
1282 **
1283 ** Additive expression:
1284 ** <addExpr> := <multExpr> (("+" | "-") <multExpr>)*
1285 **
1286 private Expr additiveExpr()
1287 {
1288 expr := multiplicativeExpr
1289 while (curt === Token.plus || curt === Token.minus)
1290 expr = ShortcutExpr.makeBinary(expr, consume.kind, multiplicativeExpr)
1291 return expr
1292 }
1293
1294 **
1295 ** Multiplicative expression:
1296 ** <multExpr> := <parenExpr> (("*" | "/" | "%") <parenExpr>)*
1297 **
1298 private Expr multiplicativeExpr()
1299 {
1300 expr := parenExpr
1301 while (curt === Token.star || curt === Token.slash || curt === Token.percent)
1302 expr = ShortcutExpr.makeBinary(expr, consume.kind, parenExpr)
1303 return expr
1304 }
1305
1306 **
1307 ** Paren grouped expression:
1308 ** <parenExpr> := <unaryExpr> | <castExpr> | <groupedExpr>
1309 ** <castExpr> := "(" <type> ")" <parenExpr>
1310 ** <groupedExpr> := "(" <expr> ")" <termChain>*
1311 **
1312 private Expr parenExpr()
1313 {
1314 if (curt != Token.lparen)
1315 return unaryExpr
1316
1317 // consume opening paren
1318 loc := cur
1319 consume(Token.lparen)
1320
1321 // In Fan just like C# and Java, a paren could mean
1322 // either a cast or a parenthesized expression
1323 mark := pos
1324 castType := tryType
1325 if (curt === Token.rparen)
1326 {
1327 consume
1328 return TypeCheckExpr.make(loc, ExprId.cast, parenExpr, castType)
1329 }
1330 reset(mark)
1331
1332 // this is just a normal parenthesized expression
1333 expr := expr
1334 consume(Token.rparen)
1335 while (true)
1336 {
1337 chained := termChainExpr(expr)
1338 if (chained == null) break
1339 expr = chained
1340 }
1341 return expr
1342 }
1343
1344 **
1345 ** Unary expression:
1346 ** <unaryExpr> := <prefixExpr> | <termExpr> | <postfixExpr>
1347 ** <prefixExpr> := ("!" | "+" | "-" | "~" | "++" | "--") <parenExpr>
1348 ** <postfixExpr> := <termExpr> ("++" | "--")
1349 **
1350 private Expr unaryExpr()
1351 {
1352 loc := cur
1353 tok := cur
1354 tokt := curt
1355
1356 if (tokt === Token.bang)
1357 {
1358 consume
1359 return UnaryExpr.make(loc, tokt.toExprId, tokt, parenExpr)
1360 }
1361
1362 if (tokt === Token.amp)
1363 {
1364 consume
1365 return CurryExpr.make(loc, parenExpr)
1366 }
1367
1368 if (tokt === Token.plus)
1369 {
1370 consume
1371 return parenExpr // optimize +expr to just expr
1372 }
1373
1374 if (tokt === Token.tilde || tokt === Token.minus)
1375 {
1376 consume
1377 return ShortcutExpr.makeUnary(loc, tokt, parenExpr)
1378 }
1379
1380 if (tokt === Token.increment || tokt === Token.decrement)
1381 {
1382 consume
1383 return ShortcutExpr.makeUnary(loc, tokt, parenExpr)
1384 }
1385
1386 expr := termExpr
1387
1388 tokt = curt
1389 if (tokt === Token.increment || tokt == Token.decrement)
1390 {
1391 consume
1392 shortcut := ShortcutExpr.makeUnary(loc, tokt, expr)
1393 shortcut.isPostfixLeave = true
1394 return shortcut
1395 }
1396
1397 return expr
1398 }
1399
1400 //////////////////////////////////////////////////////////////////////////
1401 // Term Expr
1402 //////////////////////////////////////////////////////////////////////////
1403
1404 **
1405 ** A term is a base terminal such as a variable, call, or literal,
1406 ** optionally followed by a chain of accessor expressions - such
1407 ** as "x.y[z](a, b)".
1408 **
1409 ** <termExpr> := <termBase> <termChain>* [withBlock]
1410 **
1411 private Expr termExpr(Expr target := null)
1412 {
1413 if (target == null) target = termBaseExpr
1414 while (true)
1415 {
1416 chained := termChainExpr(target)
1417 if (chained == null) break
1418 target = chained
1419 }
1420 if (curt == Token.lbrace)
1421 return withBlock(target)
1422 return target
1423 }
1424
1425 **
1426 ** Atomic base of a termExpr
1427 **
1428 ** <termBase> := <literal> | <idExpr> | <closure>
1429 ** <literal> := "null" | "this" | "super" | <bool> | <int> |
1430 ** <float> | <str> | <duration> | <list> | <map> | <uri>
1431 **
1432 private Expr termBaseExpr()
1433 {
1434 loc := cur
1435
1436 ctype := tryType
1437 if (ctype != null) return typeBaseExpr(loc, ctype)
1438
1439 switch (curt)
1440 {
1441 case Token.at: return idExpr(null, false)
1442 case Token.identifier: return idExpr(null, false)
1443 case Token.intLiteral: return LiteralExpr.make(loc, ExprId.intLiteral, ns.intType, consume.val)
1444 case Token.floatLiteral: return LiteralExpr.make(loc, ExprId.floatLiteral, ns.floatType, consume.val)
1445 case Token.strLiteral: return LiteralExpr.make(loc, ExprId.strLiteral, ns.strType, consume.val)
1446 case Token.durationLiteral: return LiteralExpr.make(loc, ExprId.durationLiteral, ns.durationType, consume.val)
1447 case Token.uriLiteral: return LiteralExpr.make(loc, ExprId.uriLiteral, ns.uriType, consume.val)
1448 case Token.lbracket: return collectionLiteralExpr(loc, null)
1449 case Token.falseKeyword: consume; return LiteralExpr.make(loc, ExprId.falseLiteral, ns.boolType, false)
1450 case Token.nullKeyword: consume; return LiteralExpr.make(loc, ExprId.nullLiteral, ns.objType, null)
1451 case Token.superKeyword: consume; return SuperExpr.make(loc)
1452 case Token.thisKeyword: consume; return ThisExpr.make(loc)
1453 case Token.trueKeyword: consume; return LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true)
1454 }
1455 throw err("Expected expression, not '" + cur + "'")
1456 }
1457
1458 **
1459 ** Handle a term expression which begins with a type literal.
1460 **
1461 private Expr typeBaseExpr(Location loc, CType ctype)
1462 {
1463 // type literal
1464 if (curt === Token.dot && peekt === Token.identifier && peek.val == "type")
1465 {
1466 consume
1467 consume
1468 return LiteralExpr.make(loc, ExprId.typeLiteral, ns.typeType, ctype)
1469 }
1470
1471 // dot is named super or static call chain
1472 if (curt == Token.dot)
1473 {
1474 consume
1475 if (curt === Token.superKeyword)
1476 {
1477 consume
1478 return SuperExpr.make(loc, ctype)
1479 }
1480 else
1481 {
1482 return idExpr(StaticTargetExpr.make(loc, ctype), false)
1483 }
1484 }
1485
1486 // list/map literal with explicit type
1487 if (curt === Token.lbracket)
1488 {
1489 return collectionLiteralExpr(loc, ctype)
1490 }
1491
1492 // closure
1493 if (curt == Token.lbrace && ctype is FuncType)
1494 {
1495 return closure(loc, (FuncType)ctype)
1496 }
1497
1498 // simple literal type(arg)
1499 if (curt == Token.lparen)
1500 {
1501 consume
1502 arg := expr
1503 consume(Token.rparen)
1504 return SimpleLiteralExpr.make(loc, ctype, arg)
1505 }
1506
1507 // complex literal type {...}
1508 if (curt == Token.lbrace)
1509 {
1510 base := UnknownVarExpr.make(loc, StaticTargetExpr.make(loc, ctype), "make")
1511 return withBlock(base)
1512 }
1513
1514 throw err("Unexpected type literal", loc)
1515 }
1516
1517 **
1518 ** A chain expression is a piece of a term expression that may
1519 ** be chained together such as "call.var[x]". If the specified
1520 ** target expression contains a chained access, then return the new
1521 ** expression, otherwise return null.
1522 **
1523 ** <termChain> := <compiledCall> | <dynamicCall> | <indexExpr>
1524 ** <compiledCall> := "." <idExpr>
1525 ** <dynamicCall> := "->" <idExpr>
1526 **
1527 private Expr termChainExpr(Expr target)
1528 {
1529 loc := cur
1530
1531 // if ".id" field access or ".id" call
1532 if (curt === Token.dot)
1533 {
1534 consume
1535 return idExpr(target, false)
1536 }
1537
1538 // if "->id" dynamic call
1539 if (curt === Token.arrow)
1540 {
1541 consume
1542 return idExpr(target, true)
1543 }
1544
1545 // if target[...]
1546 if (curt === Token.lbracket)
1547 return indexExpr(target)
1548
1549 // if target(...)
1550 if (curt === Token.lparen)
1551 return callOp(target)
1552
1553 // we treat a with base as a dot slot access
1554 if (target.id === ExprId.withBase)
1555 return idExpr(target, false)
1556
1557 // otherwise the expression should be finished
1558 return null;
1559 }
1560
1561 **
1562 ** A with block is a series of sub-expressions
1563 ** inside {} appended to the end of an expression.
1564 **
1565 private Expr withBlock(Expr base)
1566 {
1567 // field initializers look like a with block, but
1568 // we can safely peek to see if the next token is "get",
1569 // "set", or a keyword like "private"
1570 if (inFieldInit)
1571 {
1572 if (peek.kind.keyword) return base
1573 if (peekt == Token.identifier)
1574 {
1575 if (peek.val == "get" || peek.val == "set") return base
1576 }
1577 }
1578
1579 withBlock := WithBlockExpr.make(base)
1580 consume(Token.lbrace)
1581 while (curt !== Token.rbrace)
1582 {
1583 sub := assignExpr(termExpr(WithBaseExpr.make(withBlock)))
1584 withBlock.subs.add(sub)
1585 endOfStmt
1586 }
1587 consume(Token.rbrace)
1588 return withBlock
1589 }
1590
1591 //////////////////////////////////////////////////////////////////////////
1592 // Term Expr Utils
1593 //////////////////////////////////////////////////////////////////////////
1594
1595 **
1596 ** Identifier expression:
1597 ** <idExpr> := <local> | <field> | <call>
1598 ** <local> := <id>
1599 ** <field> := ["@"] <id>
1600 **
1601 private Expr idExpr(Expr target, Bool dynamicCall)
1602 {
1603 loc := cur
1604
1605 if (curt == Token.at)
1606 {
1607 consume
1608 return UnknownVarExpr.makeStorage(loc, target, consumeId)
1609 }
1610
1611 if (peekt === Token.lparen)
1612 {
1613 call := callExpr(target)
1614 call.isDynamic = dynamicCall
1615 return call
1616 }
1617
1618 name := consumeId
1619
1620 // if we have a closure then this is a call with one arg of a closure
1621 closure := tryClosure
1622 if (closure != null)
1623 {
1624 call := CallExpr.make(loc)
1625 call.target = target
1626 call.name = name
1627 call.args.add(closure)
1628 return call
1629 }
1630
1631 // if dynamic call then we know this is a call not a field
1632 if (dynamicCall)
1633 {
1634 call := CallExpr.make(loc)
1635 call.target = target
1636 call.name = name
1637 call.isDynamic = true
1638 return call
1639 }
1640
1641 return UnknownVarExpr.make(loc, target, name)
1642 }
1643
1644 **
1645 ** Call expression:
1646 ** <call> := <id> ["(" <args> ")"] [<closure>]
1647 **
1648 private CallExpr callExpr(Expr target)
1649 {
1650 call := CallExpr.make(cur)
1651 call.target = target
1652 call.name = consumeId
1653 callArgs(call)
1654 return call
1655 }
1656
1657 **
1658 ** Parse args with known parens:
1659 ** <args> := [<expr> ("," <expr>)*] [<closure>]
1660 **
1661 private Void callArgs(CallExpr call)
1662 {
1663 consume(Token.lparen)
1664 if (curt != Token.rparen)
1665 {
1666 while (true)
1667 {
1668 call.args.add(expr)
1669 if (curt === Token.rparen) break
1670 consume(Token.comma)
1671 }
1672 }
1673 consume(Token.rparen)
1674
1675 closure := tryClosure
1676 if (closure != null) call.args.add(closure);
1677 }
1678
1679 **
1680 ** Call operator:
1681 ** <callOp> := "(" <args> ")" [<closure>]
1682 **
1683 private Expr callOp(Expr target)
1684 {
1685 loc := cur
1686 call := CallExpr.make(loc)
1687 call.target = target
1688 callArgs(call)
1689 call.name = "call${call.args.size}"
1690 return call
1691 }
1692
1693 **
1694 ** Index expression:
1695 ** <indexExpr> := "[" <expr> "]"
1696 **
1697 private Expr indexExpr(Expr target)
1698 {
1699 loc := cur
1700 consume(Token.lbracket)
1701
1702 // otherwise this must be a standard single key index
1703 expr := expr
1704 consume(Token.rbracket)
1705 return ShortcutExpr.makeGet(loc, target, expr)
1706 }
1707
1708 //////////////////////////////////////////////////////////////////////////
1709 // Collection "Literals"
1710 //////////////////////////////////////////////////////////////////////////
1711
1712 **
1713 ** Collection literal:
1714 ** <list> := [<type>] "[" <listItems> "]"
1715 ** <listItems> := "," | (<expr> ("," <expr>)*)
1716 ** <map> := [<mapType>] "[" <mapItems> "]"
1717 ** <mapItems> := ":" | (<mapPair> ("," <mapPair>)*)
1718 ** <mapPair> := <expr> ":" <expr>
1719 **
1720 private Expr collectionLiteralExpr(Location loc, CType explicitType)
1721 {
1722 // empty list [,]
1723 if (peekt === Token.comma)
1724 return listLiteralExpr(loc, explicitType, null)
1725
1726 // empty map [:]
1727 if (peekt === Token.colon)
1728 return mapLiteralExpr(loc, explicitType, null)
1729
1730 // opening bracket
1731 consume(Token.lbracket)
1732
1733 // [] is error
1734 if (curt === Token.rbracket)
1735 {
1736 err("Invalid list literal; use '[,]' for empty Obj[] list", loc)
1737 consume
1738 return ListLiteralExpr.make(loc)
1739 }
1740
1741 // read first expression
1742 first := expr
1743
1744 // at this point we can determine if it is a list or a map
1745 if (curt === Token.colon)
1746 return mapLiteralExpr(loc, explicitType, first)
1747 else
1748 return listLiteralExpr(loc, explicitType, first)
1749 }
1750
1751 **
1752 ** Parse List literal; if first is null then
1753 ** cur must be on lbracket
1754 ** else
1755 ** cur must be on comma after first item
1756 **
1757 private ListLiteralExpr listLiteralExpr(Location loc, CType explicitType, Expr first)
1758 {
1759 // explicitType is type of List: Str[,]
1760 if (explicitType != null)
1761 explicitType = explicitType.toListOf
1762
1763 list := ListLiteralExpr.make(loc, (ListType)explicitType)
1764
1765 // if first is null, must be on lbracket
1766 if (first == null)
1767 {
1768 consume(Token.lbracket)
1769
1770 // if [,] empty list
1771 if (curt === Token.comma)
1772 {
1773 consume
1774 consume(Token.rbracket)
1775 return list
1776 }
1777
1778 first = expr
1779 }
1780
1781 list.vals.add(first)
1782 while (curt === Token.comma)
1783 {
1784 consume
1785 if (curt === Token.rbracket) break // allow extra trailing comma
1786 list.vals.add(expr)
1787 }
1788 consume(Token.rbracket)
1789 return list
1790 }
1791
1792 **
1793 ** Parse Map literal; if first is null:
1794 ** cur must be on lbracket
1795 ** else
1796 ** cur must be on colon of first key/value pair
1797 **
1798 private MapLiteralExpr mapLiteralExpr(Location loc, CType explicitType, Expr first)
1799 {
1800 // explicitType is *the* map type: Str:Str[,]
1801 if (explicitType != null && !(explicitType is MapType))
1802 {
1803 err("Invalid map type '$explicitType' for map literal", loc)
1804 explicitType = null
1805 }
1806
1807 map := MapLiteralExpr.make(loc, (MapType)explicitType)
1808
1809 // if first is null, must be on lbracket
1810 if (first == null)
1811 {
1812 consume(Token.lbracket)
1813
1814 // if [,] empty list
1815 if (curt === Token.colon)
1816 {
1817 consume
1818 consume(Token.rbracket)
1819 return map
1820 }
1821
1822 first = expr
1823 }
1824
1825 map.keys.add(first)
1826 consume(Token.colon)
1827 map.vals.add(expr)
1828 while (curt === Token.comma)
1829 {
1830 consume
1831 if (curt === Token.rbracket) break // allow extra trailing comma
1832 map.keys.add(expr)
1833 consume(Token.colon)
1834 map.vals.add(expr)
1835 }
1836 consume(Token.rbracket)
1837 return map
1838 }
1839
1840 //////////////////////////////////////////////////////////////////////////
1841 // Closure
1842 //////////////////////////////////////////////////////////////////////////
1843
1844 **
1845 ** Attempt to parse a closure expression or return null if we
1846 ** aren't positioned at the start of a closure expression.
1847 **
1848 private ClosureExpr tryClosure()
1849 {
1850 loc := cur
1851
1852 // if no pipe, then no closure
1853 if (curt !== Token.pipe) return null
1854
1855 // otherwise this can only be a FuncType declaration,
1856 // so give it a whirl, and bail if that fails
1857 mark := pos
1858 funcType := (FuncType)tryType
1859 if (funcType == null) return null
1860
1861 // if we don't see opening brace for body - no go
1862 if (curt !== Token.lbrace) { reset(mark); return null }
1863
1864 return closure(loc, funcType)
1865 }
1866
1867 **
1868 ** Parse body of closure expression and return ClosureExpr.
1869 **
1870 private ClosureExpr closure(Location loc, FuncType funcType)
1871 {
1872 if (curMethod == null)
1873 throw err("Unexpected closure outside of a method")
1874
1875 // closure anonymous class name: class$method$count
1876 name := "${curType.name}\$${curMethod.name}\$${closureCount++}"
1877
1878 // create closure
1879 closure := ClosureExpr.make(loc, curType, curMethod, curClosure, funcType, name)
1880
1881 // save all closures in global list and list per type
1882 closures.add(closure)
1883 curType.closures.add(closure)
1884
1885 // parse block; temporarily change our inVoid flag and curClosure
1886 oldInVoid := inVoid
1887 oldClosure := curClosure
1888 curClosure = closure
1889 closure.code = block(funcType.ret.isVoid)
1890 curClosure = oldClosure
1891 inVoid = oldInVoid
1892
1893 return closure
1894 }
1895
1896 //////////////////////////////////////////////////////////////////////////
1897 // Types
1898 //////////////////////////////////////////////////////////////////////////
1899
1900 **
1901 ** Parse a type production into a CType and wrap it as AST TypeRef.
1902 **
1903 private TypeRef typeRef()
1904 {
1905 Location loc := cur
1906 return TypeRef.make(loc, ctype)
1907 }
1908
1909 **
1910 ** If the current stream of tokens can be parsed as a
1911 ** valid type production return it. Otherwise leave
1912 ** the parser positioned on the current token.
1913 **
1914 private CType tryType()
1915 {
1916 // types can only begin with identifier, | or [
1917 if (curt !== Token.identifier && curt !== Token.pipe && curt !== Token.lbracket)
1918 return null
1919
1920 suppressErr = true
1921 mark := pos
1922 CType type := null
1923 try
1924 {
1925 type = ctype
1926 }
1927 catch (SuppressedErr e)
1928 {
1929 }
1930 suppressErr = false
1931 if (type == null) reset(mark)
1932 return type
1933 }
1934
1935 **
1936 ** Type signature:
1937 ** <type> := <simpleType> | <listType> | <mapType> | <funcType>
1938 ** <listType> := <type> "[]"
1939 ** <mapType> := ["["] <type> ":" <type> ["]"]
1940 **
1941 private CType ctype()
1942 {
1943 CType t := null
1944
1945 // Types can begin with:
1946 // - id
1947 // - [k:v]
1948 // - |a, b -> r|
1949 if (curt === Token.identifier)
1950 {
1951 t = simpleType
1952 }
1953 else if (curt === Token.lbracket)
1954 {
1955 loc := consume(Token.lbracket)
1956 t = ctype
1957 consume(Token.rbracket)
1958 if (!(t is MapType)) err("Invalid map type", loc)
1959 }
1960 else if (curt === Token.pipe)
1961 {
1962 t = funcType
1963 }
1964 else
1965 {
1966 throw err("Expecting type name")
1967 }
1968
1969 // trailing [] for lists
1970 while (curt === Token.lbracket && peekt === Token.rbracket)
1971 {
1972 consume(Token.lbracket)
1973 consume(Token.rbracket)
1974 t = t.toListOf
1975 }
1976
1977 // check for ":" for map type
1978 if (curt === Token.colon)
1979 {
1980 consume(Token.colon)
1981 key := t
1982 val := ctype
1983 t = MapType.make(key, val)
1984 }
1985
1986 return t
1987 }
1988
1989 **
1990 ** Simple type signature:
1991 ** <simpleType> := <id> ["::" <id>]
1992 **
1993 private CType simpleType()
1994 {
1995 loc := cur
1996 id := consumeId
1997
1998 // fully qualified
1999 if (curt === Token.doubleColon)
2000 {
2001 consume
2002 return ResolveImports.resolveQualified(this, id, consumeId, loc)
2003 }
2004
2005 // unqualified name, lookup in imported types
2006 types := unit.importedTypes[id]
2007 if (types == null)
2008 {
2009 // handle sys generic parameters
2010 if (isSys && id.size == 1)
2011 return ns.genericParameter(id)
2012
2013 // not found in imports
2014 err("Unknown type '$id'", loc)
2015 return ns.voidType
2016 }
2017
2018 // if more then one it is ambiguous
2019 if (types.size > 1) err("Ambiguous type: " + types.join(", "))
2020
2021 // got it
2022 return types.first
2023 }
2024
2025 **
2026 ** Method type signature:
2027 ** <funcType> := "|" <formals> ["->" <type> "|"
2028 ** <formals> := [<formal> ("," <formal>)*]
2029 ** <formal> := <type> <id>
2030 **
2031 private CType funcType()
2032 {
2033 params := CType[,]
2034 names := Str[,]
2035 ret := ns.voidType
2036
2037 // opening pipe
2038 consume(Token.pipe)
2039
2040 // |,| is the empty method type
2041 if (curt === Token.comma)
2042 {
2043 consume
2044 consume(Token.pipe)
2045 return FuncType.make(params, names, ret)
2046 }
2047
2048 // params, must be one if no ->
2049 if (curt !== Token.arrow)
2050 {
2051 params.add(ctype)
2052 names.add(consumeId)
2053 }
2054 while (curt === Token.comma)
2055 {
2056 consume
2057 params.add(ctype)
2058 names.add(consumeId)
2059 }
2060
2061 // optional arrow
2062 if (curt === Token.arrow)
2063 {
2064 consume
2065 ret = ctype
2066 }
2067
2068 // closing pipe
2069 consume(Token.pipe)
2070 return FuncType.make(params, names, ret)
2071 }
2072
2073 //////////////////////////////////////////////////////////////////////////
2074 // Misc
2075 //////////////////////////////////////////////////////////////////////////
2076
2077 **
2078 ** Parse fandoc or retur null
2079 **
2080 private Str[] doc()
2081 {
2082 Str[] doc := null
2083 while (curt === Token.docComment)
2084 doc = (Str[])consume(Token.docComment).val
2085 return doc
2086 }
2087
2088 //////////////////////////////////////////////////////////////////////////
2089 // Errors
2090 //////////////////////////////////////////////////////////////////////////
2091
2092 override CompilerErr err(Str msg, Location loc := null)
2093 {
2094 if (suppressErr) throw SuppressedErr.make
2095 if (loc == null) loc = cur
2096 return super.err(msg, loc)
2097 }
2098
2099 //////////////////////////////////////////////////////////////////////////
2100 // Tokens
2101 //////////////////////////////////////////////////////////////////////////
2102
2103 **
2104 ** Verify current is an identifier, consume it, and return it.
2105 **
2106 private Str consumeId()
2107 {
2108 if (curt !== Token.identifier)
2109 throw err("Expected identifier, not '$cur'");
2110 return (Str)consume.val;
2111 }
2112
2113 **
2114 ** Check that the current token matches the specified
2115 ** type, but do not consume it.
2116 **
2117 private Void verify(Token kind)
2118 {
2119 if (curt !== kind)
2120 throw err("Expected '$kind.symbol', not '$cur'");
2121 }
2122
2123 **
2124 ** Consume the current token and return consumed token.
2125 ** If kind is non-null then verify first
2126 **
2127 private TokenVal consume(Token kind := null)
2128 {
2129 // verify if not null
2130 if (kind != null) verify(kind)
2131
2132 // save the current we are about to consume for return
2133 result := cur
2134
2135 // get the next token from the buffer, if pos is past numTokens,
2136 // then always use the last token which will be eof
2137 TokenVal next;
2138 pos++;
2139 if (pos+1 < numTokens)
2140 next = tokens[pos+1] // next peek is cur+1
2141 else
2142 next = tokens[numTokens-1]
2143
2144 this.cur = peek
2145 this.peek = next
2146 this.curt = cur.kind
2147 this.peekt = peek.kind
2148
2149 return result
2150 }
2151
2152 **
2153 ** Statements can be terminated with a semicolon, end of line
2154 ** or } end of block. Return true on success. On failure
2155 ** return false if errMsg is null or log/throw an exception.
2156 **
2157 private Bool endOfStmt(Str errMsg := "Expected end of statement: semicolon, newline, or end of block; not '$cur'")
2158 {
2159 if (cur.newline) return true
2160 if (curt === Token.semicolon) { consume; return true }
2161 if (curt === Token.rbrace) return true
2162 if (errMsg == null) return false
2163 throw err(errMsg)
2164 }
2165
2166 **
2167 ** Reset the current position to the specified tokens index.
2168 **
2169 private Void reset(Int pos)
2170 {
2171 this.pos = pos
2172 this.cur = tokens[pos]
2173 if (pos+1 < numTokens)
2174 this.peek = tokens[pos+1]
2175 else
2176 this.peek = tokens[pos]
2177 this.curt = cur.kind
2178 this.peekt = peek.kind
2179 }
2180
2181 //////////////////////////////////////////////////////////////////////////
2182 // Parser Flags
2183 //////////////////////////////////////////////////////////////////////////
2184
2185 // These are flags used only by the parser we merge with FConst
2186 // flags by starting from most significant bit and working down
2187 const static Int Readonly := 0x80000000
2188 const static Int ParserFlagsMask := Readonly
2189
2190 // Bitwise and this mask to clear all protection scope flags
2191 const static Int ProtectionMask := ~(FConst.Public|FConst.Protected|FConst.Private|FConst.Internal)
2192
2193 //////////////////////////////////////////////////////////////////////////
2194 // Fields
2195 //////////////////////////////////////////////////////////////////////////
2196
2197 private CompilationUnit unit // compilation unit to generate
2198 private TokenVal[] tokens // tokens all read in
2199 private Int numTokens // number of tokens
2200 private Int pos; // offset Into tokens for cur
2201 private TokenVal cur // current token
2202 private Token curt // current token type
2203 private TokenVal peek // next token
2204 private Token peekt // next token type
2205 private Bool suppressErr // throw SuppressedErr instead of CompilerErr
2206 private Bool isSys := false // are we parsing the sys pod itself
2207 private Bool inVoid // are we currently in a void method
2208 private Bool inFieldInit := false // are we currently in a field initializer
2209 private TypeDef curType // current TypeDef scope
2210 private MethodDef curMethod // current MethodDef scope
2211 private ClosureExpr curClosure // current ClosureExpr if inside closure
2212 private Int closureCount // number of closures parsed inside curMethod
2213 private ClosureExpr[] closures // list of all closures parsed
2214
2215 }
2216
2217 //////////////////////////////////////////////////////////////////////////
2218 // SuppressedErr
2219 //////////////////////////////////////////////////////////////////////////
2220
2221 const class SuppressedErr : Err
2222 {
2223 new make() : super(null, null) {}
2224 }
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 15 Sep 05 Brian Frank Creation
7 // 6 Jun 06 Brian Frank Ported from Java to Fan
8 //
9
10 **
11 ** Parser is responsible for parsing a list of tokens into the
12 ** abstract syntax tree. At this point the CompilationUnit, Usings,
13 ** and TypeDefs are already populated by the ScanForUsingAndTypes
14 ** step.
15 **
16 public class Parser : CompilerSupport
17 {
18
19 //////////////////////////////////////////////////////////////////////////
20 // Construction
21 //////////////////////////////////////////////////////////////////////////
22
23 **
24 ** Construct the parser for the specified compilation unit.
25 **
26 new make(Compiler compiler, CompilationUnit unit, ClosureExpr[] closures)
27 : super(compiler)
28 {
29 this.unit = unit
30 this.tokens = unit.tokens
31 this.numTokens = unit.tokens.size
32 this.closures = closures
33 this.suppressErr = false
34 if (compiler != null) this.isSys = compiler.isSys
35 reset(0)
36 }
37
38 //////////////////////////////////////////////////////////////////////////
39 // Access
40 //////////////////////////////////////////////////////////////////////////
41
42 **
43 ** Top level parse a compilation unit:
44 **
45 ** <compilationUnit> := [<usings>] <typeDef>*
46 **
47 Void parse()
48 {
49 usings
50 while (curt !== Token.eof) typeDef
51 }
52
53 //////////////////////////////////////////////////////////////////////////
54 // Usings
55 //////////////////////////////////////////////////////////////////////////
56
57 **
58 ** Parse <using>* - note that we are just skipping them because
59 ** they are already parsed by ScanForUsingsAndTypes.
60 **
61 ** <using> := <usingPod> | <usingType> | <usingAs>
62 ** <usingPod> := "using" <id> <eos>
63 ** <usingType> := "using" <id> "::" <id> <eos>
64 ** <usingAs> := "using" <id> "::" <id> "as" <id> <eos>
65 **
66 private Void usings()
67 {
68 while (curt == Token.usingKeyword)
69 {
70 consume
71 consumeId
72 if (curt === Token.doubleColon)
73 {
74 consume
75 consumeId
76 if (curt === Token.asKeyword)
77 {
78 consume
79 consumeId
80 }
81 }
82 endOfStmt
83 }
84 }
85
86 //////////////////////////////////////////////////////////////////////////
87 // TypeDef
88 //////////////////////////////////////////////////////////////////////////
89
90 **
91 ** TypeDef:
92 ** <typeDef> := <classDef> | <mixinDef> | <enumDef>
93 **
94 ** <classDef> := <classHeader> <classBody>
95 ** <classHeader> := [<doc>] <facets> <typeFlags> "class" [<inheritance>]
96 ** <classFlags> := [<protection>] ["abstract"] ["final"]
97 ** <classBody> := "{" <slotDefs> "}"
98 **
99 ** <enumDef> := <enumHeader> <enumBody>
100 ** <enumHeader> := [<doc>] <facets> <protection> "enum" [<inheritance>]
101 ** <enumBody> := "{" <enumDefs> <slotDefs> "}"
102 **
103 ** <mixinDef> := <enumHeader> <enumBody>
104 ** <mixinHeader> := [<doc>] <facets> <protection> "mixin" [<inheritance>]
105 ** <mixinBody> := "{" <slotDefs> "}"
106 **
107 ** <protection> := "public" | "protected" | "private" | "internal"
108 ** <inheritance> := ":" <typeList>
109 **
110 Void typeDef()
111 {
112 // [<doc>]
113 doc := doc()
114 if (curt === Token.eof) return
115
116 // <facets>
117 facets := facets()
118
119 // <flags>
120 flags := flags(false)
121 if (flags & ~ProtectionMask == 0) flags |= FConst.Public
122
123 // local working variables
124 loc := cur
125 isMixin := false
126 isEnum := false
127
128 // mixin, enum, or class
129 if (curt === Token.mixinKeyword)
130 {
131 if (flags & FConst.Abstract != 0) err("The 'abstract' modifier is implied on mixin", loc)
132 if (flags & FConst.Const != 0) err("Cannot use 'const' modifier on mixin", loc)
133 if (flags & FConst.Final != 0) err("Cannot use 'final' modifier on mixin", loc)
134 flags |= FConst.Mixin | FConst.Abstract
135 isMixin = true
136 consume
137 }
138 else if (curt === Token.enumKeyword)
139 {
140 if (flags & FConst.Const != 0) err("The 'const' modifier is implied on enum", loc)
141 if (flags & FConst.Final != 0) err("The 'final' modifier is implied on enum", loc)
142 if (flags & FConst.Abstract != 0) err("Cannot use 'abstract' modifier on enum", loc)
143 flags |= FConst.Enum | FConst.Const | FConst.Final
144 isEnum = true
145 consume
146 }
147 else
148 {
149 consume(Token.classKeyword)
150 }
151
152 // name
153 name := consumeId
154 // lookup TypeDef
155 def := unit.types.find |TypeDef def->Bool| { return def.name == name }
156 if (def == null) throw err("Invalid class definition", cur)
157
158 // populate it's doc, facets, and flags
159 def.doc = doc
160 def.facets = facets
161 def.flags = flags
162
163 // inheritance
164 if (curt === Token.colon)
165 {
166 // first inheritance type can be extends or mixin
167 consume
168 first := typeRef
169 if (!first.isMixin)
170 def.base = first
171 else
172 def.mixins.add(first)
173
174 // additional mixins
175 while (curt === Token.comma)
176 {
177 consume
178 def.mixins.add(typeRef)
179 }
180 }
181
182 // if no inheritance specified then apply default base class
183 if (def.base == null)
184 {
185 def.baseSpecified = false
186 if (isEnum)
187 def.base = ns.enumType
188 else if (def.qname != "sys::Obj")
189 def.base = ns.objType
190 }
191
192 // start class body
193 consume(Token.lbrace)
194
195 // if enum, parse values
196 if (isEnum) enumDefs(def)
197
198 // slots
199 curType = def
200 closureCount = 0
201 while (true)
202 {
203 doc = this.doc
204 if (curt === Token.rbrace) break
205 slot := slotDef(def, doc)
206
207 // do duplicate name error checking here
208 if (def.hasSlotDef(slot.name))
209 {
210 err("Duplicate slot name '$slot.name'", slot.location)
211 }
212 else
213 {
214 def.addSlot(slot)
215 }
216 }
217 closureCount = null
218 curType = null
219
220 // end of class body
221 consume(Token.rbrace)
222 }
223
224 private Void mixins(TypeDef def)
225 {
226 consume // extends or mixin
227 def.mixins.add(typeRef)
228 while (curt === Token.comma)
229 {
230 consume
231 def.mixins.add(typeRef)
232 }
233 }
234
235 //////////////////////////////////////////////////////////////////////////
236 // Flags
237 //////////////////////////////////////////////////////////////////////////
238
239 **
240 ** Parse any list of flags in any order, we will check invalid
241 ** combinations in the CheckErrors step.
242 **
243 private Int flags(Bool normalize := true)
244 {
245 loc := cur
246 flags := 0
247 protection := false
248 for (done := false; !done; )
249 {
250 oldFlags := flags
251 switch (curt)
252 {
253 case Token.abstractKeyword: flags |= FConst.Abstract
254 case Token.constKeyword: flags |= FConst.Const
255 case Token.finalKeyword: flags |= FConst.Final
256 case Token.internalKeyword: flags |= FConst.Internal; protection = true
257 case Token.nativeKeyword: flags |= FConst.Native
258 case Token.newKeyword: flags |= FConst.Ctor
259 case Token.overrideKeyword: flags |= FConst.Override
260 case Token.privateKeyword: flags |= FConst.Private; protection = true
261 case Token.protectedKeyword: flags |= FConst.Protected; protection = true
262 case Token.publicKeyword: flags |= FConst.Public; protection = true
263 case Token.readonlyKeyword: flags |= Readonly // Parser only flag
264 case Token.staticKeyword: flags |= FConst.Static
265 case Token.virtualKeyword: flags |= FConst.Virtual
266 default: done = true
267 }
268 if (done) break
269 if (oldFlags == flags) err("Repeated modifier")
270 oldFlags = flags
271 consume
272 }
273
274 if ((flags & FConst.Abstract !== 0) && (flags & FConst.Virtual !== 0))
275 err("Abstract implies virtual", loc)
276 if ((flags & FConst.Override !== 0) && (flags & FConst.Virtual !== 0))
277 err("Override implies virtual", loc)
278
279 if (normalize)
280 {
281 if (!protection) flags |= FConst.Public
282 if (flags & FConst.Abstract !== 0) flags |= FConst.Virtual
283 if (flags & FConst.Override !== 0)
284 {
285 if (flags & FConst.Final !== 0)
286 flags &= ~FConst.Final
287 else
288 flags |= FConst.Virtual
289 }
290 }
291
292 return flags
293 }
294
295 //////////////////////////////////////////////////////////////////////////
296 // Enum
297 //////////////////////////////////////////////////////////////////////////
298
299 **
300 ** Enum definition list:
301 ** <enumDefs> := <enumDef> ("," <enumDef>)* <eos>
302 **
303 private Void enumDefs(TypeDef def)
304 {
305 ordinal := 0
306 def.enumDefs.add(enumDef(ordinal++))
307 while (curt === Token.comma)
308 {
309 consume
310 def.enumDefs.add(enumDef(ordinal++))
311 }
312 endOfStmt
313 }
314
315 **
316 ** Enum definition:
317 ** <enumDef> := <id> ["(" <args> ")"]
318 **
319 private EnumDef enumDef(Int ordinal)
320 {
321 doc := doc()
322
323 def := EnumDef.make(cur)
324 def.doc = doc
325 def.ordinal = ordinal
326 def.name = consumeId
327
328 // optional ctor args
329 if (curt === Token.lparen)
330 {
331 consume(Token.lparen)
332 if (curt != Token.rparen)
333 {
334 while (true)
335 {
336 def.ctorArgs.add( expr )
337 if (curt === Token.rparen) break
338 consume(Token.comma);
339 }
340 }
341 consume(Token.rparen)
342 }
343
344 return def
345 }
346
347 //////////////////////////////////////////////////////////////////////////
348 // Slots
349 //////////////////////////////////////////////////////////////////////////
350
351 **
352 ** Slot definition:
353 ** <slotDef> := <fieldDef> | <methodDef> | <ctorDef>
354 **
355 private SlotDef slotDef(TypeDef parent, Str[] doc)
356 {
357 // check for static {} class initialization
358 if (curt === Token.staticKeyword && peekt === Token.lbrace)
359 {
360 location := cur
361 consume
362 curMethod = MethodDef.makeStaticInit(location, parent, null)
363 curMethod.code = block(true)
364 return curMethod
365 }
366
367 // all members start with facets, flags
368 loc := cur
369 facets := facets()
370 flags := flags()
371
372 // check if this is a Java style constructor, log error and parse like Fan sytle ctor
373 if (curt === Token.identifier && cur.val == parent.name && peekt == Token.lparen)
374 {
375 err("Invalid constructor syntax - use new keyword")
376 return methodDef(loc, parent, doc, facets, flags|FConst.Ctor, TypeRef.make(loc, ns.voidType), consumeId)
377 }
378
379 // check for inferred typed field
380 // if = used rather than := then fieldDef() will log error
381 if (curt === Token.identifier && (peekt === Token.defAssign || peekt === Token.assign))
382 {
383 name := consumeId
384 return fieldDef(loc, parent, doc, facets, flags, null, name)
385 }
386
387 // check for constructor
388 if (flags & FConst.Ctor !== 0)
389 {
390 name := consumeId
391 return methodDef(loc, parent, doc, facets, flags, TypeRef.make(loc, ns.voidType), name)
392 }
393
394 // otherwise must be field or method
395 type := typeRef
396 name := consumeId
397 if (curt === Token.lparen)
398 {
399 return methodDef(loc, parent, doc, facets, flags, type, name)
400 }
401 else
402 {
403 return fieldDef(loc, parent, doc, facets, flags, type, name)
404 }
405 }
406
407 //////////////////////////////////////////////////////////////////////////
408 // FieldDef
409 //////////////////////////////////////////////////////////////////////////
410
411 **
412 ** Field definition:
413 ** <fieldDef> := <facets> <fieldFlags> [<type>] <id> [":=" <expr>]
414 ** [ "{" [<fieldGetter>] [<fieldSetter>] "}" ] <eos>
415 ** <fieldFlags> := [<protection>] ["readonly"] ["static"]
416 ** <fieldGetter> := "get" (<eos> | <block>)
417 ** <fieldSetter> := <protection> "set" (<eos> | <block>)
418 **
419 private FieldDef fieldDef(Location loc, TypeDef parent, Str[] doc, Str:FacetDef facets, Int flags, TypeRef type, Str name)
420 {
421 // define field itself
422 field := FieldDef.make(loc, parent)
423 field.doc = doc
424 field.facets = facets
425 field.flags = flags & ~ParserFlagsMask
426 field.fieldType = type
427 field.name = name
428
429 // const always has storage, otherwise assume no storage
430 // until proved otherwise in ResolveExpr step or we
431 // auto-generate getters/setters
432 if (field.isConst)
433 field.flags |= FConst.Storage
434
435 // field initializer
436 if (curt === Token.defAssign || curt === Token.assign)
437 {
438 if (curt === Token.assign) err("Must use := for field initialization")
439 consume
440 inFieldInit = true
441 field.init = expr
442 inFieldInit = false
443 }
444
445 // disable type inference for now - doing inference for literals is
446 // pretty trivial, but other types is tricky; I'm not sure it is such
447 // a hot idea anyways so it may just stay disabled forever
448 if (type == null)
449 err("Type inference not supported for fields", loc)
450
451 // if not const, define getter/setter methods
452 if (!field.isConst) defGetAndSet(field)
453
454 // explicit getter or setter
455 if (curt === Token.lbrace)
456 {
457 consume(Token.lbrace)
458 getOrSet(field)
459 getOrSet(field)
460 consume(Token.rbrace)
461 }
462
463 // generate synthetic getter or setter code if necessary
464 if (!field.isConst)
465 {
466 if (field.get.code == null) genSyntheticGet(field)
467 if (field.set.code == null) genSyntheticSet(field)
468 }
469
470 // readonly is syntatic sugar for { private set }
471 if (flags & Readonly !== 0)
472 {
473 field.set.flags = (field.set.flags & ProtectionMask) | FConst.Private
474 }
475
476 endOfStmt
477 return field
478 }
479
480 private Void defGetAndSet(FieldDef f)
481 {
482 loc := f.location
483
484 // getter MethodDef
485 get := MethodDef.make(loc, f.parentDef)
486 get.accessorFor = f
487 get.flags = f.flags | FConst.Getter
488 get.name = f.name
489 get.ret = f.fieldType
490 f.get = get
491
492 // setter MethodDef
493 set := MethodDef.make(loc, f.parentDef)
494 set.accessorFor = f
495 set.flags = f.flags | FConst.Setter
496 set.name = f.name
497 set.ret = ns.voidType
498 set.params.add(ParamDef.make(loc, f.fieldType, "val"))
499 f.set = set
500 }
501
502 private Void genSyntheticGet(FieldDef f)
503 {
504 loc := f.location
505 f.get.flags |= FConst.Synthetic
506 if (!f.isAbstract)
507 {
508 f.flags |= FConst.Storage
509 f.get.code = Block.make(loc)
510 f.get.code.add(ReturnStmt.make(loc, f.makeAccessorExpr(loc, false)))
511 }
512 }
513
514 private Void genSyntheticSet(FieldDef f)
515 {
516 loc := f.location
517 f.set.flags |= FConst.Synthetic
518 if (!f.isAbstract)
519 {
520 f.flags |= FConst.Storage
521 lhs := f.makeAccessorExpr(loc, false)
522 rhs := UnknownVarExpr.make(loc, null, "val")
523 f.set.code = Block.make(loc)
524 f.set.code.add(BinaryExpr.makeAssign(lhs, rhs).toStmt)
525 f.set.code.add(ReturnStmt.make(loc))
526 }
527 }
528
529 private Void getOrSet(FieldDef f)
530 {
531 loc := cur
532 accessorFlags := flags(false)
533 if (curt === Token.identifier)
534 {
535 // get or set
536 idLoc := cur
537 id := consumeId
538
539 if (id == "get")
540 curMethod = f.get
541 else
542 curMethod = f.set
543
544 // { ...block... }
545 Block block := null
546 if (curt === Token.lbrace)
547 block = this.block(id != "get")
548 else
549 endOfStmt
550
551 // const field cannot have getter/setter
552 if (f.isConst)
553 {
554 err("Const field '$f.name' cannot have ${id}ter", idLoc)
555 return
556 }
557
558 // map to get or set on FieldDef
559 if (id == "get")
560 {
561 if (accessorFlags != 0) err("Cannot use modifiers on field getter", loc)
562 f.get.code = block
563 }
564 else if (id.equals("set"))
565 {
566 if (accessorFlags != 0)
567 {
568 if (accessorFlags & ProtectionMask != 0)
569 err("Cannot use modifiers on field setter except to narrow protection", loc)
570 f.set.flags = (f.set.flags & ProtectionMask) | accessorFlags
571 }
572 f.set.code = block
573 }
574 else
575 {
576 err("Expected 'get' or 'set', not '$id'", idLoc)
577 }
578 }
579 }
580
581 //////////////////////////////////////////////////////////////////////////
582 // MethodDef
583 //////////////////////////////////////////////////////////////////////////
584
585 **
586 ** Method definition:
587 ** <methodDef> := <facets> <methodFlags> <type> <id> "(" <params> ")" <methodBody>
588 ** <methodFlags> := [<protection>] ["virtual"] ["override"] ["abstract"] ["static"]
589 ** <params> := [<param> ("," <param>)*]
590 ** <param> := <type> <id> [":=" <expr>]
591 ** <methodBody> := <eos> | ( "{" <stmts> "}" )
592 **
593 private MethodDef methodDef(Location loc, TypeDef parent, Str[] doc, Str:FacetDef facets, Int flags, TypeRef ret, Str name)
594 {
595 method := MethodDef.make(loc, parent)
596 method.doc = doc
597 method.facets = facets
598 method.flags = flags
599 method.ret = ret
600 method.name = name
601
602 // enter scope
603 curMethod = method
604
605 // parameters
606 consume(Token.lparen)
607 if (curt !== Token.rparen)
608 {
609 while (true)
610 {
611 method.params.add(paramDef)
612 if (curt === Token.rparen) break
613 consume(Token.comma)
614 }
615 }
616 consume(Token.rparen)
617
618 // if no body expected
619 if (flags & FConst.Abstract !== 0 || flags & FConst.Native !== 0 || isSys)
620 {
621 if (curt === Token.lbrace)
622 {
623 err("Abstract and native methods cannot have method body")
624 block(ret.isVoid) // keep parsing
625 }
626 else
627 {
628 endOfStmt
629 }
630 return method
631 }
632
633 // ctor chain
634 if ((flags & FConst.Ctor !== 0) && (curt === Token.colon))
635 method.ctorChain = ctorChain(method);
636
637 // body
638 if (curt != Token.lbrace)
639 err("Expecting method body")
640 else
641 method.code = block(ret.isVoid)
642
643 // exit scope
644 curMethod = null
645
646 return method
647 }
648
649 private ParamDef paramDef()
650 {
651 param := ParamDef.make(cur)
652 param.paramType = typeRef
653 param.name = consumeId
654 if (curt === Token.defAssign || curt === Token.assign)
655 {
656 if (curt === Token.assign) err("Must use := for parameter default");
657 consume
658 param.def = expr
659 }
660 return param
661 }
662
663 private CallExpr ctorChain(MethodDef method)
664 {
665 consume(Token.colon)
666 loc := cur
667
668 call := CallExpr.make(loc)
669 call.isCtorChain = true
670 switch (curt)
671 {
672 case Token.superKeyword: consume; call.target = SuperExpr.make(loc)
673 case Token.thisKeyword: consume; call.target = ThisExpr.make(loc)
674 default: throw err("Expecting this or super for constructor chaining", loc);
675 }
676
677 // we can omit name if super
678 if (call.target.id === ExprId.superExpr && curt != Token.dot)
679 {
680 call.name = method.name
681 }
682 else
683 {
684 consume(Token.dot)
685 call.name = consumeId
686 }
687
688 // TODO: omit args if pass thru?
689 callArgs(call)
690 return call
691 }
692
693 //////////////////////////////////////////////////////////////////////////
694 // Facets
695 //////////////////////////////////////////////////////////////////////////
696
697 private Str:FacetDef facets()
698 {
699 if (curt !== Token.at) return null
700
701 facets := Str:FacetDef[:]
702 while (curt === Token.at)
703 {
704 consume
705 loc := cur
706 name := consumeId
707 Expr val
708 if (curt === Token.assign)
709 {
710 consume()
711 val = expr
712 }
713 else
714 {
715 val = LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true)
716 }
717 if (facets[name] != null) err("Duplicate facet '$name'", loc)
718 facets[name] = FacetDef.make(loc, name, val)
719 }
720 return facets
721 }
722
723 //////////////////////////////////////////////////////////////////////////
724 // Block
725 //////////////////////////////////////////////////////////////////////////
726
727 **
728 ** Top level for blocks which must be surrounded by braces
729 **
730 private Block block(Bool inVoid)
731 {
732 this.inVoid = inVoid
733 verify(Token.lbrace)
734 return stmtOrBlock
735 }
736
737 **
738 ** <block> := <stmt> | ( "{" <stmts> "}" )
739 ** <stmts> := <stmt>*
740 **
741 private Block stmtOrBlock()
742 {
743 block := Block.make(cur)
744
745 if (curt !== Token.lbrace)
746 {
747 block.stmts.add( stmt )
748 }
749 else
750 {
751 consume(Token.lbrace)
752 while (curt != Token.rbrace)
753 block.stmts.add( stmt )
754 consume(Token.rbrace)
755 }
756
757 return block
758 }
759
760 //////////////////////////////////////////////////////////////////////////
761 // Statements
762 //////////////////////////////////////////////////////////////////////////
763
764 **
765 ** Statement:
766 ** <stmt> := <break> | <continue> | <for> | <if> | <return> | <switch> |
767 ** <throw> | <while> | <try> | <exprStmt> | <localDef>
768 **
769 private Stmt stmt()
770 {
771 // check for statement keywords
772 switch (curt)
773 {
774 case Token.breakKeyword: return breakStmt
775 case Token.continueKeyword: return continueStmt
776 case Token.forKeyword: return forStmt
777 case Token.ifKeyword: return ifStmt
778 case Token.returnKeyword: return returnStmt
779 case Token.switchKeyword: return switchStmt
780 case Token.throwKeyword: return throwStmt
781 case Token.tryKeyword: return tryStmt
782 case Token.whileKeyword: return whileStmt
783 }
784
785 // at this point we either have an expr or local var declaration
786 return exprOrLocalDefStmt(true)
787 }
788
789 **
790 ** Expression or local variable declaration:
791 ** <exprStmt> := <expr> <eos>
792 ** <localDef> := [<type>] <id> [":=" <expr>] <eos>
793 **
794 private Stmt exprOrLocalDefStmt(Bool isEndOfStmt)
795 {
796 // see if this statement begins with a type literal
797 loc := cur
798 mark := pos
799 localType := tryType
800
801 // type followed by identifier must be local variable declaration
802 if (localType != null && curt === Token.identifier)
803 {
804 return localDefStmt(loc, localType, isEndOfStmt)
805 }
806 reset(mark)
807
808 // identifier followed by def assign is inferred typed local var declaration
809 if (curt === Token.identifier && peekt === Token.defAssign)
810 {
811 return localDefStmt(loc, null, isEndOfStmt)
812 }
813
814 // if current is an identifer, save for special error handling
815 Str id := (curt === Token.identifier) ? (Str)cur.val : null
816
817 // otherwise assume it's a stand alone expression statement
818 stmt := ExprStmt.make(expr)
819 if (!isEndOfStmt) return stmt
820 if (endOfStmt(null)) return stmt
821
822 // report error
823 if (id != null && curt === Token.identifier && (peekt === Token.defAssign || peekt === Token.assign))
824 throw err("Unknown type '$id' for local declaration", loc)
825 else
826 throw err("Expected expression statement", loc)
827 }
828
829 **
830 ** Parse local variable declaration, the current token must be
831 ** the identifier of the local variable.
832 **
833 private LocalDefStmt localDefStmt(Location loc, CType localType, Bool isEndOfStmt)
834 {
835 stmt := LocalDefStmt.make(loc)
836 stmt.ctype = localType
837 stmt.name = consumeId
838
839 if (curt === Token.defAssign || curt === Token.assign)
840 {
841 if (curt === Token.assign) err("Must use := for declaration assignments")
842 consume
843 stmt.init = expr
844 }
845
846 if (isEndOfStmt) endOfStmt
847 return stmt
848 }
849
850 **
851 ** If/else statement:
852 ** <if> := "if" "(" <expr> ")" <block> [ "else" <block> ]
853 **
854 private IfStmt ifStmt()
855 {
856 stmt := IfStmt.make(cur)
857 consume(Token.ifKeyword)
858 consume(Token.lparen)
859 stmt.condition = expr
860 consume(Token.rparen)
861 stmt.trueBlock = stmtOrBlock
862 if (curt === Token.elseKeyword)
863 {
864 consume(Token.elseKeyword)
865 stmt.falseBlock = stmtOrBlock
866 }
867 return stmt
868 }
869
870 **
871 ** Return statement:
872 ** <return> := "return" [<expr>] <eos>
873 **
874 private ReturnStmt returnStmt()
875 {
876 stmt := ReturnStmt.make(cur)
877 consume(Token.returnKeyword)
878 if (inVoid)
879 {
880 endOfStmt("Expected end of statement after return in Void method")
881 }
882 else
883 {
884 stmt.expr = expr
885 endOfStmt
886 }
887 return stmt
888 }
889
890 **
891 ** Throw statement:
892 ** <throw> := "throw" <expr> <eos>
893 **
894 private ThrowStmt throwStmt()
895 {
896 stmt := ThrowStmt.make(cur)
897 consume(Token.throwKeyword)
898 stmt.exception = expr
899 endOfStmt
900 return stmt
901 }
902
903 **
904 ** While statement:
905 ** <while> := "while" "(" <expr> ")" <block>
906 **
907 private WhileStmt whileStmt()
908 {
909 stmt := WhileStmt.make(cur)
910 consume(Token.whileKeyword)
911 consume(Token.lparen)
912 stmt.condition = expr
913 consume(Token.rparen)
914 stmt.block = stmtOrBlock
915 return stmt
916 }
917
918 **
919 ** For statement:
920 ** <for> := "for" "(" [<forInit>] ";" <expr> ";" <expr> ")" <block>
921 ** <forInit> := <expr> | <localDef>
922 **
923 private ForStmt forStmt()
924 {
925 stmt := ForStmt.make(cur)
926 consume(Token.forKeyword)
927 consume(Token.lparen)
928
929 if (curt !== Token.semicolon) stmt.init = exprOrLocalDefStmt(false)
930 consume(Token.semicolon)
931
932 if (curt != Token.semicolon) stmt.condition = expr
933 consume(Token.semicolon)
934
935 if (curt != Token.rparen) stmt.update = expr
936 consume(Token.rparen)
937
938 stmt.block = stmtOrBlock
939 return stmt
940 }
941
942 **
943 ** Break statement:
944 ** <break> := "break" <eos>
945 **
946 private BreakStmt breakStmt()
947 {
948 stmt := BreakStmt.make(cur)
949 consume(Token.breakKeyword)
950 endOfStmt
951 return stmt
952 }
953
954 **
955 ** Continue statement:
956 ** <continue> := "continue" <eos>
957 **
958 private ContinueStmt continueStmt()
959 {
960 stmt := ContinueStmt.make(cur)
961 consume(Token.continueKeyword)
962 endOfStmt
963 return stmt
964 }
965
966 **
967 ** Try-catch-finally statement:
968 ** <try> := "try" "{" <stmt>* "}" <catch>* [<finally>]
969 ** <catch> := "catch" [<catchDef>] "{" <stmt>* "}"
970 ** <catchDef> := "(" <type> <id> ")"
971 ** <finally> := "finally" "{" <stmt>* "}"
972 **
973 private TryStmt tryStmt()
974 {
975 stmt := TryStmt.make(cur)
976 consume(Token.tryKeyword)
977 verify(Token.lbrace)
978 stmt.block = block(inVoid)
979 if (curt !== Token.catchKeyword && curt !== Token.finallyKeyword)
980 throw err("Expecting catch or finally block")
981 while (curt === Token.catchKeyword)
982 {
983 stmt.catches.add(tryCatch)
984 }
985 if (curt === Token.finallyKeyword)
986 {
987 consume
988 verify(Token.lbrace)
989 stmt.finallyBlock = block(inVoid)
990 }
991 return stmt
992 }
993
994 private Catch tryCatch()
995 {
996 c := Catch.make(cur)
997 consume(Token.catchKeyword)
998
999 if (curt === Token.lparen)
1000 {
1001 consume(Token.lparen)
1002 c.errType = typeRef
1003 c.errVariable = consumeId
1004 consume(Token.rparen)
1005 }
1006
1007 c.block = block(inVoid)
1008
1009 // insert implicit local variable declaration
1010 if (c.errVariable != null)
1011 c.block.stmts.insert(0, LocalDefStmt.makeCatchVar(c))
1012
1013 return c
1014 }
1015
1016 **
1017 ** Switch statement:
1018 ** <switch> := "switch" "(" <expr> ")" "{" <case>* [<default>] "}"
1019 ** <case> := "case" <expr> ":" <stmts>
1020 ** <default> := "default" ":" <stmts>
1021 **
1022 private SwitchStmt switchStmt()
1023 {
1024 stmt := SwitchStmt.make(cur)
1025 consume(Token.switchKeyword)
1026 consume(Token.lparen)
1027 stmt.condition = expr
1028 consume(Token.rparen)
1029 consume(Token.lbrace)
1030 while (curt != Token.rbrace)
1031 {
1032 if (curt === Token.caseKeyword)
1033 {
1034 c := Case.make(cur)
1035 while (curt === Token.caseKeyword)
1036 {
1037 consume
1038 c.cases.add(expr)
1039 consume(Token.colon)
1040 }
1041 if (curt !== Token.defaultKeyword) // optimize away case fall-thru to default
1042 {
1043 c.block = switchBlock
1044 stmt.cases.add(c)
1045 }
1046 }
1047 else if (curt === Token.defaultKeyword)
1048 {
1049 if (stmt.defaultBlock != null) err("Duplicate default blocks")
1050 consume
1051 consume(Token.colon)
1052 stmt.defaultBlock = switchBlock
1053 }
1054 else
1055 {
1056 throw err("Expected case or default statement")
1057 }
1058 }
1059 consume(Token.rbrace)
1060 endOfStmt
1061 return stmt
1062 }
1063
1064 private Block switchBlock()
1065 {
1066 Block block := null
1067 while (curt !== Token.caseKeyword && curt != Token.defaultKeyword && curt !== Token.rbrace)
1068 {
1069 if (block == null) block = Block.make(cur)
1070 block.stmts.add(stmt)
1071 }
1072 return block;
1073 }
1074
1075 //////////////////////////////////////////////////////////////////////////
1076 // Expr
1077 //////////////////////////////////////////////////////////////////////////
1078
1079 **
1080 ** Expression:
1081 ** <expr> := <assignExpr>
1082 **
1083 private Expr expr()
1084 {
1085 return assignExpr
1086 }
1087
1088 **
1089 ** Assignment expression:
1090 ** <assignExpr> := <condOrExpr> [<assignOp> <assignExpr>]
1091 ** <assignOp> := "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|="
1092 **
1093 private Expr assignExpr(Expr expr := null)
1094 {
1095 // this is tree if built to the right (others to the left)
1096 if (expr == null) expr = ternary
1097 if (curt.isAssign)
1098 {
1099 if (curt === Token.assign)
1100 return BinaryExpr.make(expr, consume.kind, assignExpr)
1101 else
1102 return ShortcutExpr.makeBinary(expr, consume.kind, assignExpr)
1103 }
1104 return expr
1105 }
1106
1107 **
1108 ** Ternary expression:
1109 ** <ternaryExpr> := <condOrExpr> "?" <condOrExpr> ":" <condOrExpr>
1110 **
1111 private Expr ternary()
1112 {
1113 expr := condOrExpr
1114 if (curt === Token.question)
1115 {
1116 condition := expr
1117 consume(Token.question);
1118 trueExpr := condOrExpr
1119 consume(Token.colon)
1120 falseExpr := condOrExpr
1121 expr = TernaryExpr.make(condition, trueExpr, falseExpr)
1122 }
1123 return expr
1124 }
1125
1126 **
1127 ** Conditional or expression:
1128 ** <condOrExpr> := <condAndExpr> ("||" <condAndExpr>)*
1129 **
1130 private Expr condOrExpr()
1131 {
1132 expr := condAndExpr
1133 if (curt === Token.doublePipe)
1134 {
1135 cond := CondExpr.make(expr, cur.kind)
1136 while (curt === Token.doublePipe)
1137 {
1138 consume
1139 cond.operands.add(condAndExpr)
1140 }
1141 expr = cond
1142 }
1143 return expr
1144 }
1145
1146 **
1147 ** Conditional and expression:
1148 ** <condAndExpr> := <equalityExpr> ("&&" <equalityExpr>)*
1149 **
1150 private Expr condAndExpr()
1151 {
1152 expr := equalityExpr
1153 if (curt === Token.doubleAmp)
1154 {
1155 cond := CondExpr.make(expr, cur.kind)
1156 while (curt === Token.doubleAmp)
1157 {
1158 consume
1159 cond.operands.add(equalityExpr)
1160 }
1161 expr = cond
1162 }
1163 return expr
1164 }
1165
1166 **
1167 ** Equality expression:
1168 ** <equalityExpr> := <relationalExpr> (("==" | "!=" | "===" | "!==") <relationalExpr>)*
1169 **
1170 private Expr equalityExpr()
1171 {
1172 expr := relationalExpr
1173 while (curt === Token.eq || curt === Token.notEq ||
1174 curt === Token.same || curt === Token.notSame)
1175 {
1176 lhs := expr
1177 tok := consume.kind
1178 rhs := relationalExpr
1179
1180 // optimize for null literal
1181 if (lhs.id === ExprId.nullLiteral || rhs.id === ExprId.nullLiteral)
1182 {
1183 id := (tok === Token.eq || tok === Token.same) ? ExprId.cmpNull : ExprId.cmpNotNull
1184 operand := (lhs.id === ExprId.nullLiteral) ? rhs : lhs
1185 expr = UnaryExpr.make(lhs.location, id, tok, operand)
1186 }
1187 else
1188 {
1189 if (tok === Token.same || tok === Token.notSame)
1190 expr = BinaryExpr.make(lhs, tok, rhs)
1191 else
1192 expr = ShortcutExpr.makeBinary(lhs, tok, rhs)
1193 }
1194 }
1195 return expr
1196 }
1197
1198 **
1199 ** Relational expression:
1200 ** <relationalExpr> := <rangeExpr> (("is" | "as" | "<" | "<=" | ">" | ">=" | "<=>") <rangeExpr>)*
1201 **
1202 private Expr relationalExpr()
1203 {
1204 expr := rangeExpr
1205 while (curt === Token.isKeyword || curt === Token.asKeyword ||
1206 curt === Token.lt || curt === Token.ltEq ||
1207 curt === Token.gt || curt === Token.gtEq ||
1208 curt === Token.cmp)
1209 {
1210 if (curt === Token.isKeyword)
1211 {
1212 consume
1213 expr = TypeCheckExpr.make(expr.location, ExprId.isExpr, expr, ctype)
1214 }
1215 else if (curt === Token.asKeyword)
1216 {
1217 consume
1218 expr = TypeCheckExpr.make(expr.location, ExprId.asExpr, expr, ctype)
1219 }
1220 else
1221 {
1222 expr = ShortcutExpr.makeBinary(expr, consume.kind, rangeExpr)
1223 }
1224 }
1225 return expr
1226 }
1227
1228 **
1229 ** Range expression:
1230 ** <rangeExpr> := <bitOrExpr> ((".." | "...") <bitOrExpr>)*
1231 **
1232 private Expr rangeExpr()
1233 {
1234 expr := bitOrExpr
1235 if (curt === Token.dotDot || curt === Token.dotDotDot)
1236 {
1237 range := RangeLiteralExpr.make(expr.location, ns.rangeType)
1238 range.start = expr
1239 range.exclusive = consume.kind === Token.dotDotDot
1240 range.end = bitOrExpr
1241 return range
1242 }
1243 return expr
1244 }
1245
1246 **
1247 ** Bitwise or expression:
1248 ** <bitOrExpr> := <bitAndExpr> (("^" | "|") <bitAndExpr>)*
1249 **
1250 private Expr bitOrExpr()
1251 {
1252 expr := bitAndExpr
1253 while (curt === Token.caret || curt === Token.pipe)
1254 expr = ShortcutExpr.makeBinary(expr, consume.kind, bitAndExpr)
1255 return expr
1256 }
1257
1258 **
1259 ** Bitwise and expression:
1260 ** <bitAndExpr> := <shiftExpr> (("&" <shiftExpr>)*
1261 **
1262 private Expr bitAndExpr()
1263 {
1264 expr := shiftExpr
1265 while (curt === Token.amp)
1266 expr = ShortcutExpr.makeBinary(expr, consume.kind, shiftExpr)
1267 return expr
1268 }
1269
1270 **
1271 ** Bitwise shift expression:
1272 ** <shiftExpr> := <addExpr> (("<<" | ">>") <addExpr>)*
1273 **
1274 private Expr shiftExpr()
1275 {
1276 expr := additiveExpr
1277 while (curt === Token.lshift || curt === Token.rshift)
1278 expr = ShortcutExpr.makeBinary(expr, consume.kind, additiveExpr)
1279 return expr
1280 }
1281
1282 **
1283 ** Additive expression:
1284 ** <addExpr> := <multExpr> (("+" | "-") <multExpr>)*
1285 **
1286 private Expr additiveExpr()
1287 {
1288 expr := multiplicativeExpr
1289 while (curt === Token.plus || curt === Token.minus)
1290 expr = ShortcutExpr.makeBinary(expr, consume.kind, multiplicativeExpr)
1291 return expr
1292 }
1293
1294 **
1295 ** Multiplicative expression:
1296 ** <multExpr> := <parenExpr> (("*" | "/" | "%") <parenExpr>)*
1297 **
1298 private Expr multiplicativeExpr()
1299 {
1300 expr := parenExpr
1301 while (curt === Token.star || curt === Token.slash || curt === Token.percent)
1302 expr = ShortcutExpr.makeBinary(expr, consume.kind, parenExpr)
1303 return expr
1304 }
1305
1306 **
1307 ** Paren grouped expression:
1308 ** <parenExpr> := <unaryExpr> | <castExpr> | <groupedExpr>
1309 ** <castExpr> := "(" <type> ")" <parenExpr>
1310 ** <groupedExpr> := "(" <expr> ")" <termChain>*
1311 **
1312 private Expr parenExpr()
1313 {
1314 if (curt != Token.lparen)
1315 return unaryExpr
1316
1317 // consume opening paren
1318 loc := cur
1319 consume(Token.lparen)
1320
1321 // In Fan just like C# and Java, a paren could mean
1322 // either a cast or a parenthesized expression
1323 mark := pos
1324 castType := tryType
1325 if (curt === Token.rparen)
1326 {
1327 consume
1328 return TypeCheckExpr.make(loc, ExprId.cast, parenExpr, castType)
1329 }
1330 reset(mark)
1331
1332 // this is just a normal parenthesized expression
1333 expr := expr
1334 consume(Token.rparen)
1335 while (true)
1336 {
1337 chained := termChainExpr(expr)
1338 if (chained == null) break
1339 expr = chained
1340 }
1341 return expr
1342 }
1343
1344 **
1345 ** Unary expression:
1346 ** <unaryExpr> := <prefixExpr> | <termExpr> | <postfixExpr>
1347 ** <prefixExpr> := ("!" | "+" | "-" | "~" | "++" | "--") <parenExpr>
1348 ** <postfixExpr> := <termExpr> ("++" | "--")
1349 **
1350 private Expr unaryExpr()
1351 {
1352 loc := cur
1353 tok := cur
1354 tokt := curt
1355
1356 if (tokt === Token.bang)
1357 {
1358 consume
1359 return UnaryExpr.make(loc, tokt.toExprId, tokt, parenExpr)
1360 }
1361
1362 if (tokt === Token.amp)
1363 {
1364 consume
1365 return CurryExpr.make(loc, parenExpr)
1366 }
1367
1368 if (tokt === Token.plus)
1369 {
1370 consume
1371 return parenExpr // optimize +expr to just expr
1372 }
1373
1374 if (tokt === Token.tilde || tokt === Token.minus)
1375 {
1376 consume
1377 return ShortcutExpr.makeUnary(loc, tokt, parenExpr)
1378 }
1379
1380 if (tokt === Token.increment || tokt === Token.decrement)
1381 {
1382 consume
1383 return ShortcutExpr.makeUnary(loc, tokt, parenExpr)
1384 }
1385
1386 expr := termExpr
1387
1388 tokt = curt
1389 if (tokt === Token.increment || tokt == Token.decrement)
1390 {
1391 consume
1392 shortcut := ShortcutExpr.makeUnary(loc, tokt, expr)
1393 shortcut.isPostfixLeave = true
1394 return shortcut
1395 }
1396
1397 return expr
1398 }
1399
1400 //////////////////////////////////////////////////////////////////////////
1401 // Term Expr
1402 //////////////////////////////////////////////////////////////////////////
1403
1404 **
1405 ** A term is a base terminal such as a variable, call, or literal,
1406 ** optionally followed by a chain of accessor expressions - such
1407 ** as "x.y[z](a, b)".
1408 **
1409 ** <termExpr> := <termBase> <termChain>* [withBlock]
1410 **
1411 private Expr termExpr(Expr target := null)
1412 {
1413 if (target == null) target = termBaseExpr
1414 while (true)
1415 {
1416 chained := termChainExpr(target)
1417 if (chained == null) break
1418 target = chained
1419 }
1420 if (curt == Token.lbrace)
1421 return withBlock(target)
1422 return target
1423 }
1424
1425 **
1426 ** Atomic base of a termExpr
1427 **
1428 ** <termBase> := <literal> | <idExpr> | <closure>
1429 ** <literal> := "null" | "this" | "super" | <bool> | <int> |
1430 ** <float> | <str> | <duration> | <list> | <map> | <uri>
1431 **
1432 private Expr termBaseExpr()
1433 {
1434 loc := cur
1435
1436 ctype := tryType
1437 if (ctype != null) return typeBaseExpr(loc, ctype)
1438
1439 switch (curt)
1440 {
1441 case Token.at: return idExpr(null, false)
1442 case Token.identifier: return idExpr(null, false)
1443 case Token.intLiteral: return LiteralExpr.make(loc, ExprId.intLiteral, ns.intType, consume.val)
1444 case Token.floatLiteral: return LiteralExpr.make(loc, ExprId.floatLiteral, ns.floatType, consume.val)
1445 case Token.strLiteral: return LiteralExpr.make(loc, ExprId.strLiteral, ns.strType, consume.val)
1446 case Token.durationLiteral: return LiteralExpr.make(loc, ExprId.durationLiteral, ns.durationType, consume.val)
1447 case Token.uriLiteral: return LiteralExpr.make(loc, ExprId.uriLiteral, ns.uriType, consume.val)
1448 case Token.lbracket: return collectionLiteralExpr(loc, null)
1449 case Token.falseKeyword: consume; return LiteralExpr.make(loc, ExprId.falseLiteral, ns.boolType, false)
1450 case Token.nullKeyword: consume; return LiteralExpr.make(loc, ExprId.nullLiteral, ns.objType, null)
1451 case Token.superKeyword: consume; return SuperExpr.make(loc)
1452 case Token.thisKeyword: consume; return ThisExpr.make(loc)
1453 case Token.trueKeyword: consume; return LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true)
1454 }
1455 throw err("Expected expression, not '" + cur + "'")
1456 }
1457
1458 **
1459 ** Handle a term expression which begins with a type literal.
1460 **
1461 private Expr typeBaseExpr(Location loc, CType ctype)
1462 {
1463 // type literal
1464 if (curt === Token.dot && peekt === Token.identifier && peek.val == "type")
1465 {
1466 consume
1467 consume
1468 return LiteralExpr.make(loc, ExprId.typeLiteral, ns.typeType, ctype)
1469 }
1470
1471 // dot is named super or static call chain
1472 if (curt == Token.dot)
1473 {
1474 consume
1475 if (curt === Token.superKeyword)
1476 {
1477 consume
1478 return SuperExpr.make(loc, ctype)
1479 }
1480 else
1481 {
1482 return idExpr(StaticTargetExpr.make(loc, ctype), false)
1483 }
1484 }
1485
1486 // list/map literal with explicit type
1487 if (curt === Token.lbracket)
1488 {
1489 return collectionLiteralExpr(loc, ctype)
1490 }
1491
1492 // closure
1493 if (curt == Token.lbrace && ctype is FuncType)
1494 {
1495 return closure(loc, (FuncType)ctype)
1496 }
1497
1498 // simple literal type(arg)
1499 if (curt == Token.lparen)
1500 {
1501 consume
1502 arg := expr
1503 consume(Token.rparen)
1504 return SimpleLiteralExpr.make(loc, ctype, arg)
1505 }
1506
1507 // complex literal type {...}
1508 if (curt == Token.lbrace)
1509 {
1510 base := UnknownVarExpr.make(loc, StaticTargetExpr.make(loc, ctype), "make")
1511 return withBlock(base)
1512 }
1513
1514 throw err("Unexpected type literal", loc)
1515 }
1516
1517 **
1518 ** A chain expression is a piece of a term expression that may
1519 ** be chained together such as "call.var[x]". If the specified
1520 ** target expression contains a chained access, then return the new
1521 ** expression, otherwise return null.
1522 **
1523 ** <termChain> := <compiledCall> | <dynamicCall> | <indexExpr>
1524 ** <compiledCall> := "." <idExpr>
1525 ** <dynamicCall> := "->" <idExpr>
1526 **
1527 private Expr termChainExpr(Expr target)
1528 {
1529 loc := cur
1530
1531 // if ".id" field access or ".id" call
1532 if (curt === Token.dot)
1533 {
1534 consume
1535 return idExpr(target, false)
1536 }
1537
1538 // if "->id" dynamic call
1539 if (curt === Token.arrow)
1540 {
1541 consume
1542 return idExpr(target, true)
1543 }
1544
1545 // if target[...]
1546 if (curt === Token.lbracket)
1547 return indexExpr(target)
1548
1549 // if target(...)
1550 if (curt === Token.lparen)
1551 return callOp(target)
1552
1553 // we treat a with base as a dot slot access
1554 if (target.id === ExprId.withBase)
1555 return idExpr(target, false)
1556
1557 // otherwise the expression should be finished
1558 return null;
1559 }
1560
1561 **
1562 ** A with block is a series of sub-expressions
1563 ** inside {} appended to the end of an expression.
1564 **
1565 private Expr withBlock(Expr base)
1566 {
1567 // field initializers look like a with block, but
1568 // we can safely peek to see if the next token is "get",
1569 // "set", or a keyword like "private"
1570 if (inFieldInit)
1571 {
1572 if (peek.kind.keyword) return base
1573 if (peekt == Token.identifier)
1574 {
1575 if (peek.val == "get" || peek.val == "set") return base
1576 }
1577 }
1578
1579 withBlock := WithBlockExpr.make(base)
1580 consume(Token.lbrace)
1581 while (curt !== Token.rbrace)
1582 {
1583 sub := assignExpr(termExpr(WithBaseExpr.make(withBlock)))
1584 withBlock.subs.add(sub)
1585 endOfStmt
1586 }
1587 consume(Token.rbrace)
1588 return withBlock
1589 }
1590
1591 //////////////////////////////////////////////////////////////////////////
1592 // Term Expr Utils
1593 //////////////////////////////////////////////////////////////////////////
1594
1595 **
1596 ** Identifier expression:
1597 ** <idExpr> := <local> | <field> | <call>
1598 ** <local> := <id>
1599 ** <field> := ["@"] <id>
1600 **
1601 private Expr idExpr(Expr target, Bool dynamicCall)
1602 {
1603 loc := cur
1604
1605 if (curt == Token.at)
1606 {
1607 consume
1608 return UnknownVarExpr.makeStorage(loc, target, consumeId)
1609 }
1610
1611 if (peekt === Token.lparen)
1612 {
1613 call := callExpr(target)
1614 call.isDynamic = dynamicCall
1615 return call
1616 }
1617
1618 name := consumeId
1619
1620 // if we have a closure then this is a call with one arg of a closure
1621 closure := tryClosure
1622 if (closure != null)
1623 {
1624 call := CallExpr.make(loc)
1625 call.target = target
1626 call.name = name
1627 call.args.add(closure)
1628 return call
1629 }
1630
1631 // if dynamic call then we know this is a call not a field
1632 if (dynamicCall)
1633 {
1634 call := CallExpr.make(loc)
1635 call.target = target
1636 call.name = name
1637 call.isDynamic = true
1638 return call
1639 }
1640
1641 return UnknownVarExpr.make(loc, target, name)
1642 }
1643
1644 **
1645 ** Call expression:
1646 ** <call> := <id> ["(" <args> ")"] [<closure>]
1647 **
1648 private CallExpr callExpr(Expr target)
1649 {
1650 call := CallExpr.make(cur)
1651 call.target = target
1652 call.name = consumeId
1653 callArgs(call)
1654 return call
1655 }
1656
1657 **
1658 ** Parse args with known parens:
1659 ** <args> := [<expr> ("," <expr>)*] [<closure>]
1660 **
1661 private Void callArgs(CallExpr call)
1662 {
1663 consume(Token.lparen)
1664 if (curt != Token.rparen)
1665 {
1666 while (true)
1667 {
1668 call.args.add(expr)
1669 if (curt === Token.rparen) break
1670 consume(Token.comma)
1671 }
1672 }
1673 consume(Token.rparen)
1674
1675 closure := tryClosure
1676 if (closure != null) call.args.add(closure);
1677 }
1678
1679 **
1680 ** Call operator:
1681 ** <callOp> := "(" <args> ")" [<closure>]
1682 **
1683 private Expr callOp(Expr target)
1684 {
1685 loc := cur
1686 call := CallExpr.make(loc)
1687 call.target = target
1688 callArgs(call)
1689 call.name = "call${call.args.size}"
1690 return call
1691 }
1692
1693 **
1694 ** Index expression:
1695 ** <indexExpr> := "[" <expr> "]"
1696 **
1697 private Expr indexExpr(Expr target)
1698 {
1699 loc := cur
1700 consume(Token.lbracket)
1701
1702 // otherwise this must be a standard single key index
1703 expr := expr
1704 consume(Token.rbracket)
1705 return ShortcutExpr.makeGet(loc, target, expr)
1706 }
1707
1708 //////////////////////////////////////////////////////////////////////////
1709 // Collection "Literals"
1710 //////////////////////////////////////////////////////////////////////////
1711
1712 **
1713 ** Collection literal:
1714 ** <list> := [<type>] "[" <listItems> "]"
1715 ** <listItems> := "," | (<expr> ("," <expr>)*)
1716 ** <map> := [<mapType>] "[" <mapItems> "]"
1717 ** <mapItems> := ":" | (<mapPair> ("," <mapPair>)*)
1718 ** <mapPair> := <expr> ":" <expr>
1719 **
1720 private Expr collectionLiteralExpr(Location loc, CType explicitType)
1721 {
1722 // empty list [,]
1723 if (peekt === Token.comma)
1724 return listLiteralExpr(loc, explicitType, null)
1725
1726 // empty map [:]
1727 if (peekt === Token.colon)
1728 return mapLiteralExpr(loc, explicitType, null)
1729
1730 // opening bracket
1731 consume(Token.lbracket)
1732
1733 // [] is error
1734 if (curt === Token.rbracket)
1735 {
1736 err("Invalid list literal; use '[,]' for empty Obj[] list", loc)
1737 consume
1738 return ListLiteralExpr.make(loc)
1739 }
1740
1741 // read first expression
1742 first := expr
1743
1744 // at this point we can determine if it is a list or a map
1745 if (curt === Token.colon)
1746 return mapLiteralExpr(loc, explicitType, first)
1747 else
1748 return listLiteralExpr(loc, explicitType, first)
1749 }
1750
1751 **
1752 ** Parse List literal; if first is null then
1753 ** cur must be on lbracket
1754 ** else
1755 ** cur must be on comma after first item
1756 **
1757 private ListLiteralExpr listLiteralExpr(Location loc, CType explicitType, Expr first)
1758 {
1759 // explicitType is type of List: Str[,]
1760 if (explicitType != null)
1761 explicitType = explicitType.toListOf
1762
1763 list := ListLiteralExpr.make(loc, (ListType)explicitType)
1764
1765 // if first is null, must be on lbracket
1766 if (first == null)
1767 {
1768 consume(Token.lbracket)
1769
1770 // if [,] empty list
1771 if (curt === Token.comma)
1772 {
1773 consume
1774 consume(Token.rbracket)
1775 return list
1776 }
1777
1778 first = expr
1779 }
1780
1781 list.vals.add(first)
1782 while (curt === Token.comma)
1783 {
1784 consume
1785 if (curt === Token.rbracket) break // allow extra trailing comma
1786 list.vals.add(expr)
1787 }
1788 consume(Token.rbracket)
1789 return list
1790 }
1791
1792 **
1793 ** Parse Map literal; if first is null:
1794 ** cur must be on lbracket
1795 ** else
1796 ** cur must be on colon of first key/value pair
1797 **
1798 private MapLiteralExpr mapLiteralExpr(Location loc, CType explicitType, Expr first)
1799 {
1800 // explicitType is *the* map type: Str:Str[,]
1801 if (explicitType != null && !(explicitType is MapType))
1802 {
1803 err("Invalid map type '$explicitType' for map literal", loc)
1804 explicitType = null
1805 }
1806
1807 map := MapLiteralExpr.make(loc, (MapType)explicitType)
1808
1809 // if first is null, must be on lbracket
1810 if (first == null)
1811 {
1812 consume(Token.lbracket)
1813
1814 // if [,] empty list
1815 if (curt === Token.colon)
1816 {
1817 consume
1818 consume(Token.rbracket)
1819 return map
1820 }
1821
1822 first = expr
1823 }
1824
1825 map.keys.add(first)
1826 consume(Token.colon)
1827 map.vals.add(expr)
1828 while (curt === Token.comma)
1829 {
1830 consume
1831 if (curt === Token.rbracket) break // allow extra trailing comma
1832 map.keys.add(expr)
1833 consume(Token.colon)
1834 map.vals.add(expr)
1835 }
1836 consume(Token.rbracket)
1837 return map
1838 }
1839
1840 //////////////////////////////////////////////////////////////////////////
1841 // Closure
1842 //////////////////////////////////////////////////////////////////////////
1843
1844 **
1845 ** Attempt to parse a closure expression or return null if we
1846 ** aren't positioned at the start of a closure expression.
1847 **
1848 private ClosureExpr tryClosure()
1849 {
1850 loc := cur
1851
1852 // if no pipe, then no closure
1853 if (curt !== Token.pipe) return null
1854
1855 // otherwise this can only be a FuncType declaration,
1856 // so give it a whirl, and bail if that fails
1857 mark := pos
1858 funcType := (FuncType)tryType
1859 if (funcType == null) return null
1860
1861 // if we don't see opening brace for body - no go
1862 if (curt !== Token.lbrace) { reset(mark); return null }
1863
1864 return closure(loc, funcType)
1865 }
1866
1867 **
1868 ** Parse body of closure expression and return ClosureExpr.
1869 **
1870 private ClosureExpr closure(Location loc, FuncType funcType)
1871 {
1872 if (curMethod == null)
1873 throw err("Unexpected closure outside of a method")
1874
1875 // closure anonymous class name: class$method$count
1876 name := "${curType.name}\$${curMethod.name}\$${closureCount++}"
1877
1878 // create closure
1879 closure := ClosureExpr.make(loc, curType, curMethod, curClosure, funcType, name)
1880
1881 // save all closures in global list and list per type
1882 closures.add(closure)
1883 curType.closures.add(closure)
1884
1885 // parse block; temporarily change our inVoid flag and curClosure
1886 oldInVoid := inVoid
1887 oldClosure := curClosure
1888 curClosure = closure
1889 closure.code = block(funcType.ret.isVoid)
1890 curClosure = oldClosure
1891 inVoid = oldInVoid
1892
1893 return closure
1894 }
1895
1896 //////////////////////////////////////////////////////////////////////////
1897 // Types
1898 //////////////////////////////////////////////////////////////////////////
1899
1900 **
1901 ** Parse a type production into a CType and wrap it as AST TypeRef.
1902 **
1903 private TypeRef typeRef()
1904 {
1905 Location loc := cur
1906 return TypeRef.make(loc, ctype)
1907 }
1908
1909 **
1910 ** If the current stream of tokens can be parsed as a
1911 ** valid type production return it. Otherwise leave
1912 ** the parser positioned on the current token.
1913 **
1914 private CType tryType()
1915 {
1916 // types can only begin with identifier, | or [
1917 if (curt !== Token.identifier && curt !== Token.pipe && curt !== Token.lbracket)
1918 return null
1919
1920 suppressErr = true
1921 mark := pos
1922 CType type := null
1923 try
1924 {
1925 type = ctype
1926 }
1927 catch (SuppressedErr e)
1928 {
1929 }
1930 suppressErr = false
1931 if (type == null) reset(mark)
1932 return type
1933 }
1934
1935 **
1936 ** Type signature:
1937 ** <type> := <simpleType> | <listType> | <mapType> | <funcType>
1938 ** <listType> := <type> "[]"
1939 ** <mapType> := ["["] <type> ":" <type> ["]"]
1940 **
1941 private CType ctype()
1942 {
1943 CType t := null
1944
1945 // Types can begin with:
1946 // - id
1947 // - [k:v]
1948 // - |a, b -> r|
1949 if (curt === Token.identifier)
1950 {
1951 t = simpleType
1952 }
1953 else if (curt === Token.lbracket)
1954 {
1955 loc := consume(Token.lbracket)
1956 t = ctype
1957 consume(Token.rbracket)
1958 if (!(t is MapType)) err("Invalid map type", loc)
1959 }
1960 else if (curt === Token.pipe)
1961 {
1962 t = funcType
1963 }
1964 else
1965 {
1966 throw err("Expecting type name")
1967 }
1968
1969 // trailing [] for lists
1970 while (curt === Token.lbracket && peekt === Token.rbracket)
1971 {
1972 consume(Token.lbracket)
1973 consume(Token.rbracket)
1974 t = t.toListOf
1975 }
1976
1977 // check for ":" for map type
1978 if (curt === Token.colon)
1979 {
1980 consume(Token.colon)
1981 key := t
1982 val := ctype
1983 t = MapType.make(key, val)
1984 }
1985
1986 return t
1987 }
1988
1989 **
1990 ** Simple type signature:
1991 ** <simpleType> := <id> ["::" <id>]
1992 **
1993 private CType simpleType()
1994 {
1995 loc := cur
1996 id := consumeId
1997
1998 // fully qualified
1999 if (curt === Token.doubleColon)
2000 {
2001 consume
2002 return ResolveImports.resolveQualified(this, id, consumeId, loc)
2003 }
2004
2005 // unqualified name, lookup in imported types
2006 types := unit.importedTypes[id]
2007 if (types == null)
2008 {
2009 // handle sys generic parameters
2010 if (isSys && id.size == 1)
2011 return ns.genericParameter(id)
2012
2013 // not found in imports
2014 err("Unknown type '$id'", loc)
2015 return ns.voidType
2016 }
2017
2018 // if more then one it is ambiguous
2019 if (types.size > 1) err("Ambiguous type: " + types.join(", "))
2020
2021 // got it
2022 return types.first
2023 }
2024
2025 **
2026 ** Method type signature:
2027 ** <funcType> := "|" <formals> ["->" <type> "|"
2028 ** <formals> := [<formal> ("," <formal>)*]
2029 ** <formal> := <type> <id>
2030 **
2031 private CType funcType()
2032 {
2033 params := CType[,]
2034 names := Str[,]
2035 ret := ns.voidType
2036
2037 // opening pipe
2038 consume(Token.pipe)
2039
2040 // |,| is the empty method type
2041 if (curt === Token.comma)
2042 {
2043 consume
2044 consume(Token.pipe)
2045 return FuncType.make(params, names, ret)
2046 }
2047
2048 // params, must be one if no ->
2049 if (curt !== Token.arrow)
2050 {
2051 params.add(ctype)
2052 names.add(consumeId)
2053 }
2054 while (curt === Token.comma)
2055 {
2056 consume
2057 params.add(ctype)
2058 names.add(consumeId)
2059 }
2060
2061 // optional arrow
2062 if (curt === Token.arrow)
2063 {
2064 consume
2065 ret = ctype
2066 }
2067
2068 // closing pipe
2069 consume(Token.pipe)
2070 return FuncType.make(params, names, ret)
2071 }
2072
2073 //////////////////////////////////////////////////////////////////////////
2074 // Misc
2075 //////////////////////////////////////////////////////////////////////////
2076
2077 **
2078 ** Parse fandoc or retur null
2079 **
2080 private Str[] doc()
2081 {
2082 Str[] doc := null
2083 while (curt === Token.docComment)
2084 doc = (Str[])consume(Token.docComment).val
2085 return doc
2086 }
2087
2088 //////////////////////////////////////////////////////////////////////////
2089 // Errors
2090 //////////////////////////////////////////////////////////////////////////
2091
2092 override CompilerErr err(Str msg, Location loc := null)
2093 {
2094 if (suppressErr) throw SuppressedErr.make
2095 if (loc == null) loc = cur
2096 return super.err(msg, loc)
2097 }
2098
2099 //////////////////////////////////////////////////////////////////////////
2100 // Tokens
2101 //////////////////////////////////////////////////////////////////////////
2102
2103 **
2104 ** Verify current is an identifier, consume it, and return it.
2105 **
2106 private Str consumeId()
2107 {
2108 if (curt !== Token.identifier)
2109 throw err("Expected identifier, not '$cur'");
2110 return (Str)consume.val;
2111 }
2112
2113 **
2114 ** Check that the current token matches the specified
2115 ** type, but do not consume it.
2116 **
2117 private Void verify(Token kind)
2118 {
2119 if (curt !== kind)
2120 throw err("Expected '$kind.symbol', not '$cur'");
2121 }
2122
2123 **
2124 ** Consume the current token and return consumed token.
2125 ** If kind is non-null then verify first
2126 **
2127 private TokenVal consume(Token kind := null)
2128 {
2129 // verify if not null
2130 if (kind != null) verify(kind)
2131
2132 // save the current we are about to consume for return
2133 result := cur
2134
2135 // get the next token from the buffer, if pos is past numTokens,
2136 // then always use the last token which will be eof
2137 TokenVal next;
2138 pos++;
2139 if (pos+1 < numTokens)
2140 next = tokens[pos+1] // next peek is cur+1
2141 else
2142 next = tokens[numTokens-1]
2143
2144 this.cur = peek
2145 this.peek = next
2146 this.curt = cur.kind
2147 this.peekt = peek.kind
2148
2149 return result
2150 }
2151
2152 **
2153 ** Statements can be terminated with a semicolon, end of line
2154 ** or } end of block. Return true on success. On failure
2155 ** return false if errMsg is null or log/throw an exception.
2156 **
2157 private Bool endOfStmt(Str errMsg := "Expected end of statement: semicolon, newline, or end of block; not '$cur'")
2158 {
2159 if (cur.newline) return true
2160 if (curt === Token.semicolon) { consume; return true }
2161 if (curt === Token.rbrace) return true
2162 if (errMsg == null) return false
2163 throw err(errMsg)
2164 }
2165
2166 **
2167 ** Reset the current position to the specified tokens index.
2168 **
2169 private Void reset(Int pos)
2170 {
2171 this.pos = pos
2172 this.cur = tokens[pos]
2173 if (pos+1 < numTokens)
2174 this.peek = tokens[pos+1]
2175 else
2176 this.peek = tokens[pos]
2177 this.curt = cur.kind
2178 this.peekt = peek.kind
2179 }
2180
2181 //////////////////////////////////////////////////////////////////////////
2182 // Parser Flags
2183 //////////////////////////////////////////////////////////////////////////
2184
2185 // These are flags used only by the parser we merge with FConst
2186 // flags by starting from most significant bit and working down
2187 const static Int Readonly := 0x80000000
2188 const static Int ParserFlagsMask := Readonly
2189
2190 // Bitwise and this mask to clear all protection scope flags
2191 const static Int ProtectionMask := ~(FConst.Public|FConst.Protected|FConst.Private|FConst.Internal)
2192
2193 //////////////////////////////////////////////////////////////////////////
2194 // Fields
2195 //////////////////////////////////////////////////////////////////////////
2196
2197 private CompilationUnit unit // compilation unit to generate
2198 private TokenVal[] tokens // tokens all read in
2199 private Int numTokens // number of tokens
2200 private Int pos; // offset Into tokens for cur
2201 private TokenVal cur // current token
2202 private Token curt // current token type
2203 private TokenVal peek // next token
2204 private Token peekt // next token type
2205 private Bool suppressErr // throw SuppressedErr instead of CompilerErr
2206 private Bool isSys := false // are we parsing the sys pod itself
2207 private Bool inVoid // are we currently in a void method
2208 private Bool inFieldInit := false // are we currently in a field initializer
2209 private TypeDef curType // current TypeDef scope
2210 private MethodDef curMethod // current MethodDef scope
2211 private ClosureExpr curClosure // current ClosureExpr if inside closure
2212 private Int closureCount // number of closures parsed inside curMethod
2213 private ClosureExpr[] closures // list of all closures parsed
2214
2215 }
2216
2217 //////////////////////////////////////////////////////////////////////////
2218 // SuppressedErr
2219 //////////////////////////////////////////////////////////////////////////
2220
2221 const class SuppressedErr : Err
2222 {
2223 new make() : super(null, null) {}
2224 }