From b05ff83a9ddaafc951dc8d4926de179c949a101d Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Tue, 20 Aug 2019 10:59:53 -0400 Subject: parameter lists, return types, function bodies --- parse.c | 230 ++++++++++++++++++++++++++++++++++++++++++++------------ test.toc | 8 +- util/blockarr.c | 12 +-- 3 files changed, 193 insertions(+), 57 deletions(-) diff --git a/parse.c b/parse.c index 015666a..706c898 100644 --- a/parse.c +++ b/parse.c @@ -1,4 +1,5 @@ typedef enum { + TYPE_VOID, TYPE_BUILTIN } TypeKind; @@ -32,11 +33,15 @@ typedef struct { Type type; } Param; +typedef struct { + Array stmts; +} Block; + typedef struct { Array params; Type ret_type; - Array stmts; -} FnExpr; /* an expression such as fn(x: int) int {return 2 * x;} */ + Block body; +} FnExpr; /* an expression such as fn(x: int) int {return 2 * x;} */ typedef enum { EXPR_INT_LITERAL, @@ -182,6 +187,53 @@ static bool type_parse(Type *type, Parser *p) { return false; } +static bool param_parse(Param *p, Parser *parser) { + Tokenizer *t = parser->tokr; + if (t->token->kind != TOKEN_IDENT) { + tokr_err(t, "Expected parameter name."); + return false; + } + p->name = t->token->ident; + t->token++; + if (!token_is_kw(t->token, KW_COLON)) { + tokr_err(t, "Expected ':' between parameter name and type."); + return false; + } + t->token++; + if (!type_parse(&p->type, parser)) + return false; + return true; +} + +static bool stmt_parse(Statement *s, Parser *p); + +static bool block_parse(Block *b, Parser *p) { + Tokenizer *t = p->tokr; + if (!token_is_kw(t->token, KW_LBRACE)) { + tokr_err(t, "Expected '{' to open block."); + return false; + } + t->token++; /* move past { */ + arr_create(&b->stmts, sizeof(Statement)); + + if (!token_is_kw(t->token, KW_RBRACE)) { + /* non-empty function body */ + while (1) { + Statement *stmt = arr_add(&b->stmts); + if (!stmt_parse(stmt, p)) + return false; + if (token_is_kw(t->token, KW_RBRACE)) break; + if (t->token->kind == TOKEN_EOF) { + tokr_err(t, "Expected '}' to close function body."); + return false; + } + } + } + + t->token++; /* move past } */ + return true; +} + static bool fn_expr_parse(FnExpr *f, Parser *p) { Tokenizer *t = p->tokr; /* only called when token is fn */ @@ -191,24 +243,36 @@ static bool fn_expr_parse(FnExpr *f, Parser *p) { tokr_err(t, "Expected '(' after 'fn'."); return false; } + arr_create(&f->params, sizeof(Param)); t->token++; + if (!token_is_kw(t->token, KW_RPAREN)) { - tokr_err(t, "Expected ')' at end of parameter list."); - return false; - } - t->token++; - if (!token_is_kw(t->token, KW_LBRACE)) { - tokr_err(t, "Expected '{' to open function body."); - return false; + /* non-empty parameter list */ + while (1) { + Param *param = arr_add(&f->params); + if (!param_parse(param, p)) + return false; + if (token_is_kw(t->token, KW_RPAREN)) break; + if (token_is_kw(t->token, KW_COMMA)) { + t->token++; + continue; + } + tokr_err(t, "Expected ',' or ')' to continue or end parameter list."); + return false; + } } - t->token++; - if (!token_is_kw(t->token, KW_RBRACE)) { - tokr_err(t, "Expected '}' to close function body."); - return false; + + t->token++; /* move past ) */ + if (token_is_kw(t->token, KW_LBRACE)) { + /* void function */ + f->ret_type.kind = TYPE_VOID; + } else { + if (!type_parse(&f->ret_type, p)) { + return false; + } } - t->token++; - return true; + return block_parse(&f->body, p); } #define NOT_AN_OP -1 @@ -223,7 +287,7 @@ static int op_precedence(Keyword op) { } } -static bool expr_parse(Expression *e, Parser *p, Token *end) { +static bool expr_parse(Expression *e, Parser *p, Token *end) { Tokenizer *t = p->tokr; if (end == NULL) return false; e->flags = 0; @@ -264,6 +328,21 @@ static bool expr_parse(Expression *e, Parser *p, Token *end) { t->token = end; return true; } + if (token_is_kw(t->token, KW_FN)) { + /* this is a function */ + e->kind = EXPR_FN; + if (!fn_expr_parse(&e->fn, p)) { + t->token = end + 1; /* move token past end for further parsing */ + return false; + } + if (t->token != end) { + tokr_err(t, "Direct function calling in an expression is not supported yet."); + /* TODO */ + return false; + } + return true; + } + /* Find the lowest-precedence operator not in parentheses */ int paren_level = 0; int lowest_precedence = NOT_AN_OP; @@ -318,18 +397,7 @@ static bool expr_parse(Expression *e, Parser *p, Token *end) { } if (lowest_precedence == NOT_AN_OP) { /* function calls, array accesses, etc. */ - if (token_is_kw(t->token, KW_FN)) { - /* this is a function */ - e->kind = EXPR_FN; - if (!fn_expr_parse(&e->fn, p)) - return false; - if (t->token != end) { - tokr_err(t, "Direct function calling in an expression is not supported yet."); - /* TODO */ - return false; - } - return true; - } + tokr_err(t, "Not implemented yet."); return false; } @@ -408,34 +476,64 @@ typedef enum { } ExprEndKind; static Token *expr_find_end(Parser *p, ExprEndKind ends_with) { Tokenizer *t = p->tokr; - long bracket_level = 0; + int bracket_level = 0; + int brace_level = 0; Token *token = t->token; while (1) { switch (ends_with) { case EXPR_END_RPAREN_OR_COMMA: if (token->kind == TOKEN_KW) { - if (token->kw == KW_COMMA && bracket_level == 0) - return token; - if (token->kw == KW_LPAREN) + switch (token->kw) { + case KW_COMMA: + if (bracket_level == 0) + return token; + break; + case KW_LPAREN: bracket_level++; - if (token->kw == KW_RPAREN) { + break; + case KW_RPAREN: bracket_level--; - if (bracket_level == 0) { + if (bracket_level == 0) return token; - } + break; + default: break; } } break; case EXPR_END_SEMICOLON: - if (token_is_kw(token, KW_SEMICOLON)) - return token; + if (token->kind == TOKEN_KW) { + switch (token->kw) { + case KW_SEMICOLON: + /* ignore semicolons inside braces {} */ + if (brace_level == 0) + return token; + break; + case KW_LBRACE: + brace_level++; + break; + case KW_RBRACE: + brace_level--; + if (brace_level < 0) { + t->token = token; + tokr_err(t, "Closing '}' without matching opening '{'."); + return NULL; + } + break; + default: break; + } + } break; } if (token->kind == TOKEN_EOF) { switch (ends_with) { case EXPR_END_SEMICOLON: - tokr_err(t, "Could not find ';' at end of expression."); - return NULL; + if (brace_level > 0) { + tokr_err(t, "Opening brace was never closed."); /* FEATURE: Find out where this is */ + return NULL; + } else { + tokr_err(t, "Could not find ';' at end of expression."); + return NULL; + } case EXPR_END_RPAREN_OR_COMMA: if (bracket_level > 0) { tokr_err(t, "Opening parenthesis was never closed."); /* FEATURE: Find out where this is */ @@ -444,7 +542,6 @@ static Token *expr_find_end(Parser *p, ExprEndKind ends_with) { tokr_err(t, "Could not find ')' or ',' at end of expression."); return NULL; } - return NULL; } } token++; @@ -550,6 +647,49 @@ static bool file_parse(ParsedFile *f, Parser *p) { #define PARSE_PRINT_LOCATION(l) //fprintf(out, "[l%lu]", (unsigned long)(l).line); + +static void type_fprint(FILE *out, Type *t) { + PARSE_PRINT_LOCATION(t->where); + switch (t->kind) { + case TYPE_BUILTIN: + fprintf(out, "%s", keywords[builtin_type_to_kw(t->builtin)]); + break; + case TYPE_VOID: + fprintf(out, "void"); + break; + } +} + +static void param_fprint(FILE *out, Param *p) { + ident_fprint(out, p->name); + fprintf(out, ": "); + type_fprint(out, &p->type); +} + +static void stmt_fprint(FILE *out, Statement *s); + +static void block_fprint(FILE *out, Block *b) { + fprintf(out, "{\n"); + arr_foreach(&b->stmts, Statement, stmt) { + stmt_fprint(out, stmt); + } + fprintf(out, "}"); + +} + +static void fn_expr_fprint(FILE *out, FnExpr *f) { + fprintf(out, "fn ("); + arr_foreach(&f->params, Param, param) { + if (param != f->params.data) + fprintf(out, ", "); + param_fprint(out, param); + } + fprintf(out, ") "); + type_fprint(out, &f->ret_type); + fprintf(out, " "); + block_fprint(out, &f->body); +} + static void expr_fprint(FILE *out, Expression *e) { PARSE_PRINT_LOCATION(e->where); switch (e->kind) { @@ -588,19 +728,11 @@ static void expr_fprint(FILE *out, Expression *e) { fprintf(out, ")"); break; case EXPR_FN: - fprintf(out, "function!"); + fn_expr_fprint(out, &e->fn); break; } } -static void type_fprint(FILE *out, Type *t) { - PARSE_PRINT_LOCATION(t->where); - switch (t->kind) { - case TYPE_BUILTIN: - fprintf(out, "%s", keywords[builtin_type_to_kw(t->builtin)]); - break; - } -} static void decl_fprint(FILE *out, Declaration *d) { PARSE_PRINT_LOCATION(d->where); diff --git a/test.toc b/test.toc index 3cccd6d..986b13a 100644 --- a/test.toc +++ b/test.toc @@ -1,4 +1,8 @@ -x :- 3 + 4 - (3 + ((-3--b-5)+6++8)---+a+-4); main :- fn () { + bar := fn (x: int, y: int, z: float) float { -}; + foo :- fn () { + x:=7+y; + }; + }; +}; \ No newline at end of file diff --git a/util/blockarr.c b/util/blockarr.c index bcd42fa..ea333df 100644 --- a/util/blockarr.c +++ b/util/blockarr.c @@ -8,7 +8,7 @@ typedef struct { void *data; size_t n; /* number of things in this block so far */ void *last; /* last one of them */ -} Block; +} ArrBlock; typedef struct { size_t item_sz; @@ -22,15 +22,15 @@ Note: the block size must be a power of 2, to use right shifting instead of divi (for optimization)! */ void block_arr_create(BlockArr *arr, int lg_block_sz, size_t item_sz) { - arr_create(&arr->blocks, sizeof(Block)); + arr_create(&arr->blocks, sizeof(ArrBlock)); arr->item_sz = item_sz; arr->lg_block_sz = lg_block_sz; } void *block_arr_add(BlockArr *arr) { if (arr->blocks.data == NULL || - (unsigned long)((Block*)arr->blocks.last)->n >= (1UL << arr->lg_block_sz)) { - Block *block; + (unsigned long)((ArrBlock*)arr->blocks.last)->n >= (1UL << arr->lg_block_sz)) { + ArrBlock *block; /* no blocks yet / ran out of blocks*/ block = arr_add(&arr->blocks); block->data = malloc(arr->item_sz << arr->lg_block_sz); @@ -38,7 +38,7 @@ void *block_arr_add(BlockArr *arr) { block->last = block->data; return block->data; } else { - Block *last_block; + ArrBlock *last_block; last_block = arr->blocks.last; last_block->last = (char*)last_block->last + arr->item_sz; return last_block->last; @@ -51,7 +51,7 @@ void *block_arr_add(BlockArr *arr) { /* } */ void block_arr_free(BlockArr *arr) { - arr_foreach(&arr->blocks, Block, block) { + arr_foreach(&arr->blocks, ArrBlock, block) { free(block->data); } arr_free(&arr->blocks); -- cgit v1.2.3