diff --git a/doc/grammar.bnf b/doc/grammar.bnf index cfa42c9..038d0a6 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -8,6 +8,9 @@ EXPR ::= | BLOCK | IF | return EXPR +| FUN_DECL +FUN_DECL ::= +| fun ident opar PARAMS cpar EXPR* end IF ::= if EXPR BLOCK (else (BLOCK | IF))? BLOCK ::= begin EXPR* end ASSIGN ::= ident assign EXPR diff --git a/features/fun.sk b/features/fun.sk index 7168ebf..7a5311a 100644 --- a/features/fun.sk +++ b/features/fun.sk @@ -80,3 +80,8 @@ assert k() eq 39 assert k() eq 40 assert k() eq 41 +fun l(x) + 3 * x +end + +assert l(7) eq 21 diff --git a/lib/include/parser.h b/lib/include/parser.h index 18dcca3..c526470 100644 --- a/lib/include/parser.h +++ b/lib/include/parser.h @@ -19,6 +19,7 @@ struct node* parser_try(struct parser* self, struct node* parser_try_parse(struct parser* self); struct node* parser_try_root(struct parser* self); struct node* parser_try_expr(struct parser* self); +struct node* parser_try_fun_decl(struct parser* self); struct node* parser_try_block(struct parser* self); struct node* parser_try_inner_block(struct parser* self); struct node* parser_try_if(struct parser* self); diff --git a/lib/src/parser.c b/lib/src/parser.c index 5173d87..1a7b170 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -137,9 +137,73 @@ struct node* parser_try_expr(struct parser* self) return SK_TRY(parser_try_if); } + if (lexer_next_is(&self->lexer, TOKEN_FUN) + && lexer_next_nth_is(&self->lexer, TOKEN_IDENT, 1)) + { + return SK_TRY(parser_try_fun_decl); + } + return SK_TRY(parser_try_or); } +struct node* parser_try_fun_decl(struct parser* self) +{ + if (!lexer_next_is(&self->lexer, TOKEN_FUN)) + { + return NULL; + } + + struct node* fun = malloc(sizeof(struct node)); + node_init(fun, NODE_FUN, lexer_try_new_next(&self->lexer)); + + if (!lexer_next_is(&self->lexer, TOKEN_IDENT)) + { + node_free(fun); + free(fun); + return NULL; + } + + struct node* ident = malloc(sizeof(struct node)); + node_init(ident, NODE_IDENT, + lexer_try_new_next(&self->lexer)); + + if (!lexer_next_is(&self->lexer, TOKEN_OPAR)) + { + node_free(fun); free(fun); + node_free(ident); free(ident); + return NULL; + } + lexer_consume_next(&self->lexer); + + struct node* params = SK_TRY(parser_try_params); + node_push_new_child(fun, params); + + if (!lexer_next_is(&self->lexer, TOKEN_CPAR)) + { + node_free(fun); free(fun); + node_free(ident); free(ident); + return NULL; + } + lexer_consume_next(&self->lexer); + + struct node* body = SK_TRY(parser_try_inner_block); + node_push_new_child(fun, body); + + if (!lexer_next_is(&self->lexer, TOKEN_END)) + { + node_free(fun); free(fun); + node_free(ident); free(ident); + return NULL; + } + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_CONST_DECL, lexer_try_new_next(&self->lexer)); + + node_push_new_child(node, ident); + node_push_new_child(node, fun); + return node; +} + struct node* parser_try_block(struct parser* self) { assert(self); diff --git a/tests/parser.h b/tests/parser.h index a7cf199..946b97a 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -140,6 +140,11 @@ static void test_parser_function() test_parser("ROOT(FUN(PARAMS,BLOCK))", "fun () end"); + test_parser("ROOT(CONST_DECL(IDENT[hello]" + ",FUN(PARAMS(IDENT[x],IDENT[y])," + "BLOCK(INT[0],INT[1]))))", + "fun hello (x, y) 0 1 end"); + test_parser("ROOT(CALL(IDENT[hello],ARGS))", "hello()");