diff options
-rw-r--r-- | cgen.c | 2 | ||||
-rw-r--r-- | eval.c | 22 | ||||
-rw-r--r-- | foreign.c | 48 | ||||
-rw-r--r-- | instance_table.c | 21 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | parse.c | 23 | ||||
-rw-r--r-- | test.toc | 10 | ||||
-rw-r--r-- | types.c | 14 | ||||
-rw-r--r-- | types.h | 8 |
9 files changed, 118 insertions, 32 deletions
@@ -303,6 +303,7 @@ static void cgen_type_pre(CGenerator *g, Type *t) { case BUILTIN_F64: cgen_write(g, "f64"); break; case BUILTIN_NMS: case BUILTIN_TYPE: + case BUILTIN_VARARGS: assert(0); break; } break; case TYPE_PTR: @@ -1725,6 +1726,7 @@ static void cgen_val_ptr(CGenerator *g, void *v, Type *t) { case BUILTIN_BOOL: cgen_write(g, "%s", *(bool *)v ? "true" : "false"); break; case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: assert(0); break; } @@ -40,6 +40,7 @@ static bool builtin_truthiness(Value v, BuiltinType b) { case BUILTIN_F64: return v.f64 != 0; case BUILTIN_BOOL: return v.boolv; case BUILTIN_CHAR: return v.charv != 0; + case BUILTIN_VARARGS: return arr_len(v.varargs) != 0; case BUILTIN_TYPE: case BUILTIN_NMS: break; @@ -179,6 +180,13 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) { case BUILTIN_F64: fprintf(f, F64_FMT, *(F64 *)p); break; case BUILTIN_CHAR: fprint_char_literal(f, *(char *)p); break; case BUILTIN_BOOL: fprintf(f, "%s", *(bool *)p ? "true" : "false"); break; + case BUILTIN_VARARGS: + fprintf(f, "...("); + arr_foreach(*(VarArg **)p, VarArg, varg) { + fprint_val(f, varg->val, varg->type); + } + fprintf(f, ")"); + break; case BUILTIN_TYPE: fprint_type(f, *(Type **)p); break; @@ -318,7 +326,9 @@ static inline void val_free_ptr(Value *v, Type *t) { case BUILTIN_CHAR: vout->charv = (char)vin->low; break; \ case BUILTIN_BOOL: vout->boolv = vin->low != 0; break; \ case BUILTIN_NMS: \ - case BUILTIN_TYPE: assert(0); break; \ + case BUILTIN_TYPE: \ + case BUILTIN_VARARGS: \ + assert(0); break; \ } break #define builtin_float_casts(low, up) \ @@ -329,6 +339,7 @@ static inline void val_free_ptr(Value *v, Type *t) { case BUILTIN_CHAR: \ case BUILTIN_TYPE: \ case BUILTIN_NMS: \ + case BUILTIN_VARARGS: \ assert(0); break; \ } break @@ -359,11 +370,13 @@ static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinT case BUILTIN_BOOL: case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: assert(0); break; } break; case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: assert(0); break; } @@ -440,6 +453,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case BUILTIN_F64: case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: assert(0); break; } break; @@ -515,6 +529,9 @@ static void eval_deref(Value *v, void *ptr, Type *type) { case BUILTIN_TYPE: v->type = *(Type **)ptr; break; + case BUILTIN_VARARGS: + assert(0); + break; } break; case TYPE_SLICE: @@ -554,6 +571,9 @@ static void eval_deref_set(void *set, Value *to, Type *type) { case BUILTIN_TYPE: *(Type **)set = to->type; break; + case BUILTIN_VARARGS: + assert(0); + break; } break; case TYPE_SLICE: @@ -142,6 +142,9 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val, case BUILTIN_NMS: av_start_ptr(*arg_list, fn, Namespace *, &return_val->nms); break; + case BUILTIN_VARARGS: + assert(0); + break; } break; case TYPE_STRUCT: { @@ -187,7 +190,7 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val, return true; } -static bool arg_list_add(av_alist *arg_list, Value *val, Type *type, Location where) { +static bool arg_list_add(av_alist *arg_list, Value val, Type *type, Location where) { switch (type->kind) { case TYPE_VOID: case TYPE_TUPLE: @@ -199,63 +202,68 @@ static bool arg_list_add(av_alist *arg_list, Value *val, Type *type, Location wh return false; } case TYPE_PTR: - av_ptr(*arg_list, void *, val->ptr); + av_ptr(*arg_list, void *, val.ptr); break; case TYPE_FN: warn_print(where, "Passing toc function pointer to foreign function. This will not work if the function expects a C-style function pointer."); - av_ptr(*arg_list, FnExpr *, val->fn); + av_ptr(*arg_list, FnExpr *, val.fn); break; case TYPE_BUILTIN: switch (type->builtin) { case BUILTIN_I8: - toc_av_add(127)(*arg_list, val->i8); + toc_av_add(127)(*arg_list, val.i8); break; case BUILTIN_U8: - toc_av_add(255)(*arg_list, val->u8); + toc_av_add(255)(*arg_list, val.u8); break; case BUILTIN_I16: - toc_av_add(32767)(*arg_list, val->i16); + toc_av_add(32767)(*arg_list, val.i16); break; case BUILTIN_U16: - toc_av_add(65535)(*arg_list, val->u16); + toc_av_add(65535)(*arg_list, val.u16); break; case BUILTIN_I32: - toc_av_add(2147483647)(*arg_list, val->i32); + toc_av_add(2147483647)(*arg_list, val.i32); break; case BUILTIN_U32: - toc_av_add(4294967295)(*arg_list, val->u32); + toc_av_add(4294967295)(*arg_list, val.u32); break; case BUILTIN_I64: - toc_av_add(9223372036854775807)(*arg_list, val->i64); + toc_av_add(9223372036854775807)(*arg_list, val.i64); break; case BUILTIN_U64: - toc_av_add(18446744073709551615)(*arg_list, val->u64); + toc_av_add(18446744073709551615)(*arg_list, val.u64); break; case BUILTIN_CHAR: - av_char(*arg_list, val->charv); + av_char(*arg_list, val.charv); break; case BUILTIN_BOOL: - av_uchar(*arg_list, val->boolv); + av_uchar(*arg_list, val.boolv); break; case BUILTIN_F32: - toc_av_f32(*arg_list, val->f32); + toc_av_f32(*arg_list, val.f32); break; case BUILTIN_F64: - toc_av_f64(*arg_list, val->f64); + toc_av_f64(*arg_list, val.f64); break; case BUILTIN_TYPE: - av_ptr(*arg_list, Type *, val->type); + av_ptr(*arg_list, Type *, val.type); break; case BUILTIN_NMS: - av_ptr(*arg_list, Namespace *, val->nms); + av_ptr(*arg_list, Namespace *, val.nms); + break; + case BUILTIN_VARARGS: + arr_foreach(val.varargs, VarArg, arg) { + arg_list_add(arg_list, arg->val, arg->type, where); + } break; } break; case TYPE_SLICE: - av_struct(*arg_list, Slice, val->slice); + av_struct(*arg_list, Slice, val.slice); break; case TYPE_STRUCT: - _av_struct(*arg_list, compiler_sizeof(type), compiler_alignof(type), val->struc); + _av_struct(*arg_list, compiler_sizeof(type), compiler_alignof(type), val.struc); break; case TYPE_EXPR: assert(0); @@ -310,7 +318,7 @@ static bool foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *fn_type, Val return false; size_t nparams = arr_len(fn_type->fn.types)-1; for (size_t i = 0; i < nparams; ++i) { - if (!arg_list_add(&arg_list, &args[i], &fn_type->fn.types[i+1], call_where)) + if (!arg_list_add(&arg_list, args[i], &fn_type->fn.types[i+1], call_where)) return false; } av_call(arg_list); diff --git a/instance_table.c b/instance_table.c index 58dc635..979d030 100644 --- a/instance_table.c +++ b/instance_table.c @@ -140,6 +140,14 @@ static U64 val_ptr_hash(void *v, Type *t) { case BUILTIN_F64: return f64_hash(*(F64 *)v); case BUILTIN_CHAR: return (U64)*(char *)v; case BUILTIN_BOOL: return (U64)*(bool *)v; + case BUILTIN_VARARGS: { + U64 hash = 1; + VarArg *vals = *(VarArg **)v; + arr_foreach(vals, VarArg, varg) { + hash = hash * 0x92738fd828cb68e1 + val_hash(varg->val, varg->type); + } + return hash; + } case BUILTIN_TYPE: return type_hash(*(Type **)v); case BUILTIN_NMS: @@ -216,6 +224,19 @@ static bool val_ptr_eq(void *u, void *v, Type *t) { case BUILTIN_F64: return *(F64 *)u == *(F64 *)v; case BUILTIN_BOOL: return *(bool *)u == *(bool *)v; case BUILTIN_CHAR: return *(char *)u == *(char *)v; + case BUILTIN_VARARGS: { + VarArg *us = *(VarArg **)u, *vs = *(VarArg **)v; + size_t n = arr_len(us); + if (arr_len(vs) != n) + return false; + for (size_t i = 0; i < n; ++i) { + if (!type_eq(us[i].type, vs[i].type)) + return false; + if (!val_eq(vs[i].val, us[i].val, us[i].type)) + return false; + } + return true; + } case BUILTIN_TYPE: return type_eq(*(Type **)u, *(Type **)v); case BUILTIN_NMS: @@ -8,8 +8,10 @@ /* TODO: +are we using the val stack for struct params? we probably need to, in case a struct calls a function which returns a type which uses that struct. variadic fns #foreign variadic fns +where #returns_code (function/struct body is a block, to be evaluated at compile time, which returns the actual statements -- you can use this for implementation of printf) break continue @@ -12,9 +12,8 @@ enum { PARSE_DECL_ALLOW_EXPORT = 0x08, PARSE_DECL_DONT_SET_IDECLS = 0x10 }; -static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags); +static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 flags); static Status parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end); - static bool is_decl(Tokenizer *t); static inline bool ends_decl(Token *t, DeclEndKind ends_with); @@ -157,6 +156,7 @@ static int kw_to_builtin_type(Keyword kw) { case KW_CHAR: return BUILTIN_CHAR; case KW_TYPE: return BUILTIN_TYPE; case KW_NAMESPACE: return BUILTIN_NMS; + case KW_DOTDOT: return BUILTIN_VARARGS; default: return -1; } return -1; @@ -178,6 +178,7 @@ static Keyword builtin_type_to_kw(BuiltinType t) { case BUILTIN_CHAR: return KW_CHAR; case BUILTIN_TYPE: return KW_TYPE; case BUILTIN_NMS: return KW_NAMESPACE; + case BUILTIN_VARARGS: return KW_DOTDOT; } assert(0); return KW_COUNT; @@ -544,6 +545,10 @@ static Status parse_type(Parser *p, Type *type, Location *where) { err_print(slice_where, "You cannot have a slice of tuples."); return false; } + if (type_is_builtin(type->slice, BUILTIN_VARARGS)) { + err_print(slice_where, "You cannot have a slice of varargs."); + return false; + } break; } Token *end = expr_find_end(p, 0); @@ -557,6 +562,10 @@ static Status parse_type(Parser *p, Type *type, Location *where) { err_print(of_where, "You cannot have an array of tuples."); return false; } + if (type_is_builtin(type->arr.of, BUILTIN_VARARGS)) { + err_print(of_where, "You cannot have an array of varargs."); + return false; + } } break; case KW_LT: /* tuple! */ @@ -571,6 +580,10 @@ static Status parse_type(Parser *p, Type *type, Location *where) { err_print(child_where, "Tuples cannot contain tuples."); return false; } + if (type_is_builtin(child, BUILTIN_VARARGS)) { + err_print(child_where, "Tuples cannot contain varargs."); + return false; + } if (token_is_kw(t->token, KW_GT)) { /* we're done with the tuple */ ++t->token; /* move past > */ break; @@ -595,6 +608,10 @@ static Status parse_type(Parser *p, Type *type, Location *where) { err_print(ptr_where, "You cannot have a pointer to a tuple."); return false; } + if (type_is_builtin(type->ptr, BUILTIN_VARARGS)) { + err_print(ptr_where, "You cannot have a pointer to varargs."); + return false; + } } break; case KW_STRUCT: { /* struct */ @@ -819,6 +836,8 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { ++t->token; } } break; + case KW_DOTDOT: + return true; case KW_AMPERSAND: ++t->token; /* continue; see if next thing is definitely a type */ goto continu; @@ -1,11 +1,7 @@ #include "std/io.toc", io; -arr_sum ::= fn(t,n::=, a:[n]t) t { - total := 0 as t; - for x := a { - total += x; - } - total +foo ::= fn(x: ..) { + }; main ::= fn() { @@ -13,7 +9,5 @@ main ::= fn() { a[0] = 1; a[1] = 1; a[2] = 1; - - io.puti(arr_sum(a)); }; main();
\ No newline at end of file @@ -46,6 +46,7 @@ static size_t compiler_sizeof_builtin(BuiltinType b) { case BUILTIN_BOOL: return sizeof(bool); case BUILTIN_TYPE: return sizeof(Type *); case BUILTIN_NMS: return sizeof(Namespace *); + case BUILTIN_VARARGS: return sizeof(VarArg *); } assert(0); return 0; @@ -66,6 +67,7 @@ static size_t compiler_alignof_builtin(BuiltinType b) { case BUILTIN_BOOL: return toc_alignof(bool); case BUILTIN_TYPE: return toc_alignof(Type *); case BUILTIN_NMS: return toc_alignof(Namespace *); + case BUILTIN_VARARGS: return toc_alignof(VarArg *); } assert(0); return 0; @@ -863,6 +865,7 @@ static bool type_can_be_truthy(Type *t) { case BUILTIN_F64: case BUILTIN_CHAR: case BUILTIN_BOOL: + case BUILTIN_VARARGS: return true; } case TYPE_EXPR: @@ -917,6 +920,7 @@ static CastStatus type_cast_status(Type *from, Type *to) { return CAST_STATUS_NONE; case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: return CAST_STATUS_ERR; } assert(0); @@ -948,6 +952,7 @@ static CastStatus type_cast_status(Type *from, Type *to) { case BUILTIN_CHAR: case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: return CAST_STATUS_ERR; } assert(0); @@ -960,6 +965,7 @@ static CastStatus type_cast_status(Type *from, Type *to) { return type_can_be_truthy(to) ? CAST_STATUS_NONE : CAST_STATUS_ERR; case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VARARGS: return CAST_STATUS_ERR; } break; @@ -2858,12 +2864,18 @@ static Status types_decl(Typer *tr, Declaration *d) { success = false; goto ret; } - } else if (d->type.kind == TYPE_UNKNOWN) { + } + if (d->type.kind == TYPE_UNKNOWN) { if (!d->where.file->ctx->have_errored) /* don't do an error if we haven't already done one, because it might be because of that */ err_print(d->where, "Can't determine type of declaration."); success = false; goto ret; } + if (type_is_builtin(&d->type, BUILTIN_VARARGS) && !(d->flags & DECL_IS_PARAM)) { + err_print(d->where, "Only parameters can be varargs."); + success = false; + goto ret; + } if (d->flags & DECL_IS_CONST) { if (d->type.kind == TYPE_PTR) { err_print(d->where, "You can't have a constant pointer."); @@ -175,8 +175,15 @@ typedef union Value { Slice slice; struct Type *type; struct Namespace *nms; + struct VarArg *varargs; /* dynamic array */ } Value; +typedef struct VarArg { + struct Type *type; + Value val; +} VarArg; + + typedef enum { IDECL_NONE, IDECL_DECL, @@ -425,6 +432,7 @@ typedef enum { BUILTIN_CHAR, BUILTIN_BOOL, BUILTIN_TYPE, + BUILTIN_VARARGS, BUILTIN_NMS } BuiltinType; |