diff --git a/lang/ast/expr/arith.c b/lang/ast/expr/arith.c index 6ee8068..3fede0f 100644 --- a/lang/ast/expr/arith.c +++ b/lang/ast/expr/arith.c @@ -81,8 +81,7 @@ enum ivy_status arith_push_operand( } case IVY_TOK_ATOM: { struct ivy_ast_atom_node *v - = (struct ivy_ast_atom_node *)ast_node_create( - IVY_AST_ATOM); + = (struct ivy_ast_atom_node *)ast_node_create(IVY_AST_ATOM); v->n_content = tok; b_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); break; @@ -646,7 +645,6 @@ struct token_parse_result arith_parse_left_brace( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_NOT_SUPPORTED, 0); - } struct token_parse_result arith_parse_right_brace( @@ -655,14 +653,29 @@ struct token_parse_result arith_parse_right_brace( struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); - if (state->s_terminator == IVY_SYM_RIGHT_BRACE) { - state->s_prev_token = IVY_SYM_RIGHT_BRACE; - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; - } + state->s_prev_token = IVY_SYM_RIGHT_BRACE; + struct token_parse_result result = expr_finalise_and_return(ctx, state); + result.r_flags = PARSE_REPEAT_TOKEN; + return result; +} - return PARSE_RESULT(IVY_ERR_NOT_SUPPORTED, 0); +struct token_parse_result arith_parse_left_bracket( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + parser_push_state(ctx, IVY_AST_LAMBDA, 0); + return PARSE_RESULT(IVY_OK, 0); +} + +struct token_parse_result arith_parse_right_bracket( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct expr_parser_state *state + = parser_get_state(ctx, struct expr_parser_state); + + state->s_prev_token = IVY_SYM_RIGHT_BRACKET; + struct token_parse_result result = expr_finalise_and_return(ctx, state); + result.r_flags = PARSE_REPEAT_TOKEN; + return result; } static struct ivy_ast_selector_node *keyword_selector_from_label_list(b_queue *labels) @@ -1088,7 +1101,8 @@ struct token_parse_result arith_parse_comma( = parser_get_state(ctx, struct expr_parser_state); if (state->s_terminator == IVY_SYM_COMMA) { - struct token_parse_result result = expr_finalise_and_return(ctx, state); + struct token_parse_result result + = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } diff --git a/lang/ast/expr/expr.c b/lang/ast/expr/expr.c index 8e1cfe0..2b87cb0 100644 --- a/lang/ast/expr/expr.c +++ b/lang/ast/expr/expr.c @@ -35,6 +35,8 @@ struct ast_node_type expr_node_ops = { SYM_PARSER(RIGHT_PAREN, arith_parse_right_paren), SYM_PARSER(LEFT_BRACE, arith_parse_left_brace), SYM_PARSER(RIGHT_BRACE, arith_parse_right_brace), + SYM_PARSER(LEFT_BRACKET, arith_parse_left_bracket), + SYM_PARSER(RIGHT_BRACKET, arith_parse_right_bracket), SYM_PARSER(SEMICOLON, arith_parse_semicolon), SYM_PARSER(UNDERSCORE, arith_parse_operand), SYM_PARSER(CARET, arith_parse_caret), diff --git a/lang/ast/expr/expr.h b/lang/ast/expr/expr.h index 4f8e264..34d6afc 100644 --- a/lang/ast/expr/expr.h +++ b/lang/ast/expr/expr.h @@ -122,6 +122,10 @@ extern struct token_parse_result arith_parse_left_brace( struct ivy_parser *ctx, struct ivy_token *tok); extern struct token_parse_result arith_parse_right_brace( struct ivy_parser *ctx, struct ivy_token *tok); +extern struct token_parse_result arith_parse_left_bracket( + struct ivy_parser *ctx, struct ivy_token *tok); +extern struct token_parse_result arith_parse_right_bracket( + struct ivy_parser *ctx, struct ivy_token *tok); extern struct token_parse_result arith_parse_semicolon( struct ivy_parser *ctx, struct ivy_token *tok); extern struct token_parse_result arith_parse_dot( diff --git a/lang/ast/lambda.c b/lang/ast/lambda.c new file mode 100644 index 0000000..1361820 --- /dev/null +++ b/lang/ast/lambda.c @@ -0,0 +1,179 @@ +#include "block.h" +#include "ctx.h" +#include "iterate.h" +#include "node.h" + +#include + +struct lambda_parser_state { + struct parser_state s_base; + + struct ivy_ast_node *s_prev_node; + unsigned int s_prev; + + b_queue s_args; + struct ivy_ast_node *s_body; +}; + +static struct token_parse_result parse_expr_begin( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct lambda_parser_state *state + = parser_get_state(ctx, struct lambda_parser_state); + + if (state->s_prev != IVY_SYM_LEFT_BRACKET && state->s_prev != IVY_SYM_PIPE) { + /* unexpected expression. */ + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + struct block_parser_state *block + = (struct block_parser_state *)parser_push_state( + ctx, IVY_AST_BLOCK, 0); + block->s_terminator = IVY_SYM_RIGHT_BRACKET; + return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); +} + +static struct token_parse_result parse_ident( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct lambda_parser_state *state + = parser_get_state(ctx, struct lambda_parser_state); + + if (state->s_prev == IVY_SYM_LEFT_BRACKET || state->s_prev == IVY_SYM_PIPE) { + return parse_expr_begin(ctx, tok); + } + + if (state->s_prev != IVY_SYM_COLON) { + /* the only idents we're expecting are parameter names, + * which are always preceded with a colon */ + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + struct ivy_ast_ident_node *arg + = (struct ivy_ast_ident_node *)ast_node_create(IVY_AST_IDENT); + if (!arg) { + return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); + } + + arg->n_content = tok; + b_queue_push_back(&state->s_args, &arg->n_base.n_entry); + state->s_prev = IVY_TOK_IDENT; + + return PARSE_RESULT(IVY_OK, 0); +} + +static struct token_parse_result parse_colon( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct lambda_parser_state *state + = parser_get_state(ctx, struct lambda_parser_state); + + if (state->s_prev != IVY_SYM_LEFT_BRACKET + && state->s_prev != IVY_TOK_IDENT) { + /* colons can only be used before arg names */ + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + state->s_prev = IVY_SYM_COLON; + return PARSE_RESULT(IVY_OK, 0); +} + +static struct token_parse_result parse_pipe( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct lambda_parser_state *state + = parser_get_state(ctx, struct lambda_parser_state); + + if (state->s_prev != IVY_TOK_IDENT) { + /* pipe can only be used after an arg name. */ + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + state->s_prev = IVY_SYM_PIPE; + return PARSE_RESULT(IVY_OK, 0); +} + +static void finalise_lambda(struct lambda_parser_state *state) +{ + struct ivy_ast_lambda_node *lambda + = (struct ivy_ast_lambda_node *)state->s_base.s_node; + + lambda->n_arg = state->s_args; + lambda->n_body = state->s_body; + + state->s_args = B_QUEUE_INIT; + state->s_body = NULL; +} + +static struct token_parse_result parse_right_bracket( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct lambda_parser_state *state + = parser_get_state(ctx, struct lambda_parser_state); + + if (!state->s_prev_node) { + /* empty lambda */ + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + state->s_body = state->s_prev_node; + state->s_prev_node = NULL; + + finalise_lambda(state); + parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); + return PARSE_RESULT(IVY_OK, 0); +} + +static enum ivy_status add_child( + struct parser_state *parent, struct ivy_ast_node *child) +{ + struct lambda_parser_state *state = (struct lambda_parser_state *)parent; + + if (state->s_prev_node) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_node = child; + return IVY_OK; +} + +static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) +{ + struct lambda_parser_state *state = (struct lambda_parser_state *)sp; + state->s_prev = IVY_SYM_LEFT_BRACKET; +} + +static void collect_children( + struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) +{ + struct ivy_ast_lambda_node *lambda = (struct ivy_ast_lambda_node *)node; + b_queue_iterator it = {0}; + b_queue_foreach (&it, &lambda->n_arg) { + struct ivy_ast_node *expr + = b_unbox(struct ivy_ast_node, it.entry, n_entry); + ast_node_iterator_enqueue_node(iterator, node, expr); + } + + if (lambda->n_body) { + ast_node_iterator_enqueue_node(iterator, node, lambda->n_body); + } +} + +struct ast_node_type lambda_node_ops = { + .n_add_child = add_child, + .n_init_state = init_state, + .n_collect_children = collect_children, + .n_state_size = sizeof(struct lambda_parser_state), + .n_node_size = sizeof(struct ivy_ast_lambda_node), + .n_token_parsers = { + TOK_PARSER(IDENT, parse_ident), + }, + .n_symbol_parsers = { + SYM_PARSER(RIGHT_BRACKET, parse_right_bracket), + SYM_PARSER(PIPE, parse_pipe), + SYM_PARSER(COLON, parse_colon), + }, + .n_expr_parser = { + .expr_begin = parse_expr_begin, + }, +}; diff --git a/lang/ast/node.c b/lang/ast/node.c index e7f6cc6..a5a82d2 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -30,6 +30,7 @@ extern struct ast_node_type while_loop_node_ops; extern struct ast_node_type for_loop_node_ops; extern struct ast_node_type return_node_ops; extern struct ast_node_type property_node_ops; +extern struct ast_node_type lambda_node_ops; extern struct ast_node_type discard_node_ops; static const struct ast_node_type *node_ops[] = { @@ -57,6 +58,7 @@ static const struct ast_node_type *node_ops[] = { [IVY_AST_FOR_LOOP] = &for_loop_node_ops, [IVY_AST_RETURN] = &return_node_ops, [IVY_AST_PROPERTY] = &property_node_ops, + [IVY_AST_LAMBDA] = &lambda_node_ops, [IVY_AST_DISCARD] = &discard_node_ops, }; static const size_t nr_node_ops = sizeof node_ops / sizeof node_ops[0]; @@ -85,6 +87,8 @@ enum token_expr_type get_token_expr_type(struct ivy_token *tok) case IVY_TOK_SYMBOL: switch (tok->t_symbol) { case IVY_SYM_LEFT_PAREN: + case IVY_SYM_LEFT_BRACKET: + case IVY_SYM_LEFT_BRACE: case IVY_SYM_CARET: return TOK_EXPR_BEGIN; case IVY_SYM_COMMA: diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index ecc6f5b..363fa47 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -118,7 +118,7 @@ struct ivy_ast_msgh_node { struct ivy_ast_property_node { struct ivy_ast_node n_base; struct ivy_token *n_ident; - + /* if get/set is set in these flags but the corresponding child node * is NULL, the getter/setter should be synthesised by the compiler. */ enum { @@ -142,10 +142,11 @@ struct ivy_ast_property_node { struct ivy_ast_lambda_node { struct ivy_ast_node n_base; - /* queue of struct lex_token; contains the names of the lambda parameters. */ + /* queue of struct ivy_ast_ident_node; contains the names of the lambda + * parameters. */ b_queue n_arg; /* expressions to evaluate when lambda is executed. */ - struct ivy_ast_block_node *n_body; + struct ivy_ast_node *n_body; }; struct ivy_ast_unit_package_node {