summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.html33
-rw-r--r--README.md33
-rw-r--r--cgen.c1
-rw-r--r--copy.c21
-rw-r--r--docs/00.md50
-rw-r--r--eval.c25
-rw-r--r--instance_table.c5
-rw-r--r--main.c1
-rw-r--r--parse.c9
-rw-r--r--toc.c15
-rw-r--r--types.c14
-rw-r--r--types.h13
12 files changed, 190 insertions, 30 deletions
diff --git a/README.html b/README.html
new file mode 100644
index 0000000..d3476a5
--- /dev/null
+++ b/README.html
@@ -0,0 +1,33 @@
+<h2>toc</h2>
+
+<p><code>toc</code> is a language which compiles to C.</p>
+
+<hr />
+
+<h3>About</h3>
+
+<p><code>toc</code> is currently in development. <strong>It is not a stable language,
+and there are almost definitely bugs right now.</strong>
+I would recommend against using it for anything big or important.
+Many parts of it may change in the future.</p>
+
+<p><code>toc</code> improves on C's syntax (and semantics) in many ways,
+To declare <code>x</code> as an integer and set it to 5,
+you can do:</p>
+
+<p><code>
+x := 5; // Declare x and set x to 5 (infer type) <br />
+x : int = 5; // Explicitly make the type int. <br />
+x : int; x = 5; // Declare x as an integer, then set it to 5.
+</code></p>
+
+<p><code>toc</code> is statically typed and has many of C's features, but
+it is just as fast in theory.</p>
+
+<p>See <code>docs</code> for more information.</p>
+
+<hr />
+
+<h3>Help</h3>
+
+<p>If you find a bug in <code>toc</code>, please <a href="https://github.com/pommicket/toc/issues">report an issue</a> on GitHub.</p>
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d946dce
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
+## toc
+
+`toc` is a language which compiles to C.
+
+---
+
+### About
+
+`toc` is currently in development. **It is not a stable language,
+and there are almost definitely bugs right now.**
+I would recommend against using it for anything big or important.
+Many parts of it may change in the future.
+
+`toc` improves on C's syntax (and semantics) in many ways,
+To declare `x` as an integer and set it to 5,
+you can do:
+
+```
+x := 5; // Declare x and set x to 5 (infer type)
+x : int = 5; // Explicitly make the type int.
+x : int; x = 5; // Declare x as an integer, then set it to 5.
+```
+
+`toc` is statically typed and has many of C's features, but
+it is nearly as fast in theory.
+
+See `docs` for more information.
+
+---
+
+### Help
+
+If you find a bug in `toc`, please [report an issue](https://github.com/pommicket/toc/issues) on GitHub. \ No newline at end of file
diff --git a/cgen.c b/cgen.c
index 1b959d2..44222b3 100644
--- a/cgen.c
+++ b/cgen.c
@@ -231,6 +231,7 @@ static bool cgen_uses_ptr(Type *t) {
case TYPE_TYPE:
return false;
case TYPE_USER:
+ case TYPE_CALL:
return cgen_uses_ptr(type_user_underlying(t));
}
assert(0);
diff --git a/copy.c b/copy.c
index d6654f9..3062115 100644
--- a/copy.c
+++ b/copy.c
@@ -36,6 +36,7 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) {
memcpy(out->struc, in->struc, bytes);
} break;
case TYPE_USER:
+ case TYPE_CALL:
copy_val(a, out, in, type_user_underlying(t));
break;
case TYPE_TYPE:
@@ -53,8 +54,10 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) {
}
}
+/* does not work on resolved types */
static void copy_type(Copier *c, Type *out, Type *in) {
- /* needs to handle resolved and unresolved types properly */
+ assert(!(in->flags & TYPE_IS_RESOLVED));
+
*out = *in;
switch (in->kind) {
case TYPE_BUILTIN:
@@ -63,6 +66,14 @@ static void copy_type(Copier *c, Type *out, Type *in) {
case TYPE_UNKNOWN:
case TYPE_USER:
break;
+ case TYPE_CALL: {
+ copy_type(c, out->call.calling = allocr_malloc(c->allocr, sizeof *out->call.calling),
+ in->call.calling);
+ out->call.args = NULL;
+ arr_foreach(in->call.args, Expression, arg) {
+ copy_expr(c, arr_add(&out->call.args), arg);
+ }
+ } break;
case TYPE_FN: {
size_t ntypes = arr_len(in->fn.types);
out->fn.types = NULL;
@@ -80,10 +91,10 @@ static void copy_type(Copier *c, Type *out, Type *in) {
}
} break;
case TYPE_ARR:
- if (!(in->flags & TYPE_IS_RESOLVED)) {
- out->arr.n_expr = allocr_malloc(c->allocr, sizeof *out->arr.n_expr);
- copy_expr(c, out->arr.n_expr, in->arr.n_expr);
- }
+ /* if (!(in->flags & TYPE_IS_RESOLVED)) { */
+ out->arr.n_expr = allocr_malloc(c->allocr, sizeof *out->arr.n_expr);
+ copy_expr(c, out->arr.n_expr, in->arr.n_expr);
+ /* } */
out->arr.of = allocr_malloc(c->allocr, sizeof *out->arr.of);
copy_type(c, out->arr.of, in->arr.of);
break;
diff --git a/docs/00.md b/docs/00.md
new file mode 100644
index 0000000..e4e8d41
--- /dev/null
+++ b/docs/00.md
@@ -0,0 +1,50 @@
+## Declarations in toc
+
+Declarations have the following syntax:
+```
+<name> : [type] [= expression];
+```
+
+The square brackets (`[]`) indicate something optional.
+
+All of the following statements
+declare an new variable `x` which is an integer, and has a value of 0:
+```
+x : int;
+x : int = 0;
+x := 0;
+```
+Note that in the first of those statements, although no expression
+is specified, it defaults to 0. This is not true in C,
+and there will eventually probably be an option to
+leave `x` uninitialized.
+
+If you wanted x to be a floating-point number, you could use:
+```
+x : float;
+x : float = 0;
+x := 0.0;
+```
+
+Note that `0` can be used as both a `float` and an `int`eger, but
+when no type is specified, it defaults to an `int`, whereas `0.0`
+defaults to a `float`.
+
+Here are all of toc's builtin types and their ranges of values:
+
+- `int` - A 64-bit signed integer (always), -9223372036854775808 to 9223372036854775807
+- `i8` - An 8-bit signed integer, -128 to 128
+- `i16` - 16-bit signed integer, -32768 to 32767
+- `i32` - 32-bit signed integer, -2147483648 to 2147483647
+- `i64` - 64-bit signed integer (same as `int`, but more explicit about the size), -9223372036854775808 to 9223372036854775807
+- `u8` - An 8-bit unsigned integer, 0 to 255
+- `u16` - 16-bit unsigned integer, 0 to 65535
+- `u32` - 32-bit unsigned integer, 0 to 4294967295
+- `u64` - 64-bit unsigned integer, 0 to 18446744073709551615
+- `float` - A 32-bit floating-point number,
+- `f32`
+- `f64`
+- `bool`
+- `char`
+
+At the moment, it is not technically guaranteed that `f32`/`float` is actually 32-bit and that `f64` is actually 64-bit; they are platform dependent. Perhaps someday there will be a version of toc which does not compile to C, where that could be guaranteed.
diff --git a/eval.c b/eval.c
index 2ac4170..e06dd9e 100644
--- a/eval.c
+++ b/eval.c
@@ -71,6 +71,7 @@ static size_t compiler_alignof(Type *t) {
case TYPE_TYPE:
return sizeof(Type *);
case TYPE_USER:
+ case TYPE_CALL:
return compiler_alignof(type_user_underlying(t));
case TYPE_STRUCT: {
/* assume the align of a struct is (at most) the greatest align out of its children's */
@@ -129,6 +130,7 @@ static size_t compiler_sizeof(Type *t) {
case TYPE_TYPE:
return sizeof(Type *);
case TYPE_USER:
+ case TYPE_CALL:
return compiler_sizeof(type_user_underlying(t));
case TYPE_STRUCT: {
eval_struct_find_offsets(t);
@@ -169,6 +171,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_CALL:
case TYPE_USER:
case TYPE_TYPE:
case TYPE_TUPLE:
@@ -246,6 +249,7 @@ static void *val_get_ptr(Value *v, Type *t) {
case TYPE_TYPE:
return v;
case TYPE_USER:
+ case TYPE_CALL:
return val_get_ptr(v, type_user_underlying(t));
case TYPE_ARR:
return v->arr;
@@ -320,6 +324,7 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) {
fprint_type(f, *(Type **)p);
break;
case TYPE_USER:
+ case TYPE_CALL:
fprint_val_ptr(f, p, type_user_underlying(t));
break;
case TYPE_STRUCT:
@@ -365,6 +370,7 @@ static void *val_ptr_to_free(Value *v, Type *t) {
case TYPE_STRUCT:
return v->struc;
case TYPE_USER:
+ case TYPE_CALL:
return val_ptr_to_free(v, type_user_underlying(t));
}
assert(0); return NULL;
@@ -452,7 +458,8 @@ 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) {
+ if (from->kind == TYPE_USER || to->kind == TYPE_USER
+ || from->kind == TYPE_CALL || to->kind == TYPE_CALL) {
*vout = *vin;
return;
}
@@ -462,6 +469,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
case TYPE_UNKNOWN:
case TYPE_TUPLE:
case TYPE_USER:
+ case TYPE_CALL:
case TYPE_TYPE:
case TYPE_STRUCT:
assert(0); break;
@@ -484,6 +492,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
}
break;
case TYPE_USER:
+ case TYPE_CALL:
case TYPE_STRUCT:
case TYPE_SLICE:
case TYPE_VOID:
@@ -506,8 +515,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
vout->fn = vin->fn;
break;
case TYPE_USER:
- *vout = *vin;
- break;
+ case TYPE_CALL:
case TYPE_SLICE:
case TYPE_UNKNOWN:
case TYPE_TUPLE:
@@ -542,8 +550,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
vout->fn = vin->ptr;
break;
case TYPE_USER:
- *vout = *vin;
- break;
+ case TYPE_CALL:
case TYPE_SLICE:
case TYPE_UNKNOWN:
case TYPE_TUPLE:
@@ -564,8 +571,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
vout->arr = vin->arr;
break;
case TYPE_USER:
- *vout = *vin;
- break;
+ case TYPE_CALL:
case TYPE_SLICE:
case TYPE_FN:
case TYPE_UNKNOWN:
@@ -589,8 +595,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
vout->slice = vin->slice;
break;
case TYPE_USER:
- *vout = *vin;
- break;
+ case TYPE_CALL:
case TYPE_FN:
case TYPE_UNKNOWN:
case TYPE_TUPLE:
@@ -635,6 +640,7 @@ static void eval_deref(Value *v, void *ptr, Type *type) {
v->type = *(Type **)ptr;
break;
case TYPE_USER:
+ case TYPE_CALL:
eval_deref(v, ptr, type_user_underlying(type));
break;
case TYPE_VOID:
@@ -674,6 +680,7 @@ static void eval_deref_set(void *set, Value *to, Type *type) {
*(Type **)set = to->type;
break;
case TYPE_USER:
+ case TYPE_CALL:
eval_deref_set(set, to, type_user_underlying(type));
break;
case TYPE_VOID:
diff --git a/instance_table.c b/instance_table.c
index 948e4e5..63879ce 100644
--- a/instance_table.c
+++ b/instance_table.c
@@ -97,7 +97,9 @@ static U64 val_ptr_hash(void *v, Type *t) {
}
case TYPE_PTR: return (U64)*(void **)v;
case TYPE_TYPE: return (U64)*(Type **)v;
- case TYPE_USER: return val_ptr_hash(v, type_inner(t));
+ case TYPE_USER:
+ case TYPE_CALL:
+ return val_ptr_hash(v, type_inner(t));
case TYPE_ARR: {
U32 x = 1;
U64 hash = 0;
@@ -162,6 +164,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) {
case TYPE_FN:
return *(FnExpr **)u == *(FnExpr **)v;
case TYPE_USER:
+ case TYPE_CALL:
return val_ptr_eq(u, v, type_inner(t));
case TYPE_PTR:
return *(void **)u == *(void **)v;
diff --git a/main.c b/main.c
index 87f5037..1866e5f 100644
--- a/main.c
+++ b/main.c
@@ -3,6 +3,7 @@ TODO:
struct parameters
- struct type parameters
test ArrInt @= Arr(int);
+
packages
don't allow while {3; 5} (once break is added)
any odd number of "s for a string
diff --git a/parse.c b/parse.c
index 1452dcc..df47ee9 100644
--- a/parse.c
+++ b/parse.c
@@ -256,6 +256,15 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
free(ident_str);
return ret;
}
+ case TYPE_CALL: {
+ size_t written = 0;
+ written += type_to_str_(t->call.calling, buffer + written, bufsize - written);
+ written += str_copy(buffer + written, bufsize - written, "(");
+ /* TODO: show values if resolved */
+ written += str_copy(buffer + written, bufsize - written, "...");
+ written += str_copy(buffer + written, bufsize - written, ")");
+ return written;
+ }
}
assert(0);
diff --git a/toc.c b/toc.c
index 05697a3..cd931ed 100644
--- a/toc.c
+++ b/toc.c
@@ -13,12 +13,19 @@
#include "types.h"
+/* can be used on TYPE_USERs and TYPE_CALLs */
static Type *type_user_underlying(Type *t) {
- assert(t->kind == TYPE_USER);
assert(t->flags & TYPE_IS_RESOLVED);
- Declaration *d = t->user.decl;
- assert(d->flags & DECL_FOUND_VAL);
- return (d->type.kind == TYPE_TUPLE ? d->val.tuple[t->user.index] : d->val).type;
+ switch (t->kind) {
+ case TYPE_USER: {
+ Declaration *d = t->user.decl;
+ assert(d->flags & DECL_FOUND_VAL);
+ return (d->type.kind == TYPE_TUPLE ? d->val.tuple[t->user.index] : d->val).type;
+ }
+ case TYPE_CALL:
+ return &t->call.instance->type;
+ default: assert(0);
+ }
}
static Type *type_inner(Type *t) {
diff --git a/types.c b/types.c
index d4d0414..f5b8e5e 100644
--- a/types.c
+++ b/types.c
@@ -28,9 +28,9 @@ static bool type_eq(Type *a, Type *b) {
assert(a->flags & TYPE_IS_RESOLVED);
assert(b->flags & TYPE_IS_RESOLVED);
- if (a->kind == TYPE_USER && a->user.is_alias)
+ if ((a->kind == TYPE_USER || a->kind == TYPE_CALL) && a->user.is_alias)
return type_eq(type_user_underlying(a), b);
- if (b->kind == TYPE_USER && b->user.is_alias)
+ if ((b->kind == TYPE_USER || a->kind == TYPE_CALL) && b->user.is_alias)
return type_eq(a, type_user_underlying(b));
@@ -57,6 +57,8 @@ static bool type_eq(Type *a, Type *b) {
case TYPE_TYPE: return true;
case TYPE_USER:
return a->user.decl == b->user.decl && a->user.index == b->user.index;
+ case TYPE_CALL:
+ return a->call.instance == b->call.instance;
case TYPE_BUILTIN:
return a->builtin == b->builtin;
case TYPE_STRUCT: return false;
@@ -541,6 +543,7 @@ static bool type_can_be_truthy(Type *t) {
case TYPE_ARR:
case TYPE_TYPE:
case TYPE_USER:
+ case TYPE_CALL:
case TYPE_STRUCT:
return false;
case TYPE_FN:
@@ -563,13 +566,13 @@ typedef enum {
static Status type_cast_status(Type *from, Type *to) {
if (to->kind == TYPE_UNKNOWN)
return STATUS_NONE;
- if (from->kind == TYPE_USER) {
+ if (from->kind == TYPE_USER || from->kind == TYPE_CALL) {
if (from->user.is_alias) {
return type_cast_status(type_user_underlying(from), to);
}
return type_eq(type_user_underlying(from), to) ? STATUS_NONE : STATUS_ERR;
}
- if (to->kind == TYPE_USER) {
+ if (to->kind == TYPE_USER || to->kind == TYPE_CALL) {
if (to->user.is_alias) {
return type_cast_status(from, type_user_underlying(to));
}
@@ -604,7 +607,7 @@ static Status type_cast_status(Type *from, Type *to) {
case TYPE_STRUCT:
case TYPE_ARR:
case TYPE_VOID:
- case TYPE_USER: /* handled above */
+ case TYPE_USER: case TYPE_CALL: /* handled above */
return STATUS_ERR;
}
break;
@@ -642,6 +645,7 @@ static Status type_cast_status(Type *from, Type *to) {
return STATUS_NONE;
return STATUS_ERR;
case TYPE_USER:
+ case TYPE_CALL:
break;
}
assert(0);
diff --git a/types.h b/types.h
index ab41519..599ca67 100644
--- a/types.h
+++ b/types.h
@@ -291,7 +291,8 @@ typedef enum {
TYPE_SLICE,
TYPE_TYPE,
TYPE_USER, /* user-defined type */
- TYPE_STRUCT
+ TYPE_STRUCT,
+ TYPE_CALL /* "calling" a type function, e.g. Arr(int) */
} TypeKind;
typedef enum {
@@ -367,9 +368,9 @@ typedef struct Type {
} struc;
struct {
- Type *calling;
- Expression *arguments;
- struct Instance *instance; /* instance of struct, NULL if this is not an instance. set during resolution. */
+ struct Type *calling;
+ struct Expression *args;
+ struct Instance *instance; /* instance of struct. set during type resolution. */
} call; /* "calling" a function returning a type */
};
} Type;
@@ -529,10 +530,10 @@ typedef struct FnExpr {
} FnExpr; /* an expression such as fn(x: int) int { 2 * x } */
typedef struct Instance {
- Value val;
+ Value val; /* key into hash table */
union {
FnExpr fn; /* the typed function */
- Type struc; /* the structure, resolved */
+ Type type; /* the type, resolved */
};
struct {
U64 id;