summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c2
-rw-r--r--eval.c22
-rw-r--r--foreign.c48
-rw-r--r--instance_table.c21
-rw-r--r--main.c2
-rw-r--r--parse.c23
-rw-r--r--test.toc10
-rw-r--r--types.c14
-rw-r--r--types.h8
9 files changed, 118 insertions, 32 deletions
diff --git a/cgen.c b/cgen.c
index 33fc840..3cd9510 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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;
}
diff --git a/eval.c b/eval.c
index b40fe4d..d19f365 100644
--- a/eval.c
+++ b/eval.c
@@ -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:
diff --git a/foreign.c b/foreign.c
index cbceba4..6ad9011 100644
--- a/foreign.c
+++ b/foreign.c
@@ -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:
diff --git a/main.c b/main.c
index f53cce2..9f7e554 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/parse.c b/parse.c
index 92d106a..117e395 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
diff --git a/test.toc b/test.toc
index f9e9d40..441cc5f 100644
--- a/test.toc
+++ b/test.toc
@@ -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
diff --git a/types.c b/types.c
index 18064ff..782f3d6 100644
--- a/types.c
+++ b/types.c
@@ -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.");
diff --git a/types.h b/types.h
index 85c7d73..35fe207 100644
--- a/types.h
+++ b/types.h
@@ -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;