summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c4
-rw-r--r--copy.c32
-rw-r--r--decls_cgen.c4
-rw-r--r--err.c22
-rw-r--r--eval.c2
-rw-r--r--foreign.c2
-rw-r--r--infer.c15
-rw-r--r--instance_table.c4
-rw-r--r--main.c5
-rw-r--r--parse.c54
-rwxr-xr-xtest-build.sh1
-rw-r--r--test.toc75
-rw-r--r--types.c106
-rw-r--r--types.h18
14 files changed, 148 insertions, 196 deletions
diff --git a/cgen.c b/cgen.c
index d453149..2a469ea 100644
--- a/cgen.c
+++ b/cgen.c
@@ -295,7 +295,7 @@ static void cgen_struct_name(CGenerator *g, StructDef *sdef) {
}
if (sdef->instance_id) {
possibly_static_assert(sizeof sdef->instance_id == 8);
- cgen_write(g, U64_FMT, sdef->instance_id);
+ cgen_write(g, U64_FMT "_", sdef->instance_id);
}
}
@@ -515,7 +515,7 @@ static void cgen_val_ptr(CGenerator *g, void *v, Type *t) {
arr_foreach(t->struc->fields, Field, f) {
if (f != t->struc->fields)
cgen_write(g, ", ");
- cgen_val_ptr(g, (char *)v + f->offset, &f->type);
+ cgen_val_ptr(g, (char *)v + f->offset, f->type);
}
cgen_write(g, "}");
break;
diff --git a/copy.c b/copy.c
index e57dc51..a68b6e5 100644
--- a/copy.c
+++ b/copy.c
@@ -90,22 +90,30 @@ static void copy_val_full(Copier *c, Value *out, Value in, Type *t) {
static void copy_struct(Copier *c, StructDef *out, StructDef *in) {
*out = *in;
- size_t nfields = arr_len(in->fields);
- out->fields = NULL;
-
out->scope = in->scope;
idents_create(&out->scope.idents, c->allocr, &out->scope);
Block *prev = c->block;
copy_block(c, &out->scope, &in->scope, 0);
c->block = &out->scope;
+ if (in->flags & STRUCT_DEF_RESOLVED) {
+ size_t nfields = arr_len(in->fields);
+ out->fields = NULL;
- arr_set_lena(&out->fields, nfields, c->allocr);
- for (size_t i = 0; i < nfields; ++i) {
- Field *fout = &out->fields[i];
- Field *fin = &in->fields[i];
- *fout = *fin;
- copy_type(c, &fout->type, &fin->type);
+ arr_set_lena(&out->fields, nfields, c->allocr);
+ for (size_t i = 0; i < nfields; ++i) {
+ Field *fout = &out->fields[i];
+ Field *fin = &in->fields[i];
+ *fout = *fin;
+ fout->type = copy_type_(c, fin->type);
+ }
+ out->constants = NULL;
+ size_t nconstants = arr_len(in->constants);
+ arr_set_lena(&out->constants, nconstants, c->allocr);
+ for (size_t i = 0; i < nconstants; ++i) {
+ copy_decl(c, out->constants[i] = allocr_malloc(c->allocr, sizeof *out->constants[i]),
+ in->constants[i]);
+ }
}
size_t nparams = arr_len(in->params);
out->params = NULL;
@@ -113,12 +121,6 @@ static void copy_struct(Copier *c, StructDef *out, StructDef *in) {
for (size_t i = 0; i < nparams; ++i) {
copy_decl(c, &out->params[i], &in->params[i]);
}
- out->constants = NULL;
- size_t nconstants = arr_len(in->constants);
- arr_set_lena(&out->constants, nconstants, c->allocr);
- for (size_t i = 0; i < nconstants; ++i) {
- copy_decl(c, &out->constants[i], &in->constants[i]);
- }
c->block = prev;
}
diff --git a/decls_cgen.c b/decls_cgen.c
index 048dd9d..967294f 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -182,10 +182,10 @@ static void cgen_decls_type(CGenerator *g, Type *type) {
cgen_nl(g);
++g->indent_lvl;
arr_foreach(sdef->fields, Field, f) {
- cgen_type_pre(g, &f->type);
+ cgen_type_pre(g, f->type);
cgen_write(g, " ");
cgen_ident_simple(g, f->name);
- cgen_type_post(g, &f->type);
+ cgen_type_post(g, f->type);
cgen_write(g, ";");
cgen_nl(g);
}
diff --git a/err.c b/err.c
index 571b7b7..514f9ed 100644
--- a/err.c
+++ b/err.c
@@ -79,16 +79,7 @@ static void print_location_highlight(FILE *out, Location where) {
/* for debugging */
static void fprint_location(FILE *out, Location location) {
- if (location.start) {
- fprintf(out, "Line %ld of %s: ", (long)location.start->pos.line, location.file->filename);
- } else {
- U32 line = location.simple_location.line;
- if (line)
- fprintf(out, "Line %lu of %s: ", (unsigned long)line, location.file->filename);
- else
- fprintf(out, "In file %s: ", location.file->filename);
- return;
- }
+ fprintf(out, "Line %ld of %s: ", (long)location.start->pos.line, location.file->filename);
print_location_highlight(out, location);
}
@@ -151,16 +142,7 @@ static void err_vfprint(ErrCtx *ctx, const char *fmt, va_list args) {
static void err_print_line_file(Location where) {
ErrCtx *ctx = where.file->ctx;
- if (where.start) {
- err_fprint(ctx, " at line %lu of %s:\n", (unsigned long)where.start->pos.line, where.file->filename);
- } else {
- U32 line = where.simple_location.line;
- if (line)
- err_fprint(ctx, " at line %lu of %s:\n", (unsigned long)line, where.file->filename);
- else
- err_fprint(ctx, ":\n");
- }
-
+ err_fprint(ctx, " at line %lu of %s:\n", (unsigned long)where.start->pos.line, where.file->filename);
}
static void err_print_header_(Location where) {
diff --git a/eval.c b/eval.c
index 78307e3..4dfb618 100644
--- a/eval.c
+++ b/eval.c
@@ -245,7 +245,7 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) {
fprintf(f, ", ");
fprint_ident_debug(f, fi->name);
fprintf(f, ": ");
- fprint_val_ptr(f, (char *)p + fi->offset, &fi->type);
+ fprint_val_ptr(f, (char *)p + fi->offset, fi->type);
}
fprintf(f, "]");
break;
diff --git a/foreign.c b/foreign.c
index 6018487..6e25a77 100644
--- a/foreign.c
+++ b/foreign.c
@@ -176,7 +176,7 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val,
splittable = true;
size_t word_size = sizeof(__avword);
arr_foreach(struc->fields, Field, f) {
- if (f->offset / word_size != (f->offset + compiler_sizeof(&f->type) - 1) / word_size) {
+ if (f->offset / word_size != (f->offset + compiler_sizeof(f->type) - 1) / word_size) {
splittable = false;
break;
}
diff --git a/infer.c b/infer.c
index 348b43b..0a88c82 100644
--- a/infer.c
+++ b/infer.c
@@ -197,17 +197,10 @@ static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents
if (!infer_from_type(tr, match->slice, to->slice, idents, vals, types, where))
return false;
break;
- case TYPE_STRUCT: {
- if (to->kind != TYPE_STRUCT) return true;
- Field *fields_m = match->struc->fields;
- Field *fields_t = to->struc->fields;
- size_t i, len = arr_len(fields_m);
- if (len != arr_len(fields_t)) return true;
- for (i = 0; i < len; ++i) {
- if (!infer_from_type(tr, &fields_m[i].type, &fields_t[i].type, idents, vals, types, where))
- return false;
- }
- } break;
+ case TYPE_STRUCT:
+ /* this would be difficult because match could contain #ifs and
+ no sane person will ever write something that needs this */
+ break;
case TYPE_EXPR: {
Expression *to_expr = to->was_expr;
Expression e = {0};
diff --git a/instance_table.c b/instance_table.c
index d1533cd..125c2cf 100644
--- a/instance_table.c
+++ b/instance_table.c
@@ -192,7 +192,7 @@ static U64 val_ptr_hash(void *v, Type *t) {
U32 x = 1;
U64 hash = 0;
arr_foreach(t->struc->fields, Field, f) {
- hash += (U64)x * val_ptr_hash((char *)v + f->offset, &f->type);
+ hash += (U64)x * val_ptr_hash((char *)v + f->offset, f->type);
x = rand_u32(x);
}
return hash;
@@ -287,7 +287,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) {
}
case TYPE_STRUCT:
arr_foreach(t->struc->fields, Field, f) {
- if (!val_ptr_eq((char *)u + f->offset, (char *)v + f->offset, &f->type))
+ if (!val_ptr_eq((char *)u + f->offset, (char *)v + f->offset, f->type))
return false;
}
return true;
diff --git a/main.c b/main.c
index e89af41..e06e818 100644
--- a/main.c
+++ b/main.c
@@ -8,10 +8,8 @@
/*
TODO:
-allow #ifs in structs
- - you can just have a dyn array of stmts and when you want to resolve the struct,
- just type the statements, then loop over them (going into blocks if necessary)
use
+ - use with a decl, e.g. use p : Point;
&&, ||
start making a standard library... (printf; stringbuilder would be nice to have)
switch
@@ -81,6 +79,7 @@ int main(int argc, char **argv) {
signal(SIGSEGV, signal_handler);
#endif
#ifdef RUN_TESTS
+ printf("running tests...\n");
test_all();
#endif
diff --git a/parse.c b/parse.c
index 66f847d..9a24d26 100644
--- a/parse.c
+++ b/parse.c
@@ -14,6 +14,10 @@ enum {
};
static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 flags);
static Status parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end);
+enum {
+ PARSE_BLOCK_DONT_CREATE_IDENTS = 0x01
+};
+static bool parse_block(Parser *p, Block *b, U8 flags);
static bool is_decl(Tokenizer *t);
static inline bool ends_decl(Token *t, DeclEndKind ends_with);
@@ -574,9 +578,7 @@ static Status parse_type(Parser *p, Type *type, Location *where) {
struc->name = NULL;
/* help cgen out */
struc->c.id = 0;
- struc->fields = NULL;
struc->params = NULL;
- struc->constants = NULL;
struc->where = parser_mk_loc(p);
struc->where.start = t->token;
memset(&struc->scope, 0, sizeof struc->scope);
@@ -615,48 +617,11 @@ static Status parse_type(Parser *p, Type *type, Location *where) {
param->flags |= DECL_IS_PARAM;
}
}
- if (!token_is_kw(t->token, KW_LBRACE)) {
- tokr_err(t, "Expected { to follow struct.");
- goto struct_fail;
- }
- ++t->token;
- {
- while (!token_is_kw(t->token, KW_RBRACE)) {
- Declaration field_decl;
- if (!parse_decl(p, &field_decl, DECL_END_SEMICOLON, PARSE_DECL_DONT_SET_IDECLS)) {
- goto struct_fail;
- }
- if (field_decl.flags & DECL_IS_CONST) {
- Declaration *d = parser_arr_add(p, &struc->constants);
- *d = field_decl;
- } else {
- if (field_decl.flags & DECL_HAS_EXPR) {
- err_print(field_decl.where, "struct members cannot have initializers.");
- goto struct_fail;
- }
- long idx = 0;
- arr_foreach(field_decl.idents, Identifier, fident) {
- Type *ftype = field_decl.type.kind == TYPE_TUPLE ? &field_decl.type.tuple[idx] : &field_decl.type;
- Field *f = parser_arr_add(p, &struc->fields);
- f->name = *fident;
- f->where = field_decl.where;
- f->type = *ftype;
- ++idx;
- }
- }
- }
- arr_foreach(struc->constants, Declaration, c) {
- arr_foreach(c->idents, Identifier, ip) {
- Identifier i = *ip;
- i->decl = c;
- i->decl_kind = IDECL_DECL;
- }
- }
- ++t->token;
- struc->where.end = t->token;
- }
- struc->scope.where = struc->where;
+
p->block = prev_block;
+ if (!parse_block(p, &struc->scope, PARSE_BLOCK_DONT_CREATE_IDENTS))
+ return false;
+ struc->where = struc->scope.where;
break;
struct_fail:
@@ -819,9 +784,6 @@ static bool parser_is_definitely_type(Parser *p, Token **end) {
return ret;
}
-enum {
- PARSE_BLOCK_DONT_CREATE_IDENTS = 0x01
-};
static Status parse_block(Parser *p, Block *b, U8 flags) {
Tokenizer *t = p->tokr;
Block *prev_block = p->block;
diff --git a/test-build.sh b/test-build.sh
index 370e329..263c657 100755
--- a/test-build.sh
+++ b/test-build.sh
@@ -4,5 +4,6 @@ for CC in tcc gcc clang g++ ; do
CC="$CC" CFLAGS='-Werror' ./build.sh || exit 1
CC="$CC" CFLAGS='-Werror' ./build.sh release || exit 1
done
+CC=''
CFLAGS='-Werror' ./build.sh release || exit 1
CFLAGS='-Werror' ./build.sh || exit 1
diff --git a/test.toc b/test.toc
index 8797e39..b1d5e06 100644
--- a/test.toc
+++ b/test.toc
@@ -1,65 +1,24 @@
#include "std/io.toc", io;
-plusone ::= fn(n : int) x := n {
- defer x += 1;
-}
-
-same ::= fn(n : int) int {
- x := n;
- defer x += 1;
- x
-}
-
-thing1 ::= fn() (int, int) {
- x := 5;
- y := 6;
- defer x += 1;
- x, y
-}
-thing2 ::= fn() x := 5, y := 6 {
- defer x += 1;
+s ::= struct (t :: Type, hasz ::= true) {
+ x, y: t;
+ #if hasz {
+ z: t;
+ a :: t = 3 as t;
+ }
}
main ::= fn() {
- io.puti(plusone(3));
- io.puti(same(3));
- a, b := thing1();
- c, d := thing2();
- io.puti(a);
- io.puti(b);
- io.puti(c);
- io.puti(d);
- defer io.puts("deferred from main()");
- for i := 1..10 {
- defer io.puts("deferred from for");
- io.puti(i);
- if i == 2 {
- defer io.puts("deferred from if1");
- defer io.puts("deferred from if2");
- defer io.puts("deferred from if3");
- defer io.puts("deferred from if4");
- defer io.puts("deferred from if5");
- defer io.puts("deferred from if6");
- defer io.puts("deferred from if7");
- defer io.puts("deferred from if8");
- continue;
- }
- if i == 8 {
- break;
- }
- }
- i := 0;
- while {
- defer io.puts("deferred from while");
- i += 1;
- io.puti(i);
- if i % 2 == 0 { continue; }
- if i == 7 {
- defer io.puts("deferred from if");
- break;
- }
-
- }
- io.puts("end of main()");
+ p: s(float);
+ p.x = 7;
+ p.y = 13;
+ p.z = 12;
+ io.puti(p.x as int);
+ io.puti(s(int).a as int);
+ q: s(int, false);
+ q.x = 13;
+ io.puti(q.x);
+ //io.puti(q.a);
}
+
diff --git a/types.c b/types.c
index 852e142..06d11f9 100644
--- a/types.c
+++ b/types.c
@@ -85,12 +85,12 @@ static Status struct_find_offsets(StructDef *s) {
size_t bytes = 0;
size_t total_align = 1;
arr_foreach(s->fields, Field, f) {
- size_t size = compiler_sizeof(&f->type);
+ size_t size = compiler_sizeof(f->type);
if (size == SIZE_MAX) {
info_print(f->where, "... while descending into this field of a struct.");
return false;
}
- size_t falign = compiler_alignof(&f->type);
+ size_t falign = compiler_alignof(f->type);
if (falign > total_align)
total_align = falign;
/* align */
@@ -648,7 +648,6 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *
}
/* are we inside this declaration? */
- typedef Declaration *DeclarationPtr;
arr_foreach(tr->in_decls, DeclarationPtr, in_decl) {
if (d == *in_decl) {
/* d needn't have an expression, because it could be its type that refers to itself */
@@ -728,6 +727,68 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *
}
return true;
}
+static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s) {
+ arr_foreach(b->stmts, Statement, stmt) {
+ if (stmt->kind == STMT_EXPR) {
+ if (stmt->expr.kind == EXPR_BLOCK) {
+ if (!add_block_to_struct(tr, stmt->expr.block, s))
+ return false;
+ continue;
+ }
+ }
+ if (stmt->kind != STMT_DECL) {
+ err_print(stmt->where, "structs can only contain declarations.");
+ return false;
+ }
+ Declaration *d = stmt->decl;
+ DeclFlags flags = d->flags;
+ if (flags & DECL_EXPORT) {
+ err_print(d->where, "struct members can't be exported.");
+ return false;
+ }
+ if (flags & DECL_IS_CONST) {
+ if (flags & DECL_INFER) {
+ err_print(d->where, "struct members can't be inferred.");
+ return false;
+ }
+ *(Declaration **)typer_arr_add(tr, &s->constants) = d;
+ } else {
+ if (flags & DECL_SEMI_CONST) {
+ err_print(d->where, "struct members can't be semi-constant.");
+ return false;
+ }
+ if (flags & DECL_HAS_EXPR) {
+ err_print(d->where, "Non-constant struct members can't have initializers.");
+ return false;
+ }
+ int i = 0;
+ arr_foreach(d->idents, Identifier, ident) {
+ Field *field = typer_arr_add(tr, &s->fields);
+ field->where = d->where;
+ field->name = *ident;
+ field->type = decl_type_at_index(d, i);
+ ++i;
+ }
+ }
+ if (b != &s->scope) {
+ /* we need to translate d's identifiers to s's scope */
+ arr_foreach(d->idents, Identifier, ip) {
+ Identifier redeclared = ident_get(&s->scope.idents, (*ip)->str);
+ if (redeclared && redeclared->decl_kind != IDECL_NONE) {
+ char *str = ident_to_str(*ip);
+ err_print(d->where, "Redeclaration of struct member %s", str);
+ info_print(ident_decl_location(d->where.file, redeclared), "Previous declaration was here.");
+ free(str);
+ return false;
+ }
+ *ip = ident_translate_forced(*ip, &s->scope.idents);
+ (*ip)->decl_kind = IDECL_DECL;
+ (*ip)->decl = d;
+ }
+ }
+ }
+ return true;
+}
/* fixes the type (replaces [5+3]int with [8]int, etc.) */
static Status type_resolve(Typer *tr, Type *t, Location where) {
@@ -789,24 +850,17 @@ static Status type_resolve(Typer *tr, Type *t, Location where) {
return false;
break;
case TYPE_STRUCT: {
- if (!(t->struc->flags & STRUCT_DEF_RESOLVED)) {
- typer_block_enter(tr, &t->struc->scope);
- arr_foreach(t->struc->fields, Field, f) {
- if (!type_resolve(tr, &f->type, where)) {
- typer_block_exit(tr);
- return false;
- }
- }
- arr_foreach(t->struc->constants, Declaration, c) {
- if (!types_decl(tr, c)) {
- typer_block_exit(tr);
- return false;
- }
- }
- typer_block_exit(tr);
- assert(tr->block != &t->struc->scope);
- t->struc->instance_id = 0;
- t->struc->flags |= STRUCT_DEF_RESOLVED;
+ StructDef *s = t->struc;
+ if (!(s->flags & STRUCT_DEF_RESOLVED)) {
+ if (!types_block(tr, &s->scope))
+ return false;
+ s->fields = NULL;
+ s->constants = NULL;
+ if (!add_block_to_struct(tr, &s->scope, s))
+ return false;
+
+ s->instance_id = 0;
+ s->flags |= STRUCT_DEF_RESOLVED;
}
} break;
case TYPE_EXPR: {
@@ -1422,7 +1476,11 @@ static void get_builtin_val_type(Allocator *a, BuiltinVal val, Type *t) {
/* gets a struct's constant or parameter, and puts it into e->val. */
-static Status get_struct_constant(StructDef *struc, Identifier member, Expression *e) {
+static Status get_struct_constant(StructDef *struc, Identifier member, Expression *e) {
+ if (struc->params && !(struc->params[0].flags & DECL_FOUND_VAL)) {
+ err_print(e->where, "To access constants from a parameterized struct, you must supply its arguments.");
+ return false;
+ }
Identifier i = ident_translate(member, &struc->scope.idents);
if (!i || i->decl_kind == IDECL_NONE) {
char *member_s = ident_to_str(member);
@@ -2785,7 +2843,7 @@ static Status types_expr(Typer *tr, Expression *e) {
arr_foreach(lhs_type->struc->fields, Field, f) {
if (ident_eq_str(f->name, field_name.slice.data)) {
is_field = true;
- *t = f->type;
+ *t = *f->type;
e->binary.dot.field = f;
}
}
@@ -2898,7 +2956,7 @@ static Status types_expr(Typer *tr, Expression *e) {
arr_foreach(struct_type->struc->fields, Field, f) {
if (ident_eq(f->name, rhs->ident)) {
is_field = true;
- *t = f->type;
+ *t = *f->type;
e->binary.dot.field = f;
}
}
diff --git a/types.h b/types.h
index d6f6e24..96f474f 100644
--- a/types.h
+++ b/types.h
@@ -200,7 +200,6 @@ typedef struct IdentSlot {
};
struct Identifiers *idents;
struct Namespace *nms; /* only exists after typing, and only for namespace-level declarations (i.e. not local variables) */
- SOURCE_LOCATION
} IdentSlot;
typedef struct StrHashTableSlot {
@@ -386,14 +385,8 @@ typedef struct {
typedef struct Location {
File *file;
- /* if start is NULL, simple_location will be used. */
Token *start;
- union {
- Token *end; /* Exclusive */
- struct {
- U32 line; /* if 0, this is a null location */
- } simple_location;
- };
+ Token *end; /* Exclusive */
} Location;
@@ -486,7 +479,7 @@ typedef struct Type {
typedef struct Field {
Location where;
Identifier name;
- Type type;
+ Type *type;
size_t offset; /* offset during compile time */
} Field;
@@ -520,11 +513,13 @@ enum {
STRUCT_DEF_RESOLVED = 0x10
};
typedef struct StructDef {
+ /* these two only exist after resolving (before then, it's scope.stmts) */
Field *fields;
- struct Declaration *constants;
+ struct Declaration **constants;
+
Location where;
U8 flags;
- Block scope; /* to make sure that parameters and constants live somewhere. fields are not kept here. */
+ Block scope; /* parameters and constants live here. statements aren't used after resolving (but are kept around because why not) */
union {
HashTable instances;
struct {
@@ -908,6 +903,7 @@ typedef struct Declaration {
/* OPTIM: some block array of values somewhere which we can just use a pointer to, which is freed when the block is exited? */
Value **val_stack;
} Declaration;
+typedef Declaration *DeclarationPtr;
typedef enum {
STMT_DECL,