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.
parent afa27628
...@@ -333,6 +333,10 @@ JSON: ...@@ -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 @@ ...@@ -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) { ...@@ -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() { ...@@ -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*/[]) { ...@@ -963,7 +972,7 @@ int main(int /*argc*/, const char * /*argv*/[]) {
FuzzTest2(); FuzzTest2();
ErrorTest(); ErrorTest();
ScientificTest(); ValueTest();
EnumStringsTest(); EnumStringsTest();
IntegerOutOfRangeTest(); IntegerOutOfRangeTest();
UnicodeTest(); UnicodeTest();
......
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