diff --git a/lib/src/Makefile.am b/lib/src/Makefile.am index f485b02..193862a 100644 --- a/lib/src/Makefile.am +++ b/lib/src/Makefile.am @@ -44,6 +44,7 @@ libcypher_parser_la_SOURCES = \ ast_function_name.c \ ast_identifier.c \ ast_index_name.c \ + ast_inf.c \ ast_integer.c \ ast_label.c \ ast_labels_operator.c \ @@ -57,6 +58,7 @@ libcypher_parser_la_SOURCES = \ ast_merge_action.c \ ast_merge_properties.c \ ast_named_path.c \ + ast_nan.c \ ast_node_id_lookup.c \ ast_node_index_lookup.c \ ast_node_index_query.c \ diff --git a/lib/src/ast.c b/lib/src/ast.c index e3e18bf..ddf7926 100644 --- a/lib/src/ast.c +++ b/lib/src/ast.c @@ -114,6 +114,8 @@ struct cypher_astnode_vts const struct cypher_astnode_vt *true_literal; const struct cypher_astnode_vt *false_literal; const struct cypher_astnode_vt *null_literal; + const struct cypher_astnode_vt *nan_literal; + const struct cypher_astnode_vt *inf_literal; const struct cypher_astnode_vt *label; const struct cypher_astnode_vt *reltype; const struct cypher_astnode_vt *prop_name; @@ -232,6 +234,8 @@ static const struct cypher_astnode_vts cypher_astnode_vts = .true_literal = &cypher_true_astnode_vt, .false_literal = &cypher_false_astnode_vt, .null_literal = &cypher_null_astnode_vt, + .nan_literal = &cypher_nan_astnode_vt, + .inf_literal = &cypher_inf_astnode_vt, .label = &cypher_label_astnode_vt, .reltype = &cypher_reltype_astnode_vt, .prop_name = &cypher_prop_name_astnode_vt, @@ -361,6 +365,8 @@ const uint8_t CYPHER_AST_BOOLEAN = VT_OFFSET(boolean_literal); const uint8_t CYPHER_AST_TRUE = VT_OFFSET(true_literal); const uint8_t CYPHER_AST_FALSE = VT_OFFSET(false_literal); const uint8_t CYPHER_AST_NULL = VT_OFFSET(null_literal); +const uint8_t CYPHER_AST_NAN = VT_OFFSET(nan_literal); +const uint8_t CYPHER_AST_INF = VT_OFFSET(inf_literal); const uint8_t CYPHER_AST_LABEL = VT_OFFSET(label); const uint8_t CYPHER_AST_RELTYPE = VT_OFFSET(reltype); const uint8_t CYPHER_AST_PROP_NAME = VT_OFFSET(prop_name); diff --git a/lib/src/ast_inf.c b/lib/src/ast_inf.c new file mode 100644 index 0000000..e018e2a --- /dev/null +++ b/lib/src/ast_inf.c @@ -0,0 +1,80 @@ +/* vi:set ts=4 sw=4 expandtab: + * + * Copyright 2016, Chris Leishman (http://github.com/cleishm) + * + * 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 "../../config.h" +#include "astnode.h" +#include "operators.h" +#include "util.h" +#include + + +struct inf_literal +{ + cypher_astnode_t _astnode; +}; + + +static cypher_astnode_t *clone(const cypher_astnode_t *self, + cypher_astnode_t **children); +static ssize_t detailstr(const cypher_astnode_t *self, char *str, size_t size); + + +static const struct cypher_astnode_vt *parents[] = + { &cypher_expression_astnode_vt }; + +const struct cypher_astnode_vt cypher_inf_astnode_vt = + { .parents = parents, + .nparents = 1, + .name = "INF", + .detailstr = detailstr, + .release = cypher_astnode_release, + .clone = clone }; + + +cypher_astnode_t *cypher_ast_inf(struct cypher_input_range range) +{ + struct inf_literal *node = calloc(1, sizeof(struct inf_literal)); + if (node == NULL) + { + return NULL; + } + if (cypher_astnode_init(&(node->_astnode), CYPHER_AST_INF, + NULL, 0, range)) + { + free(node); + return NULL; + } + return &(node->_astnode); +} + + +cypher_astnode_t *clone(const cypher_astnode_t *self, + cypher_astnode_t **children) +{ + REQUIRE_TYPE(self, CYPHER_AST_INF, NULL); + return cypher_ast_inf(self->range); +} + + +ssize_t detailstr(const cypher_astnode_t *self, char *str, size_t size) +{ + REQUIRE_TYPE(self, CYPHER_AST_INF, -1); + if (size > 0) + { + str[0] = '\0'; + } + return 0; +} diff --git a/lib/src/ast_nan.c b/lib/src/ast_nan.c new file mode 100644 index 0000000..c01c050 --- /dev/null +++ b/lib/src/ast_nan.c @@ -0,0 +1,80 @@ +/* vi:set ts=4 sw=4 expandtab: + * + * Copyright 2016, Chris Leishman (http://github.com/cleishm) + * + * 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 "../../config.h" +#include "astnode.h" +#include "operators.h" +#include "util.h" +#include + + +struct nan_literal +{ + cypher_astnode_t _astnode; +}; + + +static cypher_astnode_t *clone(const cypher_astnode_t *self, + cypher_astnode_t **children); +static ssize_t detailstr(const cypher_astnode_t *self, char *str, size_t size); + + +static const struct cypher_astnode_vt *parents[] = + { &cypher_expression_astnode_vt }; + +const struct cypher_astnode_vt cypher_nan_astnode_vt = + { .parents = parents, + .nparents = 1, + .name = "NAN", + .detailstr = detailstr, + .release = cypher_astnode_release, + .clone = clone }; + + +cypher_astnode_t *cypher_ast_nan(struct cypher_input_range range) +{ + struct nan_literal *node = calloc(1, sizeof(struct nan_literal)); + if (node == NULL) + { + return NULL; + } + if (cypher_astnode_init(&(node->_astnode), CYPHER_AST_NAN, + NULL, 0, range)) + { + free(node); + return NULL; + } + return &(node->_astnode); +} + + +cypher_astnode_t *clone(const cypher_astnode_t *self, + cypher_astnode_t **children) +{ + REQUIRE_TYPE(self, CYPHER_AST_NAN, NULL); + return cypher_ast_nan(self->range); +} + + +ssize_t detailstr(const cypher_astnode_t *self, char *str, size_t size) +{ + REQUIRE_TYPE(self, CYPHER_AST_NAN, -1); + if (size > 0) + { + str[0] = '\0'; + } + return 0; +} diff --git a/lib/src/astnode.h b/lib/src/astnode.h index 743aca3..1728f47 100644 --- a/lib/src/astnode.h +++ b/lib/src/astnode.h @@ -227,6 +227,8 @@ extern const struct cypher_astnode_vt cypher_boolean_astnode_vt; extern const struct cypher_astnode_vt cypher_true_astnode_vt; extern const struct cypher_astnode_vt cypher_false_astnode_vt; extern const struct cypher_astnode_vt cypher_null_astnode_vt; +extern const struct cypher_astnode_vt cypher_nan_astnode_vt; +extern const struct cypher_astnode_vt cypher_inf_astnode_vt; extern const struct cypher_astnode_vt cypher_label_astnode_vt; extern const struct cypher_astnode_vt cypher_reltype_astnode_vt; extern const struct cypher_astnode_vt cypher_prop_name_astnode_vt; diff --git a/lib/src/cypher-parser.h.in b/lib/src/cypher-parser.h.in index 399f91e..ff7d3a4 100644 --- a/lib/src/cypher-parser.h.in +++ b/lib/src/cypher-parser.h.in @@ -314,6 +314,10 @@ extern const cypher_astnode_type_t CYPHER_AST_TRUE; extern const cypher_astnode_type_t CYPHER_AST_FALSE; /** Type for an AST NULL literal node. */ extern const cypher_astnode_type_t CYPHER_AST_NULL; +/** Type for an AST NAN literal node. */ +extern const cypher_astnode_type_t CYPHER_AST_NAN; +/** Type for an AST INF literal node. */ +extern const cypher_astnode_type_t CYPHER_AST_INF; /** Type for an AST label node. */ extern const cypher_astnode_type_t CYPHER_AST_LABEL; /** Type for an AST reltype node. */ @@ -4835,6 +4839,27 @@ cypher_astnode_t *cypher_ast_false(struct cypher_input_range range); __cypherlang_must_check cypher_astnode_t *cypher_ast_null(struct cypher_input_range range); +/** + * Construct a `CYPHER_AST_NAN` node. + * + * The node will also be an instance of `CYPHER_AST_EXPRESSION`. + * + * @param [range] The input range. + * @return An AST node, or NULL if an error occurs (errno will be set). + */ +__cypherlang_must_check +cypher_astnode_t *cypher_ast_nan(struct cypher_input_range range); + +/** + * Construct a `CYPHER_AST_INF` node. + * + * The node will also be an instance of `CYPHER_AST_EXPRESSION`. + * + * @param [range] The input range. + * @return An AST node, or NULL if an error occurs (errno will be set). + */ +__cypherlang_must_check +cypher_astnode_t *cypher_ast_inf(struct cypher_input_range range); /** * Construct a `CYPHER_AST_LABEL` node. diff --git a/lib/src/parser.c b/lib/src/parser.c index 63d6b5b..39eb987 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -438,6 +438,10 @@ static cypher_astnode_t *_true_literal(yycontext *yy); static cypher_astnode_t *_false_literal(yycontext *yy); #define null_literal() _null_literal(yy) static cypher_astnode_t *_null_literal(yycontext *yy); +#define nan_literal() _nan_literal(yy) +static cypher_astnode_t *_nan_literal(yycontext *yy); +#define inf_literal() _inf_literal(yy) +static cypher_astnode_t *_inf_literal(yycontext *yy); #define strbuf_label() _strbuf_label(yy) static cypher_astnode_t *_strbuf_label(yycontext *yy); #define strbuf_reltype() _strbuf_reltype(yy) @@ -2808,6 +2812,21 @@ cypher_astnode_t *_null_literal(yycontext *yy) return add_terminal(yy, cypher_ast_null(range)); } +cypher_astnode_t *_nan_literal(yycontext *yy) +{ + assert(yy->prev_block != NULL && + "An AST node can only be created immediately after a `>` in the grammar"); + struct cypher_input_range range = yy->prev_block->range; + return add_terminal(yy, cypher_ast_nan(range)); +} + +cypher_astnode_t *_inf_literal(yycontext *yy) +{ + assert(yy->prev_block != NULL && + "An AST node can only be created immediately after a `>` in the grammar"); + struct cypher_input_range range = yy->prev_block->range; + return add_terminal(yy, cypher_ast_inf(range)); +} cypher_astnode_t *_strbuf_label(yycontext *yy) { diff --git a/lib/src/parser.leg b/lib/src/parser.leg index cbab84d..a9c9435 100644 --- a/lib/src/parser.leg +++ b/lib/src/parser.leg @@ -94,6 +94,9 @@ cypher-param-value = true-literal | false-literal | null-literal + | nan-literal + | inf-literal + | infinity-literal | string-literal | collection-literal | map-literal @@ -522,6 +525,9 @@ atom = true-literal | false-literal | null-literal + | nan-literal + | inf-literal + | infinity-literal | string-literal | float-literal | integer-literal @@ -715,6 +721,15 @@ false-literal = null-literal = < NULL > { $$ = null_literal(); } - +nan-literal = + < NAN > { $$ = nan_literal(); } + - +inf-literal = + < INF > { $$ = inf_literal(); } + - +infinity-literal = + < INFINITY > { $$ = inf_literal(); } + - parameter = _block_start_ { strbuf_reset(); } ( ( '$' - parameter-name ) ~{ERR("a parameter")} @@ -1114,6 +1129,9 @@ FIELDTERMINATOR = ([Ff][Ii][Ee][Ll][Dd][Tt][Ee][Rr][Mm][Ii][Nn][Aa][Tt][Oo][Rr] TRUE = ([Tt][Rr][Uu][Ee] WB) ~{ERR("TRUE")} FALSE = ([Ff][Aa][Ll][Ss][Ee] WB) ~{ERR("FALSE")} NULL = ([Nn][Uu][Ll][Ll] WB) ~{ERR("NULL")} +NAN = ([Nn][Aa][Nn] WB) ~{ERR("NAN")} +INF = ([Ii][Nn][Ff] WB) ~{ERR("INF")} +INFINITY = ([Ii][Nn][Ff][Ii][Nn][Ii][Tt][Yy] WB) ~{ERR("INFINITY")} SHORTESTPATH = ([Ss][Hh][Oo][Rr][Tt][Ee][Ss][Tt][Pp][Aa][Tt][Hh] WB -) ~{ERR("shortestPath")}