• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.parse;
18 
19 import static com.google.turbine.parse.Token.COMMA;
20 import static com.google.turbine.parse.Token.INTERFACE;
21 import static com.google.turbine.parse.Token.LPAREN;
22 import static com.google.turbine.parse.Token.RPAREN;
23 import static com.google.turbine.parse.Token.SEMI;
24 import static com.google.turbine.tree.TurbineModifier.PROTECTED;
25 import static com.google.turbine.tree.TurbineModifier.PUBLIC;
26 
27 import com.google.common.collect.ImmutableList;
28 import com.google.common.collect.ImmutableSet;
29 import com.google.errorprone.annotations.CheckReturnValue;
30 import com.google.turbine.diag.SourceFile;
31 import com.google.turbine.diag.TurbineError;
32 import com.google.turbine.diag.TurbineError.ErrorKind;
33 import com.google.turbine.model.TurbineConstantTypeKind;
34 import com.google.turbine.model.TurbineTyKind;
35 import com.google.turbine.tree.Tree;
36 import com.google.turbine.tree.Tree.Anno;
37 import com.google.turbine.tree.Tree.ArrTy;
38 import com.google.turbine.tree.Tree.ClassTy;
39 import com.google.turbine.tree.Tree.CompUnit;
40 import com.google.turbine.tree.Tree.Expression;
41 import com.google.turbine.tree.Tree.Ident;
42 import com.google.turbine.tree.Tree.ImportDecl;
43 import com.google.turbine.tree.Tree.Kind;
44 import com.google.turbine.tree.Tree.MethDecl;
45 import com.google.turbine.tree.Tree.ModDecl;
46 import com.google.turbine.tree.Tree.ModDirective;
47 import com.google.turbine.tree.Tree.ModExports;
48 import com.google.turbine.tree.Tree.ModOpens;
49 import com.google.turbine.tree.Tree.ModProvides;
50 import com.google.turbine.tree.Tree.ModRequires;
51 import com.google.turbine.tree.Tree.ModUses;
52 import com.google.turbine.tree.Tree.PkgDecl;
53 import com.google.turbine.tree.Tree.PrimTy;
54 import com.google.turbine.tree.Tree.TyDecl;
55 import com.google.turbine.tree.Tree.TyParam;
56 import com.google.turbine.tree.Tree.Type;
57 import com.google.turbine.tree.Tree.VarDecl;
58 import com.google.turbine.tree.Tree.WildTy;
59 import com.google.turbine.tree.TurbineModifier;
60 import java.util.ArrayDeque;
61 import java.util.Deque;
62 import java.util.EnumSet;
63 import java.util.List;
64 import java.util.Optional;
65 import javax.annotation.Nullable;
66 
67 /**
68  * A parser for the subset of Java required for header compilation.
69  *
70  * <p>See JLS 19: https://docs.oracle.com/javase/specs/jls/se8/html/jls-19.html
71  */
72 public class Parser {
73 
74   private static final String CTOR_NAME = "<init>";
75   private final Lexer lexer;
76 
77   private Token token;
78   private int position;
79 
parse(String source)80   public static CompUnit parse(String source) {
81     return parse(new SourceFile(null, source));
82   }
83 
parse(SourceFile source)84   public static CompUnit parse(SourceFile source) {
85     return new Parser(new StreamLexer(new UnicodeEscapePreprocessor(source))).compilationUnit();
86   }
87 
Parser(Lexer lexer)88   private Parser(Lexer lexer) {
89     this.lexer = lexer;
90     this.token = lexer.next();
91   }
92 
compilationUnit()93   public CompUnit compilationUnit() {
94     // TODO(cushon): consider enforcing package, import, and declaration order
95     // and make it bug-compatible with javac:
96     // http://mail.openjdk.java.net/pipermail/compiler-dev/2013-August/006968.html
97     Optional<PkgDecl> pkg = Optional.empty();
98     Optional<ModDecl> mod = Optional.empty();
99     EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class);
100     ImmutableList.Builder<ImportDecl> imports = ImmutableList.builder();
101     ImmutableList.Builder<TyDecl> decls = ImmutableList.builder();
102     ImmutableList.Builder<Anno> annos = ImmutableList.builder();
103     while (true) {
104       switch (token) {
105         case PACKAGE:
106           {
107             next();
108             pkg = Optional.of(packageDeclaration(annos.build()));
109             annos = ImmutableList.builder();
110             break;
111           }
112         case IMPORT:
113           {
114             next();
115             ImportDecl i = importDeclaration();
116             if (i == null) {
117               continue;
118             }
119             imports.add(i);
120             break;
121           }
122         case PUBLIC:
123           next();
124           access.add(PUBLIC);
125           break;
126         case PROTECTED:
127           next();
128           access.add(PROTECTED);
129           break;
130         case PRIVATE:
131           next();
132           access.add(TurbineModifier.PRIVATE);
133           break;
134         case STATIC:
135           next();
136           access.add(TurbineModifier.STATIC);
137           break;
138         case ABSTRACT:
139           next();
140           access.add(TurbineModifier.ABSTRACT);
141           break;
142         case FINAL:
143           next();
144           access.add(TurbineModifier.FINAL);
145           break;
146         case STRICTFP:
147           next();
148           access.add(TurbineModifier.STRICTFP);
149           break;
150         case AT:
151           {
152             next();
153             if (token == INTERFACE) {
154               decls.add(annotationDeclaration(access, annos.build()));
155               access = EnumSet.noneOf(TurbineModifier.class);
156               annos = ImmutableList.builder();
157             } else {
158               annos.add(annotation());
159             }
160             break;
161           }
162         case CLASS:
163           decls.add(classDeclaration(access, annos.build()));
164           access = EnumSet.noneOf(TurbineModifier.class);
165           annos = ImmutableList.builder();
166           break;
167         case INTERFACE:
168           decls.add(interfaceDeclaration(access, annos.build()));
169           access = EnumSet.noneOf(TurbineModifier.class);
170           annos = ImmutableList.builder();
171           break;
172         case ENUM:
173           decls.add(enumDeclaration(access, annos.build()));
174           access = EnumSet.noneOf(TurbineModifier.class);
175           annos = ImmutableList.builder();
176           break;
177         case EOF:
178           // TODO(cushon): check for dangling modifiers?
179           return new CompUnit(position, pkg, mod, imports.build(), decls.build(), lexer.source());
180         case SEMI:
181           // TODO(cushon): check for dangling modifiers?
182           next();
183           continue;
184         case IDENT:
185           {
186             Ident ident = ident();
187             if (access.isEmpty()
188                 && (ident.value().equals("module") || ident.value().equals("open"))) {
189               boolean open = false;
190               if (ident.value().equals("open")) {
191                 ident = eatIdent();
192                 open = true;
193               }
194               if (!ident.value().equals("module")) {
195                 throw error(token);
196               }
197               next();
198               mod = Optional.of(moduleDeclaration(open, annos.build()));
199               annos = ImmutableList.builder();
200               break;
201             }
202           }
203           // fall through
204         default:
205           throw error(token);
206       }
207     }
208   }
209 
next()210   private void next() {
211     token = lexer.next();
212     position = lexer.position();
213   }
214 
interfaceDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos)215   private TyDecl interfaceDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
216     eat(Token.INTERFACE);
217     int pos = position;
218     Ident name = eatIdent();
219     ImmutableList<TyParam> typarams;
220     if (token == Token.LT) {
221       typarams = typarams();
222     } else {
223       typarams = ImmutableList.of();
224     }
225     ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder();
226     if (token == Token.EXTENDS) {
227       next();
228       do {
229         interfaces.add(classty());
230       } while (maybe(Token.COMMA));
231     }
232     eat(Token.LBRACE);
233     ImmutableList<Tree> members = classMembers();
234     eat(Token.RBRACE);
235     return new TyDecl(
236         pos,
237         access,
238         annos,
239         name,
240         typarams,
241         Optional.<ClassTy>empty(),
242         interfaces.build(),
243         members,
244         TurbineTyKind.INTERFACE);
245   }
246 
annotationDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos)247   private TyDecl annotationDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
248     eat(Token.INTERFACE);
249     int pos = position;
250     Ident name = eatIdent();
251     eat(Token.LBRACE);
252     ImmutableList<Tree> members = classMembers();
253     eat(Token.RBRACE);
254     return new TyDecl(
255         pos,
256         access,
257         annos,
258         name,
259         ImmutableList.<TyParam>of(),
260         Optional.<ClassTy>empty(),
261         ImmutableList.<ClassTy>of(),
262         members,
263         TurbineTyKind.ANNOTATION);
264   }
265 
enumDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos)266   private TyDecl enumDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
267     eat(Token.ENUM);
268     int pos = position;
269     Ident name = eatIdent();
270     ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder();
271     if (token == Token.IMPLEMENTS) {
272       next();
273       do {
274         interfaces.add(classty());
275       } while (maybe(Token.COMMA));
276     }
277     eat(Token.LBRACE);
278     ImmutableList<Tree> members =
279         ImmutableList.<Tree>builder().addAll(enumMembers(name)).addAll(classMembers()).build();
280     eat(Token.RBRACE);
281     return new TyDecl(
282         pos,
283         access,
284         annos,
285         name,
286         ImmutableList.<TyParam>of(),
287         Optional.<ClassTy>empty(),
288         interfaces.build(),
289         members,
290         TurbineTyKind.ENUM);
291   }
292 
moduleName()293   private String moduleName() {
294     return flatname('.', qualIdent());
295   }
296 
packageName()297   private String packageName() {
298     return flatname('/', qualIdent());
299   }
300 
moduleDeclaration(boolean open, ImmutableList<Anno> annos)301   private ModDecl moduleDeclaration(boolean open, ImmutableList<Anno> annos) {
302     int pos = position;
303     String moduleName = moduleName();
304     eat(Token.LBRACE);
305     ImmutableList.Builder<ModDirective> directives = ImmutableList.builder();
306     OUTER:
307     while (true) {
308       switch (token) {
309         case IDENT:
310           {
311             String ident = lexer.stringValue();
312             next();
313             switch (ident) {
314               case "requires":
315                 directives.add(moduleRequires());
316                 break;
317               case "exports":
318                 directives.add(moduleExports());
319                 break;
320               case "opens":
321                 directives.add(moduleOpens());
322                 break;
323               case "uses":
324                 directives.add(moduleUses());
325                 break;
326               case "provides":
327                 directives.add(moduleProvides());
328                 break;
329               default: // fall out
330             }
331             break;
332           }
333         case RBRACE:
334           break OUTER;
335         default:
336           throw error(token);
337       }
338     }
339     eat(Token.RBRACE);
340     return new ModDecl(pos, annos, open, moduleName, directives.build());
341   }
342 
flatname(char join, ImmutableList<Ident> idents)343   private String flatname(char join, ImmutableList<Ident> idents) {
344     StringBuilder sb = new StringBuilder();
345     boolean first = true;
346     for (Ident ident : idents) {
347       if (!first) {
348         sb.append(join);
349       }
350       sb.append(ident.value());
351       first = false;
352     }
353     return sb.toString();
354   }
355 
moduleRequires()356   private ModRequires moduleRequires() {
357     int pos = position;
358     EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class);
359     while (true) {
360       if (token == Token.IDENT && lexer.stringValue().equals("transitive")) {
361         next();
362         access.add(TurbineModifier.TRANSITIVE);
363         break;
364       }
365       if (token == Token.STATIC) {
366         next();
367         access.add(TurbineModifier.STATIC);
368         break;
369       }
370       break;
371     }
372 
373     String moduleName = moduleName();
374     eat(Token.SEMI);
375     return new ModRequires(pos, ImmutableSet.copyOf(access), moduleName);
376   }
377 
moduleExports()378   private ModExports moduleExports() {
379     int pos = position;
380 
381     String packageName = packageName();
382     ImmutableList.Builder<String> moduleNames = ImmutableList.builder();
383     if (lexer.stringValue().equals("to")) {
384       next();
385       do {
386 
387         moduleNames.add(moduleName());
388       } while (maybe(Token.COMMA));
389     }
390     eat(Token.SEMI);
391     return new ModExports(pos, packageName, moduleNames.build());
392   }
393 
moduleOpens()394   private ModOpens moduleOpens() {
395     int pos = position;
396 
397     String packageName = packageName();
398     ImmutableList.Builder<String> moduleNames = ImmutableList.builder();
399     if (lexer.stringValue().equals("to")) {
400       next();
401       do {
402 
403         String moduleName = moduleName();
404         moduleNames.add(moduleName);
405       } while (maybe(Token.COMMA));
406     }
407     eat(Token.SEMI);
408     return new ModOpens(pos, packageName, moduleNames.build());
409   }
410 
moduleUses()411   private ModUses moduleUses() {
412     int pos = position;
413     ImmutableList<Ident> uses = qualIdent();
414     eat(Token.SEMI);
415     return new ModUses(pos, uses);
416   }
417 
moduleProvides()418   private ModProvides moduleProvides() {
419     int pos = position;
420     ImmutableList<Ident> typeName = qualIdent();
421     if (!eatIdent().value().equals("with")) {
422       throw error(token);
423     }
424     ImmutableList.Builder<ImmutableList<Ident>> implNames = ImmutableList.builder();
425     do {
426       ImmutableList<Ident> implName = qualIdent();
427       implNames.add(implName);
428     } while (maybe(Token.COMMA));
429     eat(Token.SEMI);
430     return new ModProvides(pos, typeName, implNames.build());
431   }
432 
433   private static final ImmutableSet<TurbineModifier> ENUM_CONSTANT_MODIFIERS =
434       ImmutableSet.of(
435           TurbineModifier.PUBLIC,
436           TurbineModifier.STATIC,
437           TurbineModifier.ACC_ENUM,
438           TurbineModifier.FINAL);
439 
enumMembers(Ident enumName)440   private ImmutableList<Tree> enumMembers(Ident enumName) {
441     ImmutableList.Builder<Tree> result = ImmutableList.builder();
442     ImmutableList.Builder<Anno> annos = ImmutableList.builder();
443     OUTER:
444     while (true) {
445       switch (token) {
446         case IDENT:
447           {
448             Ident name = eatIdent();
449             if (token == Token.LPAREN) {
450               dropParens();
451             }
452             // TODO(cushon): consider desugaring enum constants later
453             if (token == Token.LBRACE) {
454               dropBlocks();
455             }
456             maybe(Token.COMMA);
457             result.add(
458                 new VarDecl(
459                     position,
460                     ENUM_CONSTANT_MODIFIERS,
461                     annos.build(),
462                     new ClassTy(
463                         position,
464                         Optional.<ClassTy>empty(),
465                         enumName,
466                         ImmutableList.<Type>of(),
467                         ImmutableList.of()),
468                     name,
469                     Optional.<Expression>empty()));
470             annos = ImmutableList.builder();
471             break;
472           }
473         case SEMI:
474           next();
475           annos = ImmutableList.builder();
476           break OUTER;
477         case RBRACE:
478           annos = ImmutableList.builder();
479           break OUTER;
480         case AT:
481           next();
482           annos.add(annotation());
483           break;
484         default:
485           throw error(token);
486       }
487     }
488     return result.build();
489   }
490 
classDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos)491   private TyDecl classDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
492     eat(Token.CLASS);
493     int pos = position;
494     Ident name = eatIdent();
495     ImmutableList<TyParam> tyParams = ImmutableList.of();
496     if (token == Token.LT) {
497       tyParams = typarams();
498     }
499     ClassTy xtnds = null;
500     if (token == Token.EXTENDS) {
501       next();
502       xtnds = classty();
503     }
504     ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder();
505     if (token == Token.IMPLEMENTS) {
506       next();
507       do {
508         interfaces.add(classty());
509       } while (maybe(Token.COMMA));
510     }
511     eat(Token.LBRACE);
512     ImmutableList<Tree> members = classMembers();
513     eat(Token.RBRACE);
514     return new TyDecl(
515         pos,
516         access,
517         annos,
518         name,
519         tyParams,
520         Optional.ofNullable(xtnds),
521         interfaces.build(),
522         members,
523         TurbineTyKind.CLASS);
524   }
525 
classMembers()526   private ImmutableList<Tree> classMembers() {
527     ImmutableList.Builder<Tree> acc = ImmutableList.builder();
528     EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class);
529     ImmutableList.Builder<Anno> annos = ImmutableList.builder();
530     while (true) {
531       switch (token) {
532         case PUBLIC:
533           next();
534           access.add(TurbineModifier.PUBLIC);
535           break;
536         case PROTECTED:
537           next();
538           access.add(TurbineModifier.PROTECTED);
539           break;
540         case PRIVATE:
541           next();
542           access.add(TurbineModifier.PRIVATE);
543           break;
544         case STATIC:
545           next();
546           access.add(TurbineModifier.STATIC);
547           break;
548         case ABSTRACT:
549           next();
550           access.add(TurbineModifier.ABSTRACT);
551           break;
552         case FINAL:
553           next();
554           access.add(TurbineModifier.FINAL);
555           break;
556         case NATIVE:
557           next();
558           access.add(TurbineModifier.NATIVE);
559           break;
560         case SYNCHRONIZED:
561           next();
562           access.add(TurbineModifier.SYNCHRONIZED);
563           break;
564         case TRANSIENT:
565           next();
566           access.add(TurbineModifier.TRANSIENT);
567           break;
568         case VOLATILE:
569           next();
570           access.add(TurbineModifier.VOLATILE);
571           break;
572         case STRICTFP:
573           next();
574           access.add(TurbineModifier.STRICTFP);
575           break;
576         case DEFAULT:
577           next();
578           access.add(TurbineModifier.DEFAULT);
579           break;
580         case AT:
581           {
582             // TODO(cushon): de-dup with top-level parsing
583             next();
584             if (token == INTERFACE) {
585               acc.add(annotationDeclaration(access, annos.build()));
586               access = EnumSet.noneOf(TurbineModifier.class);
587               annos = ImmutableList.builder();
588             } else {
589               annos.add(annotation());
590             }
591             break;
592           }
593 
594         case IDENT:
595         case BOOLEAN:
596         case BYTE:
597         case SHORT:
598         case INT:
599         case LONG:
600         case CHAR:
601         case DOUBLE:
602         case FLOAT:
603         case VOID:
604         case LT:
605           acc.addAll(classMember(access, annos.build()));
606           access = EnumSet.noneOf(TurbineModifier.class);
607           annos = ImmutableList.builder();
608           break;
609         case LBRACE:
610           dropBlocks();
611           access = EnumSet.noneOf(TurbineModifier.class);
612           annos = ImmutableList.builder();
613           break;
614         case CLASS:
615           acc.add(classDeclaration(access, annos.build()));
616           access = EnumSet.noneOf(TurbineModifier.class);
617           annos = ImmutableList.builder();
618           break;
619         case INTERFACE:
620           acc.add(interfaceDeclaration(access, annos.build()));
621           access = EnumSet.noneOf(TurbineModifier.class);
622           annos = ImmutableList.builder();
623           break;
624         case ENUM:
625           acc.add(enumDeclaration(access, annos.build()));
626           access = EnumSet.noneOf(TurbineModifier.class);
627           annos = ImmutableList.builder();
628           break;
629         case RBRACE:
630           return acc.build();
631         case SEMI:
632           next();
633           continue;
634         default:
635           throw error(token);
636       }
637     }
638   }
639 
classMember( EnumSet<TurbineModifier> access, ImmutableList<Anno> annos)640   private ImmutableList<Tree> classMember(
641       EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
642     ImmutableList<TyParam> typaram = ImmutableList.of();
643     Type result;
644     Ident name;
645 
646     if (token == Token.LT) {
647       typaram = typarams();
648     }
649 
650     if (token == Token.AT) {
651       annos = ImmutableList.<Anno>builder().addAll(annos).addAll(maybeAnnos()).build();
652     }
653 
654     switch (token) {
655       case VOID:
656         {
657           result = new Tree.VoidTy(position);
658           next();
659           int pos = position;
660           name = eatIdent();
661           return memberRest(pos, access, annos, typaram, result, name);
662         }
663       case BOOLEAN:
664       case BYTE:
665       case SHORT:
666       case INT:
667       case LONG:
668       case CHAR:
669       case DOUBLE:
670       case FLOAT:
671         {
672           result = referenceType(ImmutableList.of());
673           int pos = position;
674           name = eatIdent();
675           return memberRest(pos, access, annos, typaram, result, name);
676         }
677       case IDENT:
678         {
679           int pos = position;
680           Ident ident = eatIdent();
681           switch (token) {
682             case LPAREN:
683               {
684                 name = ident;
685                 return ImmutableList.of(methodRest(pos, access, annos, typaram, null, name));
686               }
687             case IDENT:
688               {
689                 result =
690                     new ClassTy(
691                         position,
692                         Optional.<ClassTy>empty(),
693                         ident,
694                         ImmutableList.<Type>of(),
695                         ImmutableList.of());
696                 pos = position;
697                 name = eatIdent();
698                 return memberRest(pos, access, annos, typaram, result, name);
699               }
700             case AT:
701             case LBRACK:
702               {
703                 result =
704                     new ClassTy(
705                         position,
706                         Optional.<ClassTy>empty(),
707                         ident,
708                         ImmutableList.<Type>of(),
709                         ImmutableList.of());
710                 result = maybeDims(maybeAnnos(), result);
711                 break;
712               }
713             case LT:
714               {
715                 result =
716                     new ClassTy(
717                         position, Optional.<ClassTy>empty(), ident, tyargs(), ImmutableList.of());
718                 result = maybeDims(maybeAnnos(), result);
719                 break;
720               }
721             case DOT:
722               result =
723                   new ClassTy(
724                       position,
725                       Optional.<ClassTy>empty(),
726                       ident,
727                       ImmutableList.<Type>of(),
728                       ImmutableList.of());
729               break;
730             default:
731               throw error(token);
732           }
733           if (result == null) {
734             throw error(token);
735           }
736           if (token == Token.DOT) {
737             next();
738             // TODO(cushon): is this cast OK?
739             result = classty((ClassTy) result);
740           }
741           result = maybeDims(maybeAnnos(), result);
742           pos = position;
743           name = eatIdent();
744           switch (token) {
745             case LPAREN:
746               return ImmutableList.of(methodRest(pos, access, annos, typaram, result, name));
747             case LBRACK:
748             case SEMI:
749             case ASSIGN:
750             case COMMA:
751               {
752                 if (!typaram.isEmpty()) {
753                   throw error(ErrorKind.UNEXPECTED_TYPE_PARAMETER, typaram);
754                 }
755                 return fieldRest(pos, access, annos, result, name);
756               }
757             default:
758               throw error(token);
759           }
760         }
761       default:
762         throw error(token);
763     }
764   }
765 
maybeAnnos()766   private ImmutableList<Anno> maybeAnnos() {
767     if (token != Token.AT) {
768       return ImmutableList.of();
769     }
770     ImmutableList.Builder<Anno> builder = ImmutableList.builder();
771     while (token == Token.AT) {
772       next();
773       builder.add(annotation());
774     }
775     return builder.build();
776   }
777 
memberRest( int pos, EnumSet<TurbineModifier> access, ImmutableList<Anno> annos, ImmutableList<TyParam> typaram, Type result, Ident name)778   private ImmutableList<Tree> memberRest(
779       int pos,
780       EnumSet<TurbineModifier> access,
781       ImmutableList<Anno> annos,
782       ImmutableList<TyParam> typaram,
783       Type result,
784       Ident name) {
785     switch (token) {
786       case ASSIGN:
787       case AT:
788       case COMMA:
789       case LBRACK:
790       case SEMI:
791         {
792           if (!typaram.isEmpty()) {
793             throw error(ErrorKind.UNEXPECTED_TYPE_PARAMETER, typaram);
794           }
795           return fieldRest(pos, access, annos, result, name);
796         }
797       case LPAREN:
798         return ImmutableList.of(methodRest(pos, access, annos, typaram, result, name));
799       default:
800         throw error(token);
801     }
802   }
803 
fieldRest( int pos, EnumSet<TurbineModifier> access, ImmutableList<Anno> annos, Type baseTy, Ident name)804   private ImmutableList<Tree> fieldRest(
805       int pos,
806       EnumSet<TurbineModifier> access,
807       ImmutableList<Anno> annos,
808       Type baseTy,
809       Ident name) {
810     ImmutableList.Builder<Tree> result = ImmutableList.builder();
811     VariableInitializerParser initializerParser = new VariableInitializerParser(token, lexer);
812     List<List<SavedToken>> bits = initializerParser.parseInitializers();
813     token = initializerParser.token;
814 
815     boolean first = true;
816     int expressionStart = pos;
817     for (List<SavedToken> bit : bits) {
818       IteratorLexer lexer = new IteratorLexer(this.lexer.source(), bit.iterator());
819       Parser parser = new Parser(lexer);
820       if (first) {
821         first = false;
822       } else {
823         name = parser.eatIdent();
824       }
825       Type ty = baseTy;
826       ty = parser.extraDims(ty);
827       // TODO(cushon): skip more fields that are definitely non-const
828       ConstExpressionParser constExpressionParser = new ConstExpressionParser(lexer, lexer.next());
829       expressionStart = lexer.position();
830       Expression init = constExpressionParser.expression();
831       if (init != null && init.kind() == Tree.Kind.ARRAY_INIT) {
832         init = null;
833       }
834       result.add(new VarDecl(pos, access, annos, ty, name, Optional.ofNullable(init)));
835     }
836     if (token != SEMI) {
837       throw TurbineError.format(lexer.source(), expressionStart, ErrorKind.UNTERMINATED_EXPRESSION);
838     }
839     eat(Token.SEMI);
840     return result.build();
841   }
842 
methodRest( int pos, EnumSet<TurbineModifier> access, ImmutableList<Anno> annos, ImmutableList<TyParam> typaram, Type result, Ident name)843   private Tree methodRest(
844       int pos,
845       EnumSet<TurbineModifier> access,
846       ImmutableList<Anno> annos,
847       ImmutableList<TyParam> typaram,
848       Type result,
849       Ident name) {
850     eat(Token.LPAREN);
851     ImmutableList.Builder<VarDecl> formals = ImmutableList.builder();
852     formalParams(formals, access);
853     eat(Token.RPAREN);
854 
855     result = extraDims(result);
856 
857     ImmutableList.Builder<ClassTy> exceptions = ImmutableList.builder();
858     if (token == Token.THROWS) {
859       next();
860       exceptions.addAll(exceptions());
861     }
862     Tree defaultValue = null;
863     switch (token) {
864       case SEMI:
865         next();
866         break;
867       case LBRACE:
868         dropBlocks();
869         break;
870       case DEFAULT:
871         {
872           ConstExpressionParser cparser = new ConstExpressionParser(lexer, lexer.next());
873           Tree expr = cparser.expression();
874           token = cparser.token;
875           if (expr == null && token == Token.AT) {
876             next();
877             expr = annotation();
878           }
879           if (expr == null) {
880             throw error(token);
881           }
882           defaultValue = expr;
883           eat(Token.SEMI);
884           break;
885         }
886       default:
887         throw error(token);
888     }
889     if (result == null) {
890       name = new Ident(position, CTOR_NAME);
891     }
892     return new MethDecl(
893         pos,
894         access,
895         annos,
896         typaram,
897         Optional.<Tree>ofNullable(result),
898         name,
899         formals.build(),
900         exceptions.build(),
901         Optional.ofNullable(defaultValue));
902   }
903 
904   /**
905    * Given a base {@code type} and some number of {@code extra} c-style array dimension specifiers,
906    * construct a new array type.
907    *
908    * <p>For reasons that are unclear from the spec, {@code int @A [] x []} is equivalent to {@code
909    * int [] @A [] x}, not {@code int @A [] [] x}.
910    */
extraDims(Type ty)911   private Type extraDims(Type ty) {
912     ImmutableList<Anno> annos = maybeAnnos();
913     if (!annos.isEmpty() && token != Token.LBRACK) {
914       // orphaned type annotations
915       throw error(token);
916     }
917     Deque<ImmutableList<Anno>> extra = new ArrayDeque<>();
918     while (maybe(Token.LBRACK)) {
919       eat(Token.RBRACK);
920       extra.push(annos);
921       annos = maybeAnnos();
922     }
923     ty = extraDims(ty, extra);
924     return ty;
925   }
926 
extraDims(Type type, Deque<ImmutableList<Anno>> extra)927   private Type extraDims(Type type, Deque<ImmutableList<Anno>> extra) {
928     if (extra.isEmpty()) {
929       return type;
930     }
931     if (type.kind() == Kind.ARR_TY) {
932       ArrTy arrTy = (ArrTy) type;
933       return new ArrTy(arrTy.position(), arrTy.annos(), extraDims(arrTy.elem(), extra));
934     }
935     return new ArrTy(type.position(), extra.pop(), extraDims(type, extra));
936   }
937 
exceptions()938   private ImmutableList<ClassTy> exceptions() {
939     ImmutableList.Builder<ClassTy> result = ImmutableList.builder();
940     result.add(classty());
941     while (maybe(Token.COMMA)) {
942       result.add(classty());
943     }
944     return result.build();
945   }
946 
formalParams( ImmutableList.Builder<VarDecl> builder, EnumSet<TurbineModifier> access)947   private void formalParams(
948       ImmutableList.Builder<VarDecl> builder, EnumSet<TurbineModifier> access) {
949     while (token != Token.RPAREN) {
950       VarDecl formal = formalParam();
951       builder.add(formal);
952       if (formal.mods().contains(TurbineModifier.VARARGS)) {
953         access.add(TurbineModifier.VARARGS);
954       }
955       if (token != Token.COMMA) {
956         break;
957       }
958       next();
959     }
960   }
961 
formalParam()962   private VarDecl formalParam() {
963     ImmutableList.Builder<Anno> annos = ImmutableList.builder();
964     EnumSet<TurbineModifier> access = modifiersAndAnnotations(annos);
965     Type ty = referenceType(ImmutableList.of());
966     ImmutableList<Anno> typeAnnos = maybeAnnos();
967     if (maybe(Token.ELLIPSIS)) {
968       access.add(TurbineModifier.VARARGS);
969       ty = new ArrTy(position, typeAnnos, ty);
970     } else {
971       ty = maybeDims(typeAnnos, ty);
972     }
973     // the parameter name is `this` for receiver parameters, and a qualified this expression
974     // for inner classes
975     Ident name = identOrThis();
976     while (token == Token.DOT) {
977       eat(Token.DOT);
978       // Overwrite everything up to the terminal 'this' for inner classes; we don't need it
979       name = identOrThis();
980     }
981     ty = extraDims(ty);
982     return new VarDecl(position, access, annos.build(), ty, name, Optional.<Expression>empty());
983   }
984 
identOrThis()985   private Ident identOrThis() {
986     switch (token) {
987       case IDENT:
988         return eatIdent();
989       case THIS:
990         int position = lexer.position();
991         eat(Token.THIS);
992         return new Ident(position, "this");
993       default:
994         throw error(token);
995     }
996   }
997 
dropParens()998   private void dropParens() {
999     eat(Token.LPAREN);
1000     int depth = 1;
1001     while (depth > 0) {
1002       switch (token) {
1003         case RPAREN:
1004           depth--;
1005           break;
1006         case LPAREN:
1007           depth++;
1008           break;
1009         case EOF:
1010           throw error(ErrorKind.UNEXPECTED_EOF);
1011         default:
1012           break;
1013       }
1014       next();
1015     }
1016   }
1017 
dropBlocks()1018   private void dropBlocks() {
1019     eat(Token.LBRACE);
1020     int depth = 1;
1021     while (depth > 0) {
1022       switch (token) {
1023         case RBRACE:
1024           depth--;
1025           break;
1026         case LBRACE:
1027           depth++;
1028           break;
1029         case EOF:
1030           throw error(ErrorKind.UNEXPECTED_EOF);
1031         default:
1032           break;
1033       }
1034       next();
1035     }
1036   }
1037 
typarams()1038   private ImmutableList<TyParam> typarams() {
1039     ImmutableList.Builder<TyParam> acc = ImmutableList.builder();
1040     eat(Token.LT);
1041     OUTER:
1042     while (true) {
1043       ImmutableList<Anno> annotations = maybeAnnos();
1044       Ident name = eatIdent();
1045       ImmutableList<Tree> bounds = ImmutableList.of();
1046       if (token == Token.EXTENDS) {
1047         next();
1048         bounds = tybounds();
1049       }
1050       acc.add(new TyParam(position, name, bounds, annotations));
1051       switch (token) {
1052         case COMMA:
1053           eat(Token.COMMA);
1054           continue;
1055         case GT:
1056           next();
1057           break OUTER;
1058         default:
1059           throw error(token);
1060       }
1061     }
1062     return acc.build();
1063   }
1064 
tybounds()1065   private ImmutableList<Tree> tybounds() {
1066     ImmutableList.Builder<Tree> acc = ImmutableList.builder();
1067     do {
1068       acc.add(classty());
1069     } while (maybe(Token.AND));
1070     return acc.build();
1071   }
1072 
classty()1073   private ClassTy classty() {
1074     return classty(null);
1075   }
1076 
classty(ClassTy ty)1077   private ClassTy classty(ClassTy ty) {
1078     return classty(ty, null);
1079   }
1080 
classty(ClassTy ty, @Nullable ImmutableList<Anno> typeAnnos)1081   private ClassTy classty(ClassTy ty, @Nullable ImmutableList<Anno> typeAnnos) {
1082     int pos = position;
1083     do {
1084       if (typeAnnos == null) {
1085         typeAnnos = maybeAnnos();
1086       }
1087       Ident name = eatIdent();
1088       ImmutableList<Type> tyargs = ImmutableList.of();
1089       if (token == Token.LT) {
1090         tyargs = tyargs();
1091       }
1092       ty = new ClassTy(pos, Optional.ofNullable(ty), name, tyargs, typeAnnos);
1093       typeAnnos = null;
1094     } while (maybe(Token.DOT));
1095     return ty;
1096   }
1097 
tyargs()1098   private ImmutableList<Type> tyargs() {
1099     ImmutableList.Builder<Type> acc = ImmutableList.builder();
1100     eat(Token.LT);
1101     OUTER:
1102     do {
1103       ImmutableList<Anno> typeAnnos = maybeAnnos();
1104       switch (token) {
1105         case COND:
1106           {
1107             next();
1108             switch (token) {
1109               case EXTENDS:
1110                 next();
1111                 Type upper = referenceType(maybeAnnos());
1112                 acc.add(
1113                     new WildTy(position, typeAnnos, Optional.of(upper), Optional.<Type>empty()));
1114                 break;
1115               case SUPER:
1116                 next();
1117                 Type lower = referenceType(maybeAnnos());
1118                 acc.add(
1119                     new WildTy(position, typeAnnos, Optional.<Type>empty(), Optional.of(lower)));
1120                 break;
1121               case COMMA:
1122                 acc.add(
1123                     new WildTy(
1124                         position, typeAnnos, Optional.<Type>empty(), Optional.<Type>empty()));
1125                 continue OUTER;
1126               case GT:
1127               case GTGT:
1128               case GTGTGT:
1129                 acc.add(
1130                     new WildTy(
1131                         position, typeAnnos, Optional.<Type>empty(), Optional.<Type>empty()));
1132                 break OUTER;
1133               default:
1134                 throw error(token);
1135             }
1136             break;
1137           }
1138         case IDENT:
1139         case BOOLEAN:
1140         case BYTE:
1141         case SHORT:
1142         case INT:
1143         case LONG:
1144         case CHAR:
1145         case DOUBLE:
1146         case FLOAT:
1147           acc.add(referenceType(typeAnnos));
1148           break;
1149         default:
1150           throw error(token);
1151       }
1152     } while (maybe(Token.COMMA));
1153     switch (token) {
1154       case GT:
1155         next();
1156         break;
1157       case GTGT:
1158         token = Token.GT;
1159         break;
1160       case GTGTGT:
1161         token = Token.GTGT;
1162         break;
1163       default:
1164         throw error(token);
1165     }
1166     return acc.build();
1167   }
1168 
referenceType(ImmutableList<Anno> typeAnnos)1169   private Type referenceType(ImmutableList<Anno> typeAnnos) {
1170     Type ty;
1171     switch (token) {
1172       case IDENT:
1173         ty = classty(null, typeAnnos);
1174         break;
1175       case BOOLEAN:
1176         next();
1177         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.BOOLEAN);
1178         break;
1179       case BYTE:
1180         next();
1181         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.BYTE);
1182         break;
1183       case SHORT:
1184         next();
1185         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.SHORT);
1186         break;
1187       case INT:
1188         next();
1189         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.INT);
1190         break;
1191       case LONG:
1192         next();
1193         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.LONG);
1194         break;
1195       case CHAR:
1196         next();
1197         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.CHAR);
1198         break;
1199       case DOUBLE:
1200         next();
1201         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.DOUBLE);
1202         break;
1203       case FLOAT:
1204         next();
1205         ty = new PrimTy(position, typeAnnos, TurbineConstantTypeKind.FLOAT);
1206         break;
1207       default:
1208         throw error(token);
1209     }
1210     ty = maybeDims(maybeAnnos(), ty);
1211     return ty;
1212   }
1213 
maybeDims(ImmutableList<Anno> typeAnnos, Type ty)1214   private Type maybeDims(ImmutableList<Anno> typeAnnos, Type ty) {
1215     while (maybe(Token.LBRACK)) {
1216       eat(Token.RBRACK);
1217       ty = new ArrTy(position, typeAnnos, ty);
1218       typeAnnos = maybeAnnos();
1219     }
1220     return ty;
1221   }
1222 
modifiersAndAnnotations(ImmutableList.Builder<Anno> annos)1223   private EnumSet<TurbineModifier> modifiersAndAnnotations(ImmutableList.Builder<Anno> annos) {
1224     EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class);
1225     while (true) {
1226       switch (token) {
1227         case PUBLIC:
1228           next();
1229           access.add(TurbineModifier.PUBLIC);
1230           break;
1231         case PROTECTED:
1232           next();
1233           access.add(TurbineModifier.PROTECTED);
1234           break;
1235         case PRIVATE:
1236           next();
1237           access.add(TurbineModifier.PRIVATE);
1238           break;
1239         case STATIC:
1240           next();
1241           access.add(TurbineModifier.STATIC);
1242           break;
1243         case ABSTRACT:
1244           next();
1245           access.add(TurbineModifier.ABSTRACT);
1246           break;
1247         case FINAL:
1248           next();
1249           access.add(TurbineModifier.FINAL);
1250           break;
1251         case NATIVE:
1252           next();
1253           access.add(TurbineModifier.NATIVE);
1254           break;
1255         case SYNCHRONIZED:
1256           next();
1257           access.add(TurbineModifier.SYNCHRONIZED);
1258           break;
1259         case TRANSIENT:
1260           next();
1261           access.add(TurbineModifier.TRANSIENT);
1262           break;
1263         case VOLATILE:
1264           next();
1265           access.add(TurbineModifier.VOLATILE);
1266           break;
1267         case STRICTFP:
1268           next();
1269           access.add(TurbineModifier.STRICTFP);
1270           break;
1271         case AT:
1272           next();
1273           annos.add(annotation());
1274           break;
1275         default:
1276           return access;
1277       }
1278     }
1279   }
1280 
importDeclaration()1281   private ImportDecl importDeclaration() {
1282     boolean stat = maybe(Token.STATIC);
1283 
1284     int pos = position;
1285     ImmutableList.Builder<Ident> type = ImmutableList.builder();
1286     type.add(eatIdent());
1287     boolean wild = false;
1288     OUTER:
1289     while (maybe(Token.DOT)) {
1290       switch (token) {
1291         case IDENT:
1292           type.add(eatIdent());
1293           break;
1294         case MULT:
1295           eat(Token.MULT);
1296           wild = true;
1297           break OUTER;
1298         default:
1299           break;
1300       }
1301     }
1302     eat(Token.SEMI);
1303     return new ImportDecl(pos, type.build(), stat, wild);
1304   }
1305 
packageDeclaration(ImmutableList<Anno> annos)1306   private PkgDecl packageDeclaration(ImmutableList<Anno> annos) {
1307     PkgDecl result = new PkgDecl(position, qualIdent(), annos);
1308     eat(Token.SEMI);
1309     return result;
1310   }
1311 
qualIdent()1312   private ImmutableList<Ident> qualIdent() {
1313     ImmutableList.Builder<Ident> name = ImmutableList.builder();
1314     name.add(eatIdent());
1315     while (maybe(Token.DOT)) {
1316       name.add(eatIdent());
1317     }
1318     return name.build();
1319   }
1320 
annotation()1321   private Anno annotation() {
1322     int pos = position;
1323     ImmutableList<Ident> name = qualIdent();
1324 
1325     ImmutableList.Builder<Expression> args = ImmutableList.builder();
1326     if (token == Token.LPAREN) {
1327       eat(LPAREN);
1328       while (token != RPAREN) {
1329         ConstExpressionParser cparser = new ConstExpressionParser(lexer, token);
1330         Expression arg = cparser.expression();
1331         if (arg == null) {
1332           throw error(ErrorKind.INVALID_ANNOTATION_ARGUMENT);
1333         }
1334         args.add(arg);
1335         token = cparser.token;
1336         if (!maybe(COMMA)) {
1337           break;
1338         }
1339       }
1340       eat(Token.RPAREN);
1341     }
1342 
1343     return new Anno(pos, name, args.build());
1344   }
1345 
ident()1346   private Ident ident() {
1347     int position = lexer.position();
1348     String value = lexer.stringValue();
1349     return new Ident(position, value);
1350   }
1351 
eatIdent()1352   private Ident eatIdent() {
1353     Ident ident = ident();
1354     eat(Token.IDENT);
1355     return ident;
1356   }
1357 
eat(Token kind)1358   private void eat(Token kind) {
1359     if (token != kind) {
1360       throw error(ErrorKind.EXPECTED_TOKEN, kind);
1361     }
1362     next();
1363   }
1364 
maybe(Token kind)1365   private boolean maybe(Token kind) {
1366     if (token == kind) {
1367       next();
1368       return true;
1369     }
1370     return false;
1371   }
1372 
1373   @CheckReturnValue
error(Token token)1374   TurbineError error(Token token) {
1375     switch (token) {
1376       case IDENT:
1377         return error(ErrorKind.UNEXPECTED_IDENTIFIER, lexer.stringValue());
1378       case EOF:
1379         return error(ErrorKind.UNEXPECTED_EOF);
1380       default:
1381         return error(ErrorKind.UNEXPECTED_TOKEN, token);
1382     }
1383   }
1384 
1385   @CheckReturnValue
error(ErrorKind kind, Object... args)1386   private TurbineError error(ErrorKind kind, Object... args) {
1387     return TurbineError.format(
1388         lexer.source(),
1389         Math.min(lexer.position(), lexer.source().source().length() - 1),
1390         kind,
1391         args);
1392   }
1393 }
1394