summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-04-25 15:01:47 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-04-25 15:01:47 -0400
commit7ee5fc2721e40471f01f9377dd901ded4b969a33 (patch)
tree4b7326e96e89607b86b37d38fd0a8754144f370a
parent7aa21a12d1b5505ba6258f2a74ce8716e72387c3 (diff)
fixed problems with using future types
-rw-r--r--eval.c4
-rw-r--r--main.c4
-rw-r--r--test.toc46
-rwxr-xr-xtests/test.sh1
-rw-r--r--tests/types.toc48
-rw-r--r--tests/types_expected13
-rw-r--r--toc.c2
-rw-r--r--types.c135
-rw-r--r--types.h37
9 files changed, 205 insertions, 85 deletions
diff --git a/eval.c b/eval.c
index 88e6f13..9a65ff9 100644
--- a/eval.c
+++ b/eval.c
@@ -4,11 +4,7 @@
You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>.
*/
-static Status types_block(Typer *tr, Block *b);
-static Status types_decl(Typer *tr, Declaration *d);
-static Status type_resolve(Typer *tr, Type *t, Location where);
static Status eval_block(Evaluator *ev, Block *b, Value *v);
-static Status eval_expr(Evaluator *ev, Expression *e, Value *v);
static Status eval_address_of(Evaluator *ev, Expression *e, void **ptr);
static Value get_builtin_val(BuiltinVal val);
diff --git a/main.c b/main.c
index 2d42a45..0ac2443 100644
--- a/main.c
+++ b/main.c
@@ -15,10 +15,14 @@ use
compile to a temp file, then move it if compilation succeeds
fix including something twice - just use the non-namespacey version if it exists or pick one namespace to use everywhere otherwise
&void
+null
simplify eval macros with val_to_u/i64
#if should not create a block
&&, ||
start making a standard library... (printf; stringbuilder would be nice to have)
+improve type_to_str:
+ Foo ::= struct(t::Type) {}
+ type_to_str(Foo(int))
switch
- #fallthrough
enums
diff --git a/test.toc b/test.toc
index 2a171ed..0b84b8a 100644
--- a/test.toc
+++ b/test.toc
@@ -1,6 +1,48 @@
#include "std/io.toc", io;
-use io;
+#include "std/mem.toc";
+
main ::= fn() {
- puts("hi");
+ nums := news(int, 10);
+ for x, i := &nums {
+ *x = i*i;
+ }
+ l := slice_to_ll(nums);
+ p := &l;
+ while p {
+ io.puti(p.head);
+ p = p.tail;
+ }
+ f: Foo;
+ f.k = -173;
+ f.b = new(Bar);
+ f.b.f.b = new(Bar);
+ f.b.f.b.f.k = 9;
+ io.puti(f.k);
+ io.puti(f.b.f.k);
+ io.puti(f.b.f.b.f.k);
+}
+
+slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
+ head = slice[0];
+ if slice.len == 1 {
+ tail = 0 as &LinkedList(t);
+ } else {
+ tail = new(LinkedList(t));
+ *tail = slice_to_ll(slice[1:]);
+ }
+}
+
+LinkedList ::= struct (of :: Type) {
+ head: of;
+ tail: &LinkedList(of);
+}
+
+Foo ::= struct {
+ k: int;
+ b: &Bar;
+}
+
+Bar ::= struct {
+ f: Foo;
}
diff --git a/tests/test.sh b/tests/test.sh
index e6e8fe5..1168e5b 100755
--- a/tests/test.sh
+++ b/tests/test.sh
@@ -2,6 +2,7 @@
tests='bf
control_flow
+types
defer
sizeof
new
diff --git a/tests/types.toc b/tests/types.toc
new file mode 100644
index 0000000..4ef55e8
--- /dev/null
+++ b/tests/types.toc
@@ -0,0 +1,48 @@
+#include "io.toc", io;
+#include "mem.toc";
+
+
+main ::= fn() {
+ nums := news(int, 10);
+ for x, i := &nums {
+ *x = i*i;
+ }
+ l := slice_to_ll(nums);
+ p := &l;
+ while p {
+ io.puti(p.head);
+ p = p.tail;
+ }
+ f: Foo;
+ f.k = -173;
+ f.b = new(Bar);
+ f.b.f.b = new(Bar);
+ f.b.f.b.f.k = 9;
+ io.puti(f.k);
+ io.puti(f.b.f.k);
+ io.puti(f.b.f.b.f.k);
+}
+
+slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
+ head = slice[0];
+ if slice.len == 1 {
+ tail = 0 as &LinkedList(t);
+ } else {
+ tail = new(LinkedList(t));
+ *tail = slice_to_ll(slice[1:]);
+ }
+}
+
+LinkedList ::= struct (of :: Type) {
+ head: of;
+ tail: &LinkedList(of);
+}
+
+Foo ::= struct {
+ k: int;
+ b: &Bar;
+}
+
+Bar ::= struct {
+ f: Foo;
+}
diff --git a/tests/types_expected b/tests/types_expected
new file mode 100644
index 0000000..eef051c
--- /dev/null
+++ b/tests/types_expected
@@ -0,0 +1,13 @@
+0
+1
+4
+9
+16
+25
+36
+49
+64
+81
+-173
+0
+9
diff --git a/toc.c b/toc.c
index 5536dd8..6089c20 100644
--- a/toc.c
+++ b/toc.c
@@ -130,9 +130,9 @@ static Location token_location(File *file, Token *t);
#include "tokenizer.c"
#include "parse.c"
#include "foreign.c"
-#include "eval.c"
#include "infer.c"
#include "types.c"
+#include "eval.c"
static void cgen_decls_file(CGenerator *g, ParsedFile *f);
static void cgen_sdecls_file(CGenerator *g, ParsedFile *f);
#include "cgen.c"
diff --git a/types.c b/types.c
index af52f60..2be1237 100644
--- a/types.c
+++ b/types.c
@@ -4,8 +4,17 @@
You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>.
*/
static Status types_stmt(Typer *tr, Statement *s);
+static Status types_block(Typer *tr, Block *b);
+static Status types_decl(Typer *tr, Declaration *d);
static Status type_resolve(Typer *tr, Type *t, Location where);
-
+static Status eval_expr(Evaluator *ev, Expression *e, Value *v);
+static void val_cast(Value *vin, Type *from, Value *vout, Type *to);
+static U64 val_to_u64(Value v, BuiltinType v_type);
+static I64 val_to_i64(Value v, BuiltinType v_type);
+static bool val_truthiness(Value v, Type *t);
+static Value val_zero(Type *t);
+static Status eval_stmt(Evaluator *ev, Statement *stmt);
+static Status struct_resolve(Typer *tr, StructDef *s);
static inline Identifiers *typer_get_idents(Typer *tr) {
return tr->block == NULL ? tr->globals : &tr->block->idents;
@@ -140,64 +149,6 @@ static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s, Statement *
return true;
}
-static Status struct_resolve(Typer *tr, StructDef *s) {
- if (!(s->flags & STRUCT_DEF_RESOLVED)) {
- { /* resolving stuff */
- if (!types_block(tr, &s->body))
- return false;
- s->fields = NULL;
- Statement *new_stmts = NULL;
- if (!add_block_to_struct(tr, &s->body, s, &new_stmts))
- return false;
- s->body.stmts = new_stmts;
- /* set the field of each declaration, so that we can lookup struct members quickly */
- Field *field = s->fields;
- arr_foreach(new_stmts, Statement, stmt) {
- assert(stmt->kind == STMT_DECL);
- Declaration *decl = stmt->decl;
- if (!(decl->flags & DECL_IS_CONST)) {
- assert(!(decl->flags & DECL_HAS_EXPR));
- decl->field = field;
- field += arr_len(decl->idents);
- }
- }
- s->instance_id = 0;
- }
- /* find offsets and size */
- /* assume the align of a struct is the greatest align out of its children's */
- {
- if (s->flags & STRUCT_DEF_FINDING_OFFSETS) {
- err_print(s->where, "Circular dependency in struct!");
- return false;
- }
- s->flags |= STRUCT_DEF_FINDING_OFFSETS;
- size_t bytes = 0;
- size_t total_align = 1;
- arr_foreach(s->fields, Field, f) {
- 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);
- if (falign > total_align)
- total_align = falign;
- /* align */
- bytes += ((falign - bytes) % falign + falign) % falign; /* = -bytes mod falign */
- assert(bytes % falign == 0);
- f->offset = bytes;
- /* add size */
- bytes += size;
- }
- bytes += ((total_align - bytes) % total_align + total_align) % total_align; /* = -bytes mod align */
- s->size = bytes;
- s->align = total_align;
- }
- s->flags |= STRUCT_DEF_RESOLVED;
- }
- return true;
-}
-
static size_t compiler_alignof(Type *t) {
assert(t->flags & TYPE_IS_RESOLVED);
switch (t->kind) {
@@ -246,6 +197,11 @@ static size_t compiler_sizeof(Type *t) {
case TYPE_SLICE:
return sizeof v.slice;
case TYPE_STRUCT: {
+ /* these two ifs are purely for struct_resolve, so that it can detect use of future structs in a non-pointery way */
+ if (t->struc->flags & STRUCT_DEF_RESOLVING)
+ return SIZE_MAX-1;
+ if (!(t->struc->flags & STRUCT_DEF_RESOLVED))
+ return SIZE_MAX;
return t->struc->size;
} break;
case TYPE_VOID:
@@ -258,6 +214,65 @@ static size_t compiler_sizeof(Type *t) {
return 0;
}
+static Status struct_resolve(Typer *tr, StructDef *s) {
+ if (!(s->flags & STRUCT_DEF_RESOLVED)) {
+ s->flags |= STRUCT_DEF_RESOLVING;
+ { /* resolving stuff */
+ if (!types_block(tr, &s->body))
+ return false;
+ s->fields = NULL;
+ Statement *new_stmts = NULL;
+ if (!add_block_to_struct(tr, &s->body, s, &new_stmts))
+ return false;
+ s->body.stmts = new_stmts;
+ /* set the field of each declaration, so that we can lookup struct members quickly */
+ Field *field = s->fields;
+ arr_foreach(new_stmts, Statement, stmt) {
+ assert(stmt->kind == STMT_DECL);
+ Declaration *decl = stmt->decl;
+ if (!(decl->flags & DECL_IS_CONST)) {
+ assert(!(decl->flags & DECL_HAS_EXPR));
+ decl->field = field;
+ field += arr_len(decl->idents);
+ }
+ }
+ s->instance_id = 0;
+ }
+ /* find offsets and size */
+ /* assume the align of a struct is the greatest align out of its children's */
+ {
+ size_t bytes = 0;
+ size_t total_align = 1;
+ arr_foreach(s->fields, Field, f) {
+ size_t size = compiler_sizeof(f->type);
+ if (size == SIZE_MAX) {
+ err_print(f->where, "Use of type that hasn't been declared yet (but not as a pointer/slice).\n"
+ "Either make this field a pointer or put the declaration of its type before this struct.");
+ return false;
+ } else if (size == SIZE_MAX-1) {
+ err_print(f->where, "Circular dependency in structs! You will need to make this member a pointer.");
+ return false;
+ }
+ size_t falign = compiler_alignof(f->type);
+ if (falign > total_align)
+ total_align = falign;
+ /* align */
+ bytes += ((falign - bytes) % falign + falign) % falign; /* = -bytes mod falign */
+ assert(bytes % falign == 0);
+ f->offset = bytes;
+ /* add size */
+ bytes += size;
+ }
+ bytes += ((total_align - bytes) % total_align + total_align) % total_align; /* = -bytes mod align */
+ s->size = bytes;
+ s->align = total_align;
+ }
+ s->flags &= (StructFlags)~(StructFlags)STRUCT_DEF_RESOLVING;
+ s->flags |= STRUCT_DEF_RESOLVED;
+ }
+ return true;
+}
+
/* are a and b EXACTLY equal (not counting flags)? */
static bool type_eq_exact(Type *a, Type *b) {
@@ -2000,7 +2015,6 @@ static Status types_expr(Typer *tr, Expression *e) {
} else {
char *s = cstr(i_str, i_len);
err_print(e->where, "Conflicting declarations for identifier %s.", s);
- free(s);
char *also = "";
if (previous_use_which_uses_i) {
/* i was use'd twice */
@@ -2010,6 +2024,7 @@ static Status types_expr(Typer *tr, Expression *e) {
/* i was declared then used. */
info_print(ident_decl_location(translated), "%s was declared here.", s);
}
+ free(s);
info_print(use->expr.where, "...and %simported by this use statement.", also);
return false;
}
diff --git a/types.h b/types.h
index 9a19d5b..fd02a05 100644
--- a/types.h
+++ b/types.h
@@ -58,6 +58,19 @@ typedef uint64_t U64;
#define U32_FMT "%" PRIu32
#define U64_FMT "%" PRIu64
+typedef int8_t I8;
+#define I8_MAX INT8_MAX
+typedef int16_t I16;
+#define I16_MAX INT16_MAX
+typedef int32_t I32;
+#define I32_MAX INT32_MAX
+typedef int64_t I64;
+#define I64_MAX INT64_MAX
+#define I8_FMT "%" PRId8
+#define I16_FMT "%" PRId16
+#define I32_FMT "%" PRId32
+#define I64_FMT "%" PRId64
+
#if __STDC_VERSION__ >= 199901
#include <stdbool.h>
#elif defined __cplusplus
@@ -75,19 +88,6 @@ typedef U8 bool;
#define Status bool WarnUnusedResult
-typedef int8_t I8;
-#define I8_MAX INT8_MAX
-typedef int16_t I16;
-#define I16_MAX INT16_MAX
-typedef int32_t I32;
-#define I32_MAX INT32_MAX
-typedef int64_t I64;
-#define I64_MAX INT64_MAX
-#define I8_FMT "%" PRId8
-#define I16_FMT "%" PRId16
-#define I32_FMT "%" PRId32
-#define I64_FMT "%" PRId64
-
/* NOTE: if you change these, make sure you change hash_tables.c */
typedef float F32;
typedef double F64;
@@ -500,16 +500,17 @@ typedef Block *BlockPtr;
enum {
STRUCT_DEF_FOUND_OFFSETS = 0x01,
- STRUCT_DEF_FINDING_OFFSETS = 0x02,
- STRUCT_DEF_CGEN_DECLARED = 0x04,
- STRUCT_DEF_CGEN_DEFINED = 0x08,
- STRUCT_DEF_RESOLVED = 0x10
+ STRUCT_DEF_CGEN_DECLARED = 0x02,
+ STRUCT_DEF_CGEN_DEFINED = 0x04,
+ STRUCT_DEF_RESOLVED = 0x08,
+ STRUCT_DEF_RESOLVING = 0x10
};
+typedef U8 StructFlags;
typedef struct StructDef {
/* these two only exist after resolving (before then, it's scope.stmts) */
Field *fields;
Location where;
- U8 flags;
+ StructFlags flags;
/*
use this instead of fields when looking up a field, because it will include "use"d things.
this only consists of statements which are declarations after typing (and not #ifs,