From 8b31f7583aa6fc1853a0124077e704a58998e82a Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sat, 26 Oct 2019 18:44:59 -0400 Subject: started newtype --- abbrevs.txt | 1 + cgen.c | 9 +++++++ parse.c | 79 +++++++++++++++++++++++++++++++++++-------------------------- test.toc | 20 ++-------------- tokenizer.c | 23 +++++++++++++++++- types.h | 12 ++++++++-- 6 files changed, 90 insertions(+), 54 deletions(-) diff --git a/abbrevs.txt b/abbrevs.txt index d694268..1075c21 100644 --- a/abbrevs.txt +++ b/abbrevs.txt @@ -20,5 +20,6 @@ ptr - pointer ret - return stmt - statement str - string +tdecl - type declaration tokr - tokenizer val - value diff --git a/cgen.c b/cgen.c index aede98d..6ba6cad 100644 --- a/cgen.c +++ b/cgen.c @@ -1260,6 +1260,15 @@ static bool cgen_stmt(CGenerator *g, Statement *s) { cgen_write(g, ";"); cgen_nl(g); break; + case STMT_TDECL: + cgen_write(g, "typedef "); + if (!cgen_type_pre(g, &s->tdecl.type, s->where)) return false; + cgen_write(g, " "); + cgen_ident(g, s->tdecl.name); + if (!cgen_type_post(g, &s->tdecl.type, s->where)) return false; + cgen_write(g, ";"); + cgen_nl(g); + break; case STMT_RET: if (!cgen_ret(g, s->ret.flags & RET_FLAG_EXPR ? &s->ret.expr : NULL)) return false; diff --git a/parse.c b/parse.c index a8ffa93..c3a0694 100644 --- a/parse.c +++ b/parse.c @@ -1,5 +1,5 @@ static bool parse_expr(Parser *p, Expression *e, Token *end); - +static bool parse_stmt(Parser *p, Statement *s); #define PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR 0x01 static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags); @@ -237,7 +237,7 @@ static inline Expression *parser_new_expr(Parser *p) { #define EXPR_CAN_END_WITH_LBRACE 0x02 #define EXPR_CAN_END_WITH_COLON 0x04 /* is_vbs can be NULL */ -static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) { +static Token *expr_find_end(Parser *p, U16 flags, bool *is_vbs) { Tokenizer *t = p->tokr; int paren_level = 0; int brace_level = 0; @@ -459,7 +459,6 @@ static bool parse_type(Parser *p, Type *type) { } -static bool parse_stmt(Parser *p, Statement *s); static bool parse_block(Parser *p, Block *b) { b->flags = 0; @@ -1304,7 +1303,6 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_ Tokenizer *t = p->tokr; d->flags = 0; - /* OPTIM: Maybe don't use a dynamic array or use parser allocator. */ while (1) { Identifier *ident = parser_arr_add(p, &d->idents); if (t->token->kind != TOKEN_IDENT) { @@ -1391,12 +1389,7 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_ ret_false: /* move past end of decl */ - while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_SEMICOLON)) { - t->token++; - } - if (token_is_kw(t->token, KW_SEMICOLON)) { - t->token++; /* move past ; */ - } + tokr_skip_semicolon(t); return false; } @@ -1419,30 +1412,46 @@ static bool parse_stmt(Parser *p, Statement *s) { if (t->token->kind == TOKEN_EOF) tokr_err(t, "Expected statement."); s->where = t->token->where; - - if (token_is_kw(t->token, KW_RETURN)) { - s->kind = STMT_RET; - t->token++; - s->ret.flags = 0; - if (token_is_kw(t->token, KW_SEMICOLON)) { - /* return with no expr */ + if (t->token->kind == TOKEN_KW) { + switch (t->token->kw) { + case KW_RETURN: { + s->kind = STMT_RET; t->token++; - return true; - } - s->ret.flags |= RET_FLAG_EXPR; - Token *end = expr_find_end(p, 0, NULL); - if (!end) { - while (t->token->kind != TOKEN_EOF) t->token++; /* move to end of file */ - return false; + s->ret.flags = 0; + if (token_is_kw(t->token, KW_SEMICOLON)) { + /* return with no expr */ + t->token++; + return true; + } + s->ret.flags |= RET_FLAG_EXPR; + Token *end = expr_find_end(p, 0, NULL); + if (!end) { + while (t->token->kind != TOKEN_EOF) t->token++; /* move to end of file */ + return false; + } + if (!token_is_kw(end, KW_SEMICOLON)) { + err_print(end->where, "Expected ';' at end of return statement."); + t->token = end->kind == TOKEN_EOF ? end : end + 1; + return false; + } + bool success = parse_expr(p, &s->ret.expr, end); + t->token = end + 1; + return success; } - if (!token_is_kw(end, KW_SEMICOLON)) { - err_print(end->where, "Expected ';' at end of return statement."); - t->token = end->kind == TOKEN_EOF ? end : end + 1; - return false; + case KW_NEWTYPE: + s->kind = STMT_TDECL; + t->token++; + if (t->token->kind != TOKEN_IDENT) { + tokr_err(t, "Expected identifier after \"newtype\"."); + tokr_skip_semicolon(t); + } + s->tdecl.name = t->token->ident; + t->token++; + if (!parse_type(p, &s->tdecl.type)) + return false; + return true; + default: break; } - bool success = parse_expr(p, &s->ret.expr, end); - t->token = end + 1; - return success; } if (is_decl(t)) { s->kind = STMT_DECL; @@ -1695,9 +1704,7 @@ static void fprint_stmt(FILE *out, Statement *s) { PARSE_PRINT_LOCATION(s->where); if (s->flags & STMT_FLAG_VOIDED_EXPR) fprintf(out, "(void)"); - switch (s->kind) { - case STMT_DECL: fprint_decl(out, &s->decl); fprintf(out, ";\n"); @@ -1712,6 +1719,12 @@ static void fprint_stmt(FILE *out, Statement *s) { fprint_expr(out, &s->ret.expr); fprintf(out, ";\n"); break; + case STMT_TDECL: + fprintf(out, "newtype "); + fprint_ident(out, s->tdecl.name); + fprintf(out, " "); + fprint_type(out, &s->tdecl.type); + break; } } diff --git a/test.toc b/test.toc index b9c1909..0304979 100644 --- a/test.toc +++ b/test.toc @@ -13,24 +13,8 @@ putf @= fn(x: float) { "); }; -foo @= fn() [3]int { - x : [3]int; - x[0] = 1; - x[1] = 2; - x[2] = 3; - x -}; - -getASDF @= fn(i: int) int { - ASDF @= foo(); - ASDF[i] -}; +newtype Foo int main @= fn() { - // ptriangle @= pascal(); - // puti(ptriangle[49][25]); - puti(getASDF(2)); - puti(getASDF(1)); - puti(getASDF(0)); - + // x : Foo; }; diff --git a/tokenizer.c b/tokenizer.c index 2e6bb4d..315379d 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -3,7 +3,7 @@ static const char *keywords[KW_COUNT] = "+", "-", "*", "!", "&", "/", "=", "if", "elif", "else", "while", "return", "fn", "as", - "new", "del", + "new", "del", "newtype", "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "f32", "f64", "char", "bool", "true", "false"}; @@ -490,6 +490,27 @@ static bool tokenize_string(Tokenizer *t, char *str) { return !has_err; } +/* + skip to one token past the next semicolon not in braces (or the end of the file). +*/ +static void tokr_skip_semicolon(Tokenizer *t) { + int brace_level = 0; + while (t->token->kind != TOKEN_EOF) { + if (t->token->kind == TOKEN_KW) switch (t->token->kw) { + case KW_LBRACE: brace_level++; break; + case KW_RBRACE: brace_level--; break; + case KW_SEMICOLON: + if (brace_level == 0) { + t->token++; + return; + } + break; + default: break; + } + t->token++; + } +} + /* ONLY frees tokens, not string literals. You can call this followed by tokr_free. */ static void tokr_free_tokens(Tokenizer *t) { arr_clear(&t->tokens); diff --git a/types.h b/types.h index 2d4e7e4..537c845 100644 --- a/types.h +++ b/types.h @@ -169,6 +169,7 @@ typedef enum { KW_AS, KW_NEW, KW_DEL, + KW_NEWTYPE, KW_INT, KW_I8, KW_I16, @@ -470,7 +471,8 @@ typedef struct Declaration { typedef enum { STMT_DECL, STMT_EXPR, - STMT_RET + STMT_RET, + STMT_TDECL } StatementKind; #define RET_FLAG_EXPR 0x01 @@ -479,12 +481,18 @@ typedef struct { Expression expr; } Return; +typedef struct { + Identifier name; + Type type; +} TypeDecl; + #define STMT_FLAG_VOIDED_EXPR 0x01 /* the "4;" in fn () { 4; } is a voided expression, but the "4" in fn () int { 4 } is not */ typedef struct Statement { Location where; StatementKind kind; - unsigned short flags; + U16 flags; union { + TypeDecl tdecl; Declaration decl; Expression expr; Return ret; -- cgit v1.2.3