An user-defined attribute name validation (#4689)
authorVladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>
Fri, 6 Apr 2018 16:07:59 +0000 (23:07 +0700)
committerWouter van Oortmerssen <aardappel@gmail.com>
Fri, 6 Apr 2018 16:07:59 +0000 (09:07 -0700)
* User-declared attribute should be either identifier or string with the identifier.

* Attribute can be identifier or string in metadata.

docs/source/Grammar.md
src/idl_parser.cpp

index 84e762c..bf79596 100644 (file)
@@ -10,7 +10,7 @@ include = `include` string\_constant `;`
 
 namespace\_decl = `namespace` ident ( `.` ident )* `;`
 
-attribute\_decl = `attribute` string\_constant `;`
+attribute\_decl = `attribute` ident | `"`ident`"` `;`
 
 type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`
 
index b16e3e1..3a1d7b9 100644 (file)
@@ -425,8 +425,7 @@ CheckedError Parser::Next() {
         if (IsIdentifierStart(c)) {
           // Collect all chars of an identifier:
           const char *start = cursor_ - 1;
-          while (isalnum(static_cast<unsigned char>(*cursor_)) ||
-                 *cursor_ == '_')
+          while (isalnum(static_cast<unsigned char>(*cursor_)) || *cursor_ == '_')
             cursor_++;
           attribute_.append(start, cursor_);
           token_ = kTokenIdentifier;
@@ -1223,10 +1222,13 @@ CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
     NEXT();
     for (;;) {
       auto name = attribute_;
-      EXPECT(kTokenIdentifier);
+      if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
+        return Error("attribute name must be either identifier or string: " +
+          name);
       if (known_attributes_.find(name) == known_attributes_.end())
         return Error("user define attributes must be declared before use: " +
                      name);
+      NEXT();
       auto e = new Value();
       attributes->Add(name, e);
       if (Is(':')) {
@@ -2453,7 +2455,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
     } else if (IsIdent("attribute")) {
       NEXT();
       auto name = attribute_;
-      EXPECT(kTokenStringConstant);
+      if (Is(kTokenIdentifier)) {
+        NEXT();
+      } else {
+        EXPECT(kTokenStringConstant);
+      }
       EXPECT(';');
       known_attributes_[name] = false;
     } else if (IsIdent("rpc_service")) {