1/*
2 * Copyright (C) 2016 The Android Open Source Project
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%{
18
19#include "AST.h"
20#include "Annotation.h"
21#include "ArrayType.h"
22#include "CompoundType.h"
23#include "ConstantExpression.h"
24#include "Coordinator.h"
25#include "DocComment.h"
26#include "EnumType.h"
27#include "Interface.h"
28#include "Location.h"
29#include "Method.h"
30#include "Scope.h"
31#include "TypeDef.h"
32#include "VectorType.h"
33
34#include "hidl-gen_y-helpers.h"
35
36#include <android-base/logging.h>
37#include <hidl-util/FQName.h>
38#include <hidl-util/StringHelper.h>
39#include <stdio.h>
40
41using namespace android;
42
43extern int yylex(yy::parser::semantic_type*, yy::parser::location_type*, void*, AST* const,
44                 Scope** const);
45
46void enterScope(AST* /* ast */, Scope** scope, Scope* container) {
47    CHECK(container->parent() == (*scope));
48    *scope = container;
49}
50
51void leaveScope(AST* ast, Scope** scope) {
52    CHECK((*scope) != &ast->getRootScope());
53    *scope = (*scope)->parent();
54}
55
56::android::Location convertYYLoc(const yy::parser::location_type& loc, const AST* ast) {
57    return ::android::Location(
58            ::android::Position(ast->getCoordinator().makeRelative(*(loc.begin.filename)),
59                                loc.begin.line, loc.begin.column),
60            ::android::Position(ast->getCoordinator().makeRelative(*(loc.end.filename)),
61                                loc.end.line, loc.end.column));
62}
63
64bool isValidInterfaceField(const std::string& identifier, std::string *errorMsg) {
65    static const std::vector<std::string> reserved({
66        // Injected names to C++ interfaces by auto-generated code
67        "isRemote", "descriptor", "hidlStaticBlock", "onTransact",
68        "castFrom", "Proxy", "Stub", "getService",
69
70        // Injected names to Java interfaces by auto-generated code
71        "asInterface", "castFrom", "getService", "toString",
72
73        // Inherited methods from IBase is detected in addMethod. Not added here
74        // because we need hidl-gen to compile IBase.
75
76        // Inherited names by interfaces from IInterface / IBinder
77        "onAsBinder", "asBinder", "queryLocalInterface", "getInterfaceDescriptor", "isBinderAlive",
78        "pingBinder", "dump", "transact", "checkSubclass", "attachObject", "findObject",
79        "detachObject", "localBinder", "remoteBinder", "mImpl",
80
81        // Inherited names from HidlInstrumentor
82        "InstrumentationEvent", "configureInstrumentation", "registerInstrumentationCallbacks",
83        "isInstrumentationLib", "mInstrumentationCal1lbacks", "mEnableInstrumentation",
84        "mInstrumentationLibPackage", "mInterfaceName",
85
86        // Collide with names in BsFoo
87        "mImpl", "addOnewayTask", "mOnewayQueue",
88
89        // Inherited names from Java IHwInterface
90        "asBinder",
91    });
92    if (std::find(reserved.begin(), reserved.end(), identifier) != reserved.end()) {
93        *errorMsg = identifier + " cannot be a name inside an interface";
94        return false;
95    }
96    return true;
97}
98
99bool isValidStructField(const std::string& identifier, std::string *errorMsg) {
100    static const std::vector<std::string> reserved({
101        // Injected names to structs and unions by auto-generated code
102        "readEmbeddedFromParcel", "writeEmbeddedToParcel", "readVectorFromParcel",
103        "writeVectorToParcel", "writeEmbeddedToBlob",
104    });
105    if (std::find(reserved.begin(), reserved.end(), identifier) != reserved.end()) {
106        *errorMsg = identifier + " cannot be a name inside an struct or union";
107        return false;
108    }
109    return true;
110}
111
112bool isValidCompoundTypeField(CompoundType::Style style, const std::string& identifier,
113                              std::string *errorMsg) {
114    // Unions don't support fix-up types; as such, they can't
115    // have name collisions with embedded read/write methods.
116    if (style == CompoundType::STYLE_UNION) { return true; }
117
118    return isValidStructField(identifier, errorMsg);;
119}
120
121bool isValidIdentifier(const std::string& identifier, std::string *errorMsg) {
122    static const std::vector<std::string> keywords({
123        "uint8_t", "uint16_t", "uint32_t", "uint64_t",
124        "int8_t", "int16_t", "int32_t", "int64_t", "bool", "float", "double",
125        "interface", "struct", "union", "string", "vec", "enum", "ref", "handle",
126        "package", "import", "typedef", "generates", "oneway", "extends",
127        "fmq_sync", "fmq_unsync", "safe_union",
128    });
129    static const std::vector<std::string> cppKeywords({
130        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit",
131        "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break", "case", "catch",
132        "char", "char16_t", "char32_t", "class", "compl", "concept", "const", "constexpr",
133        "const_cast", "continue", "decltype", "default", "delete", "do", "double",
134        "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float",
135        "for", "friend", "goto", "if", "inline", "int", "import", "long", "module", "mutable",
136        "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
137        "private", "protected", "public", "register", "reinterpret_cast", "requires", "return",
138        "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct",
139        "switch", "synchronized", "template", "this", "thread_local", "throw", "true", "try",
140        "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
141        "volatile", "wchar_t", "while", "xor", "xor_eq",
142    });
143    static const std::vector<std::string> javaKeywords({
144        "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package",
145        "synchronized", "boolean", "do", "if", "private", "this", "break", "double",
146        "implements", "protected", "throw", "byte", "else", "import", "public", "throws",
147        "case", "enum", "instanceof", "return", "transient", "catch", "extends", "int",
148        "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
149        "long", "strictfp", "volatile", "const", "float", "native", "super", "while",
150    });
151    static const std::vector<std::string> cppCollide({
152        "size_t", "offsetof",
153    });
154
155    // errors
156    if (std::find(keywords.begin(), keywords.end(), identifier) != keywords.end()) {
157        *errorMsg = identifier + " is a HIDL keyword "
158            "and is therefore not a valid identifier";
159        return false;
160    }
161    if (std::find(cppKeywords.begin(), cppKeywords.end(), identifier) != cppKeywords.end()) {
162        *errorMsg = identifier + " is a C++ keyword "
163            "and is therefore not a valid identifier";
164        return false;
165    }
166    if (std::find(javaKeywords.begin(), javaKeywords.end(), identifier) != javaKeywords.end()) {
167        *errorMsg = identifier + " is a Java keyword "
168            "and is therefore not a valid identifier";
169        return false;
170    }
171    if (std::find(cppCollide.begin(), cppCollide.end(), identifier) != cppCollide.end()) {
172        *errorMsg = identifier + " collides with reserved names in C++ code "
173            "and is therefore not a valid identifier";
174        return false;
175    }
176    if (StringHelper::StartsWith(identifier, "_hidl_")) {
177        *errorMsg = identifier + " starts with _hidl_ "
178            "and is therefore not a valid identifier";
179        return false;
180    }
181    if (StringHelper::StartsWith(identifier, "hidl_")) {
182        *errorMsg = identifier + " starts with hidl_ "
183            "and is therefore not a valid identifier";
184        return false;
185    }
186    if (StringHelper::EndsWith(identifier, "_cb")) {
187        *errorMsg = identifier + " ends with _cb "
188            "and is therefore not a valid identifier";
189        return false;
190    }
191
192    return true;
193}
194
195// Return true if identifier is an acceptable name for an UDT.
196bool isValidTypeName(const std::string& identifier, std::string *errorMsg) {
197    if (!isValidIdentifier(identifier, errorMsg)) {
198        return false;
199    }
200
201    if (identifier == "toString") {
202        *errorMsg = identifier + " is not a valid type name";
203        return false;
204    }
205
206    return true;
207}
208
209%}
210
211%initial-action {
212    // Initialize the initial location.
213    @$.begin.filename = @$.end.filename =
214        const_cast<std::string *>(&ast->getFilename());
215}
216
217%parse-param { void* scanner }
218%parse-param { android::AST* const ast }
219%parse-param { android::Scope** const scope }
220%lex-param { void* scanner }
221%lex-param { android::AST* const ast }
222%lex-param { android::Scope** const scope }
223%glr-parser
224%skeleton "glr.cc"
225
226%expect-rr 0
227%define parse.error verbose
228%locations
229
230%verbose
231%debug
232
233%token<str> MULTILINE_COMMENT "multiline comment"
234%token<str> DOC_COMMENT "doc comment"
235
236%token<void> ENUM "keyword `enum`"
237%token<void> EXTENDS "keyword `extends`"
238%token<str> FQNAME "fully-qualified name"
239%token<void> GENERATES "keyword `generates`"
240%token<str> IDENTIFIER "identifier"
241%token<void> IMPORT "keyword `import`"
242%token<str> INTEGER "integer value"
243%token<str> FLOAT "float value"
244%token<void> INTERFACE "keyword `interface`"
245%token<str> PACKAGE "keyword `package`"
246%token<type> TYPE "type"
247%token<void> STRUCT "keyword `struct`"
248%token<str> STRING_LITERAL "string literal"
249%token<void> TYPEDEF "keyword `typedef`"
250%token<void> UNION "keyword `union`"
251%token<void> SAFE_UNION "keyword `safe_union`"
252%token<templatedType> TEMPLATED "templated type"
253%token<void> ONEWAY "keyword `oneway`"
254%token<str> UNKNOWN "unknown character"
255
256/* Operator precedence and associativity, as per
257 * http://en.cppreference.com/w/cpp/language/operator_precedence */
258/* Precedence level 15 ternary operator */
259%right '?' ':'
260/* Precedence level 13 - 14, LTR, logical operators*/
261%left LOGICAL_OR
262%left LOGICAL_AND
263/* Precedence level 10 - 12, LTR, bitwise operators*/
264%left '|'
265%left '^'
266%left '&'
267/* Precedence level 9, LTR */
268%left EQUALITY NEQ
269/* Precedence level 8, LTR */
270%left '<' '>' LEQ GEQ
271/* Precedence level 7, LTR */
272%left LSHIFT RSHIFT
273/* Precedence level 6, LTR */
274%left '+' '-'
275/* Precedence level 5, LTR */
276%left '*' '/' '%'
277/* Precedence level 3, RTL; but we have to use %left here */
278%left UNARY_MINUS UNARY_PLUS '!' '~'
279
280%token '#'
281
282%type<docComment> doc_comment doc_comments ignore_doc_comments
283
284%type<str> error_stmt error
285%type<str> package
286%type<fqName> fqname
287%type<referenceToType> fqtype
288%type<str> valid_identifier valid_type_name
289
290%type<referenceToType> type enum_storage_type type_or_inplace_compound_declaration
291%type<referenceToType> array_type_base
292%type<arrayType> array_type
293%type<referenceToType> opt_extends
294%type<type> type_declaration commentable_type_declaration type_declaration_body
295%type<type> interface_declaration typedef_declaration
296%type<type> named_struct_or_union_declaration named_enum_declaration
297%type<type> compound_declaration annotated_compound_declaration
298
299%type<docCommentable> field_declaration commentable_field_declaration
300%type<fields> field_declarations struct_or_union_body
301%type<constantExpression> const_expr
302%type<enumValue> enum_value commentable_enum_value
303%type<enumValues> enum_values enum_declaration_body
304%type<typedVars> typed_vars non_empty_typed_vars
305%type<typedVar> typed_var uncommented_typed_var
306%type<method> method_declaration commentable_method_declaration
307%type<compoundStyle> struct_or_union_keyword
308%type<stringVec> annotation_string_values annotation_string_value
309%type<annotationParam> annotation_param
310%type<annotationParams> opt_annotation_params annotation_params
311%type<annotation> annotation
312%type<annotations> opt_annotations
313
314%start program
315
316%union {
317    const char *str;
318    android::Type* type;
319    android::Reference<android::Type>* referenceToType;
320    android::ArrayType *arrayType;
321    android::TemplatedType *templatedType;
322    android::FQName *fqName;
323    android::CompoundType *compoundType;
324    android::NamedReference<android::Type>* field;
325    std::vector<android::NamedReference<android::Type>*>* fields;
326    android::EnumValue *enumValue;
327    android::ConstantExpression *constantExpression;
328    std::vector<android::EnumValue *> *enumValues;
329    android::NamedReference<android::Type>* typedVar;
330    android::TypedVarVector *typedVars;
331    android::Method *method;
332    android::CompoundType::Style compoundStyle;
333    std::vector<std::string> *stringVec;
334    android::AnnotationParam *annotationParam;
335    android::AnnotationParamVector *annotationParams;
336    android::Annotation *annotation;
337    std::vector<android::Annotation *> *annotations;
338    android::DocComment* docComment;
339    android::DocCommentable* docCommentable;
340}
341
342%%
343
344program
345    : doc_comments package declarations ignore_doc_comments
346      {
347        ast->setHeader($1);
348      }
349    | package declarations ignore_doc_comments
350    ;
351
352doc_comment
353    : DOC_COMMENT { $$ = new DocComment($1, convertYYLoc(@1, ast), CommentType::DOC_MULTILINE); }
354    | MULTILINE_COMMENT { $$ = new DocComment($1, convertYYLoc(@1, ast), CommentType::MULTILINE); }
355    ;
356
357doc_comments
358    : doc_comment { $$ = $1; }
359    | doc_comments doc_comment
360      {
361        $1->merge($2);
362        $$ = $1;
363      }
364    ;
365
366ignore_doc_comments
367    : /*empty*/ { $$ = nullptr; }
368    | doc_comments { ast->addUnhandledComment($1); $$ = $1; }
369    ;
370
371valid_identifier
372    : IDENTIFIER
373      {
374        std::string errorMsg;
375        if (!isValidIdentifier($1, &errorMsg)) {
376            std::cerr << "ERROR: " << errorMsg << " at " << @1 << "\n";
377            YYERROR;
378        }
379        $$ = $1;
380      }
381    ;
382
383valid_type_name
384    : IDENTIFIER
385      {
386        std::string errorMsg;
387        if (!isValidTypeName($1, &errorMsg)) {
388            std::cerr << "ERROR: " << errorMsg << " at " << @1 << "\n";
389            YYERROR;
390        }
391        $$ = $1;
392      }
393    ;
394
395opt_annotations
396    : /* empty */
397      {
398          $$ = new std::vector<Annotation *>;
399      }
400    | opt_annotations annotation
401      {
402          $$ = $1;
403          $$->push_back($2);
404      }
405    ;
406
407annotation
408    : '@' IDENTIFIER opt_annotation_params
409      {
410          $$ = new Annotation($2, $3);
411      }
412    ;
413
414opt_annotation_params
415    : /* empty */
416      {
417          $$ = new AnnotationParamVector;
418      }
419    | '(' annotation_params ')'
420      {
421          $$ = $2;
422      }
423    ;
424
425annotation_params
426    : annotation_param
427      {
428          $$ = new AnnotationParamVector;
429          $$->push_back($1);
430      }
431    | annotation_params ',' annotation_param
432      {
433          $$ = $1;
434          $$->push_back($3);
435      }
436    ;
437
438annotation_param
439    : IDENTIFIER '=' annotation_string_value
440      {
441          $$ = new StringAnnotationParam($1, $3);
442      }
443    ;
444
445annotation_string_value
446    : STRING_LITERAL
447      {
448          $$ = new std::vector<std::string>;
449          $$->push_back($1);
450      }
451    | '{' annotation_string_values '}' { $$ = $2; }
452    ;
453
454annotation_string_values
455    : STRING_LITERAL
456      {
457          $$ = new std::vector<std::string>;
458          $$->push_back($1);
459      }
460    | annotation_string_values ',' STRING_LITERAL
461      {
462          $$ = $1;
463          $$->push_back($3);
464      }
465    ;
466
467error_stmt
468  : error ';'
469    {
470      $$ = $1;
471      ast->addSyntaxError();
472    }
473  ;
474
475require_semicolon
476    : ';'
477    | /* empty */
478      {
479          std::cerr << "ERROR: missing ; at " << @$ << "\n";
480          ast->addSyntaxError();
481      }
482    ;
483
484fqname
485    : FQNAME
486      {
487          $$ = new FQName();
488          if(!FQName::parse($1, $$)) {
489              std::cerr << "ERROR: FQName '" << $1 << "' is not valid at "
490                        << @1
491                        << ".\n";
492              YYERROR;
493          }
494      }
495    | valid_type_name
496      {
497          $$ = new FQName();
498          if(!FQName::parse($1, $$)) {
499              std::cerr << "ERROR: FQName '" << $1 << "' is not valid at "
500                        << @1
501                        << ".\n";
502              YYERROR;
503          }
504      }
505    ;
506
507fqtype
508    : fqname
509      {
510          $$ = new Reference<Type>($1->string(), *$1, convertYYLoc(@1, ast));
511      }
512    | TYPE
513      {
514          $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast));
515      }
516    ;
517
518package
519    : PACKAGE FQNAME require_semicolon
520      {
521          if (!ast->setPackage($2)) {
522              std::cerr << "ERROR: Malformed package identifier '"
523                        << $2
524                        << "' at "
525                        << @2
526                        << "\n";
527
528              YYERROR;
529          }
530      }
531    | error
532    {
533      std::cerr << "ERROR: Package statement must be at the beginning of the file (" << @1 << ")\n";
534      $$ = $1;
535      ast->addSyntaxError();
536    }
537    ;
538
539import_stmt
540    : IMPORT FQNAME require_semicolon
541      {
542          if (!ast->addImport($2, convertYYLoc(@2, ast))) {
543              std::cerr << "ERROR: Unable to import '" << $2 << "' at " << @2
544                        << "\n";
545              ast->addSyntaxError();
546          }
547      }
548    | IMPORT valid_type_name require_semicolon
549      {
550          if (!ast->addImport($2, convertYYLoc(@2, ast))) {
551              std::cerr << "ERROR: Unable to import '" << $2 << "' at " << @2
552                        << "\n";
553              ast->addSyntaxError();
554          }
555      }
556    | IMPORT error_stmt
557    ;
558
559opt_extends
560    : /* empty */ { $$ = nullptr; }
561    | EXTENDS fqtype { $$ = $2; }
562    ;
563
564interface_declarations
565    : /* empty */
566    | interface_declarations commentable_type_declaration
567      {
568          CHECK((*scope)->isInterface());
569
570          std::string errorMsg;
571          if ($2 != nullptr && $2->isNamedType() &&
572              !isValidInterfaceField(static_cast<NamedType*>($2)->definedName().c_str(),
573                    &errorMsg)) {
574              std::cerr << "ERROR: " << errorMsg << " at "
575                        << @2 << "\n";
576              YYERROR;
577          }
578      }
579    | interface_declarations commentable_method_declaration
580      {
581          CHECK((*scope)->isInterface());
582
583          std::string errorMsg;
584          if ($2 != nullptr &&
585              !isValidInterfaceField($2->name().c_str(), &errorMsg)) {
586              std::cerr << "ERROR: " << errorMsg << " at "
587                        << @2 << "\n";
588              YYERROR;
589          }
590
591          if ($2 != nullptr) {
592            Interface *iface = static_cast<Interface*>(*scope);
593            if (!ast->addMethod($2, iface)) {
594                std::cerr << "ERROR: Unable to add method '" << $2->name()
595                          << "' at " << @2 << "\n";
596
597                YYERROR;
598            }
599          }
600          // ignore if $2 is nullptr (from error recovery)
601      }
602    ;
603
604declarations
605    : /* empty */
606    | error_stmt
607    | declarations commentable_declaration
608    ;
609
610commentable_declaration
611    : doc_comments type_declaration
612      {
613        $2->setDocComment($1);
614      }
615    | type_declaration
616    | ignore_doc_comments import_stmt
617      {
618        // Import statements must be first. The grammar allows them later so that:
619        // - there is a nice error if imports are later
620        // - doc_comments can be factored out here to avoid shift/reduce conflicts
621        if (!ast->getRootScope().getDefinedTypes().empty()) {
622            std::cerr << "ERROR: import at " << @2
623                      << " follows type definitions, but imports must come first" << std::endl;
624
625            YYERROR;
626        }
627      }
628    ;
629
630/*
631 * For orthogonality/simplicity in the future, import_stmt could be made to share inheritance
632 * hierarchy with type_declaration, and then we could explicitly disallow import inside of
633 * interfaces
634 */
635commentable_type_declaration
636    : doc_comments type_declaration
637      {
638        $2->setDocComment($1);
639        $$ = $2;
640      }
641    | type_declaration { $$ = $1; }
642    ;
643
644type_declaration
645    : opt_annotations type_declaration_body
646      {
647          if (!$2->isTypeDef()) {
648              CHECK($2->isScope());
649              static_cast<Scope*>($2)->setAnnotations($1);
650          } else if (!$1->empty()) {
651              // Since typedefs are always resolved to their target it makes
652              // little sense to annotate them and have their annotations
653              // impose semantics other than their target type.
654              std::cerr << "ERROR: typedefs cannot be annotated at " << @2
655                        << "\n";
656
657              YYERROR;
658          }
659          $$ = $2;
660      }
661    ;
662
663type_declaration_body
664    : named_struct_or_union_declaration require_semicolon
665    | named_enum_declaration require_semicolon
666    | typedef_declaration require_semicolon
667    | interface_declaration require_semicolon
668    ;
669
670interface_declaration
671    : INTERFACE valid_type_name opt_extends
672      {
673          Reference<Type>* superType = $3;
674          bool isIBase = ast->package().package() == gIBaseFqName.package();
675
676          if (isIBase) {
677              if (superType != nullptr) {
678                  std::cerr << "ERROR: IBase must not extend any interface at " << @3
679                        << "\n";
680
681                  YYERROR;
682              }
683              superType = new Reference<Type>();
684          } else {
685              if (!ast->addImplicitImport(gIBaseFqName)) {
686                  std::cerr << "ERROR: Unable to automatically import '"
687                            << gIBaseFqName.string()
688                            << "' at " << @$
689                            << "\n";
690                  YYERROR;
691              }
692
693              if (superType == nullptr) {
694                  superType = new Reference<Type>(gIBaseFqName.string(), gIBaseFqName, convertYYLoc(@$, ast));
695              }
696          }
697
698          if ($2[0] != 'I') {
699              std::cerr << "ERROR: All interface names must start with an 'I' "
700                        << "prefix at " << @2 << "\n";
701
702              YYERROR;
703          }
704
705          if (*scope != &ast->getRootScope()) {
706              std::cerr << "ERROR: All interface must declared in "
707                        << "global scope at " << @2 << "\n";
708
709              YYERROR;
710          }
711
712          Interface* iface = new Interface(
713              $2, ast->makeFullName($2, *scope), convertYYLoc(@2, ast),
714              *scope, *superType, ast->getFileHash());
715
716          enterScope(ast, scope, iface);
717      }
718      interface_declaration_body
719      {
720          CHECK((*scope)->isInterface());
721
722          Interface *iface = static_cast<Interface *>(*scope);
723          CHECK(ast->addAllReservedMethodsToInterface(iface));
724
725          leaveScope(ast, scope);
726          ast->addScopedType(iface, *scope);
727          $$ = iface;
728      }
729    ;
730
731interface_declaration_body
732    : '{' interface_declarations ignore_doc_comments '}'
733    ;
734
735typedef_declaration
736    : TYPEDEF type valid_type_name
737      {
738          // The reason we wrap the given type in a TypeDef is simply to suppress
739          // emitting any type definitions later on, since this is just an alias
740          // to a type defined elsewhere.
741          TypeDef* typeDef = new TypeDef(
742              $3, ast->makeFullName($3, *scope), convertYYLoc(@2, ast), *scope, *$2);
743          ast->addScopedType(typeDef, *scope);
744          $$ = typeDef;
745      }
746    ;
747
748const_expr
749    : INTEGER
750      {
751          $$ = LiteralConstantExpression::tryParse($1);
752
753          if ($$ == nullptr) {
754              std::cerr << "ERROR: Could not parse literal: "
755                        << $1 << " at " << @1 << ".\n";
756              YYERROR;
757          }
758      }
759    | fqname
760      {
761          if(!$1->isValidValueName()) {
762              std::cerr << "ERROR: '" << $1->string()
763                        << "' does not refer to an enum value at "
764                        << @1 << ".\n";
765              YYERROR;
766          }
767
768          $$ = new ReferenceConstantExpression(
769              Reference<LocalIdentifier>($1->string(), *$1, convertYYLoc(@1, ast)), $1->string());
770      }
771    | fqname '#' IDENTIFIER
772      {
773          $$ = new AttributeConstantExpression(
774              Reference<Type>($1->string(), *$1, convertYYLoc(@1, ast)), $1->string(), $3);
775      }
776    | const_expr '?' const_expr ':' const_expr
777      {
778          $$ = new TernaryConstantExpression($1, $3, $5);
779      }
780    | const_expr LOGICAL_OR const_expr  { $$ = new BinaryConstantExpression($1, "||", $3); }
781    | const_expr LOGICAL_AND const_expr { $$ = new BinaryConstantExpression($1, "&&", $3); }
782    | const_expr '|' const_expr { $$ = new BinaryConstantExpression($1, "|" , $3); }
783    | const_expr '^' const_expr { $$ = new BinaryConstantExpression($1, "^" , $3); }
784    | const_expr '&' const_expr { $$ = new BinaryConstantExpression($1, "&" , $3); }
785    | const_expr EQUALITY const_expr { $$ = new BinaryConstantExpression($1, "==", $3); }
786    | const_expr NEQ const_expr { $$ = new BinaryConstantExpression($1, "!=", $3); }
787    | const_expr '<' const_expr { $$ = new BinaryConstantExpression($1, "<" , $3); }
788    | const_expr '>' const_expr { $$ = new BinaryConstantExpression($1, ">" , $3); }
789    | const_expr LEQ const_expr { $$ = new BinaryConstantExpression($1, "<=", $3); }
790    | const_expr GEQ const_expr { $$ = new BinaryConstantExpression($1, ">=", $3); }
791    | const_expr LSHIFT const_expr { $$ = new BinaryConstantExpression($1, "<<", $3); }
792    | const_expr RSHIFT const_expr { $$ = new BinaryConstantExpression($1, ">>", $3); }
793    | const_expr '+' const_expr { $$ = new BinaryConstantExpression($1, "+" , $3); }
794    | const_expr '-' const_expr { $$ = new BinaryConstantExpression($1, "-" , $3); }
795    | const_expr '*' const_expr { $$ = new BinaryConstantExpression($1, "*" , $3); }
796    | const_expr '/' const_expr { $$ = new BinaryConstantExpression($1, "/" , $3); }
797    | const_expr '%' const_expr { $$ = new BinaryConstantExpression($1, "%" , $3); }
798    | '+' const_expr %prec UNARY_PLUS  { $$ = new UnaryConstantExpression("+", $2); }
799    | '-' const_expr %prec UNARY_MINUS { $$ = new UnaryConstantExpression("-", $2); }
800    | '!' const_expr { $$ = new UnaryConstantExpression("!", $2); }
801    | '~' const_expr { $$ = new UnaryConstantExpression("~", $2); }
802    | '(' const_expr ')'
803      {
804        $2->surroundWithParens();
805        $$ = $2;
806      }
807    | '(' error ')'
808      {
809        ast->addSyntaxError();
810        // to avoid segfaults
811        $$ = ConstantExpression::Zero(ScalarType::KIND_INT32).release();
812      }
813    ;
814
815commentable_method_declaration
816    : doc_comments method_declaration
817      {
818        if ($2 != nullptr) $2->setDocComment($1);
819        $$ = $2;
820      }
821    | method_declaration
822      {
823        $$ = $1;
824      }
825
826method_declaration
827    : error_stmt { $$ = nullptr; }
828    | opt_annotations valid_identifier '(' typed_vars ')' require_semicolon
829      {
830          $$ = new Method($2 /* name */,
831                          $4 /* args */,
832                          new std::vector<NamedReference<Type>*> /* results */,
833                          false /* oneway */,
834                          $1 /* annotations */,
835                          convertYYLoc(@$, ast));
836      }
837    | opt_annotations ONEWAY valid_identifier '(' typed_vars ')' require_semicolon
838      {
839          $$ = new Method($3 /* name */,
840                          $5 /* args */,
841                          new std::vector<NamedReference<Type>*> /* results */,
842                          true /* oneway */,
843                          $1 /* annotations */,
844                          convertYYLoc(@$, ast));
845      }
846    | opt_annotations valid_identifier '(' typed_vars ')' GENERATES '(' typed_vars ')' require_semicolon
847      {
848          if ($8->empty()) {
849              std::cerr << "ERROR: generates clause used without result at " << @1 << "\n";
850              ast->addSyntaxError();
851          }
852
853          $$ = new Method($2 /* name */,
854                          $4 /* args */,
855                          $8 /* results */,
856                          false /* oneway */,
857                          $1 /* annotations */,
858                          convertYYLoc(@$, ast));
859      }
860    ;
861
862typed_vars
863    : /* empty */
864      {
865          $$ = new TypedVarVector();
866      }
867    | non_empty_typed_vars
868      {
869          $$ = $1;
870      }
871    ;
872
873non_empty_typed_vars
874    : typed_var
875      {
876          $$ = new TypedVarVector();
877          if (!$$->add($1)) {
878              std::cerr << "ERROR: duplicated argument or result name "
879                  << $1->name() << " at " << @1 << "\n";
880              ast->addSyntaxError();
881          }
882      }
883    | non_empty_typed_vars ',' typed_var
884      {
885          $$ = $1;
886          if (!$$->add($3)) {
887              std::cerr << "ERROR: duplicated argument or result name "
888                  << $3->name() << " at " << @3 << "\n";
889              ast->addSyntaxError();
890          }
891      }
892    ;
893
894typed_var
895    : ignore_doc_comments uncommented_typed_var { $$ = $2; }
896    ;
897
898uncommented_typed_var
899    : type valid_identifier ignore_doc_comments
900      {
901          $$ = new NamedReference<Type>($2, *$1, convertYYLoc(@2, ast));
902      }
903    | type
904      {
905          $$ = new NamedReference<Type>("", *$1, convertYYLoc(@1, ast));
906
907          const std::string typeName = $$->isResolved()
908              ? $$->get()->typeName() : $$->getLookupFqName().string();
909
910          std::cerr << "ERROR: variable of type " << typeName
911              << " is missing a variable name at " << @1 << "\n";
912          ast->addSyntaxError();
913      }
914    ;
915
916
917struct_or_union_keyword
918    : STRUCT { $$ = CompoundType::STYLE_STRUCT; }
919    | UNION { $$ = CompoundType::STYLE_UNION; }
920    | SAFE_UNION { $$ = CompoundType::STYLE_SAFE_UNION; }
921    ;
922
923named_struct_or_union_declaration
924    : struct_or_union_keyword valid_type_name
925      {
926          CompoundType *container = new CompoundType(
927              $1, $2, ast->makeFullName($2, *scope), convertYYLoc(@2, ast), *scope);
928          enterScope(ast, scope, container);
929      }
930      struct_or_union_body
931      {
932          CHECK((*scope)->isCompoundType());
933          CompoundType *container = static_cast<CompoundType *>(*scope);
934
935          leaveScope(ast, scope);
936          ast->addScopedType(container, *scope);
937          $$ = container;
938      }
939    ;
940
941struct_or_union_body
942    : '{' field_declarations ignore_doc_comments '}' { $$ = $2; }
943    ;
944
945field_declarations
946    : /* empty */ { $$ = nullptr; }
947    | field_declarations commentable_field_declaration
948      {
949          $$ = nullptr;
950      }
951    ;
952
953commentable_field_declaration
954    : doc_comments field_declaration
955    {
956      if ($2 != nullptr) $2->setDocComment($1);
957      $$ = $2;
958    }
959    | field_declaration { $$ = $1; }
960
961field_declaration
962    : error_stmt { $$ = nullptr; }
963    | type_or_inplace_compound_declaration valid_identifier require_semicolon
964      {
965          CHECK((*scope)->isCompoundType());
966
967          std::string errorMsg;
968          CompoundType* compoundType = static_cast<CompoundType *>(*scope);
969          auto style = compoundType->style();
970
971          if (!isValidCompoundTypeField(style, $2, &errorMsg)) {
972              std::cerr << "ERROR: " << errorMsg << " at "
973                        << @2 << "\n";
974              YYERROR;
975          }
976
977          NamedReference<Type>* field = new NamedReference<Type>($2, *$1, convertYYLoc(@2, ast));
978          compoundType->addField(field);
979          $$ = field;
980      }
981    | annotated_compound_declaration ';'
982      {
983          CHECK((*scope)->isCompoundType());
984
985          std::string errorMsg;
986          auto style = static_cast<CompoundType *>(*scope)->style();
987
988          if ($1 != nullptr && $1->isNamedType() &&
989              !isValidCompoundTypeField(style, static_cast<NamedType*>(
990                        $1)->definedName().c_str(), &errorMsg)) {
991              std::cerr << "ERROR: " << errorMsg << " at "
992                        << @2 << "\n";
993              YYERROR;
994          }
995
996          $$ = $1;
997      }
998    ;
999
1000annotated_compound_declaration
1001    : opt_annotations compound_declaration
1002      {
1003          CHECK($2->isScope());
1004          static_cast<Scope*>($2)->setAnnotations($1);
1005          $$ = $2;
1006      }
1007    ;
1008
1009compound_declaration
1010    : named_struct_or_union_declaration { $$ = $1; }
1011    | named_enum_declaration { $$ = $1; }
1012    ;
1013
1014enum_storage_type
1015    : ':' fqtype ignore_doc_comments { $$ = $2; }
1016    | /* empty */ { $$ = nullptr; }
1017    ;
1018
1019named_enum_declaration
1020    : ENUM valid_type_name enum_storage_type
1021      {
1022          auto storageType = $3;
1023
1024          if (storageType == nullptr) {
1025              std::cerr << "ERROR: Must explicitly specify enum storage type for "
1026                        << $2 << " at " << @2 << "\n";
1027              ast->addSyntaxError();
1028              ScalarType* scalar = new ScalarType(ScalarType::KIND_INT64, *scope);
1029              storageType = new Reference<Type>(scalar->definedName(), scalar, convertYYLoc(@2, ast));
1030          }
1031
1032          EnumType* enumType = new EnumType(
1033              $2, ast->makeFullName($2, *scope), convertYYLoc(@2, ast), *storageType, *scope);
1034          enterScope(ast, scope, enumType);
1035      }
1036      enum_declaration_body
1037      {
1038          CHECK((*scope)->isEnum());
1039          EnumType* enumType = static_cast<EnumType*>(*scope);
1040
1041          leaveScope(ast, scope);
1042          ast->addScopedType(enumType, *scope);
1043          $$ = enumType;
1044      }
1045    ;
1046
1047enum_declaration_body
1048    : '{' enum_values '}' { $$ = $2; }
1049    | '{' enum_values ',' ignore_doc_comments '}' { $$ = $2; }
1050    ;
1051
1052commentable_enum_value
1053    : doc_comments enum_value ignore_doc_comments
1054      {
1055        $2->setDocComment($1);
1056        $$ = $2;
1057      }
1058    | enum_value { $$ = $1; }
1059    ;
1060
1061enum_value
1062    : valid_identifier
1063      {
1064          $$ = new EnumValue($1 /* name */, nullptr /* value */, convertYYLoc(@$, ast));
1065      }
1066    | valid_identifier '=' const_expr
1067      {
1068          $$ = new EnumValue($1 /* name */, $3 /* value */, convertYYLoc(@$, ast));
1069      }
1070    ;
1071
1072enum_values
1073    : /* empty */
1074      { /* do nothing */ }
1075    | commentable_enum_value
1076      {
1077          CHECK((*scope)->isEnum());
1078          static_cast<EnumType *>(*scope)->addValue($1);
1079      }
1080    | enum_values ',' commentable_enum_value
1081      {
1082          CHECK((*scope)->isEnum());
1083          static_cast<EnumType *>(*scope)->addValue($3);
1084      }
1085    | error ',' commentable_enum_value
1086      {
1087          ast->addSyntaxError();
1088
1089          CHECK((*scope)->isEnum());
1090          static_cast<EnumType *>(*scope)->addValue($3);
1091      }
1092    | enum_values ',' error ',' commentable_enum_value
1093      {
1094          ast->addSyntaxError();
1095
1096          CHECK((*scope)->isEnum());
1097          static_cast<EnumType *>(*scope)->addValue($5);
1098      }
1099    ;
1100
1101array_type_base
1102    : fqtype { $$ = $1; }
1103    | TEMPLATED '<' type '>'
1104      {
1105          $1->setElementType(*$3);
1106          $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast));
1107      }
1108    | TEMPLATED '<' TEMPLATED '<' type RSHIFT
1109      {
1110          $3->setElementType(*$5);
1111          $1->setElementType(Reference<Type>($3->definedName(), $3, convertYYLoc(@3, ast)));
1112          $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast));
1113      }
1114    ;
1115
1116array_type
1117    : array_type_base ignore_doc_comments '[' const_expr ']'
1118      {
1119          $$ = new ArrayType(*$1, $4, *scope);
1120      }
1121    | array_type '[' const_expr ']'
1122      {
1123          $$ = $1;
1124          $$->appendDimension($3);
1125      }
1126    ;
1127
1128type
1129    : array_type_base ignore_doc_comments { $$ = $1; }
1130    | array_type ignore_doc_comments
1131      {
1132        $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast));
1133      }
1134    | INTERFACE ignore_doc_comments
1135      {
1136        // "interface" is a synonym of android.hidl.base@1.0::IBase
1137        $$ = new Reference<Type>("interface", gIBaseFqName, convertYYLoc(@1, ast));
1138      }
1139    ;
1140
1141type_or_inplace_compound_declaration
1142    : type { $$ = $1; }
1143    | annotated_compound_declaration ignore_doc_comments
1144      {
1145          $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast), true);
1146      }
1147    ;
1148
1149%%
1150
1151void yy::parser::error(
1152        const yy::parser::location_type &where,
1153        const std::string &errstr) {
1154    std::cerr << "ERROR: " << errstr << " at " << where << "\n";
1155}
1156