summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-27 20:04:54 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-27 20:05:05 -0400
commit2d2ee05b901728efca22adc2ba02ec09397fd6a0 (patch)
treeb88148f32d6f5282f1c6ab810d972f095f41c9a3
parent3f3e320908115c0b257040d187f07f494e16d30b (diff)
user defined types
-rw-r--r--cgen.c39
-rw-r--r--eval.c41
-rw-r--r--identifiers.c23
-rw-r--r--main.c5
-rw-r--r--parse.c43
-rw-r--r--test.toc41
-rw-r--r--types.c16
-rw-r--r--types.h6
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, "<type>");
+ 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;