diff options
-rw-r--r-- | cgen.c | 36 | ||||
-rw-r--r-- | eval.c | 101 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | parse.c | 18 | ||||
-rw-r--r-- | test.toc | 14 | ||||
-rw-r--r-- | types.c | 10 | ||||
-rw-r--r-- | types.h | 4 |
7 files changed, 160 insertions, 27 deletions
@@ -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; @@ -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: @@ -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 @@ -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: @@ -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; }; @@ -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 */ @@ -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; |