From 4ebcd99d1fadac72ea58ea46012a86c5319ef7e7 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sat, 30 Oct 2021 08:16:08 +0200 Subject: Add parsing of lambda expression --- src/parser.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 24 deletions(-) (limited to 'src/parser.c') diff --git a/src/parser.c b/src/parser.c index 2d70c9d..8a6c4ce 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,6 +1,9 @@ #include "parser.h" #include "darray.h" +static Object **objects = NULL; +static Root *roots = NULL; + Token peek_token(const Parser *parser) { return parser->tokens[parser->current]; @@ -67,20 +70,82 @@ parse_symbol(Token tok) { return ret; } +Object * +parse_lambda(Parser *parser, Errors *errors) { + Token start = next_token(parser); + Object *lambda = object_alloc(start, OBJ_TYPE_LAMBDA); + array_init(lambda->params, 0); + array_init(lambda->body, 0); + + // Parse parameters. + Token tok = next_token(parser); + if (tok.type == TOKEN_LPAREN) { + while (has_next_token(parser)) { + Token tok = next_token(parser); + if (tok.type == TOKEN_RPAREN) { + break; + } + if (tok.type != TOKEN_SYMBOL) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_WRONG_ARG_TYPE, + .line = tok.line, + .col = tok.col, + }); + } + Object *symbol = parse_symbol(tok); + array_push(lambda->params, symbol); + } + } else if (tok.type != TOKEN_NIL) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_WRONG_ARG_TYPE, + .line = tok.line, + .col = tok.col, + }); + } + + // Parse body. + while (has_next_token(parser)) { + Token tok = peek_token(parser); + if (tok.type == TOKEN_RPAREN) { + next_token(parser); + break; + } + Object *expr = parse_tree(parser, errors); + array_push(lambda->body, expr); + } + return lambda; +} + Object * parse_list(Parser *parser, Errors *errors) { if (errors->n != 0) { return NULL; } + + Token tok = peek_token(parser); + if (tok.type == TOKEN_RPAREN) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_UNBALANCED_PAREN, + .line = tok.line, + .col = tok.col, + }); + return NULL; + } + if (tok.type == TOKEN_LAMBDA) { + return parse_lambda(parser, errors); + } + Token start = previous_token(parser); Object *root = object_alloc(start, OBJ_TYPE_PAIR); - root->car = NULL; - root->cdr = NULL; + root->head = NULL; + root->tail = NULL; Object *current = root; while (has_next_token(parser)) { - current->car = parse_tree(parser, errors); - if (errors->n != 0 || current->car == NULL) { - object_free(root); + current->head = parse_tree(parser, errors); + if (errors->n != 0 || current->head == NULL) { return NULL; } @@ -91,12 +156,11 @@ parse_list(Parser *parser, Errors *errors) { } Object *next = object_alloc(start, OBJ_TYPE_PAIR); - next->car = NULL; - next->cdr = NULL; - current->cdr = next; - current = current->cdr; + next->head = NULL; + next->tail = NULL; + current->tail = next; + current = current->tail; } - object_free(root); error_push(errors, (Error){ .type = ERR_TYPE_PARSER, .value = ERR_UNBALANCED_PAREN, @@ -156,7 +220,7 @@ parse_tree(Parser *parser, Errors *errors) { Root * parse(Token *tokens, Errors *errors) { - Root *roots = NULL; + // Build initial AST. array_init(roots, 0); Parser parser = { .tokens = tokens, @@ -170,15 +234,24 @@ parse(Token *tokens, Errors *errors) { } array_push(roots, root); } + + // Perform semantic analysis. + // 1. Ensure core grammar is correct. + // 2. Check that symbols are defined before usage. + // 3. Remove unnecessary statements. return roots; } Object * object_alloc(Token tok, ObjectType type) { + if (objects == NULL) { + array_init(objects, 0); + } Object *node = malloc(sizeof(Object)); node->line = tok.line; node->col = tok.col; node->type = type; + array_push(objects, node); return node; } @@ -190,35 +263,36 @@ object_free(Object *node) { if (IS_STRING(node) || IS_SYMBOL(node)) { array_free(node->text); } - if (IS_PAIR(node)) { - object_free(node->car); - object_free(node->cdr); + if (IS_LAMBDA(node)) { + array_free(node->params); + array_free(node->body); } free(node); } void -free_roots(Root *roots) { - if (roots != NULL) { - for (size_t i = 0; i < array_size(roots); i++) { - object_free(roots[i]); +free_objects(void) { + if (objects != NULL) { + for (size_t i = 0; i < array_size(objects); i++) { + object_free(objects[i]); } - array_free(roots); + array_free(objects); } + array_free(roots); } void display_pair(Object *obj) { - object_display(obj->car); - if (obj->cdr == NULL) { + object_display(obj->head); + if (obj->tail == NULL) { return; } - if (IS_PAIR(obj->cdr)) { + if (IS_PAIR(obj->tail)) { printf(" "); - display_pair(obj->cdr); + display_pair(obj->tail); } else { printf(" . "); - object_display(obj->cdr); + object_display(obj->tail); } } @@ -252,6 +326,14 @@ object_display(Object *obj) { display_pair(obj); printf(")"); } break; + case OBJ_TYPE_LAMBDA: { + printf("#{lambda( "); + for (size_t i = 0; i < array_size(obj->params); i++) { + object_display(obj->params[i]); + printf(" "); + } + printf(")}"); + } break; } return; } -- cgit v1.2.1