diff --git a/.gitmodules b/.gitmodules index 9433b3de..f92241b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "vendor/GCDWebServer"] path = vendor/GCDWebServer url = https://github.com/swisspol/GCDWebServer.git +[submodule "PEGTL"] + path = PEGTL + url = https://github.com/ColinH/PEGTL.git +[submodule "vendor/PEGTL"] + path = vendor/PEGTL + url = https://github.com/ColinH/PEGTL.git diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index 6474ffb0..c8c7d041 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -46,6 +46,8 @@ 0270BC861B7D020100010E03 /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7F1B7D020100010E03 /* schemas.js */; }; 0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; }; 0270BCD11B7D067300010E03 /* RealmReact.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReact.mm */; }; + 02786E331BF1065100937061 /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02786E311BF1065000937061 /* parser.cpp */; }; + 02786E341BF1065100937061 /* parser.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02786E321BF1065000937061 /* parser.hpp */; }; 0291DBD21BD994F700E3852C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; 029445931BDEDF40006D1617 /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029445911BDEDF40006D1617 /* transact_log_handler.cpp */; }; 029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445921BDEDF40006D1617 /* transact_log_handler.hpp */; }; @@ -200,6 +202,8 @@ 0270BC7F1B7D020100010E03 /* schemas.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = schemas.js; path = tests/schemas.js; sourceTree = SOURCE_ROOT; }; 0270BCCF1B7D067300010E03 /* RealmReact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmReact.h; path = ReactNative/RealmReact.h; sourceTree = ""; }; 0270BCD01B7D067300010E03 /* RealmReact.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmReact.mm; path = ReactNative/RealmReact.mm; sourceTree = ""; }; + 02786E311BF1065000937061 /* parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = parser.cpp; path = "src/object-store/parser/parser.cpp"; sourceTree = ""; }; + 02786E321BF1065000937061 /* parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = parser.hpp; path = "src/object-store/parser/parser.hpp"; sourceTree = ""; }; 029445911BDEDF40006D1617 /* transact_log_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = transact_log_handler.cpp; path = "src/object-store/impl/transact_log_handler.cpp"; sourceTree = ""; }; 029445921BDEDF40006D1617 /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = "src/object-store/impl/transact_log_handler.hpp"; sourceTree = ""; }; 029445951BDEDF46006D1617 /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/impl/apple/external_commit_helper.cpp"; sourceTree = ""; }; @@ -279,6 +283,8 @@ 029445921BDEDF40006D1617 /* transact_log_handler.hpp */, 029445951BDEDF46006D1617 /* external_commit_helper.cpp */, 029445961BDEDF46006D1617 /* external_commit_helper.hpp */, + 02786E311BF1065000937061 /* parser.cpp */, + 02786E321BF1065000937061 /* parser.hpp */, 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */, 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */, 02258FB11BC6E2D00075F13A /* RealmRPC.hpp */, @@ -414,6 +420,7 @@ 0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */, 02601F0E1BA0F3A7007C91FF /* schema.hpp in Headers */, 0270BC6C1B7CFC1C00010E03 /* object_store.hpp in Headers */, + 02786E341BF1065100937061 /* parser.hpp in Headers */, 0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */, F6BB7DF21BF681BC00D0A69E /* base64.hpp in Headers */, 029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */, @@ -656,6 +663,7 @@ 0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */, 02601F0D1BA0F3A7007C91FF /* schema.cpp in Sources */, 0270BC6E1B7CFC1C00010E03 /* results.cpp in Sources */, + 02786E331BF1065100937061 /* parser.cpp in Sources */, 0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */, 0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */, 02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */, @@ -936,7 +944,7 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/vendor", + "$(SRCROOT)/vendor/PEGTL", ); INFOPLIST_FILE = src/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -970,7 +978,7 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/vendor", + "$(SRCROOT)/vendor/PEGTL", ); INFOPLIST_FILE = src/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1106,7 +1114,7 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/vendor", + "$(SRCROOT)/vendor/PEGTL", ); INFOPLIST_FILE = src/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/src/object-store/parser/main.cpp b/src/object-store/parser/main.cpp new file mode 100644 index 00000000..def876c3 --- /dev/null +++ b/src/object-store/parser/main.cpp @@ -0,0 +1,7 @@ +#include "parser.hpp" + +int main( int argc, char ** argv ) +{ + realm::parser::parse(argv[1]); +} + diff --git a/src/object-store/parser/parser.cpp b/src/object-store/parser/parser.cpp index d3d1f92d..384d748a 100644 --- a/src/object-store/parser/parser.cpp +++ b/src/object-store/parser/parser.cpp @@ -1,4 +1,23 @@ -#include +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "parser.hpp" + #include #include @@ -7,126 +26,217 @@ using namespace pegtl; -namespace query +namespace realm { +namespace parser { + +// strings +struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {}; +struct escaped_char : one< '"', '\\', '/', 'b', 'f', 'n', 'r', 't' > {}; +struct escaped : sor< escaped_char, unicode > {}; +struct unescaped : utf8::range< 0x20, 0x10FFFF > {}; +struct char_ : if_then_else< one< '\\' >, must< escaped >, unescaped > {}; + +struct string_content : until< at< one< '"' > >, must< char_ > > {}; +struct string : seq< one< '"' >, must< string_content >, any > { - // strings - struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {}; - struct escaped_char : one< '"', '\\', '/', 'b', 'f', 'n', 'r', 't' > {}; - struct escaped : sor< escaped_char, unicode > {}; - struct unescaped : utf8::range< 0x20, 0x10FFFF > {}; - struct char_ : if_then_else< one< '\\' >, must< escaped >, unescaped > {}; + using content = string_content; +}; - struct string_content : until< at< one< '"' > >, must< char_ > > {}; - struct string : seq< one< '"' >, must< string_content >, any > - { - using content = string_content; - }; +// numbers +struct minus : opt< one< '-' > > {}; +struct dot : one< '.' > {}; - // numbers - struct minus : opt< one< '-' > > {}; - struct dot : one< '.' > {}; +struct float_num : sor< + seq< plus< digit >, dot, star< digit > >, + seq< star< digit >, dot, plus< digit > > +> {}; +struct hex_num : seq< one< '0' >, one< 'x', 'X' >, plus< xdigit > > {}; +struct int_num : plus< digit > {}; - struct float_num : sor< - seq< plus< digit >, dot, star< digit > >, - seq< star< digit >, dot, plus< digit > > - > {}; - struct hex_num : seq< one< '0' >, one< 'x', 'X' >, plus< xdigit > > {}; - struct int_num : plus< digit > {}; +struct number : seq< minus, sor< float_num, hex_num, int_num > > {}; - struct number : seq< minus, sor< float_num, hex_num, int_num > > {}; +// key paths +struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {}; - // key paths - struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {}; +// expressions and operators +struct expr : sor< string, key_path, number > {}; - // expressions and operators - struct expr : sor< string, key_path, number > {}; - struct oper : sor< - two< '=' >, - one< '=' >, - pegtl::string< '!', '=' >, - pegtl::string< '<', '=' >, - one< '<' >, - pegtl::string< '>', '=' >, - one< '>' > - > {}; +struct eq : sor< two< '=' >, one< '=' > > {}; +struct noteq : pegtl::string< '!', '=' > {}; +struct lteq : pegtl::string< '<', '=' > {}; +struct lt : one< '<' > {}; +struct gteq : pegtl::string< '>', '=' > {}; +struct gt : one< '<' > {}; +struct begins : istring< 'b', 'e', 'g', 'i', 'n', 's', 'w', 'i', 't', 'h' > {}; +struct ends : istring< 'e', 'n', 'd', 's', 'w', 'i', 't', 'h' > {}; +struct contains : istring< 'c', 'o', 'n', 't', 'a', 'i', 'n', 's' > {}; +struct oper : sor< eq, noteq, lteq, lt, gteq, gt, begins, ends, contains > {}; - // predicates - struct comparison_pred : seq< expr, pad< oper, blank >, expr > {}; +// predicates +struct comparison_pred : seq< expr, pad< oper, blank >, expr > {}; - struct pred; - struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {}; +struct pred; +struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {}; - struct single_pred : pad< sor< group_pred, comparison_pred >, blank > {}; - struct not_pre : sor< seq< one< '!' >, star< blank > >, seq< istring< 'N', 'O', 'T' >, plus< blank > > > {}; - struct atom_pred : seq< opt< not_pre >, single_pred > {}; +struct not_pre : sor< seq< one< '!' >, star< blank > >, seq< istring< 'N', 'O', 'T' >, plus< blank > > > {}; +struct atom_pred : seq< opt< not_pre >, pad< sor< group_pred, comparison_pred >, blank > > {}; - struct and_op : sor< two< '&' >, istring< 'A', 'N', 'D' > > {}; - struct or_op : sor< two< '|' >, istring< 'O', 'R' > > {}; +struct and_op : sor< two< '&' >, istring< 'A', 'N', 'D' > > {}; +struct or_op : sor< two< '|' >, istring< 'O', 'R' > > {}; - struct or_ext : seq< pad< or_op, blank >, pred > {}; - struct and_ext : seq< pad< and_op, blank >, pred > {}; - struct and_pred : seq< atom_pred, star< and_ext > > {}; +struct or_ext : seq< pad< or_op, blank >, pred > {}; +struct and_ext : seq< pad< and_op, blank >, pred > {}; +struct and_pred : seq< atom_pred, star< and_ext > > {}; - struct pred : seq< and_pred, star< or_ext > > {}; +struct pred : seq< and_pred, star< or_ext > > {}; - // rules - template< typename Rule > - struct action : nothing< Rule > {}; - template<> struct action< and_ext > - { - static void apply( const input & in, std::string & string_value ) - { - std::cout << "" << in.string() << std::endl; - } - }; - - template<> struct action< or_ext > - { - static void apply( const input & in, std::string & string_value ) - { - std::cout << "" << in.string() << std::endl; - } - }; - - template<> struct action< comparison_pred > - { - static void apply( const input & in, std::string & string_value ) - { - std::cout << in.string() << std::endl; - } - }; - - template<> struct action< one< '(' > > - { - static void apply( const input & in, std::string & string_value ) - { - std::cout << "" << std::endl; - } - }; - - template<> struct action< group_pred > - { - static void apply( const input & in, std::string & string_value ) - { - std::cout << "" << std::endl; - } - }; - - template<> struct action< not_pre > - { - static void apply( const input & in, std::string & string_value ) - { - std::cout << "" << std::endl; - } - }; -} - -int main( int argc, char ** argv ) +// state +struct ParserState { - if ( argc > 1 ) { - std::string intstring; - analyze< query::pred >(); - parse< must< query::pred, eof >, query::action >( 1, argv, intstring); + std::vector predicate_stack; + Predicate *current() { return predicate_stack.back(); } + + void addExpression(Expression exp) + { + if (current()->type == Predicate::Type::Comparison) { + current()->sub_expressions.emplace_back(std::move(exp)); + predicate_stack.pop_back(); + } + else { + Predicate p; + p.type = Predicate::Type::Comparison; + p.sub_expressions.emplace_back(std::move(exp)); + current()->sub_predicates.emplace_back(std::move(p)); + predicate_stack.push_back(¤t()->sub_predicates.back()); + } } +}; + +// rules +template< typename Rule > +struct action : nothing< Rule > {}; + +template<> struct action< and_ext > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << "" << in.string() << std::endl; + } +}; + +template<> struct action< or_ext > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << "" << in.string() << std::endl; + } +}; + +template<> struct action< string > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << in.string() << std::endl; + + Expression exp; + exp.type = Expression::Type::String; + exp.s = in.string(); + + state.addExpression(exp); + } +}; + +template<> struct action< key_path > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << in.string() << std::endl; + + Expression exp; + exp.type = Expression::Type::KeyPath; + exp.s = in.string(); + + state.addExpression(std::move(exp)); + } +}; + +template<> struct action< number > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << in.string() << std::endl; + + Expression exp; + exp.type = Expression::Type::Number; + exp.s = in.string(); + + state.addExpression(std::move(exp)); + } +}; + +#define OPERATOR_ACTION(rule, oper) \ +template<> struct action< rule > { \ + static void apply( const input & in, ParserState & state ) { \ + std::cout << in.string() << std::endl; \ + state.current()->op = oper; }}; + +OPERATOR_ACTION(eq, Predicate::Operator::Equal) +OPERATOR_ACTION(noteq, Predicate::Operator::NotEqual) +OPERATOR_ACTION(gteq, Predicate::Operator::GreaterThanOrEqual) +OPERATOR_ACTION(gt, Predicate::Operator::GreaterThan) +OPERATOR_ACTION(lteq, Predicate::Operator::LessThanOrEqual) +OPERATOR_ACTION(lt, Predicate::Operator::LessThan) +OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith) +OPERATOR_ACTION(ends, Predicate::Operator::EndsWith) +OPERATOR_ACTION(contains, Predicate::Operator::Contains) + + +template<> struct action< one< '(' > > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << "" << std::endl; + + Predicate group; + group.type = Predicate::Type::And; + state.current()->sub_predicates.emplace_back(std::move(group)); + state.predicate_stack.push_back(&state.current()->sub_predicates.back()); + } +}; + +template<> struct action< group_pred > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << "" << std::endl; + + state.predicate_stack.pop_back(); + } +}; + +template<> struct action< not_pre > +{ + static void apply( const input & in, ParserState & state ) + { + std::cout << "" << std::endl; + } +}; + +Predicate parse(const std::string &query) +{ + analyze< pred >(); + const std::string source = "user query"; + + Predicate out_predicate; + out_predicate.type = Predicate::Type::And; + + ParserState state; + state.predicate_stack.push_back(&out_predicate); + + pegtl::parse< must< pred, eof >, action >(query, source, state); + return out_predicate; } +}} + + diff --git a/src/object-store/parser/parser.hpp b/src/object-store/parser/parser.hpp new file mode 100644 index 00000000..416faa2e --- /dev/null +++ b/src/object-store/parser/parser.hpp @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#ifndef REALM_EXTERNAL_COMMIT_HELPER_HPP +#define REALM_EXTERNAL_COMMIT_HELPER_HPP + +#include +#include + +namespace realm { + namespace parser { + struct Expression + { + enum class Type + { + Number, + String, + KeyPath, + }; + Type type; + + std::string s; + }; + + struct Predicate + { + enum class Type + { + None, + Comparison, + Or, + And, + True, + False, + }; + Type type = Type::None; + + // for comparison + enum class Operator + { + None, + Equal, + NotEqual, + LessThan, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual, + BeginsWith, + EndsWith, + Contains, + }; + Operator op = Operator::None; + std::vector sub_expressions; + + // for compounds + std::vector sub_predicates; + }; + + Predicate parse(const std::string &query); + } +} + +#endif // REALM_EXTERNAL_COMMIT_HELPER_HPP diff --git a/vendor/PEGTL b/vendor/PEGTL new file mode 160000 index 00000000..498cb70f --- /dev/null +++ b/vendor/PEGTL @@ -0,0 +1 @@ +Subproject commit 498cb70f5b60b9d87d7f4864104155339daf561b