mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-30 23:21:38 +00:00
Added conversion operations that can be used inline in JSON.
e.g.: { myfield: cos(rad(180)) } is equivalent to writing { myfield: -1.0 }
Bug: 29338398
Change-Id: I6fc4ef1fd10bda3ba78cba464414dd071a2f50ca
Tested: on Linux.
This commit is contained in:
@@ -333,6 +333,10 @@ JSON:
|
|||||||
- A field that has the value `null` (e.g. `field: null`) is intended to
|
- A field that has the value `null` (e.g. `field: null`) is intended to
|
||||||
have the default value for that field (thus has the same effect as if
|
have the default value for that field (thus has the same effect as if
|
||||||
that field wasn't specified at all).
|
that field wasn't specified at all).
|
||||||
|
- It has some built in conversion functions, so you can write for example
|
||||||
|
`rad(180)` where ever you'd normally write `3.14159`.
|
||||||
|
Currently supports the following functions: `rad`, `deg`, `cos`, `sin`,
|
||||||
|
`tan`, `acos`, `asin`, `atan`.
|
||||||
|
|
||||||
When parsing JSON, it recognizes the following escape codes in strings:
|
When parsing JSON, it recognizes the following escape codes in strings:
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,14 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#if !defined(_USE_MATH_DEFINES)
|
||||||
|
#define _USE_MATH_DEFINES // For M_PI.
|
||||||
|
#endif // !defined(_USE_MATH_DEFINES)
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "flatbuffers/idl.h"
|
#include "flatbuffers/idl.h"
|
||||||
#include "flatbuffers/util.h"
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
@@ -1004,8 +1012,30 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CheckedError Parser::ParseSingleValue(Value &e) {
|
CheckedError Parser::ParseSingleValue(Value &e) {
|
||||||
// First check if this could be a string/identifier enum value:
|
// First see if this could be a conversion function:
|
||||||
if (e.type.base_type != BASE_TYPE_STRING &&
|
if (token_ == kTokenIdentifier && *cursor_ == '(') {
|
||||||
|
auto functionname = attribute_;
|
||||||
|
NEXT();
|
||||||
|
EXPECT('(');
|
||||||
|
ECHECK(ParseSingleValue(e));
|
||||||
|
EXPECT(')');
|
||||||
|
#define FLATBUFFERS_FN_DOUBLE(name, op) \
|
||||||
|
if (functionname == name) { \
|
||||||
|
auto x = strtod(e.constant.c_str(), nullptr); \
|
||||||
|
e.constant = NumToString(op); \
|
||||||
|
}
|
||||||
|
FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
|
||||||
|
FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 180);
|
||||||
|
FLATBUFFERS_FN_DOUBLE("sin", sin(x));
|
||||||
|
FLATBUFFERS_FN_DOUBLE("cos", cos(x));
|
||||||
|
FLATBUFFERS_FN_DOUBLE("tan", tan(x));
|
||||||
|
FLATBUFFERS_FN_DOUBLE("asin", asin(x));
|
||||||
|
FLATBUFFERS_FN_DOUBLE("acos", acos(x));
|
||||||
|
FLATBUFFERS_FN_DOUBLE("atan", atan(x));
|
||||||
|
// TODO(wvo): add more useful conversion functions here.
|
||||||
|
#undef FLATBUFFERS_FN_DOUBLE
|
||||||
|
// Then check if this could be a string/identifier enum value:
|
||||||
|
} else if (e.type.base_type != BASE_TYPE_STRING &&
|
||||||
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.
|
||||||
|
|||||||
@@ -814,20 +814,29 @@ void ErrorTest() {
|
|||||||
TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
|
TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional parser testing not covered elsewhere.
|
float TestValue(const char *json) {
|
||||||
void ScientificTest() {
|
|
||||||
flatbuffers::Parser parser;
|
flatbuffers::Parser parser;
|
||||||
|
|
||||||
// Simple schema.
|
// Simple schema.
|
||||||
TEST_EQ(parser.Parse("table X { Y:float; } root_type X;"), true);
|
TEST_EQ(parser.Parse("table X { Y:float; } root_type X;"), true);
|
||||||
|
|
||||||
// Test scientific notation numbers.
|
TEST_EQ(parser.Parse(json), true);
|
||||||
TEST_EQ(parser.Parse("{ Y:0.0314159e+2 }"), true);
|
|
||||||
auto root = flatbuffers::GetRoot<float>(parser.builder_.GetBufferPointer());
|
auto root = flatbuffers::GetRoot<float>(parser.builder_.GetBufferPointer());
|
||||||
// root will point to the table, which is a 32bit vtable offset followed
|
// root will point to the table, which is a 32bit vtable offset followed
|
||||||
// by a float:
|
// by a float:
|
||||||
TEST_EQ(sizeof(flatbuffers::soffset_t) == 4 && // Test assumes 32bit offsets
|
TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets
|
||||||
fabs(root[1] - 3.14159) < 0.001, true);
|
return root[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
|
||||||
|
|
||||||
|
// Additional parser testing not covered elsewhere.
|
||||||
|
void ValueTest() {
|
||||||
|
// Test scientific notation numbers.
|
||||||
|
TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), 3.14159), true);
|
||||||
|
|
||||||
|
// Test conversion functions.
|
||||||
|
TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumStringsTest() {
|
void EnumStringsTest() {
|
||||||
@@ -963,7 +972,7 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
|||||||
FuzzTest2();
|
FuzzTest2();
|
||||||
|
|
||||||
ErrorTest();
|
ErrorTest();
|
||||||
ScientificTest();
|
ValueTest();
|
||||||
EnumStringsTest();
|
EnumStringsTest();
|
||||||
IntegerOutOfRangeTest();
|
IntegerOutOfRangeTest();
|
||||||
UnicodeTest();
|
UnicodeTest();
|
||||||
|
|||||||
Reference in New Issue
Block a user