From 2d2ee05b901728efca22adc2ba02ec09397fd6a0 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 27 Oct 2019 20:04:54 -0400 Subject: user defined types --- cgen.c | 39 +++++++++++++++++++++++++++++++++++---- eval.c | 41 +++++++++++++++++++++++++++++++++++++---- identifiers.c | 23 ++++++++++++++++++++++- main.c | 5 ++++- parse.c | 43 +++++++++++++++++++++++++++++++------------ test.toc | 41 ++++++++++++++--------------------------- types.c | 16 +++++++++++++++- types.h | 6 +++++- 8 files changed, 163 insertions(+), 51 deletions(-) diff --git a/cgen.c b/cgen.c index 0cf65a7..947ad0d 100644 --- a/cgen.c +++ b/cgen.c @@ -103,6 +103,8 @@ static bool cgen_uses_ptr(Type *t) { case TYPE_UNKNOWN: case TYPE_TYPE: return false; + case TYPE_USER: + return cgen_uses_ptr(ident_typeval(t->user.name)); } assert(0); return false; @@ -183,6 +185,9 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { /* We should never try to generate this type */ assert(0); return false; + case TYPE_USER: + cgen_ident(g, t->user.name); + break; } return true; } @@ -255,6 +260,7 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) { case TYPE_TUPLE: case TYPE_TYPE: case TYPE_SLICE: + case TYPE_USER: break; } return true; @@ -348,6 +354,9 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E where = to_expr->where; if (!cgen_expr_pre(g, to_expr)) return false; } + while (type->kind == TYPE_USER) { + type = ident_typeval(type->user.name); + } switch (type->kind) { case TYPE_BUILTIN: case TYPE_FN: @@ -403,6 +412,7 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E if (!cgen_set_tuple(g, set_expr->tuple, NULL, NULL, to_expr)) return false; break; + case TYPE_USER: case TYPE_VOID: case TYPE_TYPE: assert(0); @@ -993,6 +1003,9 @@ static void cgen_zero_value(CGenerator *g, Type *t) { cgen_zero_value(g, t->arr.of); cgen_write(g, "}"); break; + case TYPE_USER: + cgen_zero_value(g, ident_typeval(t->user.name)); + break; case TYPE_TYPE: case TYPE_VOID: case TYPE_UNKNOWN: @@ -1066,6 +1079,10 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { return false; } break; + case TYPE_USER: + if (!cgen_val_ptr_pre(g, v, ident_typeval(t->user.name), where)) + return false; + break; case TYPE_FN: case TYPE_TYPE: case TYPE_UNKNOWN: @@ -1122,6 +1139,10 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { case BUILTIN_BOOL: cgen_write(g, "%s", *(bool *)v ? "true" : "false"); break; } break; + case TYPE_USER: + if (!cgen_val_ptr(g, v, ident_typeval(t->user.name), where)) + return false; + break; } return true; } @@ -1149,16 +1170,26 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { } else if ((d->flags & DECL_FLAG_CONST) || g->block == NULL) { /* declarations where we use a value */ for (size_t idx = 0; idx < arr_len(d->idents); idx++) { - Identifier *i = &d->idents[idx]; + Identifier i = d->idents[idx]; Type *type = is_tuple ? &d->type.tuple[idx] : &d->type; Value *val = is_tuple ? &d->val.tuple[idx] : &d->val; + if (type->kind == TYPE_TYPE) { + cgen_write(g, "typedef "); + if (!cgen_type_pre(g, val->type, d->where)) return false; + cgen_write(g, " "); + cgen_ident(g, i); + if (!cgen_type_post(g, val->type, d->where)) return false; + cgen_write(g, ";"); + cgen_nl(g); + continue; + } if (!cgen_val_pre(g, val, type, d->where)) return false; if (g->block != NULL) cgen_write(g, "static "); if (!cgen_type_pre(g, type, d->where)) return false; cgen_write(g, " "); - cgen_ident(g, *i); + cgen_ident(g, i); if (!cgen_type_post(g, type, d->where)) return false; if (has_expr) { cgen_write(g, " = "); @@ -1171,11 +1202,11 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { } else { /* declarations where we use an expression */ for (size_t idx = 0; idx < arr_len(d->idents); idx++) { - Identifier *i = &d->idents[idx]; + Identifier i = d->idents[idx]; Type *type = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx] : &d->type; if (!cgen_type_pre(g, type, d->where)) return false; cgen_write(g, " "); - cgen_ident(g, *i); + cgen_ident(g, i); if (!cgen_type_post(g, type, d->where)) return false; if (!has_expr) { cgen_write(g, " = "); diff --git a/eval.c b/eval.c index 445e5c8..de3d1ac 100644 --- a/eval.c +++ b/eval.c @@ -57,6 +57,8 @@ static size_t compiler_sizeof(Type *t) { return sizeof(Slice); case TYPE_TYPE: return sizeof(Type *); + case TYPE_USER: + return compiler_sizeof(ident_typeval(t->user.name)); case TYPE_VOID: case TYPE_UNKNOWN: return 0; @@ -92,6 +94,7 @@ static bool val_truthiness(Value *v, Type *t) { case TYPE_FN: return v->fn != NULL; case TYPE_ARR: return t->arr.n > 0; case TYPE_SLICE: return v->slice.n > 0; + case TYPE_USER: case TYPE_TYPE: case TYPE_TUPLE: break; @@ -181,6 +184,9 @@ 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_USER: + val_copy(ev, dest, src, ident_typeval(t->user.name)); + break; } } @@ -198,6 +204,8 @@ static void *val_ptr_to_free(Value *v, Type *t) { return v->arr; case TYPE_TUPLE: return v->tuple; + case TYPE_USER: + return val_ptr_to_free(v, ident_typeval(t->user.name)); } assert(0); return NULL; } @@ -285,10 +293,14 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { return; } switch (from->kind) { - case TYPE_VOID: assert(0); break; - case TYPE_UNKNOWN: assert(0); break; - case TYPE_TUPLE: assert(0); break; - case TYPE_TYPE: assert(0); break; + case TYPE_VOID: + case TYPE_UNKNOWN: + case TYPE_TUPLE: + case TYPE_TYPE: + assert(0); break; + case TYPE_USER: + *vout = *vin; + break; case TYPE_BUILTIN: switch (to->kind) { case TYPE_BUILTIN: @@ -307,6 +319,9 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { default: assert(0); break; } break; + case TYPE_USER: + *vout = *vin; + break; case TYPE_SLICE: case TYPE_VOID: case TYPE_UNKNOWN: @@ -327,6 +342,9 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_FN: vout->fn = vin->fn; break; + case TYPE_USER: + *vout = *vin; + break; case TYPE_SLICE: case TYPE_UNKNOWN: case TYPE_TUPLE: @@ -359,6 +377,9 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_FN: vout->fn = vin->ptr; break; + case TYPE_USER: + *vout = *vin; + break; case TYPE_SLICE: case TYPE_UNKNOWN: case TYPE_TUPLE: @@ -377,6 +398,9 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_ARR: vout->arr = vin->arr; break; + case TYPE_USER: + *vout = *vin; + break; case TYPE_SLICE: case TYPE_FN: case TYPE_UNKNOWN: @@ -398,6 +422,9 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_SLICE: vout->slice = vin->slice; break; + case TYPE_USER: + *vout = *vin; + break; case TYPE_FN: case TYPE_UNKNOWN: case TYPE_TUPLE: @@ -439,6 +466,9 @@ static void eval_deref(Value *v, void *ptr, Type *type) { case TYPE_TYPE: v->type = *(Type **)ptr; break; + case TYPE_USER: + eval_deref(v, ptr, ident_typeval(type->user.name)); + break; case TYPE_VOID: case TYPE_UNKNOWN: assert(0); @@ -474,6 +504,9 @@ static void eval_deref_set(void *set, Value *to, Type *type) { case TYPE_TYPE: *(Type **)set = to->type; break; + case TYPE_USER: + eval_deref_set(set, to, ident_typeval(type->user.name)); + break; case TYPE_VOID: case TYPE_UNKNOWN: assert(0); diff --git a/identifiers.c b/identifiers.c index 2dfa812..3dc4099 100644 --- a/identifiers.c +++ b/identifiers.c @@ -1,4 +1,3 @@ -/* OPTIM: use a hash table */ #if CHAR_MAX - CHAR_MIN > 255 #error "Currently only systems with 8-bit characters can compile toc." /* TODO: maybe do a run-time error for large characters? */ @@ -177,3 +176,25 @@ static void idents_test(void) { assert(strcmp(s, " bar") == 0); idents_free(&ids); } + +/* if i has a non-constant declaration, returns NULL. */ +static Value *ident_decl_val(Identifier i) { + IdentDecl *idecl = ident_decl(i); + if (!idecl) return NULL; + Declaration *d = idecl->decl; + if (!(d->flags & DECL_FLAG_CONST)) + return NULL; + if (d->type.kind == TYPE_TUPLE) { + size_t idx; + for (idx = 0; idx < arr_len(d->idents); idx++) { + if (d->idents[idx] == i) + break; + } + assert(idx < arr_len(d->idents)); + return &d->val.tuple[idx]; + } else return &d->val; +} + +static inline Type *ident_typeval(Identifier i) { + return ident_decl_val(i)->type; +} diff --git a/main.c b/main.c index ea6e821..e876310 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,6 @@ /* TODO: +make sure user defined types work structs length of slice/arr with .len don't allow while {3; 5} (once break is added) @@ -54,7 +55,9 @@ int main(int argc, char **argv) { Identifiers file_idents; idents_create(&file_idents); Tokenizer t; - ErrCtx err_ctx = {in_filename, true}; + ErrCtx err_ctx; + err_ctx.filename = in_filename; + err_ctx.enabled = true; tokr_create(&t, &file_idents, &err_ctx); if (!tokenize_string(&t, contents)) { err_fprint(TEXT_IMPORTANT("Errors occured while preprocessing.\n")); diff --git a/parse.c b/parse.c index 73cbe80..8b7f7fd 100644 --- a/parse.c +++ b/parse.c @@ -205,6 +205,11 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) { } case TYPE_TYPE: return str_copy(buffer, bufsize, ""); + case TYPE_USER: { + char *ident_str = ident_to_str(t->user.name); + size_t ret = str_copy(buffer, bufsize, ident_str); + return ret; + } } assert(0); @@ -323,7 +328,8 @@ static Token *expr_find_end(Parser *p, U16 flags, bool *is_vbs) { } } -static bool parse_type(Parser *p, Type *type) { +#define PARSE_TYPE_EXPR 0x01 /* this might actually be an expression */ +static bool parse_type(Parser *p, Type *type, U16 flags) { Tokenizer *t = p->tokr; type->where = t->token->where; type->flags = 0; @@ -354,7 +360,7 @@ static bool parse_type(Parser *p, Type *type) { if (!token_is_kw(t->token, KW_RPAREN)) { while (1) { Type *param_type = parser_arr_add(p, &type->fn.types); - if (!parse_type(p, param_type)) return false; + if (!parse_type(p, param_type, flags)) return false; if (param_type->kind == TYPE_TUPLE) { err_print(param_type->where, "Functions cannot have tuples as parameters."); return false; @@ -380,7 +386,7 @@ static bool parse_type(Parser *p, Type *type) { ret_type->kind = TYPE_VOID; ret_type->flags = 0; } else { - if (!parse_type(p, ret_type)) + if (!parse_type(p, ret_type, flags)) return false; } break; @@ -395,7 +401,7 @@ static bool parse_type(Parser *p, Type *type) { type->kind = TYPE_SLICE; type->slice = parser_malloc(p, sizeof *type->slice); t->token++; /* move past ] */ - if (!parse_type(p, type->slice)) return false; + if (!parse_type(p, type->slice, flags)) return false; if (type->slice->kind == TYPE_TUPLE) { err_print(type->where, "You cannot have a slice of tuples."); return false; @@ -407,7 +413,7 @@ static bool parse_type(Parser *p, Type *type) { if (!parse_expr(p, type->arr.n_expr, end)) return false; t->token = end + 1; /* go past ] */ type->arr.of = parser_malloc(p, sizeof *type->arr.of); - if (!parse_type(p, type->arr.of)) return false; + if (!parse_type(p, type->arr.of, flags)) return false; if (type->arr.of->kind == TYPE_TUPLE) { err_print(type->where, "You cannot have an array of tuples."); return false; @@ -420,7 +426,7 @@ static bool parse_type(Parser *p, Type *type) { t->token++; /* move past ( */ while (1) { Type *child = parser_arr_add(p, &type->tuple); - if (!parse_type(p, child)) return false; + if (!parse_type(p, child, flags)) return false; if (child->kind == TYPE_TUPLE) { err_print(child->where, "Tuples cannot contain tuples."); return false; @@ -443,7 +449,7 @@ static bool parse_type(Parser *p, Type *type) { type->kind = TYPE_PTR; type->ptr = parser_malloc(p, sizeof *type->ptr); t->token++; /* move past & */ - if (!parse_type(p, type->ptr)) return false; + if (!parse_type(p, type->ptr, flags)) return false; if (type->ptr->kind == TYPE_TUPLE) { err_print(type->ptr->where, "You cannot have a pointer to a tuple."); return false; @@ -454,6 +460,18 @@ static bool parse_type(Parser *p, Type *type) { return false; } break; + case TOKEN_IDENT: + if (!(flags & PARSE_TYPE_EXPR)) { + /* user-defined type */ + puts("user-defined type"); + type->kind = TYPE_USER; + type->user.name = t->token->ident; + t->token++; + } else { + tokr_err(t, "Unrecognized type."); + return false; + } + break; default: tokr_err(t, "Unrecognized type."); return false; @@ -595,7 +613,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { f->ret_type = f->ret_decls[0].type; } } else { - if (!parse_type(p, &f->ret_type)) { + if (!parse_type(p, &f->ret_type, 0)) { ret = false; } } @@ -682,9 +700,10 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { bool prev = t->err_ctx->enabled; t->err_ctx->enabled = false; /* temporarily disable error context */ Token *before = t->token; - if (parse_type(p, &e->typeval) && t->token == end) { + if (parse_type(p, &e->typeval, PARSE_TYPE_EXPR) && t->token == end) { /* it's a type! */ e->kind = EXPR_TYPE; + t->err_ctx->enabled = prev; return true; } t->token = before; @@ -977,7 +996,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { err_print(t->token->where, "Expected ( to follow new."); } t->token++; - if (!parse_type(p, &e->new.type)) return false; + if (!parse_type(p, &e->new.type, 0)) return false; if (token_is_kw(t->token, KW_COMMA)) { /* new(int, 5) */ t->token++; @@ -1028,7 +1047,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { if (!parse_expr(p, casted, lowest_precedence_op)) return false; t->token = lowest_precedence_op + 1; - if (!parse_type(p, &e->cast.type)) + if (!parse_type(p, &e->cast.type, 0)) return false; if (t->token != end) { tokr_err(t, "Cast expression continues after type"); @@ -1352,7 +1371,7 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_ if (annotates_type) { d->flags |= DECL_FLAG_ANNOTATES_TYPE; Type type; - if (!parse_type(p, &type)) { + if (!parse_type(p, &type, 0)) { goto ret_false; } d->type = type; diff --git a/test.toc b/test.toc index 652af26..3cc5c91 100644 --- a/test.toc +++ b/test.toc @@ -1,34 +1,21 @@ -// puti @= fn(x: int) { -// #C("printf(\"%ld\\n\", (long)x); -// "); -// }; +puti @= fn(x: int) { + #C("printf(\"%ld\\n\", (long)x); +"); +}; -// putch @= fn(x: char) { -// #C("printf(\"%c\\n\", x); -// "); -// }; +putch @= fn(x: char) { + #C("printf(\"%c\\n\", x); +"); +}; -// putf @= fn(x: float) { -// #C("printf(\"%f\\n\", (double)x); -// "); -// }; +putf @= fn(x: float) { + #C("printf(\"%f\\n\", (double)x); +"); +}; Foo @= int; -x, y : int; -a, b := 3, 5; -c: int; -d := 8; main @= fn() { - x, y : int; - a, b := 3, 5; - c: int; - d := 8; + a := 35238 as Foo; + puti(a as int); }; - -// main @= fn() { -// f := fn(x: int) { p := &x; *p = 5; }; -// x, y := 3; -// // f(3); -// // x : Foo; -// }; diff --git a/types.c b/types.c index 0acc468..27295fe 100644 --- a/types.c +++ b/types.c @@ -41,6 +41,8 @@ static bool type_eq(Type *a, Type *b) { case TYPE_VOID: return true; case TYPE_UNKNOWN: assert(0); return false; case TYPE_TYPE: return true; + case TYPE_USER: + return a->user.name == b->user.name; case TYPE_BUILTIN: return a->builtin == b->builtin; case TYPE_FN: { @@ -354,6 +356,7 @@ static bool type_resolve(Typer *tr, Type *t) { if (!type_resolve(tr, t->slice)) return false; break; + case TYPE_USER: case TYPE_UNKNOWN: case TYPE_VOID: case TYPE_TYPE: @@ -370,6 +373,7 @@ static bool type_can_be_truthy(Type *t) { case TYPE_TUPLE: case TYPE_ARR: case TYPE_TYPE: + case TYPE_USER: return false; case TYPE_FN: case TYPE_UNKNOWN: @@ -391,6 +395,13 @@ typedef enum { static Status type_cast_status(Type *from, Type *to) { if (to->kind == TYPE_UNKNOWN) return STATUS_NONE; + fprint_type(stdout, from); puts(""); + if (from->kind == TYPE_USER) { + return type_eq(to, ident_typeval(from->user.name)) ? STATUS_NONE : STATUS_ERR; + } + if (to->kind == TYPE_USER) { + return type_eq(from, ident_typeval(to->user.name)) ? STATUS_NONE : STATUS_ERR; + } switch (from->kind) { case TYPE_UNKNOWN: return STATUS_NONE; case TYPE_TYPE: @@ -418,6 +429,7 @@ static Status type_cast_status(Type *from, Type *to) { case TYPE_SLICE: case TYPE_ARR: case TYPE_VOID: + case TYPE_USER: /* handled above */ return STATUS_ERR; } break; @@ -431,7 +443,7 @@ static Status type_cast_status(Type *from, Type *to) { return STATUS_NONE; return STATUS_ERR; case BUILTIN_BOOL: - return type_can_be_truthy(to); + return type_can_be_truthy(to) ? STATUS_NONE : STATUS_ERR; } break; case TYPE_TUPLE: return STATUS_ERR; @@ -454,6 +466,8 @@ static Status type_cast_status(Type *from, Type *to) { if (to->kind == TYPE_PTR && type_eq(from->slice, to->ptr)) return STATUS_NONE; return STATUS_ERR; + case TYPE_USER: + break; } assert(0); return STATUS_ERR; diff --git a/types.h b/types.h index 5faa096..f7e0658 100644 --- a/types.h +++ b/types.h @@ -249,7 +249,8 @@ typedef enum { TYPE_ARR, TYPE_PTR, TYPE_SLICE, - TYPE_TYPE + TYPE_TYPE, + TYPE_USER /* user-defined type */ } TypeKind; typedef enum { @@ -289,6 +290,9 @@ typedef struct Type { } arr; struct Type *ptr; struct Type *slice; + struct { + Identifier name; + } user; }; } Type; -- cgit v1.2.3