hidl-gen: some error recovery.
Detect some errors and attempt to recover when a
';' is seen.
Attempt to remind the writer for missing ';'s.
TODO: more error recovery should be done
for hidl/errorhal/error/1.0/IEx1.hal
Bug: 31367057 (partly fixes)
Test: mma
Test: `hidl-gen -Lc++ -r tests.errors:system/tools/hidl/test/errorhal -o
~/temp tests.errors.syntax@1.0`
The output has the correct positions marked for the errors.
Change-Id: I858129e08a10cc12a9978adc7fe0c0b94ffbf83e
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index f5c9406..4e81a49 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -107,6 +107,7 @@
/* Precedence level 3, RTL; but we have to use %left here */
%left UNARY_MINUS UNARY_PLUS '!' '~'
+%type<str> error_stmt opt_error_stmt error
%type<str> package
%type<fqName> fqname
%type<type> fqtype
@@ -261,8 +262,34 @@
}
;
+error_stmt
+ : error ';'
+ {
+ $$ = $1;
+ ast->addSyntaxError();
+ // std::cerr << "WARNING: skipping errors until " << @2 << ".\n";
+ }
+ ;
+
+opt_error_stmt
+ : /* empty */ { $$ = NULL; }
+ | error_stmt { $$ = $1; }
+ ;
+
+require_semicolon
+ : ';'
+ | /* empty */
+ {
+ std::cerr << "ERROR: missing ; at " << @$ << "\n";
+ ast->addSyntaxError();
+ }
+ ;
+
program
- : package imports body
+ : opt_error_stmt
+ package
+ imports
+ body
;
fqname
@@ -304,7 +331,7 @@
;
package
- : PACKAGE FQNAME ';'
+ : PACKAGE FQNAME require_semicolon
{
if (!ast->setPackage($2)) {
std::cerr << "ERROR: Malformed package identifier '"
@@ -317,26 +344,30 @@
}
}
+import_stmt
+ : IMPORT FQNAME require_semicolon
+ {
+ if (!ast->addImport($2)) {
+ std::cerr << "ERROR: Unable to import '" << $2 << "' at " << @2
+ << "\n";
+ ast->addSyntaxError();
+ }
+ }
+ | IMPORT IDENTIFIER require_semicolon
+ {
+ if (!ast->addImport($2)) {
+ std::cerr << "ERROR: Unable to import '" << $2 << "' at " << @2
+ << "\n";
+ ast->addSyntaxError();
+ }
+ }
+ | IMPORT error_stmt
+ ;
+
+
imports
: /* empty */
- | imports IMPORT FQNAME ';'
- {
- if (!ast->addImport($3)) {
- std::cerr << "ERROR: Unable to import '" << $3 << "' at " << @3
- << "\n";
-
- YYERROR;
- }
- }
- | imports IMPORT IDENTIFIER ';'
- {
- if (!ast->addImport($3)) {
- std::cerr << "ERROR: Unable to import '" << $3 << "' at " << @3
- << "\n";
-
- YYERROR;
- }
- }
+ | imports import_stmt
;
opt_extends
@@ -352,18 +383,28 @@
| interface_declarations type_declaration
| interface_declarations method_declaration
{
- Interface *iface = static_cast<Interface *>(ast->scope());
- if (!iface->addMethod($2)) {
- std::cerr << "ERROR: Unable to add method '" << $2->name()
- << "' at " << @2 << "\n";
+ if ($2 != nullptr) {
+ if (!ast->scope()->isInterface()) {
+ std::cerr << "ERROR: unknown error in interface declaration at "
+ << @2 << "\n";
+ YYERROR;
+ }
- YYERROR;
+ Interface *iface = static_cast<Interface *>(ast->scope());
+ if (!iface->addMethod($2)) {
+ std::cerr << "ERROR: Unable to add method '" << $2->name()
+ << "' at " << @2 << "\n";
+
+ YYERROR;
+ }
}
+ // ignore if $2 is nullptr (from error recovery)
}
;
type_declarations
: /* empty */
+ | error_stmt
| type_declarations type_declaration
;
@@ -385,17 +426,17 @@
;
type_declaration_body
- : named_struct_or_union_declaration ';'
- | named_enum_declaration ';'
- | typedef_declaration ';'
- | interface_declaration ';'
+ : named_struct_or_union_declaration require_semicolon
+ | named_enum_declaration require_semicolon
+ | typedef_declaration require_semicolon
+ | interface_declaration require_semicolon
;
interface_declaration
: INTERFACE IDENTIFIER opt_extends
{
if ($3 != NULL && !$3->isInterface()) {
- std::cerr << "ERROR: You can only extend interfaces. at" << @3
+ std::cerr << "ERROR: You can only extend interfaces. at " << @3
<< "\n";
YYERROR;
@@ -422,6 +463,12 @@
}
'{' interface_declarations '}'
{
+ if (!ast->scope()->isInterface()) {
+ std::cerr << "ERROR: unknown error in interface declaration at "
+ << @5 << "\n";
+ YYERROR;
+ }
+
Interface *iface = static_cast<Interface *>(ast->scope());
ast->leaveScope();
@@ -457,13 +504,13 @@
std::string identifier = $1->name();
LocalIdentifier *iden = ast->scope()->lookupIdentifier(identifier);
if(!iden) {
- std::cerr << "ERROR: at " << @1 << ", identifier " << $1->string()
- << " could not be found.\n";
+ std::cerr << "ERROR: identifier " << $1->string()
+ << " could not be found at " << @1 << ".\n";
YYERROR;
}
if(!iden->isEnumValue()) {
- std::cerr << "ERROR: at " << @1 << ", identifier " << $1->string()
- << " is not an enum value.\n";
+ std::cerr << "ERROR: identifier " << $1->string()
+ << " is not an enum value at " << @1 << ".\n";
YYERROR;
}
$$ = new ConstantExpression(
@@ -505,18 +552,25 @@
| '!' const_expr { $$ = new ConstantExpression("!", $2); }
| '~' const_expr { $$ = new ConstantExpression("~", $2); }
| '(' const_expr ')' { $$ = $2; }
+ | '(' error ')'
+ {
+ ast->addSyntaxError();
+ // to avoid segfaults
+ $$ = new ConstantExpression(ConstantExpression::Zero(ScalarType::KIND_INT32));
+ }
;
method_declaration
- : opt_annotations IDENTIFIER '(' typed_vars ')' ';'
+ : error_stmt { $$ = nullptr; }
+ | opt_annotations IDENTIFIER '(' typed_vars ')' require_semicolon
{
$$ = new Method($2, $4, new std::vector<TypedVar *>, false, $1);
}
- | opt_annotations ONEWAY IDENTIFIER '(' typed_vars ')' ';'
+ | opt_annotations ONEWAY IDENTIFIER '(' typed_vars ')' require_semicolon
{
$$ = new Method($3, $5, new std::vector<TypedVar *>, true, $1);
}
- | opt_annotations IDENTIFIER '(' typed_vars ')' GENERATES '(' typed_vars ')' ';'
+ | opt_annotations IDENTIFIER '(' typed_vars ')' GENERATES '(' typed_vars ')' require_semicolon
{
$$ = new Method($2, $4, $8, false, $1);
}
@@ -556,6 +610,11 @@
}
struct_or_union_body
{
+ if (!ast->scope()->isCompoundType()) {
+ std::cerr << "ERROR: unknown error in struct or union declaration at "
+ << @4 << "\n";
+ YYERROR;
+ }
CompoundType *container = static_cast<CompoundType *>(ast->scope());
std::string errorMsg;
@@ -592,7 +651,8 @@
;
field_declaration
- : type IDENTIFIER ';' { $$ = new CompoundField($2, $1); }
+ : error_stmt { $$ = nullptr; }
+ | type IDENTIFIER require_semicolon { $$ = new CompoundField($2, $1); }
| annotated_compound_declaration ';' { $$ = NULL; }
;
@@ -619,7 +679,7 @@
std::cerr << "ERROR: Invalid enum storage type specified. at "
<< @2 << "\n";
- YYABORT;
+ YYERROR;
}
}
;
@@ -636,6 +696,12 @@
}
enum_declaration_body
{
+ if (!ast->scope()->isEnum()) {
+ std::cerr << "ERROR: unknown error in enum declaration at "
+ << @5 << "\n";
+ YYERROR;
+ }
+
EnumType *enumType = static_cast<EnumType *>(ast->scope());
ast->leaveScope();
@@ -663,10 +729,22 @@
{ /* do nothing */ }
| enum_value
{
+ if (!ast->scope()->isEnum()) {
+ std::cerr << "ERROR: unknown error in enum declaration at "
+ << @1 << "\n";
+ YYERROR;
+ }
+
static_cast<EnumType *>(ast->scope())->addValue($1);
}
| enum_values ',' enum_value
{
+ if (!ast->scope()->isEnum()) {
+ std::cerr << "ERROR: unknown error in enum declaration at "
+ << @3 << "\n";
+ YYERROR;
+ }
+
static_cast<EnumType *>(ast->scope())->addValue($3);
}
;