summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c37
-rw-r--r--eval.c1
-rw-r--r--main.c1
-rw-r--r--out.c3
-rw-r--r--parse.c11
-rw-r--r--test.toc4
-rw-r--r--types.c97
-rw-r--r--util/arr.c1
8 files changed, 112 insertions, 43 deletions
diff --git a/cgen.c b/cgen.c
index fc0dd50..e5d85c1 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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, "; ");
}
diff --git a/eval.c b/eval.c
index 1e23c29..6e6195d 100644
--- a/eval.c
+++ b/eval.c
@@ -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:
diff --git a/main.c b/main.c
index 281387d..f22b3c3 100644
--- a/main.c
+++ b/main.c
@@ -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 */
diff --git a/out.c b/out.c
index ed273e4..5c95e07 100644
--- a/out.c
+++ b/out.c
@@ -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) {
diff --git a/parse.c b/parse.c
index cae15bc..5a85165 100644
--- a/parse.c
+++ b/parse.c
@@ -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);
diff --git a/test.toc b/test.toc
index 0138c1e..42768de 100644
--- a/test.toc
+++ b/test.toc
@@ -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;
};
diff --git a/types.c b/types.c
index 7278d02..87fa588 100644
--- a/types.c
+++ b/types.c
@@ -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;
}
diff --git a/util/arr.c b/util/arr.c
index b3e0558..0d7ddfa 100644
--- a/util/arr.c
+++ b/util/arr.c
@@ -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--)