diff --git a/lib/src/ast_call_subquery.c b/lib/src/ast_call_subquery.c index bdf1da3..edafe0b 100644 --- a/lib/src/ast_call_subquery.c +++ b/lib/src/ast_call_subquery.c @@ -99,6 +99,23 @@ void cypher_ast_call_subquery_replace_query node->query = query; } +void cypher_ast_call_subquery_push_clause( + cypher_astnode_t *astnode, + cypher_astnode_t *clause, + unsigned int index +) { + REQUIRE_TYPE(astnode, CYPHER_AST_CALL_SUBQUERY, NULL); + struct call_subquery *subquery_node = + container_of(astnode, struct call_subquery, _astnode); + + cypher_astnode_t *new_query = + cypher_ast_query_push_clause(subquery_node->query, clause, index); + + cypher_astnode_free(subquery_node->query); + astnode->children[0] = new_query; + subquery_node->query = new_query; +} + cypher_astnode_t *clone(const cypher_astnode_t *self, cypher_astnode_t **children) { diff --git a/lib/src/ast_query.c b/lib/src/ast_query.c index da15d3f..b75779e 100644 --- a/lib/src/ast_query.c +++ b/lib/src/ast_query.c @@ -205,6 +205,48 @@ void cypher_ast_query_replace_clauses( astnode->nchildren -= end_index - start_index; } +cypher_astnode_t *cypher_ast_query_push_clause( + cypher_astnode_t *astnode, + cypher_astnode_t *clause, + unsigned int index +) +{ + REQUIRE_TYPE(astnode, CYPHER_AST_QUERY, NULL); + REQUIRE_TYPE(clause, CYPHER_AST_QUERY_CLAUSE, NULL); + struct query *query = container_of(astnode, struct query, _astnode); + + unsigned int nchildren = astnode->nchildren + 1; + unsigned int nclauses = query->nclauses + 1; + + cypher_astnode_t **clauses = calloc(nclauses, sizeof(cypher_astnode_t *)); + if (clauses == NULL) { + return NULL; + } + + cypher_astnode_t **children = calloc(nchildren, sizeof(cypher_astnode_t *)); + if (children == NULL) { + return NULL; + } + + //insert new clause + for(uint i = 0; i < index; i++) { + clauses[i] = query->clauses[i]; + children[i] = query->clauses[i]; + } + clauses[index] = clause; + children[index] = clause; + for(uint i = index + 1; i < nclauses; i++) { + clauses[i] = query->clauses[i - 1]; + children[i] = query->clauses[i - 1]; + } + + cypher_astnode_t *new_query = cypher_ast_query(NULL, 0, clauses, nclauses, + children, nchildren, astnode->range); + free(clauses); + free(children); + + return new_query; +} ssize_t detailstr(const cypher_astnode_t *self, char *str, size_t size) { diff --git a/lib/src/ast_statement.c b/lib/src/ast_statement.c index b65c931..9c2af2c 100644 --- a/lib/src/ast_statement.c +++ b/lib/src/ast_statement.c @@ -92,6 +92,26 @@ void cypher_ast_statement_replace_body } +void cypher_ast_statement_push_clause +( + cypher_astnode_t *astnode, + cypher_astnode_t *clause, + unsigned int index +) +{ + REQUIRE_TYPE(astnode, CYPHER_AST_STATEMENT, NULL); + REQUIRE_TYPE(clause, CYPHER_AST_QUERY_CLAUSE, NULL); + struct statement *node = container_of(astnode, struct statement, _astnode); + + cypher_astnode_t *body = + cypher_ast_query_push_clause(node->body, clause, index); + + astnode->children[child_index(astnode, node->body)] = body; + cypher_astnode_free(node->body); + node->body = body; +} + + cypher_astnode_t *clone(const cypher_astnode_t *self, cypher_astnode_t **children) { diff --git a/lib/src/cypher-parser.h.in b/lib/src/cypher-parser.h.in index e529b80..f824a4b 100644 --- a/lib/src/cypher-parser.h.in +++ b/lib/src/cypher-parser.h.in @@ -550,6 +550,26 @@ cypher_astnode_t *cypher_ast_statement(cypher_astnode_t * const *options, void cypher_ast_statement_replace_body(cypher_astnode_t *astnode, const cypher_astnode_t *body); +/** + * Insert clause at position `index` of a `CYPHER_AST_STATEMENT` node. + * + * If the node is not an instance of `CYPHER_AST_STATEMENT` then the result will + * be undefined. + * + * If the clause is not an instance of `CYPHER_AST_QUERY_CLAUSE` then the result + * will be undefined. + * + * @param [node] The AST node. + * @param [clause] The AST clause node. + * @param [index] The index of the new clause. + */ +void cypher_ast_statement_push_clause +( + cypher_astnode_t *astnode, + cypher_astnode_t *clause, + unsigned int index +); + /** * Get the number of options in a `CYPHER_AST_STATEMENT` node. * @@ -1328,6 +1348,26 @@ void cypher_ast_query_set_clause( void cypher_ast_query_replace_clauses( cypher_astnode_t *astnode, cypher_astnode_t *clause, unsigned int start_index, unsigned int end_index); +/** + * Insert clause at position `index` of a `CYPHER_AST_QUERY` node. + * + * If the node is not an instance of `CYPHER_AST_QUERY` then the result will + * be undefined. + * + * If the clause is not an instance of `CYPHER_AST_QUERY_CLAUSE` then the result + * will be undefined. + * + * @param [node] The AST node. + * @param [clause] The AST clause node. + * @param [index] The index of the new clause. + * @return The query, or NULL if an error occurs. + */ +cypher_astnode_t *cypher_ast_query_push_clause( + cypher_astnode_t *astnode, + cypher_astnode_t *clause, + unsigned int index +); + /** * Replace the clauses of a `CYPHER_AST_FOREACH` node. * @@ -3130,6 +3170,22 @@ void cypher_ast_call_subquery_replace_query cypher_astnode_t *query ); +/** + * Insert a new clause at position `index` of a `CYPHER_AST_CALL_SUBQUERY` node. + * + * If the node is not an instance of `CYPHER_AST_CALL_SUBQUERY` then the + * result will be undefined. + * + * @param [astnode] The AST node. + * @param [query] The query to replace the existing query with. + * @param [index] Position of the new clause + */ +void cypher_ast_call_subquery_push_clause( + cypher_astnode_t *astnode, + cypher_astnode_t *clause, + unsigned int index +); + /** * Get the proc name of a `CYPHER_AST_CALL` node. *