summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWouter van Oortmerssen <wvo@google.com>2014-11-17 17:27:26 -0800
committerWouter van Oortmerssen <wvo@google.com>2014-11-19 11:06:17 -0800
commit0952143971bdbb5ef20dae8a865e811a0e31b4b3 (patch)
treee5886d0e82dacb16685721d8c36c4ce1969fce78
parent0ce53c96c30fe5438edf50251ca60b7655db1f2a (diff)
downloadflatbuffers-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.html3
-rw-r--r--docs/html/md__schemas.html4
-rwxr-xr-xdocs/source/Grammar.md5
-rwxr-xr-xdocs/source/Schemas.md5
-rw-r--r--include/flatbuffers/idl.h26
-rw-r--r--src/idl_parser.cpp14
-rwxr-xr-xtests/monster_test.fbs2
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 &amp; 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