From b47c11c38f447b69508981b3193e695e46b85313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Thu, 8 Jun 2023 14:03:10 +0200 Subject: [PATCH] Use uniform Path representation in query parser We need to be able to handle a path that is just a sequence of strings and integers. The strings can then either be a property name or a key in a dictionary. Before we have known that the last entry in a path would be a property name. We can't assume that anymore, so we just have to follow links as long as that is possible. The rest must then be a path to the wanted value. We must also allow the syntax "dict.key" and dict["key"] to be used interchangeably. A nested dictionary can be used in the same way as an embedded object is used and so the syntax for querying on a specific property should be the same. --- src/realm/parser/driver.cpp | 250 ++++++----- src/realm/parser/driver.hpp | 63 ++- src/realm/parser/generated/query_bison.cpp | 465 ++++++++++----------- src/realm/parser/generated/query_bison.hpp | 77 +--- src/realm/parser/query_bison.yy | 26 +- src/realm/sort_descriptor.hpp | 5 + src/realm/table.cpp | 12 +- src/realm/table.hpp | 13 +- test/test_parser.cpp | 9 +- 9 files changed, 427 insertions(+), 493 deletions(-) diff --git a/src/realm/parser/driver.cpp b/src/realm/parser/driver.cpp index 561707573be..1aed0ad4b9c 100644 --- a/src/realm/parser/driver.cpp +++ b/src/realm/parser/driver.cpp @@ -834,61 +834,58 @@ Query TrueOrFalseNode::visit(ParserDriver* drv) std::unique_ptr PropertyNode::visit(ParserDriver* drv, DataType) { - bool is_keys = false; - std::string identifier = path->path_elems.back().id; - if (identifier[0] == '@') { - if (identifier == "@values") { - path->path_elems.pop_back(); - identifier = path->path_elems.back().id; - } - else if (identifier == "@keys") { - path->path_elems.pop_back(); - identifier = path->path_elems.back().id; - is_keys = true; - } - else if (identifier == "@links") { - // This is a backlink aggregate query - auto link_chain = path->visit(drv, comp_type); - auto sub = link_chain.get_backlink_count(); - return sub.clone(); - } - } - try { - m_link_chain = path->visit(drv, comp_type); - std::unique_ptr subexpr{drv->column(m_link_chain, identifier)}; - if (!path->path_elems.back().index.is_null()) { - if (auto s = dynamic_cast*>(subexpr.get())) { - subexpr = s->key(path->path_elems.back().index).clone(); + if (path->path_elems.back().is_key() && path->path_elems.back().get_key() == "@links") { + identifier = "@links"; + // This is a backlink aggregate query + path->path_elems.pop_back(); + auto link_chain = path->visit(drv, comp_type); + auto sub = link_chain.get_backlink_count(); + return sub.clone(); + } + m_link_chain = path->visit(drv, comp_type); + if (!path->at_end()) { + identifier = path->current_path_elem->get_key(); + } + std::unique_ptr subexpr{drv->column(m_link_chain, path)}; + + if (!path->at_end()) { + if (path->is_identifier()) { + auto trailing = path->next_identifier(); + if (auto dict = dynamic_cast*>(subexpr.get())) { + if (trailing == "@values") { + } + else if (trailing == "@keys") { + subexpr = std::make_unique(*dict); + } + else { + dict->key(trailing); + } } - } - if (is_keys) { - if (auto s = dynamic_cast*>(subexpr.get())) { - subexpr = std::make_unique(*s); + else { + if (!post_op && is_length_suffix(trailing)) { + // If 'length' is the operator, the last id in the path must be the name + // of a list property + path->path_elems.pop_back(); + const std::string& prop = path->path_elems.back().get_key(); + std::unique_ptr subexpr{path->visit(drv, comp_type).column(prop)}; + if (auto list = dynamic_cast(subexpr.get())) { + if (auto length_expr = list->get_element_length()) + return length_expr; + } + } + throw InvalidQueryError(util::format("Property '%1.%2' has no property '%3'", + m_link_chain.get_current_table()->get_class_name(), identifier, + trailing)); } } - - if (post_op) { - return post_op->visit(drv, subexpr.get()); + else { + throw InvalidQueryError("Index not supported"); } - return subexpr; } - catch (const InvalidQueryError&) { - // Is 'identifier' perhaps length operator? - if (!post_op && is_length_suffix(identifier) && path->path_elems.size() > 1) { - // If 'length' is the operator, the last id in the path must be the name - // of a list property - path->path_elems.pop_back(); - std::string& prop = path->path_elems.back().id; - std::unique_ptr subexpr{path->visit(drv, comp_type).column(prop)}; - if (auto list = dynamic_cast(subexpr.get())) { - if (auto length_expr = list->get_element_length()) - return length_expr; - } - } - throw; + if (post_op) { + return post_op->visit(drv, subexpr.get()); } - REALM_UNREACHABLE(); - return {}; + return subexpr; } std::unique_ptr SubqueryNode::visit(ParserDriver* drv, DataType) @@ -899,25 +896,28 @@ std::unique_ptr SubqueryNode::visit(ParserDriver* drv, DataType) variable_name)); } LinkChain lc = prop->path->visit(drv, prop->comp_type); - std::string identifier = prop->path->path_elems.back().id; - identifier = drv->translate(lc, identifier); - if (identifier.find("@links") == 0) { - drv->backlink(lc, identifier); + ColKey col_key; + std::string identifier; + if (!prop->path->at_end()) { + identifier = prop->path->next_identifier(); + col_key = lc.get_current_table()->get_column_key(identifier); } else { - ColKey col_key = lc.get_current_table()->get_column_key(identifier); - if (col_key.is_list() && col_key.get_type() != col_type_LinkList) { - throw InvalidQueryError( - util::format("A subquery can not operate on a list of primitive values (property '%1')", identifier)); - } - if (col_key.get_type() != col_type_LinkList) { - throw InvalidQueryError(util::format("A subquery must operate on a list property, but '%1' is type '%2'", - identifier, - realm::get_data_type_name(DataType(col_key.get_type())))); - } - lc.link(identifier); + identifier = prop->path->last_identifier(); + col_key = lc.get_current_col(); + } + + auto col_type = col_key.get_type(); + if (col_key.is_list() && col_type != col_type_LinkList) { + throw InvalidQueryError( + util::format("A subquery can not operate on a list of primitive values (property '%1')", identifier)); + } + if (col_type != col_type_LinkList && col_type != col_type_BackLink) { + throw InvalidQueryError(util::format("A subquery must operate on a list property, but '%1' is type '%2'", + identifier, realm::get_data_type_name(DataType(col_type)))); } + TableRef previous_table = drv->m_base_table; drv->m_base_table = lc.get_current_table().cast_away_const(); bool did_add = drv->m_mapping.add_mapping(drv->m_base_table, variable_name, ""); @@ -978,7 +978,7 @@ std::unique_ptr LinkAggrNode::visit(ParserDriver* drv, DataType) auto link_prop = dynamic_cast*>(subexpr.get()); if (!link_prop) { throw InvalidQueryError(util::format("Operation '%1' cannot apply to property '%2' because it is not a list", - agg_op_type_to_str(type), property->identifier())); + agg_op_type_to_str(type), property->get_identifier())); } const LinkChain& link_chain = property->link_chain(); prop_name = drv->translate(link_chain, prop_name); @@ -1469,52 +1469,38 @@ std::unique_ptr ListNode::visit(ParserDriver* drv, DataType hint) return ret; } -PathElem::PathElem(const PathElem& other) - : id(other.id) - , index(other.index) -{ - index.use_buffer(buffer); -} - -PathElem& PathElem::operator=(const PathElem& other) -{ - id = other.id; - index = other.index; - index.use_buffer(buffer); - - return *this; -} - LinkChain PathNode::visit(ParserDriver* drv, util::Optional comp_type) { LinkChain link_chain(drv->m_base_table, comp_type); - auto end = path_elems.end() - 1; - for (auto it = path_elems.begin(); it != end; ++it) { - if (!it->index.is_null()) { - throw InvalidQueryError("Index not supported"); - } - std::string& raw_path_elem = it->id; - auto path_elem = drv->translate(link_chain, raw_path_elem); - if (path_elem.find("@links.") == 0) { - drv->backlink(link_chain, path_elem); - continue; - } - if (path_elem == "@values") { - if (!link_chain.get_current_col().is_dictionary()) { - throw InvalidQueryError("@values only allowed on dictionaries"); + for (current_path_elem = path_elems.begin(); current_path_elem != path_elems.end(); ++current_path_elem) { + if (current_path_elem->is_key()) { + const std::string& raw_path_elem = current_path_elem->get_key(); + auto path_elem = drv->translate(link_chain, raw_path_elem); + if (path_elem.find("@links.") == 0) { + std::string_view table_column_pair(path_elem); + table_column_pair = table_column_pair.substr(7); + auto dot_pos = table_column_pair.find('.'); + auto table_name = table_column_pair.substr(0, dot_pos); + auto column_name = table_column_pair.substr(dot_pos + 1); + drv->backlink(link_chain, table_name, column_name); + continue; + } + if (path_elem == "@values") { + if (!link_chain.get_current_col().is_dictionary()) { + throw InvalidQueryError("@values only allowed on dictionaries"); + } + continue; + } + if (path_elem.empty()) { + continue; // this element has been removed, this happens in subqueries } - continue; - } - if (path_elem.empty()) { - continue; // this element has been removed, this happens in subqueries - } - try { - link_chain.link(path_elem); + if (!link_chain.link(path_elem)) { + break; + } } - // In case of exception, we have to throw InvalidQueryError - catch (const LogicError& e) { - throw InvalidQueryError(e.what()); + else { + throw InvalidQueryError("Index not supported here"); } } return link_chain; @@ -1537,20 +1523,28 @@ std::unique_ptr DescriptorOrderingNode::visit(ParserDriver* else { bool is_distinct = cur_ordering->get_type() == DescriptorNode::DISTINCT; std::vector> property_columns; - for (auto& col_names : cur_ordering->columns) { + for (Path& path : cur_ordering->columns) { std::vector columns; LinkChain link_chain(target); - for (size_t ndx_in_path = 0; ndx_in_path < col_names.size(); ++ndx_in_path) { - std::string prop_name = drv->translate(link_chain, col_names[ndx_in_path].id); - ColKey col_key = link_chain.get_current_table()->get_column_key(prop_name); - if (!col_key) { - throw InvalidQueryError(util::format( - "No property '%1' found on object type '%2' specified in '%3' clause", prop_name, - link_chain.get_current_table()->get_class_name(), is_distinct ? "distinct" : "sort")); + ColKey col_key; + for (size_t ndx_in_path = 0; ndx_in_path < path.size(); ++ndx_in_path) { + std::string prop_name = drv->translate(link_chain, path[ndx_in_path].get_key()); + // If last column was a dictionary, We will treat the next entry as a key to + // the dictionary + if (col_key && col_key.is_dictionary()) { + columns.back().set_index(prop_name); } - columns.emplace_back(col_key, col_names[ndx_in_path].index); - if (ndx_in_path < col_names.size() - 1) { - link_chain.link(col_key); + else { + col_key = link_chain.get_current_table()->get_column_key(prop_name); + if (!col_key) { + throw InvalidQueryError(util::format( + "No property '%1' found on object type '%2' specified in '%3' clause", prop_name, + link_chain.get_current_table()->get_class_name(), is_distinct ? "distinct" : "sort")); + } + columns.emplace_back(col_key); + if (ndx_in_path < path.size() - 1) { + link_chain.link(col_key); + } } } property_columns.push_back(columns); @@ -1602,7 +1596,7 @@ ParserDriver::~ParserDriver() yylex_destroy(m_yyscanner); } -Mixed ParserDriver::get_arg_for_index(const std::string& i) +PathElement ParserDriver::get_arg_for_index(const std::string& i) { REALM_ASSERT(i[0] == '$'); size_t arg_no = size_t(strtol(i.substr(1).c_str(), nullptr, 10)); @@ -1612,7 +1606,7 @@ Mixed ParserDriver::get_arg_for_index(const std::string& i) auto type = m_args.type_for_argument(arg_no); switch (type) { case type_Int: - return int64_t(m_args.long_for_argument(arg_no)); + return size_t(m_args.long_for_argument(arg_no)); case type_String: return m_args.string_for_argument(arg_no); default: @@ -1676,14 +1670,12 @@ auto ParserDriver::cmp(const std::vector& values) -> std::pair< return {std::move(left), std::move(right)}; } -auto ParserDriver::column(LinkChain& link_chain, std::string identifier) -> SubexprPtr +auto ParserDriver::column(LinkChain& link_chain, PathNode* path) -> SubexprPtr { - identifier = m_mapping.translate(link_chain, identifier); - - if (identifier.find("@links.") == 0) { - backlink(link_chain, identifier); - return link_chain.create_subexpr(ColKey()); + if (path->at_end()) { + return link_chain.create_subexpr(link_chain.m_link_cols.back()); } + auto identifier = m_mapping.translate(link_chain, path->next_identifier()); if (auto col = link_chain.column(identifier)) { return col; } @@ -1691,16 +1683,12 @@ auto ParserDriver::column(LinkChain& link_chain, std::string identifier) -> Sube util::format("'%1' has no property '%2'", link_chain.get_current_table()->get_class_name(), identifier)); } -void ParserDriver::backlink(LinkChain& link_chain, const std::string& identifier) +void ParserDriver::backlink(LinkChain& link_chain, std::string_view raw_table_name, std::string_view raw_column_name) { - auto table_column_pair = identifier.substr(7); - auto dot_pos = table_column_pair.find('.'); - - auto table_name = table_column_pair.substr(0, dot_pos); - table_name = m_mapping.translate_table_name(table_name); + std::string table_name = m_mapping.translate_table_name(raw_table_name); auto origin_table = m_base_table->get_parent_group()->get_table(table_name); - auto column_name = table_column_pair.substr(dot_pos + 1); ColKey origin_column; + std::string column_name{raw_column_name}; if (origin_table) { column_name = m_mapping.translate(origin_table, column_name); origin_column = origin_table->get_column_key(column_name); diff --git a/src/realm/parser/driver.hpp b/src/realm/parser/driver.hpp index aaa0ee00a2d..98db936d9f6 100644 --- a/src/realm/parser/driver.hpp +++ b/src/realm/parser/driver.hpp @@ -273,18 +273,44 @@ class ListNode : public ValueNode { class PathNode : public ParserNode { public: - std::vector path_elems; + Path path_elems; + Path::iterator current_path_elem; - PathNode(PathElem first) + PathNode(const PathElement& first) { add_element(first); } + bool at_end() const + { + return current_path_elem == path_elems.end(); + } + bool is_identifier() const + { + return current_path_elem->is_key(); + } + const std::string& next_identifier() + { + return (current_path_elem++)->get_key(); + } + size_t next_index() + { + return (current_path_elem++)->get_ndx(); + } + const std::string& last_identifier() + { + return path_elems.back().get_key(); + } + LinkChain visit(ParserDriver*, util::Optional = util::none); - void add_element(const PathElem& elem) + void add_element(const PathElement& elem) { if (backlink) { - path_elems.back().id = path_elems.back().id + "." + elem.id; + if (!elem.is_key()) { + throw yy::parser::syntax_error("An ID must follow @links"); + } + backlink_str += "." + elem.get_key(); if (backlink == 2) { + path_elems.push_back(backlink_str); backlink = 0; } else { @@ -292,13 +318,24 @@ class PathNode : public ParserNode { } } else { - if (elem.id == "@links") + if (elem.is_key() && elem.get_key() == "@links") { backlink = 1; - path_elems.push_back(elem); + backlink_str = "@links"; + } + else { + path_elems.push_back(elem); + } + } + } + void finish() + { + if (backlink) { + path_elems.push_back(backlink_str); } } private: + std::string backlink_str; int backlink = 0; }; @@ -312,10 +349,11 @@ class PropertyNode : public ValueNode { : path(path) , comp_type(ct) { + path->finish(); } - const std::string& identifier() const + const std::string& get_identifier() const { - return path->path_elems.back().id; + return identifier; } const LinkChain& link_chain() const { @@ -329,6 +367,7 @@ class PropertyNode : public ValueNode { private: LinkChain m_link_chain; + std::string identifier; }; class AggrNode : public ValueNode { @@ -532,7 +571,7 @@ class PostOpNode : public ParserNode { class DescriptorNode : public ParserNode { public: enum Type { SORT, DISTINCT, LIMIT }; - std::vector> columns; + std::vector columns; std::vector ascending; size_t limit = size_t(-1); Type type; @@ -624,7 +663,7 @@ class ParserDriver { parse_error = true; } - Mixed get_arg_for_index(const std::string&); + PathElement get_arg_for_index(const std::string&); double get_arg_for_coordinate(const std::string&); template @@ -632,8 +671,8 @@ class ParserDriver { template Query simple_query(int op, ColKey col_key, T val); std::pair cmp(const std::vector& values); - SubexprPtr column(LinkChain&, std::string); - void backlink(LinkChain&, const std::string&); + SubexprPtr column(LinkChain&, PathNode*); + void backlink(LinkChain&, std::string_view table_name, std::string_view column_name); std::string translate(const LinkChain&, const std::string&); private: diff --git a/src/realm/parser/generated/query_bison.cpp b/src/realm/parser/generated/query_bison.cpp index 68d82c85e36..0a8dbbd1ecf 100644 --- a/src/realm/parser/generated/query_bison.cpp +++ b/src/realm/parser/generated/query_bison.cpp @@ -231,10 +231,6 @@ namespace yy { value.YY_MOVE_OR_COPY< ListNode* > (YY_MOVE (that.value)); break; - case symbol_kind::SYM_path_elem: // path_elem - value.YY_MOVE_OR_COPY< PathElem > (YY_MOVE (that.value)); - break; - case symbol_kind::SYM_path: // path value.YY_MOVE_OR_COPY< PathNode* > (YY_MOVE (that.value)); break; @@ -372,10 +368,6 @@ namespace yy { value.move< ListNode* > (YY_MOVE (that.value)); break; - case symbol_kind::SYM_path_elem: // path_elem - value.move< PathElem > (YY_MOVE (that.value)); - break; - case symbol_kind::SYM_path: // path value.move< PathNode* > (YY_MOVE (that.value)); break; @@ -513,10 +505,6 @@ namespace yy { value.copy< ListNode* > (that.value); break; - case symbol_kind::SYM_path_elem: // path_elem - value.copy< PathElem > (that.value); - break; - case symbol_kind::SYM_path: // path value.copy< PathNode* > (that.value); break; @@ -652,10 +640,6 @@ namespace yy { value.move< ListNode* > (that.value); break; - case symbol_kind::SYM_path_elem: // path_elem - value.move< PathElem > (that.value); - break; - case symbol_kind::SYM_path: // path value.move< PathNode* > (that.value); break; @@ -1202,10 +1186,6 @@ namespace yy { { yyo << yysym.value.template as < PathNode* > (); } break; - case symbol_kind::SYM_path_elem: // path_elem - { yyo << yysym.value.template as < PathElem > ().id; } - break; - case symbol_kind::SYM_id: // id { yyo << yysym.value.template as < std::string > (); } break; @@ -1471,10 +1451,6 @@ namespace yy { yylhs.value.emplace< ListNode* > (); break; - case symbol_kind::SYM_path_elem: // path_elem - yylhs.value.emplace< PathElem > (); - break; - case symbol_kind::SYM_path: // path yylhs.value.emplace< PathNode* > (); break; @@ -2016,87 +1992,83 @@ namespace yy { { yylhs.value.as < int > () = CompareNode::LIKE; } break; - case 108: // path: path_elem - { yylhs.value.as < PathNode* > () = drv.m_parse_nodes.create(yystack_[0].value.as < PathElem > ()); } - break; - - case 109: // path: path '.' path_elem - { yystack_[2].value.as < PathNode* > ()->add_element(yystack_[0].value.as < PathElem > ()); yylhs.value.as < PathNode* > () = yystack_[2].value.as < PathNode* > (); } + case 108: // path: id + { yylhs.value.as < PathNode* > () = drv.m_parse_nodes.create(yystack_[0].value.as < std::string > ()); } break; - case 110: // path_elem: id - { yylhs.value.as < PathElem > () = PathElem{yystack_[0].value.as < std::string > ()}; } + case 109: // path: path '.' id + { yystack_[2].value.as < PathNode* > ()->add_element(yystack_[0].value.as < std::string > ()); yylhs.value.as < PathNode* > () = yystack_[2].value.as < PathNode* > (); } break; - case 111: // path_elem: id '[' "natural0" ']' - { yylhs.value.as < PathElem > () = PathElem{yystack_[3].value.as < std::string > (), int64_t(strtoll(yystack_[1].value.as < std::string > ().c_str(), nullptr, 0))}; } + case 110: // path: path '[' "natural0" ']' + { yystack_[3].value.as < PathNode* > ()->add_element(size_t(strtoll(yystack_[1].value.as < std::string > ().c_str(), nullptr, 0))); yylhs.value.as < PathNode* > () = yystack_[3].value.as < PathNode* > (); } break; - case 112: // path_elem: id '[' "string" ']' - { yylhs.value.as < PathElem > () = PathElem{yystack_[3].value.as < std::string > (), yystack_[1].value.as < std::string > ().substr(1, yystack_[1].value.as < std::string > ().size() - 2)}; } + case 111: // path: path '[' "string" ']' + { yystack_[3].value.as < PathNode* > ()->add_element(yystack_[1].value.as < std::string > ().substr(1, yystack_[1].value.as < std::string > ().size() - 2)); yylhs.value.as < PathNode* > () = yystack_[3].value.as < PathNode* > (); } break; - case 113: // path_elem: id '[' "argument" ']' - { yylhs.value.as < PathElem > () = PathElem{yystack_[3].value.as < std::string > (), drv.get_arg_for_index(yystack_[1].value.as < std::string > ())}; } + case 112: // path: path '[' "argument" ']' + { yystack_[3].value.as < PathNode* > ()->add_element(drv.get_arg_for_index(yystack_[1].value.as < std::string > ())); yylhs.value.as < PathNode* > () = yystack_[3].value.as < PathNode* > (); } break; - case 114: // id: "identifier" + case 113: // id: "identifier" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 115: // id: "@links" + case 114: // id: "@links" { yylhs.value.as < std::string > () = std::string("@links"); } break; - case 116: // id: "beginswith" + case 115: // id: "beginswith" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 117: // id: "endswith" + case 116: // id: "endswith" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 118: // id: "contains" + case 117: // id: "contains" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 119: // id: "like" + case 118: // id: "like" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 120: // id: "between" + case 119: // id: "between" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 121: // id: "key or value" + case 120: // id: "key or value" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 122: // id: "sort" + case 121: // id: "sort" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 123: // id: "distinct" + case 122: // id: "distinct" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 124: // id: "limit" + case 123: // id: "limit" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 125: // id: "ascending" + case 124: // id: "ascending" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 126: // id: "descending" + case 125: // id: "descending" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 127: // id: "in" + case 126: // id: "in" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 128: // id: "fulltext" + case 127: // id: "fulltext" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; @@ -2448,202 +2420,202 @@ namespace yy { } - const short parser::yypact_ninf_ = -193; + const short parser::yypact_ninf_ = -166; const signed char parser::yytable_ninf_ = -1; const short parser::yypact_[] = { - 106, -193, -193, -59, -193, -193, -193, -193, -193, -193, - -193, 106, -193, -193, -193, -193, -193, -193, -193, -193, - -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, - -193, -193, -193, 19, -193, -193, -193, -193, -193, -193, - 106, 428, 33, -9, -193, 234, 49, 14, -193, -193, - -193, -193, -193, -193, 372, 10, -193, 36, 495, -193, - 71, -7, 12, -33, -193, 37, -193, 106, 106, 138, - -193, -193, -193, -193, -193, -193, -193, 223, 223, 223, - 223, 167, 223, -193, -193, -193, 340, -193, 11, 284, - 63, -193, 428, 66, 453, -193, 67, 1, 89, 97, - 101, -193, -193, 428, -193, -193, 146, 129, 130, 131, - -193, -193, -193, 223, 65, -193, -193, 65, -193, -193, - 223, 126, 126, -193, -193, 105, 340, -193, 153, 160, - 161, -193, -193, -12, 474, -193, -193, -193, -193, -193, - -193, -193, -193, 495, 163, 164, 165, 495, 495, 68, - -193, 495, 495, 201, 54, 126, -193, 168, 178, 168, - -193, -193, -193, -193, -193, 182, 185, -25, -3, 53, - 97, 186, -23, 206, 168, -193, 99, 213, 106, -193, - -193, 495, -193, -193, -193, -193, 495, -193, -193, -193, - -193, 214, 168, -193, 15, -193, 178, -23, 13, -3, - 97, -23, 219, 168, -193, -193, 220, 226, -193, 111, - -193, -193, -193, 229, 267, -193, -193, 235, -193 + 105, -166, -166, -50, -166, -166, -166, -166, -166, -166, + -166, 105, -166, -166, -166, -166, -166, -166, -166, -166, + -166, -166, -166, -166, -166, -166, -166, -166, -166, -166, + -166, -166, -166, -31, -166, -166, -166, -166, -166, -166, + 105, 427, 5, 144, -166, 233, 70, -13, -166, -166, + -166, -166, -166, -166, 371, -6, -166, 494, -166, 18, + -8, 10, -60, -166, 12, -166, 105, 105, 73, -166, + -166, -166, -166, -166, -166, -166, 222, 222, 222, 222, + 166, 222, -166, -166, -166, 339, -166, 9, 283, 54, + -166, 427, 63, 452, 61, -166, -3, 7, 97, 16, + -166, -166, 427, -166, -166, 81, 13, 22, 55, -166, + -166, -166, 222, 161, -166, -166, 161, -166, -166, 222, + 131, 131, -166, -166, 62, 339, -166, 91, 98, 110, + -166, -166, -58, 473, -166, -166, -166, -166, -166, -166, + -166, -166, 120, 147, 162, 494, 494, 494, 67, -166, + 494, 494, 214, 125, 131, -166, 182, 202, 182, -166, + -166, -166, -166, -166, 212, 215, 112, -28, 167, 97, + 218, 58, 217, 182, -166, 168, 224, 105, -166, -166, + 494, -166, -166, -166, -166, 494, -166, -166, -166, -166, + 235, 182, -166, -36, -166, 202, 58, 28, -28, 97, + 58, 220, 182, -166, -166, 238, 239, -166, 180, -166, + -166, -166, 247, 270, -166, -166, 240, -166 }; - const unsigned char + const signed char parser::yydefact_[] = { 0, 85, 86, 0, 74, 75, 76, 87, 88, 89, - 115, 0, 114, 82, 69, 67, 68, 80, 81, 70, - 71, 83, 84, 72, 73, 77, 116, 117, 118, 128, - 119, 120, 127, 0, 122, 123, 124, 125, 126, 121, + 114, 0, 113, 82, 69, 67, 68, 80, 81, 70, + 71, 83, 84, 72, 73, 77, 115, 116, 117, 127, + 118, 119, 126, 0, 121, 122, 123, 124, 125, 120, 0, 64, 0, 48, 3, 0, 18, 25, 27, 28, - 26, 24, 66, 8, 0, 90, 108, 110, 0, 6, - 0, 0, 0, 0, 63, 0, 1, 0, 0, 2, - 97, 98, 100, 102, 103, 101, 99, 0, 0, 0, - 0, 0, 0, 104, 105, 106, 0, 107, 0, 0, - 0, 78, 64, 90, 0, 29, 32, 0, 0, 33, - 0, 7, 19, 0, 61, 5, 4, 0, 0, 0, - 50, 49, 51, 0, 22, 18, 25, 23, 20, 21, - 0, 9, 11, 13, 15, 0, 0, 12, 0, 0, - 0, 17, 16, 0, 0, 30, 93, 94, 95, 96, - 91, 92, 109, 0, 0, 0, 0, 0, 0, 0, - 65, 0, 0, 0, 0, 10, 14, 0, 0, 0, - 62, 31, 112, 111, 113, 0, 0, 0, 0, 0, - 53, 0, 0, 0, 0, 43, 0, 0, 0, 79, - 55, 0, 59, 60, 56, 52, 0, 58, 36, 35, - 37, 0, 0, 40, 0, 47, 0, 0, 0, 0, - 54, 0, 0, 0, 42, 44, 0, 0, 57, 0, - 45, 41, 46, 0, 0, 38, 34, 0, 39 + 26, 24, 66, 8, 0, 90, 108, 0, 6, 0, + 0, 0, 0, 63, 0, 1, 0, 0, 2, 97, + 98, 100, 102, 103, 101, 99, 0, 0, 0, 0, + 0, 0, 104, 105, 106, 0, 107, 0, 0, 0, + 78, 64, 90, 0, 0, 29, 32, 0, 33, 0, + 7, 19, 0, 61, 5, 4, 0, 0, 0, 50, + 49, 51, 0, 22, 18, 25, 23, 20, 21, 0, + 9, 11, 13, 15, 0, 0, 12, 0, 0, 0, + 17, 16, 0, 0, 30, 93, 94, 95, 96, 91, + 92, 109, 0, 0, 0, 0, 0, 0, 0, 65, + 0, 0, 0, 0, 10, 14, 0, 0, 0, 62, + 111, 110, 112, 31, 0, 0, 0, 0, 0, 53, + 0, 0, 0, 0, 43, 0, 0, 0, 79, 55, + 0, 59, 60, 56, 52, 0, 58, 36, 35, 37, + 0, 0, 40, 0, 47, 0, 0, 0, 0, 54, + 0, 0, 0, 42, 44, 0, 0, 57, 0, 45, + 41, 46, 0, 0, 38, 34, 0, 39 }; const short parser::yypgoto_[] = { - -193, -193, -10, -193, -32, 0, 2, -193, -193, -193, - -192, -140, -193, 110, -193, -193, -193, -193, -193, -193, - -193, -193, 108, 221, 216, -31, 162, -193, -37, 217, - -193, -193, -193, -193, -51, -63, -16 + -166, -166, -10, -166, -33, 0, 2, -166, -166, -166, + -165, -140, -166, 113, -166, -166, -166, -166, -166, -166, + -166, -166, 111, 225, 243, -32, 163, -166, -37, 249, + -166, -166, -166, -166, -51, -56 }; const unsigned char parser::yydefgoto_[] = { - 0, 42, 43, 44, 45, 115, 116, 48, 98, 49, - 191, 173, 194, 175, 176, 132, 69, 110, 169, 111, - 167, 112, 184, 50, 63, 51, 52, 53, 54, 95, - 96, 81, 82, 89, 55, 56, 57 + 0, 42, 43, 44, 45, 114, 115, 48, 97, 49, + 190, 172, 193, 174, 175, 131, 68, 109, 168, 110, + 166, 111, 183, 50, 62, 51, 52, 53, 54, 95, + 96, 80, 81, 88, 55, 56 }; const unsigned char parser::yytable_[] = { - 46, 59, 47, 93, 65, 206, 58, 99, 62, 209, - 64, 46, 188, 47, 189, 67, 68, 67, 68, 177, - 190, 70, 71, 72, 73, 74, 75, 7, 8, 9, - 61, 142, 144, 66, 193, 103, 145, 67, 68, 104, - 46, 180, 47, 181, 146, 114, 117, 118, 119, 121, - 122, 125, 202, 182, 183, 65, 103, 105, 106, 101, - 160, 64, 76, 211, 148, 90, 65, 46, 46, 47, - 47, 142, 150, 77, 78, 79, 80, 94, 102, 207, - 91, 154, 41, 203, 60, 142, 123, 204, 155, 127, - 128, 129, 130, 83, 84, 85, 86, 87, 88, 13, - 168, 170, 100, 17, 18, 97, 131, 21, 22, 1, - 2, 3, 4, 5, 6, 77, 78, 79, 80, 185, - 102, 186, 7, 8, 9, 10, 156, 161, 79, 80, - 199, 165, 11, 134, 143, 200, 12, 13, 14, 15, + 46, 58, 47, 92, 64, 65, 98, 61, 102, 63, + 102, 46, 103, 47, 159, 57, 66, 67, 176, 69, + 70, 71, 72, 73, 74, 7, 8, 9, 181, 182, + 60, 205, 202, 192, 59, 208, 203, 141, 89, 147, + 46, 94, 47, 113, 116, 117, 118, 120, 121, 99, + 124, 201, 66, 67, 64, 90, 104, 105, 100, 63, + 75, 93, 210, 94, 145, 64, 46, 46, 47, 47, + 149, 76, 77, 78, 79, 146, 101, 141, 150, 153, + 41, 127, 128, 129, 148, 122, 154, 151, 126, 163, + 164, 141, 142, 187, 206, 188, 143, 130, 13, 167, + 169, 189, 17, 18, 144, 66, 21, 22, 1, 2, + 3, 4, 5, 6, 82, 83, 84, 85, 86, 87, + 152, 7, 8, 9, 10, 155, 106, 107, 108, 198, + 133, 11, 94, 91, 199, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 156, 33, 34, 35, + 36, 37, 38, 157, 147, 39, 94, 197, 66, 67, + 40, 3, 4, 5, 6, 158, 41, 46, 179, 47, + 180, 119, 7, 8, 9, 10, 76, 77, 78, 79, + 160, 101, 76, 77, 78, 79, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 147, 33, 34, - 35, 36, 37, 38, 148, 195, 39, 196, 198, 149, - 67, 40, 3, 4, 5, 6, 92, 41, 46, 214, - 47, 215, 120, 7, 8, 9, 10, 77, 78, 79, - 80, 107, 108, 109, 151, 152, 153, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 157, 33, - 34, 35, 36, 37, 38, 158, 159, 39, 3, 4, - 5, 6, 113, 162, 163, 164, 171, 172, 41, 7, - 8, 9, 10, 70, 71, 72, 73, 74, 75, 174, - 178, 179, 187, 12, 13, 14, 15, 16, 17, 18, + 26, 27, 28, 29, 30, 31, 32, 161, 33, 34, + 35, 36, 37, 38, 78, 79, 39, 3, 4, 5, + 6, 112, 162, 184, 194, 185, 195, 41, 7, 8, + 9, 10, 69, 70, 71, 72, 73, 74, 213, 170, + 214, 171, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 173, 33, 34, 35, 36, 37, 38, + 177, 178, 39, 75, 186, 191, 209, 112, 3, 4, + 5, 6, 196, 41, 76, 77, 78, 79, 125, 7, + 8, 9, 10, 200, 211, 215, 212, 216, 204, 207, + 217, 165, 123, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 192, 33, 34, 35, 36, 37, - 38, 197, 201, 39, 76, 210, 212, 216, 113, 3, - 4, 5, 6, 213, 41, 77, 78, 79, 80, 126, - 7, 8, 9, 10, 217, 218, 205, 208, 133, 124, - 135, 166, 0, 0, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 0, 33, 34, 35, 36, - 37, 38, 0, 0, 39, 3, 4, 5, 6, 0, - 0, 0, 0, 0, 0, 41, 7, 8, 9, 10, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 10, 33, 34, 35, 36, 37, 38, 0, 0, - 39, 0, 12, 0, 0, 0, 0, 0, 0, 0, - 0, 41, 0, 0, 0, 91, 26, 27, 28, 29, - 30, 31, 32, 0, 0, 34, 35, 36, 37, 38, - 0, 0, 39, 0, 4, 5, 6, 0, 0, 0, - 0, 0, 0, 92, 7, 8, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 10, 136, 137, 138, 139, 0, 0, 0, - 33, 0, 0, 12, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 10, 0, 0, 0, 26, 27, 28, + 29, 30, 31, 32, 132, 33, 34, 35, 36, 37, + 38, 134, 0, 39, 3, 4, 5, 6, 0, 0, + 0, 0, 0, 0, 41, 7, 8, 9, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 10, 33, 34, 35, 36, 37, 38, 0, 0, 39, + 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 90, 26, 27, 28, 29, 30, + 31, 32, 0, 0, 34, 35, 36, 37, 38, 0, + 0, 39, 0, 4, 5, 6, 0, 0, 0, 0, + 0, 0, 91, 7, 8, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 10, 135, 136, 137, 138, 0, 0, 0, 33, + 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 26, 27, 28, 29, + 30, 31, 32, 12, 0, 34, 35, 36, 37, 38, + 139, 140, 39, 10, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 12, 0, 34, 35, 36, 37, - 38, 140, 141, 39, 10, 0, 0, 0, 26, 27, - 28, 29, 30, 31, 32, 12, 0, 34, 35, 36, - 37, 38, 140, 141, 39, 0, 0, 0, 0, 26, - 27, 28, 29, 30, 31, 32, 0, 0, 34, 35, - 36, 37, 38, 0, 0, 39 + 38, 139, 140, 39, 0, 0, 0, 0, 26, 27, + 28, 29, 30, 31, 32, 0, 0, 34, 35, 36, + 37, 38, 0, 0, 39 }; const short parser::yycheck_[] = { - 0, 11, 0, 54, 41, 197, 65, 58, 40, 201, - 41, 11, 35, 11, 37, 24, 25, 24, 25, 159, - 43, 9, 10, 11, 12, 13, 14, 16, 17, 18, - 40, 94, 31, 0, 174, 68, 35, 24, 25, 72, - 40, 66, 40, 68, 43, 77, 78, 79, 80, 81, - 82, 88, 192, 56, 57, 92, 68, 67, 68, 66, - 72, 92, 50, 203, 67, 51, 103, 67, 68, 67, - 68, 134, 103, 61, 62, 63, 64, 67, 66, 66, - 43, 113, 71, 68, 65, 148, 86, 72, 120, 89, - 27, 28, 29, 44, 45, 46, 47, 48, 49, 31, - 151, 152, 31, 35, 36, 69, 43, 39, 40, 3, - 4, 5, 6, 7, 8, 61, 62, 63, 64, 66, - 66, 68, 16, 17, 18, 19, 126, 143, 63, 64, - 181, 147, 26, 67, 67, 186, 30, 31, 32, 33, + 0, 11, 0, 54, 41, 0, 57, 40, 68, 41, + 68, 11, 72, 11, 72, 65, 24, 25, 158, 9, + 10, 11, 12, 13, 14, 16, 17, 18, 56, 57, + 40, 196, 68, 173, 65, 200, 72, 93, 51, 67, + 40, 69, 40, 76, 77, 78, 79, 80, 81, 31, + 87, 191, 24, 25, 91, 43, 66, 67, 66, 91, + 50, 67, 202, 69, 67, 102, 66, 67, 66, 67, + 102, 61, 62, 63, 64, 68, 66, 133, 65, 112, + 71, 27, 28, 29, 68, 85, 119, 65, 88, 145, + 146, 147, 31, 35, 66, 37, 35, 43, 31, 150, + 151, 43, 35, 36, 43, 24, 39, 40, 3, 4, + 5, 6, 7, 8, 44, 45, 46, 47, 48, 49, + 65, 16, 17, 18, 19, 125, 53, 54, 55, 180, + 67, 26, 69, 71, 185, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 65, 52, 53, 54, + 55, 56, 57, 65, 67, 60, 69, 177, 24, 25, + 65, 5, 6, 7, 8, 65, 71, 177, 66, 177, + 68, 15, 16, 17, 18, 19, 61, 62, 63, 64, + 70, 66, 61, 62, 63, 64, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 68, 52, 53, - 54, 55, 56, 57, 67, 66, 60, 68, 178, 68, - 24, 65, 5, 6, 7, 8, 71, 71, 178, 68, - 178, 70, 15, 16, 17, 18, 19, 61, 62, 63, - 64, 53, 54, 55, 65, 65, 65, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 65, 52, - 53, 54, 55, 56, 57, 65, 65, 60, 5, 6, - 7, 8, 65, 70, 70, 70, 35, 69, 71, 16, - 17, 18, 19, 9, 10, 11, 12, 13, 14, 71, - 68, 66, 66, 30, 31, 32, 33, 34, 35, 36, + 44, 45, 46, 47, 48, 49, 50, 70, 52, 53, + 54, 55, 56, 57, 63, 64, 60, 5, 6, 7, + 8, 65, 70, 66, 66, 68, 68, 71, 16, 17, + 18, 19, 9, 10, 11, 12, 13, 14, 68, 35, + 70, 69, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 71, 52, 53, 54, 55, 56, 57, + 68, 66, 60, 50, 66, 68, 66, 65, 5, 6, + 7, 8, 68, 71, 61, 62, 63, 64, 15, 16, + 17, 18, 19, 68, 66, 58, 67, 37, 195, 198, + 70, 148, 87, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 68, 52, 53, 54, 55, 56, - 57, 68, 68, 60, 50, 66, 66, 58, 65, 5, - 6, 7, 8, 67, 71, 61, 62, 63, 64, 15, - 16, 17, 18, 19, 37, 70, 196, 199, 92, 88, - 93, 149, -1, -1, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, -1, 52, 53, 54, 55, - 56, 57, -1, -1, 60, 5, 6, 7, 8, -1, - -1, -1, -1, -1, -1, 71, 16, 17, 18, 19, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 19, 52, 53, 54, 55, 56, 57, -1, -1, - 60, -1, 30, -1, -1, -1, -1, -1, -1, -1, - -1, 71, -1, -1, -1, 43, 44, 45, 46, 47, - 48, 49, 50, -1, -1, 53, 54, 55, 56, 57, - -1, -1, 60, -1, 6, 7, 8, -1, -1, -1, - -1, -1, -1, 71, 16, 17, 18, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 19, 20, 21, 22, 23, -1, -1, -1, - 52, -1, -1, 30, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 19, -1, -1, -1, 44, 45, 46, + 47, 48, 49, 50, 91, 52, 53, 54, 55, 56, + 57, 92, -1, 60, 5, 6, 7, 8, -1, -1, + -1, -1, -1, -1, 71, 16, 17, 18, 19, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 19, 52, 53, 54, 55, 56, 57, -1, -1, 60, + -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, + 71, -1, -1, -1, 43, 44, 45, 46, 47, 48, + 49, 50, -1, -1, 53, 54, 55, 56, 57, -1, + -1, 60, -1, 6, 7, 8, -1, -1, -1, -1, + -1, -1, 71, 16, 17, 18, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 19, 20, 21, 22, 23, -1, -1, -1, 52, + -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 19, -1, -1, -1, 44, 45, 46, 47, + 48, 49, 50, 30, -1, 53, 54, 55, 56, 57, + 58, 59, 60, 19, -1, -1, -1, 44, 45, 46, 47, 48, 49, 50, 30, -1, 53, 54, 55, 56, - 57, 58, 59, 60, 19, -1, -1, -1, 44, 45, - 46, 47, 48, 49, 50, 30, -1, 53, 54, 55, - 56, 57, 58, 59, 60, -1, -1, -1, -1, 44, - 45, 46, 47, 48, 49, 50, -1, -1, 53, 54, - 55, 56, 57, -1, -1, 60 + 57, 58, 59, 60, -1, -1, -1, -1, 44, 45, + 46, 47, 48, 49, 50, -1, -1, 53, 54, 55, + 56, 57, -1, -1, 60 }; const signed char @@ -2654,23 +2626,23 @@ namespace yy { 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 57, 60, 65, 71, 74, 75, 76, 77, 78, 79, 80, 82, - 96, 98, 99, 100, 101, 107, 108, 109, 65, 75, - 65, 75, 77, 97, 98, 101, 0, 24, 25, 89, - 9, 10, 11, 12, 13, 14, 50, 61, 62, 63, - 64, 104, 105, 44, 45, 46, 47, 48, 49, 106, - 51, 43, 71, 107, 67, 102, 103, 69, 81, 107, - 31, 66, 66, 68, 72, 75, 75, 53, 54, 55, - 90, 92, 94, 65, 77, 78, 79, 77, 77, 77, - 15, 77, 77, 78, 96, 101, 15, 78, 27, 28, - 29, 43, 88, 97, 67, 102, 20, 21, 22, 23, - 58, 59, 108, 67, 31, 35, 43, 68, 67, 68, - 98, 65, 65, 65, 77, 77, 78, 65, 65, 65, - 72, 109, 70, 70, 70, 109, 99, 93, 107, 91, - 107, 35, 69, 84, 71, 86, 87, 84, 68, 66, - 66, 68, 56, 57, 95, 66, 68, 66, 35, 37, - 43, 83, 68, 84, 85, 66, 68, 68, 75, 107, - 107, 68, 84, 68, 72, 86, 83, 66, 95, 83, - 66, 84, 66, 67, 68, 70, 58, 37, 70 + 96, 98, 99, 100, 101, 107, 108, 65, 75, 65, + 75, 77, 97, 98, 101, 0, 24, 25, 89, 9, + 10, 11, 12, 13, 14, 50, 61, 62, 63, 64, + 104, 105, 44, 45, 46, 47, 48, 49, 106, 51, + 43, 71, 107, 67, 69, 102, 103, 81, 107, 31, + 66, 66, 68, 72, 75, 75, 53, 54, 55, 90, + 92, 94, 65, 77, 78, 79, 77, 77, 77, 15, + 77, 77, 78, 96, 101, 15, 78, 27, 28, 29, + 43, 88, 97, 67, 102, 20, 21, 22, 23, 58, + 59, 108, 31, 35, 43, 67, 68, 67, 68, 98, + 65, 65, 65, 77, 77, 78, 65, 65, 65, 72, + 70, 70, 70, 108, 108, 99, 93, 107, 91, 107, + 35, 69, 84, 71, 86, 87, 84, 68, 66, 66, + 68, 56, 57, 95, 66, 68, 66, 35, 37, 43, + 83, 68, 84, 85, 66, 68, 68, 75, 107, 107, + 68, 84, 68, 72, 86, 83, 66, 95, 83, 66, + 84, 66, 67, 68, 70, 58, 37, 70 }; const signed char @@ -2687,8 +2659,8 @@ namespace yy { 99, 99, 99, 99, 99, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, - 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109, 109 + 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108 }; const signed char @@ -2705,8 +2677,8 @@ namespace yy { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, - 1, 4, 4, 4, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1 + 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -2735,8 +2707,7 @@ namespace yy { "geoloop", "geopoly_content", "geospatial", "post_query", "distinct", "distinct_param", "sort", "sort_param", "limit", "direction", "list", "list_content", "constant", "primary_key", "boolexpr", "comp_type", - "post_op", "aggr_op", "equality", "relational", "stringop", "path", - "path_elem", "id", YY_NULLPTR + "post_op", "aggr_op", "equality", "relational", "stringop", "path", "id", YY_NULLPTR }; #endif @@ -2745,19 +2716,19 @@ namespace yy { const short parser::yyrline_[] = { - 0, 187, 187, 190, 191, 192, 193, 194, 195, 198, - 199, 204, 205, 206, 207, 212, 213, 214, 217, 218, - 219, 220, 221, 222, 225, 226, 227, 228, 229, 232, - 233, 236, 240, 246, 249, 252, 253, 254, 257, 258, - 261, 262, 264, 267, 268, 271, 272, 273, 276, 277, - 278, 279, 281, 284, 285, 287, 290, 291, 293, 296, - 297, 299, 300, 303, 304, 305, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 329, 330, 331, 332, 333, 336, 337, 340, 341, 342, - 345, 346, 347, 350, 351, 352, 353, 356, 357, 358, - 361, 362, 363, 364, 367, 368, 369, 370, 373, 374, - 377, 378, 379, 380, 383, 384, 385, 386, 387, 388, - 389, 390, 391, 392, 393, 394, 395, 396, 397 + 0, 174, 174, 177, 178, 179, 180, 181, 182, 185, + 186, 191, 192, 193, 194, 199, 200, 201, 204, 205, + 206, 207, 208, 209, 212, 213, 214, 215, 216, 219, + 220, 223, 227, 233, 236, 239, 240, 241, 244, 245, + 248, 249, 251, 254, 255, 258, 259, 260, 263, 264, + 265, 266, 268, 271, 272, 274, 277, 278, 280, 283, + 284, 286, 287, 290, 291, 292, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 316, 317, 318, 319, 320, 323, 324, 327, 328, 329, + 332, 333, 334, 337, 338, 339, 340, 343, 344, 345, + 348, 349, 350, 351, 354, 355, 356, 357, 360, 361, + 362, 363, 364, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381 }; void diff --git a/src/realm/parser/generated/query_bison.hpp b/src/realm/parser/generated/query_bison.hpp index 84fe32a2c23..360dabd1656 100644 --- a/src/realm/parser/generated/query_bison.hpp +++ b/src/realm/parser/generated/query_bison.hpp @@ -72,17 +72,6 @@ class DescriptorNode; class PropertyNode; class SubqueryNode; - struct PathElem { - std::string id; - Mixed index; - std::string buffer; - PathElem() {} - PathElem(const PathElem& other); - PathElem& operator=(const PathElem& other); - PathElem(std::string s) : id(s) {} - PathElem(std::string s, Mixed i) : id(s), index(i) { index.use_buffer(buffer); } - }; - } using namespace realm::query_parser; @@ -474,47 +463,44 @@ namespace yy { // list_content char dummy7[sizeof (ListNode*)]; - // path_elem - char dummy8[sizeof (PathElem)]; - // path - char dummy9[sizeof (PathNode*)]; + char dummy8[sizeof (PathNode*)]; // post_op - char dummy10[sizeof (PostOpNode*)]; + char dummy9[sizeof (PostOpNode*)]; // prop // simple_prop - char dummy11[sizeof (PropertyNode*)]; + char dummy10[sizeof (PropertyNode*)]; // query // compare - char dummy12[sizeof (QueryNode*)]; + char dummy11[sizeof (QueryNode*)]; // subquery - char dummy13[sizeof (SubqueryNode*)]; + char dummy12[sizeof (SubqueryNode*)]; // boolexpr - char dummy14[sizeof (TrueOrFalseNode*)]; + char dummy13[sizeof (TrueOrFalseNode*)]; // value - char dummy15[sizeof (ValueNode*)]; + char dummy14[sizeof (ValueNode*)]; // direction - char dummy16[sizeof (bool)]; + char dummy15[sizeof (bool)]; // coordinate - char dummy17[sizeof (double)]; + char dummy16[sizeof (double)]; // comp_type // aggr_op // equality // relational // stringop - char dummy18[sizeof (int)]; + char dummy17[sizeof (int)]; // geopoint - char dummy19[sizeof (std::optional)]; + char dummy18[sizeof (std::optional)]; // "identifier" // "string" @@ -548,7 +534,7 @@ namespace yy { // "@type" // "key or value" // id - char dummy20[sizeof (std::string)]; + char dummy19[sizeof (std::string)]; }; /// The size of the largest semantic type. @@ -779,8 +765,7 @@ namespace yy { SYM_relational = 105, // relational SYM_stringop = 106, // stringop SYM_path = 107, // path - SYM_path_elem = 108, // path_elem - SYM_id = 109 // id + SYM_id = 108 // id }; }; @@ -852,10 +837,6 @@ namespace yy { value.move< ListNode* > (std::move (that.value)); break; - case symbol_kind::SYM_path_elem: // path_elem - value.move< PathElem > (std::move (that.value)); - break; - case symbol_kind::SYM_path: // path value.move< PathNode* > (std::move (that.value)); break; @@ -1046,18 +1027,6 @@ namespace yy { {} #endif -#if 201103L <= YY_CPLUSPLUS - basic_symbol (typename Base::kind_type t, PathElem&& v) - : Base (t) - , value (std::move (v)) - {} -#else - basic_symbol (typename Base::kind_type t, const PathElem& v) - : Base (t) - , value (v) - {} -#endif - #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, PathNode*&& v) : Base (t) @@ -1283,10 +1252,6 @@ switch (yykind) value.template destroy< ListNode* > (); break; - case symbol_kind::SYM_path_elem: // path_elem - value.template destroy< PathElem > (); - break; - case symbol_kind::SYM_path: // path value.template destroy< PathNode* > (); break; @@ -2528,7 +2493,7 @@ switch (yykind) // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. // Performed when YYTABLE does not specify something else to do. Zero // means the default is an error. - static const unsigned char yydefact_[]; + static const signed char yydefact_[]; // YYPGOTO[NTERM-NUM]. static const short yypgoto_[]; @@ -2783,9 +2748,9 @@ switch (yykind) /// Constants. enum { - yylast_ = 555, ///< Last index in yytable_. - yynnts_ = 37, ///< Number of nonterminal symbols. - yyfinal_ = 66 ///< Termination state number. + yylast_ = 554, ///< Last index in yytable_. + yynnts_ = 36, ///< Number of nonterminal symbols. + yyfinal_ = 65 ///< Termination state number. }; @@ -2894,10 +2859,6 @@ switch (yykind) value.copy< ListNode* > (YY_MOVE (that.value)); break; - case symbol_kind::SYM_path_elem: // path_elem - value.copy< PathElem > (YY_MOVE (that.value)); - break; - case symbol_kind::SYM_path: // path value.copy< PathNode* > (YY_MOVE (that.value)); break; @@ -3051,10 +3012,6 @@ switch (yykind) value.move< ListNode* > (YY_MOVE (s.value)); break; - case symbol_kind::SYM_path_elem: // path_elem - value.move< PathElem > (YY_MOVE (s.value)); - break; - case symbol_kind::SYM_path: // path value.move< PathNode* > (YY_MOVE (s.value)); break; diff --git a/src/realm/parser/query_bison.yy b/src/realm/parser/query_bison.yy index 810733ae4f1..16d51514b4b 100644 --- a/src/realm/parser/query_bison.yy +++ b/src/realm/parser/query_bison.yy @@ -34,17 +34,6 @@ class DescriptorNode; class PropertyNode; class SubqueryNode; - struct PathElem { - std::string id; - Mixed index; - std::string buffer; - PathElem() {} - PathElem(const PathElem& other); - PathElem& operator=(const PathElem& other); - PathElem(std::string s) : id(s) {} - PathElem(std::string s, Mixed i) : id(s), index(i) { index.use_buffer(buffer); } - }; - } using namespace realm::query_parser; @@ -157,7 +146,6 @@ using namespace realm::query_parser; %type post_query %type sort sort_param distinct distinct_param limit %type id -%type path_elem %type simple_prop %destructor { } @@ -170,7 +158,6 @@ using namespace realm::query_parser; if (auto alt = $$->get_altitude()) yyo << "', '" << *alt; yyo << "']"; }} >; -%printer { yyo << $$.id; } ; %printer { yyo << $$; } <*>; %printer { yyo << "<>"; } <>; @@ -370,14 +357,11 @@ stringop | LIKE { $$ = CompareNode::LIKE; } path - : path_elem { $$ = drv.m_parse_nodes.create($1); } - | path '.' path_elem { $1->add_element($3); $$ = $1; } - -path_elem - : id { $$ = PathElem{$1}; } - | id '[' NATURAL0 ']' { $$ = PathElem{$1, int64_t(strtoll($3.c_str(), nullptr, 0))}; } - | id '[' STRING ']' { $$ = PathElem{$1, $3.substr(1, $3.size() - 2)}; } - | id '[' ARG ']' { $$ = PathElem{$1, drv.get_arg_for_index($3)}; } + : id { $$ = drv.m_parse_nodes.create($1); } + | path '.' id { $1->add_element($3); $$ = $1; } + | path '[' NATURAL0 ']' { $1->add_element(size_t(strtoll($3.c_str(), nullptr, 0))); $$ = $1; } + | path '[' STRING ']' { $1->add_element($3.substr(1, $3.size() - 2)); $$ = $1; } + | path '[' ARG ']' { $1->add_element(drv.get_arg_for_index($3)); $$ = $1; } id : ID { $$ = $1; } diff --git a/src/realm/sort_descriptor.hpp b/src/realm/sort_descriptor.hpp index 5a78dfb9868..864ab682e2d 100644 --- a/src/realm/sort_descriptor.hpp +++ b/src/realm/sort_descriptor.hpp @@ -63,6 +63,11 @@ class ExtendedColumnKey { return *this; } + void set_index(Mixed index) + { + m_index = index; + m_index.use_buffer(m_buffer); + } ColKey get_col_key() const { return m_colkey; diff --git a/src/realm/table.cpp b/src/realm/table.cpp index 8128238f9a4..975f78f8b7b 100644 --- a/src/realm/table.cpp +++ b/src/realm/table.cpp @@ -336,21 +336,17 @@ std::ostream& operator<<(std::ostream& o, Table::Type table_type) } } // namespace realm -void LinkChain::add(ColKey ck) +bool LinkChain::add(ColKey ck) { // Link column can be a single Link, LinkList, or BackLink. REALM_ASSERT(m_current_table->valid_column(ck)); ColumnType type = ck.get_type(); if (type == col_type_LinkList || type == col_type_Link || type == col_type_BackLink) { m_current_table = m_current_table->get_opposite_table(ck); + m_link_cols.push_back(ck); + return true; } - else { - // Only last column in link chain is allowed to be non-link - throw LogicError(ErrorCodes::TypeMismatch, - util::format("Property '%1.%2' is not an object reference", - m_current_table->get_class_name(), m_current_table->get_column_name(ck))); - } - m_link_cols.push_back(ck); + return false; } // -- Table --------------------------------------------------------------------------------- diff --git a/src/realm/table.hpp b/src/realm/table.hpp index 1eb94a5a544..0aadde5fc5d 100644 --- a/src/realm/table.hpp +++ b/src/realm/table.hpp @@ -1024,15 +1024,12 @@ class LinkChain { return *this; } - LinkChain& link(std::string col_name) + bool link(std::string col_name) { - auto ck = m_current_table->get_column_key(col_name); - if (!ck) { - throw LogicError(ErrorCodes::InvalidProperty, - util::format("'%1' has no property '%2'", m_current_table->get_class_name(), col_name)); + if (auto ck = m_current_table->get_column_key(col_name)) { + return add(ck); } - add(ck); - return *this; + return false; } LinkChain& backlink(const Table& origin, ColKey origin_col_key) @@ -1109,7 +1106,7 @@ class LinkChain { ConstTableRef m_base_table; util::Optional m_comparison_type; - void add(ColKey ck); + bool add(ColKey ck); template std::unique_ptr create_subexpr(ColKey col_key) diff --git a/test/test_parser.cpp b/test/test_parser.cpp index 608349273ab..0e46b35be3d 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -2374,7 +2374,7 @@ TEST_TYPES(Parser_list_of_primitive_element_lengths, StringData, BinaryData) std::string message; CHECK_THROW_ANY_GET_MESSAGE(verify_query(test_context, t, "values.len == 2", 0), message); - CHECK_EQUAL(message, "Property 'table.values' is not an object reference"); + CHECK_EQUAL(message, "Property 'table.values' has no property 'len'"); } TEST_TYPES(Parser_list_of_primitive_types, Prop, Nullable, Prop, Nullable, Prop, @@ -2460,7 +2460,7 @@ TEST_TYPES(Parser_list_of_primitive_types, Prop, Nullable, Prop, } else { CHECK_THROW_ANY_GET_MESSAGE(verify_query(test_context, t, "values.length == 2", 0), message); - CHECK_EQUAL(message, "Property 'table.values' is not an object reference"); + CHECK_EQUAL(message, "Property 'table.values' has no property 'length'"); } } @@ -4978,7 +4978,7 @@ TEST(Parser_Dictionary) verify_query(test_context, foo, "dict.@values > 50", 50); verify_query(test_context, foo, "dict['Value'] > 50", expected); verify_query_sub(test_context, foo, "dict[$0] > 50", args, num_args, expected); - verify_query(test_context, foo, "dict['Value'] > 50", expected); + verify_query(test_context, foo, "dict.Value > 50", expected); verify_query(test_context, foo, "ANY dict.@keys == 'Foo'", 20); verify_query(test_context, foo, "NONE dict.@keys == 'Value'", 23); verify_query(test_context, foo, "dict.@keys == {'Bar'}", 20); @@ -5014,9 +5014,6 @@ TEST(Parser_Dictionary) dict.insert("Value", 4.5); std::string message; - CHECK_THROW_ANY_GET_MESSAGE(verify_query(test_context, origin, "link.dict.Value > 50", 3), message); - CHECK_EQUAL(message, "Property 'foo.dict' is not an object reference"); - // aggregates still work with mixed types verify_query(test_context, foo, "dict.@max == 100", 2); verify_query(test_context, foo, "dict.@min < 2", 2);