diff options
-rw-r--r-- | main.c | 6 | ||||
-rw-r--r-- | parse.c | 2 | ||||
-rw-r--r-- | std/io.toc | 16 | ||||
-rw-r--r-- | test.toc | 34 | ||||
-rw-r--r-- | types.c | 124 |
5 files changed, 120 insertions, 62 deletions
@@ -8,8 +8,6 @@ /* @TODO: -arr_add-val -test for use ... test used ret decls consider: don't do inference for function calls; get rid of was_expr -- now that we have struct params EXPR_IDENT should be a string before typing, also struct member accesses @@ -25,6 +23,9 @@ is there a problem where we can get TYPE_UNKNOWN in cgen, triggering an assert(0 -simple example, but maybe try other stuff: x := #C("5"); -also make sure you can't do x:#C("5"); local structs should not be named in C +make sure global slices work +allow use ??? if an error has already occurred +if something gets included into a namespace, and its typing fails, the namespace should still be of type namespace, not ??? make sure you can do a[i] where a is &[5]int or &[]char or something do we consistently handle x := &some_array_or_slice; x.len &void @@ -35,6 +36,7 @@ switch - #fallthrough enums unions +compile to a temp file, then move it if compilation succeeds --- switch to / add as an alternative: libffi X ::= newtype(int); or something @@ -55,7 +55,7 @@ static const char *expr_kind_to_str(ExprKind k) { case EXPR_IDENT: return "identifier"; case EXPR_SLICE: return "slice"; case EXPR_TYPE: return "type"; - case EXPR_VAL: return "value"; + case EXPR_VAL: return "constant value"; case EXPR_NMS: return "namespace"; } assert(0); @@ -2,16 +2,19 @@ putchar ::= #foreign("putchar", "libc.so.6") fn(#C int) #C int; toc_putchar ::= fn(x: char) { putchar(x as #C int); } +printf ::= #foreign("printf", "libc.so.6") fn(#C &"char const", #C ..) #C int; +writes ::= fn(x: []char) { + printf_strfmt := "%s\0"; + printf(&printf_strfmt[0], &x[0]); +} puts ::= fn(x: []char) { - for c := x { - toc_putchar(c); - } + writes(x); toc_putchar('\n'); } -puti ::= fn(x: int) { +writei ::= fn(x: int) { if x < 0 { toc_putchar('-'); // NOTE: don't do x = -x; here to make sure I64_MIN works @@ -31,5 +34,10 @@ puti ::= fn(x: int) { scan_digit /= 10; } } +} + +puti ::= fn(x: int) { + writei(x); toc_putchar('\n'); } + @@ -1,12 +1,34 @@ #include "std/io.toc", io; +#include "std/mem.toc", mem; + +use mem; main ::= fn() { - s ::= struct { - foo, e: int; - bar ::= 3; - baz: float; + Point ::= struct { + x: int; + y: int; + a ::= 3; + } + + use io; + + { + use p: Point; + use io; + x = 5; + puti(x); } - p: s; - io.puti(p["bar"]); + ps := news(Point, 5); + for use p, i := &ps { + x = i; + y = 2*i; + } + for use p := ps { + writei(x); + writes(" "); + writei(y); + puts(""); + } + dels(ps); } @@ -283,8 +283,11 @@ static Type *overriding_type(Type *a, Type *b) { return a; } -/* prints an error and returns false if the given expression is not an l-value */ -static Status expr_must_lval(Expression *e) { +/* +prints an error and returns false if the given expression is not an l-value +purpose is something like "take address of" +*/ +static Status expr_must_lval(Expression *e, char const *purpose) { /* NOTE: make sure you update eval when you change this */ switch (e->kind) { case EXPR_IDENT: { @@ -292,14 +295,14 @@ static Status expr_must_lval(Expression *e) { Declaration *d = i->decl; if (d->flags & DECL_IS_CONST) { char *istr = ident_to_str(i); - err_print(e->where, "Use of constant %s as a non-constant expression.", istr); + err_print(e->where, "Cannot %s constant %s.", purpose, istr); info_print(d->where, "%s was declared here.", istr); free(istr); return false; } if (type_is_builtin(&d->type, BUILTIN_VARARGS)) { char *istr = ident_to_str(i); - err_print(e->where, "varargs cannot be set or pointed to."); + err_print(e->where, "Cannot %s varargs.", purpose); info_print(d->where, "%s was declared here.", istr); free(istr); return false; @@ -310,7 +313,7 @@ static Status expr_must_lval(Expression *e) { if (e->unary.op == UNARY_DEREF) return true; if (e->unary.op == UNARY_LEN) { Type *of_type = &e->unary.of->type; - if (of_type->kind != TYPE_PTR && !expr_must_lval(e->unary.of)) { /* can't set length of a non-lvalue slice */ + if (of_type->kind != TYPE_PTR && !expr_must_lval(e->unary.of, purpose)) { /* can't set length of a non-lvalue slice */ return false; } @@ -318,12 +321,12 @@ static Status expr_must_lval(Expression *e) { || (of_type->kind == TYPE_PTR && of_type->kind == TYPE_SLICE); } - err_print(e->where, "Cannot use operator %s as l-value.", unary_op_to_str(e->unary.op)); + err_print(e->where, "Cannot %s operator %s.", purpose, unary_op_to_str(e->unary.op)); return false; case EXPR_BINARY_OP: switch (e->binary.op) { case BINARY_AT_INDEX: - if (!expr_must_lval(e->binary.lhs)) + if (!expr_must_lval(e->binary.lhs, purpose)) return false; if (type_is_builtin(&e->binary.lhs->type, BUILTIN_VARARGS)) { err_print(e->where, "Cannot set or take address of vararg."); @@ -333,17 +336,17 @@ static Status expr_must_lval(Expression *e) { case BINARY_DOT: return true; default: break; } - err_print(e->where, "Cannot use operator %s as l-value.", binary_op_to_str(e->binary.op)); + err_print(e->where, "Cannot %s operator %s.", purpose, binary_op_to_str(e->binary.op)); return false; case EXPR_TUPLE: /* x, y is an lval, but 3, "hello" is not. */ arr_foreach(e->tuple, Expression, x) { - if (!expr_must_lval(x)) + if (!expr_must_lval(x, purpose)) return false; } return true; default: { - err_print(e->where, "Cannot use %s as l-value.", expr_kind_to_str(e->kind)); + err_print(e->where, "Cannot %s %s.", purpose, expr_kind_to_str(e->kind)); return false; } } @@ -1524,6 +1527,46 @@ static bool fn_type_has_varargs(FnType *f) { return type_is_builtin(arr_last_ptr(f->types), BUILTIN_VARARGS); } +static Status expr_must_usable_(Expression *e) { + if (e->kind == EXPR_IDENT) return true; + if (e->kind == EXPR_BINARY_OP && e->binary.op == BINARY_DOT) + return expr_must_usable_(e->binary.lhs); + return false; +} + +static Status expr_must_usable(Expression *e) { + Type *t = &e->type; + if (t->kind != TYPE_STRUCT && !type_is_builtin(t, BUILTIN_NMS)) { + if (!(t->kind == TYPE_PTR && t->ptr->kind == TYPE_STRUCT)) { + char *str = type_to_str(&e->type); + err_print(e->where, "You cannot use something of type %s (only Namespaces and structs).", str); + free(str); + return false; + } + } + return expr_must_usable_(e); +} + + +static Status use_ident(Typer *tr, Identifier i, Type *t, Location where) { + /* add to uses */ + Use **usep; + if (tr->block) + usep = typer_arr_add_ptr(tr, tr->block->uses); + else + usep = typer_arr_add_ptr(tr, tr->uses); + Use *use = *usep = typer_calloc(tr, 1, sizeof *use); + Expression *used = &use->expr; + used->kind = EXPR_IDENT; + used->flags = EXPR_FOUND_TYPE; + used->type = *t; + used->ident = i; + used->where = where; + if (!expr_must_usable(used)) + return false; + return true; +} + static Status types_expr(Typer *tr, Expression *e) { if (e->flags & EXPR_FOUND_TYPE) return true; Type *t = &e->type; @@ -1575,7 +1618,7 @@ static Status types_expr(Typer *tr, Expression *e) { bool in_header = true;{ /* additional block because c++ */ ForExpr *fo = e->for_; Declaration *header = &fo->header; - + U32 is_range = fo->flags & FOR_IS_RANGE; typer_arr_add(tr, tr->in_decls, header); fo->body.uses = NULL; typer_block_enter(tr, &fo->body); @@ -1638,7 +1681,7 @@ static Status types_expr(Typer *tr, Expression *e) { construct_resolved_builtin_type(index_type, BUILTIN_I64); } - if (fo->flags & FOR_IS_RANGE) { + if (is_range) { if (!types_expr(tr, fo->range.from)) goto for_fail; { Type *ft = &fo->range.from->type; @@ -1872,7 +1915,7 @@ static Status types_expr(Typer *tr, Expression *e) { } } else *val_type = *iter_type; } - + arr_remove_lasta(tr->in_decls, tr->allocr); in_header = false; @@ -1881,6 +1924,16 @@ static Status types_expr(Typer *tr, Expression *e) { assert(val_type->flags & TYPE_IS_RESOLVED); header->flags |= DECL_FOUND_TYPE; + + if (header->flags & DECL_USE) { + if (ident_eq_str(header->idents[0], "_")) { + err_print(header->where, "You have to name your for loop variable in order to use it (sorry)."); + return false; + } + if (!use_ident(tr, header->idents[0], val_type, header->where)) { + return false; + } + } if (!types_block(tr, &fo->body)) goto for_fail; if (fo->body.ret_expr) { @@ -2779,7 +2832,7 @@ static Status types_expr(Typer *tr, Expression *e) { t->builtin = BUILTIN_TYPE; break; } - if (!expr_must_lval(of)) { + if (!expr_must_lval(of, "take address of")) { return false; } if (of_type->kind == TYPE_TUPLE) { @@ -2893,7 +2946,7 @@ static Status types_expr(Typer *tr, Expression *e) { case BINARY_SET_MUL: case BINARY_SET_DIV: case BINARY_SET_MOD: - if (!expr_must_lval(e->binary.lhs)) { + if (!expr_must_lval(e->binary.lhs, "set value of")) { return false; } /* fallthrough */ @@ -3402,23 +3455,13 @@ static Status types_decl(Typer *tr, Declaration *d) { if (d->flags & DECL_USE) { int idx = 0; - arr_foreach(d->idents, Identifier, ip) { - Identifier i = *ip; - /* add to uses */ - Use **usep; - if (tr->block) - usep = typer_arr_add_ptr(tr, tr->block->uses); - else - usep = typer_arr_add_ptr(tr, tr->uses); - Use *use = *usep = typer_calloc(tr, 1, sizeof *use); - Expression *used = &use->expr; - used->kind = EXPR_IDENT; - used->flags = EXPR_FOUND_TYPE; - used->type = *decl_type_at_index(d, idx++); - used->ident = i; - used->where = d->where; - + if (arr_len(d->idents) > 1) { + err_print(d->where, "Used declarations cannot have more than one identifier (you're trying to use two things at once)."); + return false; } + Identifier i = d->idents[0]; + if (!use_ident(tr, i, decl_type_at_index(d, idx++), d->where)) + return false; } if (n_idents == 1 && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_NMS) { @@ -3453,13 +3496,6 @@ static Status types_decl(Typer *tr, Declaration *d) { return success; } -static bool expr_is_usable(Expression *e) { - if (e->kind == EXPR_IDENT) return true; - if (e->kind == EXPR_BINARY_OP && e->binary.op == BINARY_DOT) - return expr_is_usable(e->binary.lhs); - return false; -} - static Status types_stmt(Typer *tr, Statement *s) { if (s->flags & STMT_TYPED) return true; switch (s->kind) { @@ -3630,19 +3666,9 @@ static Status types_stmt(Typer *tr, Statement *s) { case STMT_USE: { Use *u = s->use; Expression *e = &u->expr; - Type *t = &e->type; if (!types_expr(tr, e)) return false; - if (t->kind != TYPE_STRUCT && !type_is_builtin(t, BUILTIN_NMS)) { - if (!(t->kind == TYPE_PTR && t->ptr->kind == TYPE_STRUCT)) { - char *str = type_to_str(&e->type); - err_print(s->where, "You cannot use something of type %s (only Namespaces and structs).", str); - free(str); - return false; - } - } - if (!expr_is_usable(e)) { - err_print(e->where, "You can't use this value. You should probably assign it to a variable."); + if (!expr_must_usable(e)) { return false; } if (tr->block) |