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