diff options
-rw-r--r-- | cgen.c | 37 | ||||
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | out.c | 3 | ||||
-rw-r--r-- | parse.c | 11 | ||||
-rw-r--r-- | test.toc | 4 | ||||
-rw-r--r-- | types.c | 97 | ||||
-rw-r--r-- | util/arr.c | 1 |
8 files changed, 112 insertions, 43 deletions
@@ -35,6 +35,9 @@ static bool cgen_expr(CGenerator *g, Expression *e) { case BINARY_AT_INDEX: cgen_write(g, "["); break; + case BINARY_COMMA: + assert(0); + return false; } if (!cgen_expr(g, e->binary.rhs)) return false; if (e->binary.op == BINARY_AT_INDEX) { @@ -100,25 +103,45 @@ static void cgen_zero_value(CGenerator *g, Type *t) { } static bool cgen_decl(CGenerator *g, Declaration *d) { - arr_foreach(&d->idents, Identifier, ident) { - cgen_type_pre(g, &d->type); - if (d->flags & DECL_FLAG_CONST) { + size_t i = d->idents.len; + Expression *expr = &d->expr; + /* because , is left-associative, we want to go backwards */ + arr_foreach_reverse(&d->idents, Identifier, ident) { + Type *type; + if (d->type.kind == TYPE_TUPLE) { + /* it's a tuple! */ + type = &(((Type*)d->type.tuple.data)[--i]); + } else { + type = &d->type; + } + cgen_type_pre(g, type); + if (d->flags & DECL_FLAG_CONST) { /* TODO: remove this */ cgen_write_space(g); cgen_write(g, "const"); cgen_write_space(g); } cgen_ident(g, *ident, NULL); - cgen_type_post(g, &d->type); + cgen_type_post(g, type); cgen_write_space(g); cgen_write(g, "="); if (d->flags & DECL_FLAG_HAS_EXPR) { cgen_write_space(g); - if (!cgen_expr(g, &d->expr)) { - return false; + + if (d->type.kind == TYPE_TUPLE) { + if (expr->kind == EXPR_BINARY_OP && expr->binary.op == BINARY_COMMA) { + if (!cgen_expr(g, expr->binary.rhs)) return false; + expr = expr->binary.lhs; /* ((3,4),5),6 => (3,4),5 */ + } else { + /* last iteration */ + if (!cgen_expr(g, expr)) return false; + } + + } else { + if (!cgen_expr(g, expr)) return false; } } else { cgen_write_space(g); - cgen_zero_value(g, &d->type); + cgen_zero_value(g, type); } cgen_write(g, "; "); } @@ -56,6 +56,7 @@ static bool eval_expr_as_int(Expression *e, Integer *i) { } } case BINARY_SET: + case BINARY_COMMA: err_print(e->where, "Expected operator which returns an integer, but got %s", binary_op_to_str(e->binary.op)); return false; case BINARY_AT_INDEX: @@ -1,4 +1,3 @@ -/* TODO: don't allow setting things to void */ /* TODO: don't eval consts in C */ /* TODO: array assignment (x : [3]int = y;) */ /* TODO: Functions returning fixed-length arrays */ @@ -2,8 +2,7 @@ /* toc */ void main__(void) { - float foo = 3; float bar = 3; - float abc = bar; + int64_t salkdfj = 123; float something = 6.320000; int64_t baz = 5; int64_t bar = 4; int64_t foo = 3; } int main(void) { @@ -80,6 +80,7 @@ typedef enum { BINARY_SET, /* e.g. x = y */ BINARY_PLUS, BINARY_MINUS, + BINARY_COMMA, BINARY_AT_INDEX /* e.g. x[i] */ } BinaryOp; @@ -154,6 +155,7 @@ static const char *binary_op_to_str(BinaryOp b) { case BINARY_PLUS: return "+"; case BINARY_MINUS: return "-"; case BINARY_SET: return "="; + case BINARY_COMMA: return ","; case BINARY_AT_INDEX: return "[]"; } assert(0); @@ -292,6 +294,8 @@ static int op_precedence(Keyword op) { switch (op) { case KW_EQ: return 0; + case KW_COMMA: + return 5; case KW_PLUS: return 10; case KW_MINUS: @@ -869,6 +873,9 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { case KW_EQ: op = BINARY_SET; break; + case KW_COMMA: + op = BINARY_COMMA; + break; default: assert(0); break; } e->binary.op = op; @@ -982,6 +989,7 @@ static bool parse_single_type_in_decl(Parser *p, Declaration *d) { if (d->type.kind != TYPE_VOID) { *(Type*)arr_add(&tup_arr) = d->type; /* add current type */ } + d->type.flags = 0; d->type.kind = TYPE_TUPLE; d->type.tuple = tup_arr; for (size_t i = 0; i < n_idents_with_this_type; i++) { @@ -1197,6 +1205,9 @@ static void fprint_expr(FILE *out, Expression *e) { case BINARY_AT_INDEX: fprintf(out, "at"); break; + case BINARY_COMMA: + fprintf(out, "tuple"); + break; } fprintf(out, "("); fprint_expr(out, e->binary.lhs); @@ -1,5 +1,3 @@ main @= fn() { - foo , bar, basdf, asdf,ksdja ,dfa : int, kasjdfk, dasfjkfha , sdf, sad : fn() = 3; - x,y,z:int=3,3,3; - abc := bar; + foo, bar, baz : int, something : float, salkdfj : int = 3, 4, 5, 6.32, 123; }; @@ -134,12 +134,50 @@ static bool expr_must_lval(Expression *e) { } static bool type_of_expr(Expression *e, Type *t); -static bool type_of_decl(Declaration *d, Type *t) { +static bool type_of_ident(Location where, Identifier i, Type *t, bool allow_use_before_decl) { + IdentDecl *decl = ident_decl(i); + if (!decl) { + char *s = ident_to_str(i); + err_print(where, "Undeclared identifier: %s", s); + free(s); + return false; + } + Declaration *d = decl->decl; + if (!allow_use_before_decl) { + /* TODO: Check self-referential declarations */ + if (d->where.code > where.code) { + char *s = ident_to_str(i); + err_print(where, "Use of identifier %s before its declaration.", s); + info_print(d->where, "%s will be declared here.", s); + free(s); + return false; + } + } + + /* OPTIM: you don't always need to do so much copying */ + Type decl_type; if (d->flags & DECL_FLAG_ANNOTATES_TYPE) { - *t = d->type; - return true; + decl_type = d->type; } else { - return type_of_expr(&d->expr, t); + if (!type_of_expr(&d->expr, &decl_type)) + return false; + } + + if (d->idents.len > 1) { + /* it's a tuple! */ + + arr_foreach(&d->idents, Identifier, decl_i) { + if (*decl_i == i) { + long index = (long)(decl_i - (Identifier*)d->idents.data); + *t = ((Type*)d->type.tuple.data)[index]; + return true; + } + } + assert(0); + return false; + } else { + *t = decl_type; + return true; } } @@ -170,23 +208,7 @@ static bool type_of_expr(Expression *e, Type *t) { t->flags |= TYPE_FLAG_FLEXIBLE; break; case EXPR_IDENT: { - IdentDecl *decl = ident_decl(e->ident); - if (!decl) { - char *s = ident_to_str(e->ident); - err_print(e->where, "Undeclared identifier: %s", s); - free(s); - return false; - } - Declaration *d = decl->decl; - /* TODO: Check self-referential declarations but allow f @= fn() { foo := f; foo(); } */ - if (d->where.code > e->where.code) { - char *s = ident_to_str(e->ident); - err_print(e->where, "Use of identifier %s before its declaration.", s); - info_print(d->where, "%s will be declared here.", s); - free(s); - return false; - } - if (!type_of_decl(d, t)) return false; + if (!type_of_ident(e->where, e->ident, t, false)) return false; } break; case EXPR_CALL: { @@ -194,15 +216,7 @@ static bool type_of_expr(Expression *e, Type *t) { Type fn_type; if (f->kind == EXPR_IDENT) { /* allow calling a function before declaring it */ - IdentDecl *id_decl = ident_decl(f->ident); - if (!id_decl) { - char *s = ident_to_str(e->ident); - err_print(e->where, "Undeclared identifier: %s", s); - free(s); - } - Declaration *d = id_decl->decl; - if (!type_of_decl(d, &fn_type)) return false; - + if (!type_of_ident(e->where, e->ident, t, true)) return false; } else { if (!type_of_expr(f, &fn_type)) return false; } @@ -299,6 +313,28 @@ static bool type_of_expr(Expression *e, Type *t) { } *t = *lhs_type->arr.of; break; + case BINARY_COMMA: { + t->kind = TYPE_TUPLE; + Array *tup_types = &t->tuple; + arr_create(tup_types, sizeof(Type)); + if (lhs_type->kind == TYPE_TUPLE) { + /* tuple, x => tuple */ + arr_foreach(&lhs_type->tuple, Type, child) { + *(Type*)arr_add(tup_types) = *child; + } + } else { + *(Type*)arr_add(tup_types) = *lhs_type; + } + + if (rhs_type->kind == TYPE_TUPLE) { + /* x, tuple => tuple */ + arr_foreach(&rhs_type->tuple, Type, child) { + *(Type*)arr_add(tup_types) = *child; + } + } else { + *(Type*)arr_add(tup_types) = *rhs_type; + } + } break; } } break; } @@ -365,6 +401,7 @@ static bool types_decl(Declaration *d) { if (d->flags & DECL_FLAG_FOUND_TYPE) return true; if (d->flags & DECL_FLAG_ANNOTATES_TYPE) { /* type supplied */ + assert(d->type.kind != TYPE_VOID); /* there's no way to annotate void */ if (!type_resolve(&d->type)) return false; } @@ -52,3 +52,4 @@ static void arr_free(Array *arr) { } #define arr_foreach(arr, type, var) for (type *var = (arr)->data, *var##_foreach_last = arr_last(arr); var; var == var##_foreach_last ? var = NULL : var++) +#define arr_foreach_reverse(arr, type, var) for (type *var = arr_last(arr); var; var == (arr)->data ? var = NULL : var--) |