summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-04-22 15:57:24 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-04-22 15:57:24 -0400
commit4062e5c965bc04ec9654d82526e5e785f7f45d03 (patch)
treee12b1af103ba8e7218c4adcff4c718ab236523d1
parent2df588fb6ebc77d067e390e5c70c5da0298a47b2 (diff)
used for loops
-rw-r--r--main.c6
-rw-r--r--parse.c2
-rw-r--r--std/io.toc16
-rw-r--r--test.toc34
-rw-r--r--types.c124
5 files changed, 120 insertions, 62 deletions
diff --git a/main.c b/main.c
index 38a014e..7dc73ef 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/parse.c b/parse.c
index 47ea5bf..5f3e6a8 100644
--- a/parse.c
+++ b/parse.c
@@ -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);
diff --git a/std/io.toc b/std/io.toc
index d3ce467..2c82dc9 100644
--- a/std/io.toc
+++ b/std/io.toc
@@ -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');
}
+
diff --git a/test.toc b/test.toc
index 3f059a4..9b805fc 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
}
diff --git a/types.c b/types.c
index 7437a9c..d8998d2 100644
--- a/types.c
+++ b/types.c
@@ -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)