summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c36
-rw-r--r--eval.c101
-rw-r--r--main.c4
-rw-r--r--parse.c18
-rw-r--r--test.toc14
-rw-r--r--types.c10
-rw-r--r--types.h4
7 files changed, 160 insertions, 27 deletions
diff --git a/cgen.c b/cgen.c
index 57282af..a498bc3 100644
--- a/cgen.c
+++ b/cgen.c
@@ -93,8 +93,9 @@ static bool cgen_fn_is_direct(CGenerator *g, Declaration *d) {
static bool cgen_uses_ptr(Type *t) {
switch (t->kind) {
case TYPE_TUPLE:
- case TYPE_ARR:
+ case TYPE_STRUCT:
return true;
+ case TYPE_ARR: /* TODO: test me */
case TYPE_BUILTIN:
case TYPE_PTR:
case TYPE_FN:
@@ -117,11 +118,10 @@ static void cgen_ident(CGenerator *g, Identifier i) {
} else {
cgen_indent(g);
IdentDecl *idecl = ident_decl(i);
- assert(idecl);
- if (idecl->flags & IDECL_FLAG_CGEN_PTR)
+ if (idecl && (idecl->flags & IDECL_FLAG_CGEN_PTR))
cgen_write(g, "(*");
fprint_ident(cgen_writing_to(g), i);
- if (idecl->flags & IDECL_FLAG_CGEN_PTR)
+ if (idecl && (idecl->flags & IDECL_FLAG_CGEN_PTR))
cgen_write(g, ")");
}
}
@@ -180,6 +180,21 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) {
case TYPE_UNKNOWN:
err_print(where, "Can't determine type.");
return false;
+ case TYPE_STRUCT:
+ cgen_write(g, "struct {");
+ g->indent_lvl++;
+ cgen_nl(g);
+ arr_foreach(t->struc.fields, Field, f) {
+ if (!cgen_type_pre(g, f->type, where)) return false;
+ cgen_write(g, " ");
+ cgen_ident(g, f->name);
+ if (!cgen_type_post(g, f->type, where)) return false;
+ cgen_write(g, ";");
+ cgen_nl(g);
+ }
+ g->indent_lvl--;
+ cgen_write(g, "}");
+ break;
case TYPE_TUPLE:
case TYPE_TYPE:
/* We should never try to generate this type */
@@ -261,6 +276,7 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) {
case TYPE_TYPE:
case TYPE_SLICE:
case TYPE_USER:
+ case TYPE_STRUCT:
break;
}
return true;
@@ -364,6 +380,7 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E
case TYPE_FN:
case TYPE_PTR:
case TYPE_SLICE:
+ case TYPE_STRUCT:
case TYPE_UNKNOWN:
if (set_expr) {
if (!cgen_expr(g, set_expr)) return false;
@@ -1038,9 +1055,8 @@ static void cgen_zero_value(CGenerator *g, Type *t) {
cgen_write(g, "{NULL, 0}");
break;
case TYPE_ARR:
- cgen_write(g, "{");
- cgen_zero_value(g, t->arr.of);
- cgen_write(g, "}");
+ case TYPE_STRUCT:
+ cgen_write(g, "{0}");
break;
case TYPE_USER:
cgen_zero_value(g, ident_typeval(t->user.name));
@@ -1129,11 +1145,13 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) {
case TYPE_VOID:
case TYPE_BUILTIN:
case TYPE_PTR:
+ case TYPE_STRUCT:
break;
}
return true;
}
+/* generate a value from a pointer */
static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) {
switch (t->kind) {
case TYPE_TUPLE:
@@ -1156,6 +1174,10 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) {
case TYPE_SLICE:
cgen_write(g, "{d%p_, %lu}", v, ((Slice *)v)->n);
break;
+ case TYPE_STRUCT:
+ err_print(where, "TODO");
+ /* TODO */
+ break;
case TYPE_FN:
cgen_fn_name(g, *(FnExpr **)v);
break;
diff --git a/eval.c b/eval.c
index a8a3fe0..eb52428 100644
--- a/eval.c
+++ b/eval.c
@@ -1,3 +1,4 @@
+static size_t compiler_sizeof(Type *t);
static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v);
static bool eval_expr(Evaluator *ev, Expression *e, Value *v);
static bool block_enter(Block *b, Statement *stmts, U32 flags);
@@ -43,6 +44,68 @@ static size_t compiler_sizeof_builtin(BuiltinType b) {
return 0;
}
+static size_t compiler_alignof(Type *t) {
+ switch (t->kind) {
+ case TYPE_BUILTIN:
+ return compiler_sizeof_builtin(t->builtin);
+ case TYPE_VOID:
+ return 1;
+ case TYPE_FN:
+ return sizeof(FnExpr *);
+ case TYPE_PTR:
+ return sizeof(void *);
+ case TYPE_TUPLE:
+ return sizeof(Value *);
+ case TYPE_ARR:
+ return compiler_alignof(t->arr.of);
+ case TYPE_SLICE:
+ if (sizeof(void *) > sizeof(size_t))
+ return sizeof(void *);
+ else
+ return sizeof(size_t);
+ case TYPE_TYPE:
+ return sizeof(Type *);
+ case TYPE_USER:
+ return compiler_alignof(ident_typeval(t->user.name));
+ case TYPE_STRUCT: {
+ /* assume the align of a struct is (at most) the greatest align out of its children's */
+ size_t align = 1;
+ arr_foreach(t->struc.fields, Field, f) {
+ size_t falign = compiler_alignof(f->type);
+ if (falign > align) align = falign;
+ }
+ return align;
+ }
+ case TYPE_UNKNOWN:
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+/* finds offsets and size */
+/* OPTIM: don't do this once per Type, but once per struct */
+static void eval_struct_find_offsets(Type *t) {
+ assert(t->kind == TYPE_STRUCT);
+ if (!(t->flags & TYPE_FLAG_STRUCT_FOUND_OFFSETS)) {
+ size_t bytes = 0;
+ arr_foreach(t->struc.fields, Field, f) {
+ size_t falign = compiler_alignof(f->type);
+ /* align */
+ bytes += ((falign - bytes) % falign + falign) % falign; /* = -bytes mod falign */
+ assert(bytes % falign == 0);
+ f->offset = bytes;
+ /* add size */
+ bytes += compiler_sizeof(f->type);
+ }
+ /* final align */
+ size_t align = compiler_alignof(t);
+ bytes += ((align - bytes) % align + align) % align; /* = -bytes mod align */
+ t->struc.size = bytes;
+ t->flags |= TYPE_FLAG_STRUCT_FOUND_OFFSETS;
+ }
+}
+
/* size of a type at compile time */
static size_t compiler_sizeof(Type *t) {
switch (t->kind) {
@@ -62,6 +125,10 @@ static size_t compiler_sizeof(Type *t) {
return sizeof(Type *);
case TYPE_USER:
return compiler_sizeof(ident_typeval(t->user.name));
+ case TYPE_STRUCT: {
+ eval_struct_find_offsets(t);
+ return t->struc.size;
+ } break;
case TYPE_VOID:
case TYPE_UNKNOWN:
return 0;
@@ -100,6 +167,7 @@ static bool val_truthiness(Value *v, Type *t) {
case TYPE_USER:
case TYPE_TYPE:
case TYPE_TUPLE:
+ case TYPE_STRUCT:
break;
}
assert(0);
@@ -187,6 +255,14 @@ static void val_copy(Evaluator *ev, Value *dest, Value *src, Type *t) {
dest->tuple = err_malloc(bytes);
memcpy(dest->tuple, src->tuple, bytes);
} break;
+ case TYPE_STRUCT: {
+ size_t bytes = compiler_sizeof(t);
+ if (ev)
+ dest->struc = evalr_malloc(ev, bytes);
+ else
+ dest->struc = err_malloc(bytes);
+ memcpy(dest->struc, src->struc, bytes);
+ } break;
case TYPE_USER:
val_copy(ev, dest, src, ident_typeval(t->user.name));
break;
@@ -207,6 +283,8 @@ static void *val_ptr_to_free(Value *v, Type *t) {
return v->arr;
case TYPE_TUPLE:
return v->tuple;
+ case TYPE_STRUCT:
+ return v->struc;
case TYPE_USER:
return val_ptr_to_free(v, ident_typeval(t->user.name));
}
@@ -295,15 +373,19 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
vout->boolv = val_truthiness(vin, from);
return;
}
+ if (from->kind == TYPE_USER || to->kind == TYPE_USER) {
+ *vout = *vin;
+ return;
+ }
+
switch (from->kind) {
case TYPE_VOID:
case TYPE_UNKNOWN:
case TYPE_TUPLE:
- case TYPE_TYPE:
- assert(0); break;
case TYPE_USER:
- *vout = *vin;
- break;
+ case TYPE_TYPE:
+ case TYPE_STRUCT:
+ assert(0); break;
case TYPE_BUILTIN:
switch (to->kind) {
case TYPE_BUILTIN:
@@ -323,8 +405,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
}
break;
case TYPE_USER:
- *vout = *vin;
- break;
+ case TYPE_STRUCT:
case TYPE_SLICE:
case TYPE_VOID:
case TYPE_UNKNOWN:
@@ -355,6 +436,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
case TYPE_ARR:
case TYPE_BUILTIN:
case TYPE_TYPE:
+ case TYPE_STRUCT:
assert(0); break;
}
break;
@@ -388,6 +470,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
case TYPE_TUPLE:
case TYPE_VOID:
case TYPE_TYPE:
+ case TYPE_STRUCT:
assert(0);
break;
}
@@ -411,6 +494,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
case TYPE_VOID:
case TYPE_BUILTIN:
case TYPE_TYPE:
+ case TYPE_STRUCT:
assert(0); break;
}
break;
@@ -434,6 +518,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
case TYPE_VOID:
case TYPE_BUILTIN:
case TYPE_TYPE:
+ case TYPE_STRUCT:
assert(0); break;
}
break;
@@ -445,6 +530,7 @@ static void eval_deref(Value *v, void *ptr, Type *type) {
switch (type->kind) {
case TYPE_PTR: v->ptr = *(void **)ptr; break;
case TYPE_ARR: v->arr = ptr; break; /* when we have a pointer to an array, it points directly to the data in that array. */
+ case TYPE_STRUCT: v->struc = ptr; break; /* same for structs */
case TYPE_FN: v->fn = *(FnExpr **)ptr; break;
case TYPE_TUPLE: v->tuple = *(Value **)ptr; break;
case TYPE_BUILTIN:
@@ -482,7 +568,8 @@ static void eval_deref(Value *v, void *ptr, Type *type) {
static void eval_deref_set(void *set, Value *to, Type *type) {
switch (type->kind) {
case TYPE_PTR: *(void **)set = to->ptr; break;
- case TYPE_ARR: *(void **)set = to->arr; break;
+ case TYPE_ARR: memcpy(set, to->arr, compiler_sizeof(type)); break; /* TODO: test this */
+ case TYPE_STRUCT: memcpy(set, to->struc, compiler_sizeof(type)); break;
case TYPE_FN: *(FnExpr **)set = to->fn; break;
case TYPE_TUPLE: *(Value **)set = to->tuple; break;
case TYPE_BUILTIN:
diff --git a/main.c b/main.c
index da53706..3c0e4ef 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,11 @@
/*
TODO:
structs
+structs can't have tuple members
+dot
length of slice/arr with .len
+verify size of struct, align of fields
+pointers to futurely-declared types
don't allow while {3; 5} (once break is added)
allow omission of trailing ; in foo @= fn() {}
any odd number of "s for a string
diff --git a/parse.c b/parse.c
index 747c68b..639ec90 100644
--- a/parse.c
+++ b/parse.c
@@ -153,7 +153,6 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
return str_copy(buffer, bufsize, s);
}
case TYPE_FN: {
- /* number of chars written */
size_t written = str_copy(buffer, bufsize, "fn (");
Type *ret_type = t->fn.types;
Type *param_types = ret_type + 1;
@@ -169,7 +168,16 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
written += type_to_str_(ret_type, buffer + written, bufsize - written);
}
return written;
- } break;
+ }
+ case TYPE_STRUCT: {
+ size_t written = str_copy(buffer, bufsize, "struct { ");
+ arr_foreach(t->struc.fields, Field, f) {
+ written += type_to_str_(f->type, buffer + written, bufsize - written);
+ written += str_copy(buffer + written, bufsize - written, "; ");
+ }
+ written += str_copy(buffer + written, bufsize - written, " }");
+ return written;
+ }
case TYPE_ARR: {
size_t written = str_copy(buffer, bufsize, "[");
if (t->flags & TYPE_FLAG_RESOLVED) {
@@ -181,13 +189,13 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
written += str_copy(buffer + written, bufsize - written, "]");
written += type_to_str_(t->arr.of, buffer + written, bufsize - written);
return written;
- } break;
+ }
case TYPE_SLICE: {
size_t written = str_copy(buffer, bufsize, "[");
written += str_copy(buffer + written, bufsize - written, "]");
written += type_to_str_(t->slice, buffer + written, bufsize - written);
return written;
- } break;
+ }
case TYPE_TUPLE: {
size_t written = str_copy(buffer, bufsize, "(");
arr_foreach(t->tuple, Type, child) {
@@ -464,6 +472,7 @@ static bool parse_type(Parser *p, Type *type) {
err_print(t->token->where, "Expected { to follow struct.");
return false;
}
+ t->token++;
{
while (!token_is_kw(t->token, KW_RBRACE)) {
Declaration field_decl;
@@ -480,6 +489,7 @@ static bool parse_type(Parser *p, Type *type) {
idx++;
}
}
+ t->token++;
}
break;
default:
diff --git a/test.toc b/test.toc
index d56dc78..ebf613f 100644
--- a/test.toc
+++ b/test.toc
@@ -3,15 +3,11 @@ puti @= fn(x: int) {
");
};
-
-F @= fn(int,int);
+Point @= struct {
+ x, y : int;
+ something:fn(f32);
+};
main @= fn() {
-
- foo := (fn(x,y:int) {}) as F;
-
- bar := foo as fn(int, int);
- baz := bar as &char;
- quux := baz as int;
- puti(quux);
+ p:Point;
};
diff --git a/types.c b/types.c
index eb5b0df..65534a1 100644
--- a/types.c
+++ b/types.c
@@ -45,6 +45,7 @@ static bool type_eq(Type *a, Type *b) {
return a->user.name == b->user.name;
case TYPE_BUILTIN:
return a->builtin == b->builtin;
+ case TYPE_STRUCT: return false;
case TYPE_FN: {
if (arr_len(a->fn.types) != arr_len(b->fn.types)) return false;
@@ -367,6 +368,12 @@ static bool type_resolve(Typer *tr, Type *t, Location where) {
return false;
}
break;
+ case TYPE_STRUCT:
+ arr_foreach(t->struc.fields, Field, f) {
+ if (!type_resolve(tr, f->type, where))
+ return false;
+ }
+ break;
case TYPE_UNKNOWN:
case TYPE_VOID:
case TYPE_TYPE:
@@ -384,6 +391,7 @@ static bool type_can_be_truthy(Type *t) {
case TYPE_ARR:
case TYPE_TYPE:
case TYPE_USER:
+ case TYPE_STRUCT:
return false;
case TYPE_FN:
case TYPE_UNKNOWN:
@@ -413,6 +421,7 @@ static Status type_cast_status(Type *from, Type *to) {
}
switch (from->kind) {
case TYPE_UNKNOWN: return STATUS_NONE;
+ case TYPE_STRUCT:
case TYPE_TYPE:
case TYPE_VOID:
return STATUS_ERR;
@@ -436,6 +445,7 @@ static Status type_cast_status(Type *from, Type *to) {
case TYPE_TYPE:
case TYPE_TUPLE:
case TYPE_SLICE:
+ case TYPE_STRUCT:
case TYPE_ARR:
case TYPE_VOID:
case TYPE_USER: /* handled above */
diff --git a/types.h b/types.h
index f5e25e7..e8c739f 100644
--- a/types.h
+++ b/types.h
@@ -88,6 +88,7 @@ typedef union Value {
struct FnExpr *fn;
void *arr;
void *ptr;
+ void *struc;
union Value *tuple;
Slice slice;
struct Type *type;
@@ -272,10 +273,12 @@ typedef enum {
typedef struct {
Identifier name;
struct Type *type;
+ size_t offset; /* offset during compile time */
} Field;
#define TYPE_FLAG_FLEXIBLE 0x01
#define TYPE_FLAG_RESOLVED 0x02
+#define TYPE_FLAG_STRUCT_FOUND_OFFSETS 0x04
typedef struct Type {
Location where;
@@ -301,6 +304,7 @@ typedef struct Type {
} user;
struct {
Field *fields;
+ size_t size; /* size of this struct during compile time */
} struc;
};
} Type;