Made the parser not have any hard-coded keywords.

This prevented any keywords showing up as JSON field names, for example.

Change-Id: Ie9d0cada96778e06016ca02ca96d052410a37038
Tested: on Linux.
parent 72a99abf
...@@ -40,29 +40,28 @@ namespace flatbuffers { ...@@ -40,29 +40,28 @@ namespace flatbuffers {
// Additionally, Parser::ParseType assumes bool..string is a contiguous range // Additionally, Parser::ParseType assumes bool..string is a contiguous range
// of type tokens. // of type tokens.
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ #define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
TD(NONE, "", "", uint8_t, byte, byte, byte, uint8) \ TD(NONE, "", uint8_t, byte, byte, byte, uint8) \
TD(UTYPE, "", "", uint8_t, byte, byte, byte, uint8) /* begin scalar/int */ \ TD(UTYPE, "", uint8_t, byte, byte, byte, uint8) /* begin scalar/int */ \
TD(BOOL, "bool", "", uint8_t, boolean,byte, bool, bool) \ TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool) \
TD(CHAR, "byte", "int8", int8_t, byte, int8, sbyte, int8) \ TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8) \
TD(UCHAR, "ubyte", "uint8", uint8_t, byte, byte, byte, uint8) \ TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8) \
TD(SHORT, "short", "int16", int16_t, short, int16, short, int16) \ TD(SHORT, "short", int16_t, short, int16, short, int16) \
TD(USHORT, "ushort", "uint16", uint16_t, short, uint16, ushort, uint16) \ TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16) \
TD(INT, "int", "int32", int32_t, int, int32, int, int32) \ TD(INT, "int", int32_t, int, int32, int, int32) \
TD(UINT, "uint", "uint32", uint32_t, int, uint32, uint, uint32) \ TD(UINT, "uint", uint32_t, int, uint32, uint, uint32) \
TD(LONG, "long", "int64", int64_t, long, int64, long, int64) \ TD(LONG, "long", int64_t, long, int64, long, int64) \
TD(ULONG, "ulong", "uint64", uint64_t, long, uint64, ulong, uint64) /* end int */ \ TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64) /* end int */ \
TD(FLOAT, "float", "float32", float, float, float32, float, float32) /* begin float */ \ TD(FLOAT, "float", float, float, float32, float, float32) /* begin float */ \
TD(DOUBLE, "double", "float64", double, double, float64, double, float64) /* end float/scalar */ TD(DOUBLE, "double", double, double, float64, double, float64) /* end float/scalar */
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \ #define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
TD(STRING, "string", "", Offset<void>, int, int, StringOffset, int) \ TD(STRING, "string", Offset<void>, int, int, StringOffset, int) \
TD(VECTOR, "", "", Offset<void>, int, int, VectorOffset, int) \ TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int) \
TD(STRUCT, "", "", Offset<void>, int, int, int, int) \ TD(STRUCT, "", Offset<void>, int, int, int, int) \
TD(UNION, "", "", Offset<void>, int, int, int, int) TD(UNION, "", Offset<void>, int, int, int, int)
// The fields are: // The fields are:
// - enum // - enum
// - FlatBuffers schema type. // - FlatBuffers schema type.
// - FlatBuffers schema alias type.
// - C++ type. // - C++ type.
// - Java type. // - Java type.
// - Go type. // - Go type.
...@@ -73,7 +72,7 @@ namespace flatbuffers { ...@@ -73,7 +72,7 @@ namespace flatbuffers {
/* /*
switch (type) { switch (type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \ case BASE_TYPE_ ## ENUM: \
// do something specific to CTYPE here // do something specific to CTYPE here
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
...@@ -90,13 +89,13 @@ switch (type) { ...@@ -90,13 +89,13 @@ switch (type) {
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic. __extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
#endif #endif
enum BaseType { enum BaseType {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
BASE_TYPE_ ## ENUM, BASE_TYPE_ ## ENUM,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD #undef FLATBUFFERS_TD
}; };
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \ static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
"define largest_scalar_t as " #CTYPE); "define largest_scalar_t as " #CTYPE);
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
...@@ -575,6 +574,7 @@ private: ...@@ -575,6 +574,7 @@ private:
FLATBUFFERS_CHECKED_ERROR Next(); FLATBUFFERS_CHECKED_ERROR Next();
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark(); FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
bool Is(int t); bool Is(int t);
bool IsIdent(const char *id);
FLATBUFFERS_CHECKED_ERROR Expect(int t); FLATBUFFERS_CHECKED_ERROR Expect(int t);
std::string TokenToStringId(int t); std::string TokenToStringId(int t);
EnumDef *LookupEnum(const std::string &id); EnumDef *LookupEnum(const std::string &id);
......
...@@ -333,7 +333,7 @@ class CppGenerator : public BaseGenerator { ...@@ -333,7 +333,7 @@ class CppGenerator : public BaseGenerator {
// Return a C++ type from the table in idl.h // Return a C++ type from the table in idl.h
std::string GenTypeBasic(const Type &type, bool user_facing_type) const { std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
static const char *ctypename[] = { static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#CTYPE, #CTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD #undef FLATBUFFERS_TD
......
...@@ -241,7 +241,7 @@ static bool IsEnum(const Type& type) { ...@@ -241,7 +241,7 @@ static bool IsEnum(const Type& type) {
std::string GenTypeBasic(const Type &type, bool enableLangOverrides) { std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
static const char *java_typename[] = { static const char *java_typename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#JTYPE, #JTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
...@@ -249,7 +249,7 @@ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) { ...@@ -249,7 +249,7 @@ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
}; };
static const char *csharp_typename[] = { static const char *csharp_typename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#NTYPE, #NTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
......
...@@ -694,7 +694,7 @@ static std::string GenMethod(const FieldDef &field) { ...@@ -694,7 +694,7 @@ static std::string GenMethod(const FieldDef &field) {
static std::string GenTypeBasic(const Type &type) { static std::string GenTypeBasic(const Type &type) {
static const char *ctypename[] = { static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#GTYPE, #GTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
......
...@@ -909,7 +909,7 @@ namespace php { ...@@ -909,7 +909,7 @@ namespace php {
static std::string GenTypeBasic(const Type &type) { static std::string GenTypeBasic(const Type &type) {
static const char *ctypename[] = { static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#NTYPE, #NTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
......
...@@ -580,7 +580,7 @@ static std::string GenMethod(const FieldDef &field) { ...@@ -580,7 +580,7 @@ static std::string GenMethod(const FieldDef &field) {
static std::string GenTypeBasic(const Type &type) { static std::string GenTypeBasic(const Type &type) {
static const char *ctypename[] = { static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#PTYPE, #PTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
......
...@@ -135,7 +135,7 @@ template<> bool Print<const void *>(const void *val, ...@@ -135,7 +135,7 @@ template<> bool Print<const void *>(const void *val,
type = type.VectorType(); type = type.VectorType();
// Call PrintVector above specifically for each element type: // Call PrintVector above specifically for each element type:
switch (type.base_type) { switch (type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \ case BASE_TYPE_ ## ENUM: \
if (!PrintVector<CTYPE>( \ if (!PrintVector<CTYPE>( \
...@@ -226,7 +226,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, ...@@ -226,7 +226,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
text += " "; text += " ";
if (is_present) { if (is_present) {
switch (fd.value.type.base_type) { switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \ case BASE_TYPE_ ## ENUM: \
if (!GenField<CTYPE>(fd, table, struct_def.fixed, \ if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
...@@ -237,7 +237,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, ...@@ -237,7 +237,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD #undef FLATBUFFERS_TD
// Generate drop-thru case statements for all pointer types: // Generate drop-thru case statements for all pointer types:
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: case BASE_TYPE_ ## ENUM:
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
namespace flatbuffers { namespace flatbuffers {
const char *const kTypeNames[] = { const char *const kTypeNames[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
IDLTYPE, IDLTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
...@@ -41,7 +41,7 @@ const char *const kTypeNames[] = { ...@@ -41,7 +41,7 @@ const char *const kTypeNames[] = {
}; };
const char kTypeSizes[] = { const char kTypeSizes[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
sizeof(CTYPE), sizeof(CTYPE),
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
...@@ -165,8 +165,6 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name, ...@@ -165,8 +165,6 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
return stream.str(); return stream.str();
} }
// Declare tokens we'll use. Single character tokens are represented by their // Declare tokens we'll use. Single character tokens are represented by their
// ascii character code (e.g. '{'), others above 256. // ascii character code (e.g. '{'), others above 256.
#define FLATBUFFERS_GEN_TOKENS(TD) \ #define FLATBUFFERS_GEN_TOKENS(TD) \
...@@ -174,21 +172,7 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name, ...@@ -174,21 +172,7 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
TD(StringConstant, 257, "string constant") \ TD(StringConstant, 257, "string constant") \
TD(IntegerConstant, 258, "integer constant") \ TD(IntegerConstant, 258, "integer constant") \
TD(FloatConstant, 259, "float constant") \ TD(FloatConstant, 259, "float constant") \
TD(Identifier, 260, "identifier") \ TD(Identifier, 260, "identifier")
TD(Table, 261, "table") \
TD(Struct, 262, "struct") \
TD(Enum, 263, "enum") \
TD(Union, 264, "union") \
TD(NameSpace, 265, "namespace") \
TD(RootType, 266, "root_type") \
TD(FileIdentifier, 267, "file_identifier") \
TD(FileExtension, 268, "file_extension") \
TD(Include, 269, "include") \
TD(Attribute, 270, "attribute") \
TD(Null, 271, "null") \
TD(Service, 272, "rpc_service") \
TD(NativeInclude, 273, "native_include") \
TD(BooleanConstant, 274, "boolean constant")
#ifdef __GNUC__ #ifdef __GNUC__
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic. __extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
#endif #endif
...@@ -196,11 +180,6 @@ enum { ...@@ -196,11 +180,6 @@ enum {
#define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE, #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
#undef FLATBUFFERS_TOKEN #undef FLATBUFFERS_TOKEN
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
kToken ## ENUM,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
}; };
static std::string TokenToString(int t) { static std::string TokenToString(int t) {
...@@ -208,7 +187,7 @@ static std::string TokenToString(int t) { ...@@ -208,7 +187,7 @@ static std::string TokenToString(int t) {
#define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING, #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
#undef FLATBUFFERS_TOKEN #undef FLATBUFFERS_TOKEN
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
IDLTYPE, IDLTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
...@@ -224,7 +203,7 @@ static std::string TokenToString(int t) { ...@@ -224,7 +203,7 @@ static std::string TokenToString(int t) {
} }
std::string Parser::TokenToStringId(int t) { std::string Parser::TokenToStringId(int t) {
return TokenToString(t) + (t == kTokenIdentifier ? ": " + attribute_ : ""); return t == kTokenIdentifier ? attribute_ : TokenToString(t);
} }
// Parses exactly nibbles worth of hex digits into a number, or error. // Parses exactly nibbles worth of hex digits into a number, or error.
...@@ -240,11 +219,14 @@ CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) { ...@@ -240,11 +219,14 @@ CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
} }
CheckedError Parser::SkipByteOrderMark() { CheckedError Parser::SkipByteOrderMark() {
if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError(); if (static_cast<unsigned char>(*cursor_) != 0xef)
return NoError();
cursor_++; cursor_++;
if (static_cast<unsigned char>(*cursor_) != 0xbb) return Error("invalid utf-8 byte order mark"); if (static_cast<unsigned char>(*cursor_) != 0xbb)
return Error("invalid utf-8 byte order mark");
cursor_++; cursor_++;
if (static_cast<unsigned char>(*cursor_) != 0xbf) return Error("invalid utf-8 byte order mark"); if (static_cast<unsigned char>(*cursor_) != 0xbf)
return Error("invalid utf-8 byte order mark");
cursor_++; cursor_++;
return NoError(); return NoError();
} }
...@@ -383,76 +365,6 @@ CheckedError Parser::Next() { ...@@ -383,76 +365,6 @@ CheckedError Parser::Next() {
*cursor_ == '_') *cursor_ == '_')
cursor_++; cursor_++;
attribute_.append(start, cursor_); attribute_.append(start, cursor_);
// First, see if it is a type keyword from the table of types:
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
if (attribute_ == IDLTYPE || attribute_ == ALIASTYPE) { \
token_ = kToken ## ENUM; \
return NoError(); \
}
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
// If it's a boolean constant keyword, turn those into integers,
// which simplifies our logic downstream.
if (attribute_ == "true" || attribute_ == "false") {
attribute_ = NumToString(attribute_ == "true");
token_ = kTokenBooleanConstant;
return NoError();
}
// Check for declaration keywords:
if (attribute_ == "table") {
token_ = kTokenTable;
return NoError();
}
if (attribute_ == "struct") {
token_ = kTokenStruct;
return NoError();
}
if (attribute_ == "enum") {
token_ = kTokenEnum;
return NoError();
}
if (attribute_ == "union") {
token_ = kTokenUnion;
return NoError();
}
if (attribute_ == "namespace") {
token_ = kTokenNameSpace;
return NoError();
}
if (attribute_ == "root_type") {
token_ = kTokenRootType;
return NoError();
}
if (attribute_ == "include") {
token_ = kTokenInclude;
return NoError();
}
if (attribute_ == "attribute") {
token_ = kTokenAttribute;
return NoError();
}
if (attribute_ == "file_identifier") {
token_ = kTokenFileIdentifier;
return NoError();
}
if (attribute_ == "file_extension") {
token_ = kTokenFileExtension;
return NoError();
}
if (attribute_ == "null") {
token_ = kTokenNull;
return NoError();
}
if (attribute_ == "rpc_service") {
token_ = kTokenService;
return NoError();
}
if (attribute_ == "native_include") {
token_ = kTokenNativeInclude;
return NoError();
}
// If not, it is a user-defined identifier:
token_ = kTokenIdentifier; token_ = kTokenIdentifier;
return NoError(); return NoError();
} else if (isdigit(static_cast<unsigned char>(c)) || c == '-') { } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
...@@ -506,6 +418,10 @@ bool Parser::Is(int t) { ...@@ -506,6 +418,10 @@ bool Parser::Is(int t) {
return t == token_; return t == token_;
} }
bool Parser::IsIdent(const char *id) {
return token_ == kTokenIdentifier && attribute_ == id;
}
// Expect a given token to be next, consume it, or error if not present. // Expect a given token to be next, consume it, or error if not present.
CheckedError Parser::Expect(int t) { CheckedError Parser::Expect(int t) {
if (t != token_) { if (t != token_) {
...@@ -555,28 +471,61 @@ CheckedError Parser::ParseTypeIdent(Type &type) { ...@@ -555,28 +471,61 @@ CheckedError Parser::ParseTypeIdent(Type &type) {
// Parse any IDL type. // Parse any IDL type.
CheckedError Parser::ParseType(Type &type) { CheckedError Parser::ParseType(Type &type) {
if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) { if (token_ == kTokenIdentifier) {
type.base_type = static_cast<BaseType>(token_ - kTokenNONE); if (IsIdent("bool")) {
NEXT(); type.base_type = BASE_TYPE_BOOL;
} else { NEXT();
if (token_ == kTokenIdentifier) { } else if (IsIdent("byte") || IsIdent("int8")) {
ECHECK(ParseTypeIdent(type)); type.base_type = BASE_TYPE_CHAR;
} else if (token_ == '[') { NEXT();
} else if (IsIdent("ubyte") || IsIdent("uint8")) {
type.base_type = BASE_TYPE_UCHAR;
NEXT();
} else if (IsIdent("short") || IsIdent("int16")) {
type.base_type = BASE_TYPE_SHORT;
NEXT();
} else if (IsIdent("ushort") || IsIdent("uint16")) {
type.base_type = BASE_TYPE_USHORT;
NEXT();
} else if (IsIdent("int") || IsIdent("int32")) {
type.base_type = BASE_TYPE_INT;
NEXT();
} else if (IsIdent("uint") || IsIdent("uint32")) {
type.base_type = BASE_TYPE_UINT;
NEXT();
} else if (IsIdent("long") || IsIdent("int64")) {
type.base_type = BASE_TYPE_LONG;
NEXT();
} else if (IsIdent("ulong") || IsIdent("uint64")) {
type.base_type = BASE_TYPE_ULONG;
NEXT();
} else if (IsIdent("float") || IsIdent("float32")) {
type.base_type = BASE_TYPE_FLOAT;
NEXT();
} else if (IsIdent("double") || IsIdent("float64")) {
type.base_type = BASE_TYPE_DOUBLE;
NEXT();
} else if (IsIdent("string")) {
type.base_type = BASE_TYPE_STRING;
NEXT(); NEXT();
Type subtype;
ECHECK(ParseType(subtype));
if (subtype.base_type == BASE_TYPE_VECTOR) {
// We could support this, but it will complicate things, and it's
// easier to work around with a struct around the inner vector.
return Error(
"nested vector types not supported (wrap in table first).");
}
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
type.element = subtype.base_type;
EXPECT(']');
} else { } else {
return Error("illegal type syntax"); ECHECK(ParseTypeIdent(type));
}
} else if (token_ == '[') {
NEXT();
Type subtype;
ECHECK(ParseType(subtype));
if (subtype.base_type == BASE_TYPE_VECTOR) {
// We could support this, but it will complicate things, and it's
// easier to work around with a struct around the inner vector.
return Error(
"nested vector types not supported (wrap in table first).");
} }
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
type.element = subtype.base_type;
EXPECT(']');
} else {
return Error("illegal type syntax");
} }
return NoError(); return NoError();
} }
...@@ -945,7 +894,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, ...@@ -945,7 +894,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
ECHECK(parser->SkipAnyJsonValue()); ECHECK(parser->SkipAnyJsonValue());
} }
} else { } else {
if (parser->Is(kTokenNull)) { if (parser->IsIdent("null")) {
ECHECK(parser->Next()); // Ignore this field. ECHECK(parser->Next()); // Ignore this field.
} else { } else {
Value val = field->value; Value val = field->value;
...@@ -1023,7 +972,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, ...@@ -1023,7 +972,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
if (!struct_def.sortbysize || if (!struct_def.sortbysize ||
size == SizeOf(field_value.type.base_type)) { size == SizeOf(field_value.type.base_type)) {
switch (field_value.type.base_type) { switch (field_value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \ case BASE_TYPE_ ## ENUM: \
builder_.Pad(field->padding); \ builder_.Pad(field->padding); \
...@@ -1040,7 +989,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, ...@@ -1040,7 +989,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
break; break;
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
#undef FLATBUFFERS_TD #undef FLATBUFFERS_TD
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \ case BASE_TYPE_ ## ENUM: \
builder_.Pad(field->padding); \ builder_.Pad(field->padding); \
...@@ -1116,7 +1065,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { ...@@ -1116,7 +1065,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
// start at the back, since we're building the data backwards. // start at the back, since we're building the data backwards.
auto &val = field_stack_.back().first; auto &val = field_stack_.back().first;
switch (val.type.base_type) { switch (val.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
case BASE_TYPE_ ## ENUM: \ case BASE_TYPE_ ## ENUM: \
if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
...@@ -1317,6 +1266,7 @@ CheckedError Parser::ParseSingleValue(Value &e) { ...@@ -1317,6 +1266,7 @@ CheckedError Parser::ParseSingleValue(Value &e) {
#undef FLATBUFFERS_FN_DOUBLE #undef FLATBUFFERS_FN_DOUBLE
// Then check if this could be a string/identifier enum value: // Then check if this could be a string/identifier enum value:
} else if (e.type.base_type != BASE_TYPE_STRING && } else if (e.type.base_type != BASE_TYPE_STRING &&
e.type.base_type != BASE_TYPE_BOOL &&
e.type.base_type != BASE_TYPE_NONE && e.type.base_type != BASE_TYPE_NONE &&
(token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
if (IsIdentifierStart(attribute_[0])) { // Enum value. if (IsIdentifierStart(attribute_[0])) { // Enum value.
...@@ -1348,11 +1298,6 @@ CheckedError Parser::ParseSingleValue(Value &e) { ...@@ -1348,11 +1298,6 @@ CheckedError Parser::ParseSingleValue(Value &e) {
e, e,
BASE_TYPE_INT, BASE_TYPE_INT,
&match)); &match));
ECHECK(TryTypedValue(kTokenBooleanConstant,
IsBool(e.type.base_type),
e,
BASE_TYPE_BOOL,
&match));
ECHECK(TryTypedValue(kTokenFloatConstant, ECHECK(TryTypedValue(kTokenFloatConstant,
IsFloat(e.type.base_type), IsFloat(e.type.base_type),
e, e,
...@@ -1363,6 +1308,15 @@ CheckedError Parser::ParseSingleValue(Value &e) { ...@@ -1363,6 +1308,15 @@ CheckedError Parser::ParseSingleValue(Value &e) {
e, e,
BASE_TYPE_STRING, BASE_TYPE_STRING,
&match)); &match));
auto istrue = IsIdent("true");
if (istrue || IsIdent("false")) {
attribute_ = NumToString(istrue);
ECHECK(TryTypedValue(kTokenIdentifier,
IsBool(e.type.base_type),
e,
BASE_TYPE_BOOL,
&match));
}
if (!match) return TokenError(); if (!match) return TokenError();
} }
return NoError(); return NoError();
...@@ -1594,8 +1548,9 @@ static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { ...@@ -1594,8 +1548,9 @@ static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
CheckedError Parser::ParseDecl() { CheckedError Parser::ParseDecl() {
std::vector<std::string> dc = doc_comment_; std::vector<std::string> dc = doc_comment_;
bool fixed = Is(kTokenStruct); bool fixed = IsIdent("struct");
if (fixed) NEXT() else EXPECT(kTokenTable); if (!fixed && !IsIdent("table")) return Error("declaration expected");
NEXT();
std::string name = attribute_; std::string name = attribute_;
EXPECT(kTokenIdentifier); EXPECT(kTokenIdentifier);
StructDef *struct_def; StructDef *struct_def;
...@@ -1753,11 +1708,11 @@ static bool compareEnumVals(const EnumVal *a, const EnumVal* b) { ...@@ -1753,11 +1708,11 @@ static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
// We parse everything as identifiers instead of keywords, since we don't // We parse everything as identifiers instead of keywords, since we don't
// want protobuf keywords to become invalid identifiers in FlatBuffers. // want protobuf keywords to become invalid identifiers in FlatBuffers.
CheckedError Parser::ParseProtoDecl() { CheckedError Parser::ParseProtoDecl() {
bool isextend = attribute_ == "extend"; bool isextend = IsIdent("extend");
if (attribute_ == "package") { if (IsIdent("package")) {
// These are identical in syntax to FlatBuffer's namespace decl. // These are identical in syntax to FlatBuffer's namespace decl.
ECHECK(ParseNamespace()); ECHECK(ParseNamespace());
} else if (attribute_ == "message" || isextend) { } else if (IsIdent("message") || isextend) {
std::vector<std::string> struct_comment = doc_comment_; std::vector<std::string> struct_comment = doc_comment_;
NEXT(); NEXT();
StructDef *struct_def = nullptr; StructDef *struct_def = nullptr;
...@@ -1789,7 +1744,7 @@ CheckedError Parser::ParseProtoDecl() { ...@@ -1789,7 +1744,7 @@ CheckedError Parser::ParseProtoDecl() {
current_namespace_ = parent_namespace; current_namespace_ = parent_namespace;
} }
if (Is(';')) NEXT(); if (Is(';')) NEXT();
} else if (attribute_ == "enum") { } else if (IsIdent("enum")) {
// These are almost the same, just with different terminator: // These are almost the same, just with different terminator:
EnumDef *enum_def; EnumDef *enum_def;
ECHECK(ParseEnum(false, &enum_def)); ECHECK(ParseEnum(false, &enum_def));
...@@ -1803,15 +1758,15 @@ CheckedError Parser::ParseProtoDecl() { ...@@ -1803,15 +1758,15 @@ CheckedError Parser::ParseProtoDecl() {
if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it); if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
else ++it; else ++it;
} }
} else if (attribute_ == "syntax") { // Skip these. } else if (IsIdent("syntax")) { // Skip these.
NEXT(); NEXT();
EXPECT('='); EXPECT('=');
EXPECT(kTokenStringConstant); EXPECT(kTokenStringConstant);
EXPECT(';'); EXPECT(';');
} else if (attribute_ == "option") { // Skip these. } else if (IsIdent("option")) { // Skip these.
ECHECK(ParseProtoOption()); ECHECK(ParseProtoOption());
EXPECT(';'); EXPECT(';');
} else if (attribute_ == "service") { // Skip these. } else if (IsIdent("service")) { // Skip these.
NEXT(); NEXT();
EXPECT(kTokenIdentifier); EXPECT(kTokenIdentifier);
ECHECK(ParseProtoCurliesOrIdent()); ECHECK(ParseProtoCurliesOrIdent());
...@@ -1826,11 +1781,10 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, ...@@ -1826,11 +1781,10 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
bool inside_oneof) { bool inside_oneof) {
EXPECT('{'); EXPECT('{');
while (token_ != '}') { while (token_ != '}') {
if (attribute_ == "message" || attribute_ == "extend" || if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
attribute_ == "enum") {
// Nested declarations. // Nested declarations.
ECHECK(ParseProtoDecl()); ECHECK(ParseProtoDecl());
} else if (attribute_ == "extensions") { // Skip these. } else if (IsIdent("extensions")) { // Skip these.
NEXT(); NEXT();
EXPECT(kTokenIntegerConstant); EXPECT(kTokenIntegerConstant);
if (Is(kTokenIdentifier)) { if (Is(kTokenIdentifier)) {
...@@ -1838,10 +1792,10 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, ...@@ -1838,10 +1792,10 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
NEXT(); // num NEXT(); // num
} }
EXPECT(';'); EXPECT(';');
} else if (attribute_ == "option") { // Skip these. } else if (IsIdent("option")) { // Skip these.
ECHECK(ParseProtoOption()); ECHECK(ParseProtoOption());
EXPECT(';'); EXPECT(';');
} else if (attribute_ == "reserved") { // Skip these. } else if (IsIdent("reserved")) { // Skip these.
NEXT(); NEXT();
EXPECT(kTokenIntegerConstant); EXPECT(kTokenIntegerConstant);
while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); } while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); }
...@@ -1853,26 +1807,26 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, ...@@ -1853,26 +1807,26 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
bool repeated = false; bool repeated = false;
bool oneof = false; bool oneof = false;
if (!inside_oneof) { if (!inside_oneof) {
if (attribute_ == "optional") { if (IsIdent("optional")) {
// This is the default. // This is the default.
EXPECT(kTokenIdentifier); NEXT();
} else if (attribute_ == "required") { } else if (IsIdent("required")) {
required = true; required = true;
EXPECT(kTokenIdentifier); NEXT();
} else if (attribute_ == "repeated") { } else if (IsIdent("repeated")) {
repeated = true; repeated = true;
EXPECT(kTokenIdentifier); NEXT();
} else if (attribute_ == "oneof") { } else if (IsIdent("oneof")) {
oneof = true; oneof = true;
EXPECT(kTokenIdentifier); NEXT();
} else { } else {
// can't error, proto3 allows decls without any of the above. // can't error, proto3 allows decls without any of the above.
} }
} }
StructDef *anonymous_struct = nullptr; StructDef *anonymous_struct = nullptr;
Type type; Type type;
if (attribute_ == "group" || oneof) { if (IsIdent("group") || oneof) {
if (!oneof) EXPECT(kTokenIdentifier); if (!oneof) NEXT();
auto name = "Anonymous" + NumToString(anonymous_counter++); auto name = "Anonymous" + NumToString(anonymous_counter++);
ECHECK(StartStruct(name, &anonymous_struct)); ECHECK(StartStruct(name, &anonymous_struct));
type = Type(BASE_TYPE_STRUCT, anonymous_struct); type = Type(BASE_TYPE_STRUCT, anonymous_struct);
...@@ -1885,14 +1839,7 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, ...@@ -1885,14 +1839,7 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
type.base_type = BASE_TYPE_VECTOR; type.base_type = BASE_TYPE_VECTOR;
} }
std::string name = attribute_; std::string name = attribute_;
// Protos may use our keywords "attribute" & "namespace" as an identifier. EXPECT(kTokenIdentifier);
if (Is(kTokenAttribute) || Is(kTokenNameSpace)) {
NEXT();
// TODO: simpler to just not make these keywords?
name += "_"; // Have to make it not a keyword.
} else {
EXPECT(kTokenIdentifier);
}
if (!oneof) { if (!oneof) {
// Parse the field id. Since we're just translating schemas, not // Parse the field id. Since we're just translating schemas, not
// any kind of binary compatibility, we can safely ignore these, and // any kind of binary compatibility, we can safely ignore these, and
...@@ -2036,19 +1983,13 @@ CheckedError Parser::SkipAnyJsonValue() { ...@@ -2036,19 +1983,13 @@ CheckedError Parser::SkipAnyJsonValue() {
this); this);
} }
case kTokenStringConstant: case kTokenStringConstant:
EXPECT(kTokenStringConstant);
break;
case kTokenIntegerConstant: case kTokenIntegerConstant:
EXPECT(kTokenIntegerConstant);
break;
case kTokenFloatConstant: case kTokenFloatConstant:
EXPECT(kTokenFloatConstant); NEXT();
break;
case kTokenBooleanConstant:
EXPECT(kTokenBooleanConstant);
break; break;
default: default:
return TokenError(); if (IsIdent("true") || IsIdent("false") || IsIdent("null")) { NEXT(); }
else return TokenError();
} }
return NoError(); return NoError();
} }
...@@ -2104,16 +2045,15 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { ...@@ -2104,16 +2045,15 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
builder->Int(StringToInt(attribute_.c_str())); builder->Int(StringToInt(attribute_.c_str()));
EXPECT(kTokenIntegerConstant); EXPECT(kTokenIntegerConstant);
break; break;
case kTokenBooleanConstant:
builder->Bool(StringToInt(attribute_.c_str()) != 0);
EXPECT(kTokenBooleanConstant);
break;
case kTokenFloatConstant: case kTokenFloatConstant:
builder->Double(strtod(attribute_.c_str(), nullptr)); builder->Double(strtod(attribute_.c_str(), nullptr));
EXPECT(kTokenFloatConstant); EXPECT(kTokenFloatConstant);
break; break;
default: default:
return TokenError(); if (IsIdent("true")) { builder->Bool(true); NEXT(); }
else if (IsIdent("false")) { builder->Bool(false); NEXT(); }
else if (IsIdent("null")) { builder->Null(); NEXT(); }
else return TokenError();
} }
return NoError(); return NoError();
} }
...@@ -2202,14 +2142,11 @@ CheckedError Parser::DoParse(const char *source, ...@@ -2202,14 +2142,11 @@ CheckedError Parser::DoParse(const char *source,
(attribute_ == "option" || attribute_ == "syntax" || (attribute_ == "option" || attribute_ == "syntax" ||
attribute_ == "package")) { attribute_ == "package")) {
ECHECK(ParseProtoDecl()); ECHECK(ParseProtoDecl());
} else if (Is(kTokenNativeInclude)) { } else if (IsIdent("native_include")) {
NEXT(); NEXT();
vector_emplace_back(&native_included_files_, attribute_); vector_emplace_back(&native_included_files_, attribute_);
EXPECT(kTokenStringConstant); EXPECT(kTokenStringConstant);
} else if (Is(kTokenInclude) || } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
(opts.proto_mode &&
attribute_ == "import" &&
Is(kTokenIdentifier))) {
NEXT(); NEXT();
if (opts.proto_mode && attribute_ == "public") NEXT(); if (opts.proto_mode && attribute_ == "public") NEXT();
auto name = flatbuffers::PosixPath(attribute_.c_str()); auto name = flatbuffers::PosixPath(attribute_.c_str());
...@@ -2257,7 +2194,7 @@ CheckedError Parser::DoParse(const char *source, ...@@ -2257,7 +2194,7 @@ CheckedError Parser::DoParse(const char *source,
while (token_ != kTokenEof) { while (token_ != kTokenEof) {
if (opts.proto_mode) { if (opts.proto_mode) {
ECHECK(ParseProtoDecl()); ECHECK(ParseProtoDecl());
} else if (token_ == kTokenNameSpace) { } else if (IsIdent("namespace")) {
ECHECK(ParseNamespace()); ECHECK(ParseNamespace());
} else if (token_ == '{') { } else if (token_ == '{') {
if (!root_struct_def_) if (!root_struct_def_)
...@@ -2269,11 +2206,11 @@ CheckedError Parser::DoParse(const char *source, ...@@ -2269,11 +2206,11 @@ CheckedError Parser::DoParse(const char *source,
ECHECK(ParseTable(*root_struct_def_, nullptr, &toff)); ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
builder_.Finish(Offset<Table>(toff), builder_.Finish(Offset<Table>(toff),
file_identifier_.length() ? file_identifier_.c_str() : nullptr); file_identifier_.length() ? file_identifier_.c_str() : nullptr);
} else if (token_ == kTokenEnum) { } else if (IsIdent("enum")) {
ECHECK(ParseEnum(false, nullptr)); ECHECK(ParseEnum(false, nullptr));
} else if (token_ == kTokenUnion) { } else if (IsIdent("union")) {
ECHECK(ParseEnum(true, nullptr)); ECHECK(ParseEnum(true, nullptr));
} else if (token_ == kTokenRootType) { } else if (IsIdent("root_type")) {
NEXT(); NEXT();
auto root_type = attribute_; auto root_type = attribute_;
EXPECT(kTokenIdentifier); EXPECT(kTokenIdentifier);
...@@ -2283,7 +2220,7 @@ CheckedError Parser::DoParse(const char *source, ...@@ -2283,7 +2220,7 @@ CheckedError Parser::DoParse(const char *source,
if (root_struct_def_->fixed) if (root_struct_def_->fixed)
return Error("root type must be a table"); return Error("root type must be a table");
EXPECT(';'); EXPECT(';');
} else if (token_ == kTokenFileIdentifier) { } else if (IsIdent("file_identifier")) {
NEXT(); NEXT();
file_identifier_ = attribute_; file_identifier_ = attribute_;
EXPECT(kTokenStringConstant); EXPECT(kTokenStringConstant);
...@@ -2293,20 +2230,20 @@ CheckedError Parser::DoParse(const char *source, ...@@ -2293,20 +2230,20 @@ CheckedError Parser::DoParse(const char *source,
NumToString(FlatBufferBuilder::kFileIdentifierLength) + NumToString(FlatBufferBuilder::kFileIdentifierLength) +
" characters"); " characters");
EXPECT(';'); EXPECT(';');
} else if (token_ == kTokenFileExtension) { } else if (IsIdent("file_extension")) {
NEXT(); NEXT();
file_extension_ = attribute_; file_extension_ = attribute_;
EXPECT(kTokenStringConstant); EXPECT(kTokenStringConstant);
EXPECT(';'); EXPECT(';');
} else if(token_ == kTokenInclude) { } else if(IsIdent("include")) {
return Error("includes must come before declarations"); return Error("includes must come before declarations");
} else if(token_ == kTokenAttribute) { } else if(IsIdent("attribute")) {
NEXT(); NEXT();
auto name = attribute_; auto name = attribute_;
EXPECT(kTokenStringConstant); EXPECT(kTokenStringConstant);
EXPECT(';'); EXPECT(';');
known_attributes_[name] = false; known_attributes_[name] = false;
} else if (token_ == kTokenService) { } else if (IsIdent("rpc_service")) {
ECHECK(ParseService()); ECHECK(ParseService());
} else { } else {
ECHECK(ParseDecl()); ECHECK(ParseDecl());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment