diff options
author | Wouter van Oortmerssen <wvo@google.com> | 2014-11-17 17:27:26 -0800 |
---|---|---|
committer | Wouter van Oortmerssen <wvo@google.com> | 2014-11-19 11:06:17 -0800 |
commit | 0952143971bdbb5ef20dae8a865e811a0e31b4b3 (patch) | |
tree | e5886d0e82dacb16685721d8c36c4ce1969fce78 | |
parent | 0ce53c96c30fe5438edf50251ca60b7655db1f2a (diff) | |
download | flatbuffers-0952143971bdbb5ef20dae8a865e811a0e31b4b3.tar.gz flatbuffers-0952143971bdbb5ef20dae8a865e811a0e31b4b3.tar.bz2 flatbuffers-0952143971bdbb5ef20dae8a865e811a0e31b4b3.zip |
Added user defined attribute declarations.
This is such that if you mis-spell an attribute, it doesn't get
silently ignored.
Bug: 18294628
Change-Id: I10013f5b2a21048b7daba2e9410678f528e09761
Tested: on Linux.
-rw-r--r-- | docs/html/md__grammar.html | 3 | ||||
-rw-r--r-- | docs/html/md__schemas.html | 4 | ||||
-rwxr-xr-x | docs/source/Grammar.md | 5 | ||||
-rwxr-xr-x | docs/source/Schemas.md | 5 | ||||
-rw-r--r-- | include/flatbuffers/idl.h | 26 | ||||
-rw-r--r-- | src/idl_parser.cpp | 14 | ||||
-rwxr-xr-x | tests/monster_test.fbs | 2 |
7 files changed, 45 insertions, 14 deletions
diff --git a/docs/html/md__grammar.html b/docs/html/md__grammar.html index 8d4e525a..d46780bc 100644 --- a/docs/html/md__grammar.html +++ b/docs/html/md__grammar.html @@ -53,9 +53,10 @@ $(document).ready(function(){initNavTree('md__grammar.html','');}); <div class="title">Formal Grammar of the schema language </div> </div> </div><!--header--> <div class="contents"> -<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | object )*</p> +<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | attribute_decl | object )*</p> <p>include = <code>include</code> string_constant <code>;</code></p> <p>namespace_decl = <code>namespace</code> ident ( <code>.</code> ident )* <code>;</code></p> +<p>attribute_decl = <code>attribute</code> string_constant <code>;</code></p> <p>type_decl = ( <code>table</code> | <code>struct</code> ) ident metadata <code>{</code> field_decl+ <code>}</code></p> <p>enum_decl = ( <code>enum</code> | <code>union</code> ) ident [ <code>:</code> type ] metadata <code>{</code> commasep( enumval_decl ) <code>}</code></p> <p>root_decl = <code>root_type</code> ident <code>;</code></p> diff --git a/docs/html/md__schemas.html b/docs/html/md__schemas.html index f8f220be..daa5ab37 100644 --- a/docs/html/md__schemas.html +++ b/docs/html/md__schemas.html @@ -57,6 +57,8 @@ $(document).ready(function(){initNavTree('md__schemas.html','');}); namespace MyGame; +attribute "priority"; + enum Color : byte { Red = 1, Green, Blue } union Any { Monster, Weapon, Pickup } @@ -128,7 +130,7 @@ root_type Monster; </pre><h3>Comments & documentation</h3> <p>May be written as in most C-based languages. Additionally, a triple comment (<code>///</code>) on a line by itself signals that a comment is documentation for whatever is declared on the line after it (table/struct/field/enum/union/element), and the comment is output in the corresponding C++ code. Multiple such lines per item are allowed.</p> <h3>Attributes</h3> -<p>Attributes may be attached to a declaration, behind a field, or after the name of a table/struct/enum/union. These may either have a value or not. Some attributes like <code>deprecated</code> are understood by the compiler, others are simply ignored (like <code>priority</code> in the example above), but are available to query if you parse the schema at runtime. This is useful if you write your own code generators/editors etc., and you wish to add additional information specific to your tool (such as a help text).</p> +<p>Attributes may be attached to a declaration, behind a field, or after the name of a table/struct/enum/union. These may either have a value or not. Some attributes like <code>deprecated</code> are understood by the compiler, user defined ones need to be declared with the attribute declaration (like <code>priority</code> in the example above), and are available to query if you parse the schema at runtime. This is useful if you write your own code generators/editors etc., and you wish to add additional information specific to your tool (such as a help text).</p> <p>Current understood attributes:</p> <ul> <li><code>id: n</code> (on a table field): manually set the field identifier to <code>n</code>. If you use this attribute, you must use it on ALL fields of this table, and the numbers must be a contiguous range from 0 onwards. Additionally, since a union type effectively adds two fields, its id must be that of the second field (the first field is the type field and not explicitly declared in the schema). For example, if the last field before the union field had id 6, the union field should have id 8, and the unions type field will implicitly be 7. IDs allow the fields to be placed in any order in the schema. When a new field is added to the schema is must use the next available ID.</li> diff --git a/docs/source/Grammar.md b/docs/source/Grammar.md index 33bd1709..6aab0392 100755 --- a/docs/source/Grammar.md +++ b/docs/source/Grammar.md @@ -1,12 +1,15 @@ # Formal Grammar of the schema language schema = include* - ( namespace\_decl | type\_decl | enum\_decl | root\_decl | object )* + ( namespace\_decl | type\_decl | enum\_decl | root\_decl | + attribute\_decl | object )* include = `include` string\_constant `;` namespace\_decl = `namespace` ident ( `.` ident )* `;` +attribute\_decl = `attribute` string\_constant `;` + type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}` enum\_decl = ( `enum` | `union` ) ident [ `:` type ] metadata `{` commasep( diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md index 650e74db..9d568d02 100755 --- a/docs/source/Schemas.md +++ b/docs/source/Schemas.md @@ -9,6 +9,8 @@ first: namespace MyGame; + attribute "priority"; + enum Color : byte { Red = 1, Green, Blue } union Any { Monster, Weapon, Pickup } @@ -211,7 +213,8 @@ in the corresponding C++ code. Multiple such lines per item are allowed. Attributes may be attached to a declaration, behind a field, or after the name of a table/struct/enum/union. These may either have a value or not. Some attributes like `deprecated` are understood by the compiler, -others are simply ignored (like `priority` in the example above), but are +user defined ones need to be declared with the attribute declaration +(like `priority` in the example above), and are available to query if you parse the schema at runtime. This is useful if you write your own code generators/editors etc., and you wish to add additional information specific to your tool (such as a diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index f7b747cc..eccd1d84 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -18,6 +18,7 @@ #define FLATBUFFERS_IDL_H_ #include <map> +#include <set> #include <memory> #include <functional> @@ -260,14 +261,21 @@ struct EnumDef : public Definition { class Parser { public: - Parser(bool proto_mode = false) : - root_struct_def(nullptr), - source_(nullptr), - cursor_(nullptr), - line_(1), - proto_mode_(proto_mode) { - // Just in case none are declared: - namespaces_.push_back(new Namespace()); + Parser(bool proto_mode = false) + : root_struct_def(nullptr), + source_(nullptr), + cursor_(nullptr), + line_(1), + proto_mode_(proto_mode) { + // Just in case none are declared: + namespaces_.push_back(new Namespace()); + known_attributes_.insert("deprecated"); + known_attributes_.insert("required"); + known_attributes_.insert("id"); + known_attributes_.insert("force_align"); + known_attributes_.insert("bit_flags"); + known_attributes_.insert("original_order"); + known_attributes_.insert("nested_flatbuffer"); } ~Parser() { @@ -345,6 +353,8 @@ class Parser { std::vector<std::pair<Value, FieldDef *>> field_stack_; std::vector<uint8_t> struct_stack_; + + std::set<std::string> known_attributes_; }; // Utility functions for multiple generators: diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 3091fe60..705e2a63 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -85,7 +85,8 @@ template<> inline Offset<void> atot<Offset<void>>(const char *s) { TD(RootType, 266, "root_type") \ TD(FileIdentifier, 267, "file_identifier") \ TD(FileExtension, 268, "file_extension") \ - TD(Include, 269, "include") + TD(Include, 269, "include") \ + TD(Attribute, 270, "attribute") #ifdef __GNUC__ __extension__ // Stop GCC complaining about trailing comma with -Wpendantic. #endif @@ -222,7 +223,8 @@ void Parser::Next() { if (attribute_ == "union") { token_ = kTokenUnion; return; } if (attribute_ == "namespace") { token_ = kTokenNameSpace; return; } if (attribute_ == "root_type") { token_ = kTokenRootType; return; } - if (attribute_ == "include") { token_ = kTokenInclude; return; } + if (attribute_ == "include") { token_ = kTokenInclude; return; } + if (attribute_ == "attribute") { token_ = kTokenAttribute; return; } if (attribute_ == "file_identifier") { token_ = kTokenFileIdentifier; return; @@ -598,6 +600,8 @@ void Parser::ParseMetaData(Definition &def) { for (;;) { auto name = attribute_; Expect(kTokenIdentifier); + if (known_attributes_.find(name) == known_attributes_.end()) + Error("user define attributes must be declared before use: " + name); auto e = new Value(); def.attributes.Add(name, e); if (IsNext(':')) { @@ -1090,6 +1094,12 @@ bool Parser::Parse(const char *source, const char **include_paths, Expect(';'); } else if(token_ == kTokenInclude) { Error("includes must come before declarations"); + } else if(token_ == kTokenAttribute) { + Next(); + auto name = attribute_; + Expect(kTokenStringConstant); + Expect(';'); + known_attributes_.insert(name); } else { ParseDecl(); } diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs index 12749cbd..0ffd3dc1 100755 --- a/tests/monster_test.fbs +++ b/tests/monster_test.fbs @@ -4,6 +4,8 @@ include "include_test1.fbs"; namespace MyGame.Example; +attribute "priority"; + enum Color:byte (bit_flags) { Red = 0, Green, Blue = 3, } union Any { Monster } // TODO: add more elements |