diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-27 16:41:45 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-27 16:41:45 -0400 |
commit | 010e0cc777e77e0668e0b9d1acb5859f8c2a364c (patch) | |
tree | bb1f8635035aba71bd2e784451730f59f83367f1 | |
parent | d795c15a008a89aa2de86f83f7b01d996757fdbe (diff) |
started to add named return values
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | parse.c | 89 | ||||
-rw-r--r-- | test.toc | 8 | ||||
-rw-r--r-- | tokenizer.c | 24 | ||||
-rw-r--r-- | types.c | 11 | ||||
-rw-r--r-- | util/err.c | 22 | ||||
-rw-r--r-- | util/location.c | 1 |
7 files changed, 103 insertions, 55 deletions
@@ -39,11 +39,10 @@ int main(int argc, char **argv) { } fclose(in); - err_filename = in_filename; Identifiers file_idents; idents_create(&file_idents); Tokenizer t; - tokr_create(&t, &file_idents); + tokr_create(&t, &file_idents, in_filename); if (!tokenize_string(&t, contents)) { err_fprint(TEXT_IMPORTANT("Errors occured while preprocessing.\n")); return EXIT_FAILURE; @@ -124,6 +124,7 @@ typedef struct { typedef struct { Array params; /* declarations of the parameters to this function */ + Array ret_decls; /* array of decls, if this has named return values. otherwise, len & data will be 0. */ Type ret_type; Block body; } FnExpr; /* an expression such as fn(x: int) int { 2 * x } */ @@ -217,13 +218,14 @@ typedef struct { typedef enum { DECL_END_SEMICOLON, - DECL_END_RPAREN_COMMA -} DeclEndType; + DECL_END_RPAREN_COMMA, + DECL_END_LBRACE_COMMA +} DeclEndKind; static bool parse_expr(Parser *p, Expression *e, Token *end); #define PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR 0x01 -static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_t flags); +static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags); static const char *unary_op_to_str(UnaryOp u) { switch (u) { @@ -655,8 +657,33 @@ static bool parse_block(Parser *p, Block *b) { return ret; } +static bool is_decl(Tokenizer *t); + +static bool parse_decl_list(Parser *p, Array *decls, DeclEndKind decl_end) { + Tokenizer *t = p->tokr; + bool ret = true; + bool first = true; + while (t->token->kind != TOKEN_EOF && + (first || ( + !token_is_kw(t->token - 1, KW_RPAREN) && + !token_is_kw(t->token - 1, KW_LBRACE)))) { + first = false; + Declaration *decl = arr_add(decls); + if (!parse_decl(p, decl, decl_end, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR)) { + ret = false; + /* skip to end of param list */ + while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_RPAREN)) + t->token++; + break; + } + } + return ret; +} + static bool parse_fn_expr(Parser *p, FnExpr *f) { Tokenizer *t = p->tokr; + f->ret_decls.len = 0; + f->ret_decls.data = NULL; /* only called when token is fn */ assert(token_is_kw(t->token, KW_FN)); t->token++; @@ -670,16 +697,8 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { if (token_is_kw(t->token, KW_RPAREN)) { t->token++; } else { - while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token - 1, KW_RPAREN)) { - Declaration *decl = arr_add(&f->params); - if (!parse_decl(p, decl, DECL_END_RPAREN_COMMA, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR)) { - ret = false; - /* skip to end of param list */ - while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_RPAREN)) - t->token++; - break; - } - } + if (!parse_decl_list(p, &f->params, DECL_END_RPAREN_COMMA)) + return false; } if (t->token->kind == TOKEN_EOF) { @@ -691,6 +710,25 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { /* void function */ f->ret_type.kind = TYPE_VOID; f->ret_type.flags = 0; + } else if (is_decl(t)) { + arr_create(&f->ret_decls, sizeof(Declaration)); + if (!parse_decl_list(p, &f->ret_decls, DECL_END_LBRACE_COMMA)) + return false; + t->token--; /* move back to { */ + assert(f->ret_decls.len); + if (f->ret_decls.len > 1 || ((Declaration *)f->ret_decls.data)[0].idents.len) { + f->ret_type.kind = TYPE_TUPLE; + f->ret_type.flags = 0; + arr_create(&f->ret_type.tuple, sizeof(Type)); + arr_foreach(&f->ret_decls, Declaration, decl) { + for (size_t i = 0; i < decl->idents.len; i++) { + Type *tuple_type = arr_add(&f->ret_type.tuple); + *tuple_type = decl->type; + } + } + } else { + f->ret_type = ((Declaration *)f->ret_decls.data)[0].type; + } } else { if (!parse_type(p, &f->ret_type)) { ret = false; @@ -735,17 +773,17 @@ static void fprint_expr(FILE *out, Expression *e); #define NOT_AN_OP -1 -#define CAST_PRECEDENCE 1 +#define CAST_PRECEDENCE 2 static int op_precedence(Keyword op) { switch (op) { case KW_EQ: return 0; + case KW_COMMA: return 1; case KW_LT: return 3; case KW_GT: return 3; case KW_LE: return 3; case KW_GE: return 3; case KW_EQEQ: return 3; case KW_NE: return 3; - case KW_COMMA: return 5; case KW_PLUS: return 10; case KW_MINUS: return 20; case KW_AMPERSAND: return 25; @@ -1246,18 +1284,20 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { } } -static inline bool ends_decl(Token *t, DeclEndType ends_with) { +static inline bool ends_decl(Token *t, DeclEndKind ends_with) { if (t->kind != TOKEN_KW) return false; switch (ends_with) { case DECL_END_SEMICOLON: return t->kw == KW_SEMICOLON; case DECL_END_RPAREN_COMMA: return t->kw == KW_RPAREN || t->kw == KW_COMMA; + case DECL_END_LBRACE_COMMA: + return t->kw == KW_LBRACE || t->kw == KW_COMMA; default: assert(0); return false; } } -static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_t flags) { +static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags) { d->val = NULL; d->where = p->tokr->token->where; arr_create(&d->idents, sizeof(Identifier)); @@ -1305,8 +1345,13 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_ } d->type = type; } - char end_char = ends_with == DECL_END_SEMICOLON ? ';' : ')'; - + const char *end_str; + switch (ends_with) { + case DECL_END_SEMICOLON: end_str = "';'"; break; + case DECL_END_RPAREN_COMMA: end_str = "')' or ','"; break; + case DECL_END_LBRACE_COMMA: end_str = "'{' or ','"; break; + } + if (token_is_kw(t->token, KW_EQ)) { t->token++; d->flags |= DECL_FLAG_HAS_EXPR; @@ -1315,7 +1360,7 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_ expr_flags |= EXPR_CAN_END_WITH_COMMA; Token *end = expr_find_end(p, expr_flags, NULL); if (!end || !ends_decl(end, ends_with)) { - tokr_err(t, "Expected '%c' at end of declaration.", end_char); + tokr_err(t, "Expected %s at end of declaration.", end_str); goto ret_false; } if (!parse_expr(p, &d->expr, end)) { @@ -1325,13 +1370,13 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_ if (ends_decl(t->token, ends_with)) { t->token++; } else { - tokr_err(t, "Expected '%c' at end of declaration.", end_char); + tokr_err(t, "Expected %s at end of declaration.", end_str); goto ret_false; } } else if (ends_decl(t->token, ends_with)) { t->token++; } else { - tokr_err(t, "Expected '%c' or '=' at end of delaration.", end_char); + tokr_err(t, "Expected %s or '=' at end of delaration.", end_str); goto ret_false; } @@ -1,10 +1,6 @@ main @= fn() { - // b := !(5 > 3 && 4 <= 3 && 3 >= 2 || 0 == 1 || 5 != 3); - N, M @= 2; - foo := 3; - bar : float = foo as float; - test @= fn(x : i64, y : i32, z,w: i64) i32 { - x + (y as i64) + z + w + x as i32 + test @= fn(x : i64, y : i32, z,w: i64) ret1 : i64, ret2 : i64 { + ret1 = x; }; }; diff --git a/tokenizer.c b/tokenizer.c index 02194c5..0ed7f5a 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -151,6 +151,7 @@ typedef struct { typedef struct { Array tokens; char *s; /* string being parsed */ + const char *filename; LineNo line; Token *token; /* token currently being processed */ Identifiers *idents; @@ -214,13 +215,6 @@ static void fprint_token(FILE *out, Token *t) { } } -static Token *tokr_add(Tokenizer *t) { - Token *token = arr_add(&t->tokens); - token->where.line = t->line; - token->where.code = t->s; - return token; -} - static inline void tokr_nextchar(Tokenizer *t) { if (*(t->s) == '\n') { t->line++; @@ -252,7 +246,7 @@ static char tokr_esc_seq(Tokenizer *t) { /* to be used during tokenization */ static void tokenization_err(Tokenizer *t, const char *fmt, ...) { va_list args; - Location where = {t->line, t->s}; + Location where = {t->line, t->s, t->filename}; va_start(args, fmt); err_vprint(where, fmt, args); va_end(args); @@ -279,6 +273,7 @@ static void tokr_err_(const char *src_file, int src_line, Tokenizer *t, const ch static void tokr_put_location(Tokenizer *tokr, Token *t) { t->where.line = tokr->line; t->where.code = tokr->s; + t->where.filename = tokr->filename; } static void tokr_get_location(Tokenizer *tokr, Token *t) { @@ -286,10 +281,17 @@ static void tokr_get_location(Tokenizer *tokr, Token *t) { tokr->s = t->where.code; } -static void tokr_create(Tokenizer *t, Identifiers *idents) { +static void tokr_create(Tokenizer *t, Identifiers *idents, const char *filename) { arr_create(&t->tokens, sizeof(Token)); arr_reserve(&t->tokens, 256); t->idents = idents; + t->filename = filename; +} + +static Token *tokr_add(Tokenizer *t) { + Token *token = arr_add(&t->tokens); + tokr_put_location(t, token); + return token; } static bool tokenize_string(Tokenizer *t, char *str) { @@ -350,7 +352,7 @@ static bool tokenize_string(Tokenizer *t, char *str) { if (direct != DIRECT_COUNT) { /* it's a directive */ Token *token = tokr_add(t); - token->where.line = t->line; + tokr_put_location(t, token); token->where.code = start_s; token->kind = TOKEN_DIRECT; token->direct = direct; @@ -367,7 +369,7 @@ static bool tokenize_string(Tokenizer *t, char *str) { if (kw != KW_COUNT) { /* it's a keyword */ Token *token = tokr_add(t); - token->where.line = t->line; + tokr_put_location(t, token); token->where.code = start_s; token->kind = TOKEN_KW; token->kw = kw; @@ -176,6 +176,9 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t) { *param_type = decl->type; } } + arr_foreach(&f->ret_decls, Declaration, decl) { + if (!types_decl(tr, decl)) return false; + } return true; } @@ -233,7 +236,9 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x @= fn() {}).", s); info_print(d->where, "%s will be declared here.", s); free(s); - } /* else, there should have been an error earlier */ + } else { + err_print(d->where, "Declaration type not found yet, even though it has passed.\nThis should not happen."); + } return false; } } @@ -320,10 +325,14 @@ static bool types_expr(Typer *tr, Expression *e) { tr->ret_type = t->fn.types.data; arr_foreach(&f->params, Declaration, decl) add_ident_decls(&f->body, decl); + arr_foreach(&f->ret_decls, Declaration, decl) + add_ident_decls(&f->body, decl); bool block_success = true; block_success = types_block(tr, &e->fn.body); arr_foreach(&f->params, Declaration, decl) remove_ident_decls(&f->body, decl); + arr_foreach(&f->ret_decls, Declaration, decl) + remove_ident_decls(&f->body, decl); if (!block_success) { success = false; goto fn_ret; @@ -21,10 +21,6 @@ static inline const char *ordinals(size_t x) { } } -/* file name of file being processed */ -/* TODO: remove this */ -static const char *err_filename; - /* Write directly to the error file */ static void err_fwrite(const void *data, size_t size, size_t n) { fwrite(data, size, n, stderr); @@ -41,16 +37,16 @@ static void err_vfprint(const char *fmt, va_list args) { vfprintf(stderr, fmt, args); } -static void err_print_header_(LineNo line) { - err_fprint(TEXT_ERROR("error:") " at line %lu of %s:\n", (unsigned long)line, err_filename); +static void err_print_header_(Location where) { + err_fprint(TEXT_ERROR("error:") " at line %lu of %s:\n", (unsigned long)where.line, where.filename); } -static void info_print_header_(LineNo line) { - err_fprint(TEXT_INFO("info:") " at line %lu of %s:\n", (unsigned long)line, err_filename); +static void info_print_header_(Location where) { + err_fprint(TEXT_INFO("info:") " at line %lu of %s:\n", (unsigned long)where.line, where.filename); } -static void warn_print_header_(LineNo line) { - err_fprint(TEXT_WARN("warning:") " at line %lu of %s:\n", (unsigned long)line, err_filename); +static void warn_print_header_(Location where) { + err_fprint(TEXT_WARN("warning:") " at line %lu of %s:\n", (unsigned long)where.line, where.filename); } static void err_print_footer_(const char *context) { @@ -70,7 +66,7 @@ static void err_print_footer_(const char *context) { static void err_vprint(Location where, const char *fmt, va_list args) { - err_print_header_(where.line); + err_print_header_(where); err_vfprint(fmt, args); err_print_footer_(where.code); } @@ -89,7 +85,7 @@ static void err_print_(int line, const char *file, Location where, const char *f static void info_print(Location where, const char *fmt, ...) { va_list args; va_start(args, fmt); - info_print_header_(where.line); + info_print_header_(where); err_vfprint(fmt, args); err_print_footer_(where.code); va_end(args); @@ -98,7 +94,7 @@ static void info_print(Location where, const char *fmt, ...) { static void warn_print(Location where, const char *fmt, ...) { va_list args; va_start(args, fmt); - warn_print_header_(where.line); + warn_print_header_(where); err_vfprint(fmt, args); err_print_footer_(where.code); va_end(args); diff --git a/util/location.c b/util/location.c index 9a8beb8..4b450ce 100644 --- a/util/location.c +++ b/util/location.c @@ -2,6 +2,7 @@ typedef uint32_t LineNo; typedef struct { LineNo line; char *code; + const char *filename; } Location; bool location_after(Location a, Location b) { /* a is after b? */ |