static struct AstNode *parse_if( struct DomNode *dom, struct ParserState *state) { struct DomNode *child = NULL; struct AstNode *test = NULL; struct AstNode *true_expr = NULL; struct AstNode *false_expr = NULL; /* 1. Is compound CORE */ if (!dom_node_is_spec_compound(dom, DOM_CPD_CORE)) { return NULL; } /* 2. Has 4 children */ if (!dom_node_is_cpd_of_size(dom, 4)) { return NULL; } child = dom->cpd_children; /* 3.1. 1st child is the if keyword. */ if (!dom_node_is_spec_reserved_atom(child, DOM_RES_IF)) { return NULL; } child = child->next; /* 3.2 2nd child is a valid expression. */ if (!(test = parse_one(child, state))) { return NULL; } child = child->next; /* 3.3 3rd child is a valid expression. */ if (!(true_expr = parse_one(child, state))) { ast_node_free(test); return NULL; } child = child->next; /* 3.4 4th child is a valid expression. */ if (!(false_expr = parse_one(child, state))) { ast_node_free(test); ast_node_free(true_expr); return NULL; } return ast_make_spec_if(test, true_expr, false_expr); }
static void bif_parse_any(struct Runtime *rt, char *string) { struct AstNode *ast; ast = parse_source(string, NULL, NULL); if (!ast) { bif_text_error_parse(); return; } if (ast->next != NULL) { bif_text_error_parse(); ast_node_free(ast); return; } bif_parse_any_ast(rt, ast); ast_node_free(ast); }
static void bif_parse_atomic( struct Runtime *rt, VAL_LOC_T arg_loc, char *func, enum AstLiteralAtomicType type) { VAL_LOC_T size_loc, data_begin, data_size; struct AstNode *ast = NULL; char *source, *err; /* Assert input. */ if (!rt_val_is_string(rt, arg_loc)) { bif_text_error_arg(1, func, "must be a string"); return; } /* Push header. */ rt_val_push_tuple_init(&rt->stack, &size_loc); data_begin = rt->stack.top; source = rt_val_peek_cpd_as_string(rt, arg_loc); ast = parse_source(source, NULL, NULL); mem_free(source); /* Error detection. */ if (!ast) { err = "Failed parsing atomic literal"; rt_val_push_bool(&rt->stack, false); rt_val_push_string(&rt->stack, err, err + strlen(err)); goto end; } if (ast->next != NULL) { err = "Too many nodes."; rt_val_push_bool(&rt->stack, false); rt_val_push_string(&rt->stack, err, err + strlen(err)); goto end; } if (ast->type != AST_LITERAL_ATOMIC || ast->data.literal_atomic.type != type) { err = "Incorrect type."; rt_val_push_bool(&rt->stack, false); rt_val_push_string(&rt->stack, err, err + strlen(err)); goto end; } /* Correct case. */ rt_val_push_bool(&rt->stack, true); bif_parse_any_ast_literal_atomic(rt, &ast->data.literal_atomic); end: data_size = rt->stack.top - data_begin; rt_val_push_cpd_final(&rt->stack, size_loc, data_size); if (ast) { ast_node_free(ast); } }
void ast_node_free(ast_node n) { if (!n) return; switch (n->type) { case N_2OP: ast_node_free(n->left); ast_node_free(n->right); break; case N_NUM: break; case N_VAR: free(n->id); n->id = NULL; break; case N_COND: ast_node_free(n->left); ast_node_free(n->arg[0]); ast_node_free(n->arg[1]); break; } free(n); }
static struct AstNode *parse_binary( struct DomNode *dom, enum Reserved keyword, struct AstNode *(*constructor)( struct AstNode *, struct AstNode *), struct ParserState *state) { struct DomNode *child = NULL; struct AstNode *arg1 = NULL; struct AstNode *arg2 = NULL; /* 1. Is compound CORE */ if (!dom_node_is_spec_compound(dom, DOM_CPD_CORE)) { return NULL; } /* 2. Has 2 children */ if (!dom_node_is_cpd_of_size(dom, 3)) { return NULL; } child = dom->cpd_children; /* 2.1. 1st child is the proper keyword. */ if (!dom_node_is_spec_reserved_atom(child, keyword)) { return NULL; } child = child->next; /* 2.2 2nd child is a valid expression. */ if (!(arg1 = parse_one(child, state))) { return NULL; } child = child->next; /* 2.3 3rd child is a valid expression. */ if (!(arg2 = parse_one(child, state))) { ast_node_free(arg1); return NULL; } child = child->next; return constructor(arg1, arg2); }
static struct AstNode *parse_list( struct DomNode *dom, struct ParserState *state) { struct AstNode *node; struct AstNode *result = NULL; struct AstNode *result_end = NULL; while (dom) { if ((node = parse_one(dom, state))) { LIST_APPEND(node, &result, &result_end); } else { ast_node_free(result); return NULL; } dom = dom->next; } return result; }
static struct AstNode *parse_bind( struct DomNode *dom, struct ParserState *state) { struct DomNode *child = NULL; struct AstNode *pattern = NULL; struct AstNode *expr = NULL; /* 1. Is compound CORE */ if (!dom_node_is_spec_compound(dom, DOM_CPD_CORE)) { return NULL; } /* 2. Has 3 children */ if (!dom_node_is_cpd_of_size(dom, 3)) { return NULL; } child = dom->cpd_children; /* 2.1. 1st child is bind keyword. */ if (!dom_node_is_spec_reserved_atom(child, DOM_RES_BIND)) { return NULL; } child = child->next; /* 2.2. 2nd child is pattern. */ if (!(pattern = parse_one(child, state))) { return NULL; } child = child->next; /* 2.3 3rd child is any expression. */ if (!(expr = parse_one(child, state))) { ast_node_free(pattern); return NULL; } return ast_make_spec_bind(pattern, expr); }
static struct AstNode *parse_func_def( struct DomNode *dom, struct ParserState *state) { struct AstNode *expr = NULL; struct DomNode *child = NULL; struct DomNode *arg_child = NULL; struct AstNode *formal_args = NULL, *formal_args_end = NULL; /* 1. Is compound CORE. */ if (!dom_node_is_spec_compound(dom, DOM_CPD_CORE)) { return NULL; } /* 2. Has 3 children. */ if (!dom_node_is_cpd_of_size(dom, 3)) { return NULL; } child = dom->cpd_children; /* 2.1. 1st child is "func" keyword. */ if (!dom_node_is_spec_reserved_atom(child, DOM_RES_FUNC)) { return NULL; } child = child->next; /* 2.2. 2nd keyword is a core compound of patterns. */ if (!dom_node_is_spec_compound(child, DOM_CPD_CORE)) { return NULL; } arg_child = child->cpd_children; /* Argument list may be empty. */ if (arg_child) { while (arg_child) { struct AstNode *pattern; if (!(pattern = parse_one(arg_child, state))) { goto fail; } else { LIST_APPEND(pattern, &formal_args, &formal_args_end); } arg_child = arg_child->next; } } child = child->next; /* 2.3. Has 1 more further expression. */ if (!(expr = parse_one(child, state))) { goto fail; } return ast_make_spec_func_def(formal_args, expr); fail: if (formal_args) { ast_node_free(formal_args); } return NULL; }
static struct AstNode *parse_match( struct DomNode *dom, struct ParserState *state) { struct DomNode *child = NULL; struct AstNode *expr = NULL; struct AstNode *keys = NULL, *keys_end = NULL; struct AstNode *values = NULL, *values_end = NULL; /* 1. Is compound CORE. */ if (!dom_node_is_spec_compound(dom, DOM_CPD_CORE)) { return NULL; } /* 2. Has 3 or more children. */ if (!dom_node_is_cpd_min_size(dom, 3)) { return NULL; } child = dom->cpd_children; /* 3.1. 1st child is "match" keyword. */ if (!dom_node_is_spec_reserved_atom(child, DOM_RES_MATCH)) { return NULL; } child = child->next; /* 3.2. 2nd child is an expression. */ if (!(expr = parse_one(child, state))) { return NULL; } child = child->next; /* 3.3. Has at least one matching expression. */ while (child) { struct DomNode *match_child = NULL; struct AstNode *key = NULL; struct AstNode *value = NULL; /* 3.3.1. Is compound CORE. */ if (!dom_node_is_spec_compound(child, DOM_CPD_CORE)) { goto fail; } /* 3.3.2. Has 2 children. */ if (!dom_node_is_cpd_of_size(child, 2)) { goto fail; } match_child = child->cpd_children; /* 3.3.3. 1st child is a pattern. */ if (!(key = parse_one(match_child, state))) { goto fail; } match_child = match_child->next; /* 3.3.4. 2nd child is an expression. */ if (!(value = parse_one(match_child, state))) { goto fail; } LIST_APPEND(key, &keys, &keys_end); LIST_APPEND(value, &values, &values_end); child = child->next; } return ast_make_spec_match(expr, keys, values); fail: ast_node_free(expr); if (keys) { ast_node_free(keys); } if (values) { ast_node_free(values); } return NULL; }
void ast_node_free(ast_node* p) { if(!p) return; switch(p->type) { case AST_NODE_TYPE_UNARY_OP: ast_node_free(p->u1.unary_node.expr); free(p); break; case AST_NODE_TYPE_POSTFIX: ast_node_free(p->u1.postfix_node.expr); free(p); break; case AST_NODE_TYPE_WHILE: ast_node_free(p->u1.while_node.condition); ast_node_free(p->u1.while_node.body); free(p); break; case AST_NODE_TYPE_FOR: ast_node_free(p->u1.for_node.initialization); ast_node_free(p->u1.for_node.condition); ast_node_free(p->u1.for_node.final_expression); ast_node_free(p->u1.for_node.body); free(p); break; case AST_NODE_TYPE_STRING: free(p->u1.string_value.value); free(p); break; case AST_NODE_TYPE_RET: ast_node_free(p->u1.return_node.expr); free(p); break; case AST_NODE_TYPE_IF: ast_node_free(p->u1.if_node.condition); ast_node_free(p->u1.if_node.b1); ast_node_free(p->u1.if_node.b2); free(p); break; case AST_NODE_TYPE_NUMBER: free(p); break; case AST_NODE_TYPE_STATEMENT_LIST: { size_t i; for(i = 0; i < p->u1.statements_node.count; i++) { ast_node_free(p->u1.statements_node.statement_list[i]); } free(p->u1.statements_node.statement_list); free(p); } break; case AST_NODE_TYPE_BIN_OP: ast_node_free(p->u1.binary_node.left); ast_node_free(p->u1.binary_node.right); free(p); break; case AST_NODE_TYPE_ID: free(p->u1.id_node.name); free(p); break; case AST_NODE_TYPE_FUNC_DECL: free(p->u1.function_node.name); ast_node_free(p->u1.function_node.parameter_list); ast_node_free(p->u1.function_node.body); free(p); break; case AST_NODE_TYPE_PRINT: ast_node_free(p->u1.print_node.expr); free(p); break; case AST_NODE_TYPE_CALL: ast_node_free(p->u1.call_node.id); ast_node_free(p->u1.call_node.arguments); free(p); break; default: como_error_noreturn("p->type not implemented (%d)", p->type); break; } }