diff --git a/docs/html/md__grammar.html b/docs/html/md__grammar.html index 8d4e525a1..d46780bcc 100644 --- a/docs/html/md__grammar.html +++ b/docs/html/md__grammar.html @@ -53,9 +53,10 @@ $(document).ready(function(){initNavTree('md__grammar.html','');});
Formal Grammar of the schema language
-

schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | object )*

+

schema = include* ( 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( enumval_decl ) }

root_decl = root_type ident ;

diff --git a/docs/html/md__schemas.html b/docs/html/md__schemas.html index f8f220beb..daa5ab371 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;

Comments & documentation

May be written as in most C-based languages. Additionally, a triple comment (///) 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.

Attributes

-

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 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).

+

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, 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 help text).

Current understood attributes:

  • id: n (on a table field): manually set the field identifier to n. 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.
  • diff --git a/docs/source/Grammar.md b/docs/source/Grammar.md index 33bd17099..6aab0392a 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 650e74db8..9d568d023 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 f7b747cc4..eccd1d84f 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -18,6 +18,7 @@ #define FLATBUFFERS_IDL_H_ #include +#include #include #include @@ -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> field_stack_; std::vector struct_stack_; + + std::set known_attributes_; }; // Utility functions for multiple generators: diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 3091fe607..705e2a636 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -85,7 +85,8 @@ template<> inline Offset atot>(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 12749cbd4..0ffd3dc15 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