summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--allocator.c23
-rw-r--r--cgen.c29
-rw-r--r--copy.c12
-rw-r--r--decls_cgen.c4
-rw-r--r--eval.c4
-rw-r--r--identifiers.c4
-rw-r--r--main.c15
-rw-r--r--misc.c6
-rw-r--r--package.c17
-rw-r--r--parse.c19
-rw-r--r--test.toc15
-rw-r--r--tokenizer.c2
-rw-r--r--types.c79
-rw-r--r--types.h15
14 files changed, 198 insertions, 46 deletions
diff --git a/allocator.c b/allocator.c
index d1d1fed..0443103 100644
--- a/allocator.c
+++ b/allocator.c
@@ -1,7 +1,24 @@
/*
- Copyright (C) 2019, 2020 Leo Tenenbaum.
- This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever.
- You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>.
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+For more information, please refer to <http://unlicense.org/>
*/
static void *err_malloc(size_t bytes);
diff --git a/cgen.c b/cgen.c
index f9ebce1..1c26ac2 100644
--- a/cgen.c
+++ b/cgen.c
@@ -55,6 +55,7 @@ static bool cgen_defs_decl(CGenerator *g, Declaration *d);
case EXPR_TYPE: \
case EXPR_VAL: \
case EXPR_C: \
+ case EXPR_BUILTIN: \
case EXPR_IDENT: \
case EXPR_LITERAL_BOOL: \
case EXPR_LITERAL_INT: \
@@ -554,10 +555,12 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, U64 instance, U64 which_are
cgen_write(g, " ");
}
cgen_full_fn_name(g, f, instance);
+ if (!cgen_fn_args(g, f, instance, which_are_const))
+ return false;
if (!out_param) {
if (!cgen_type_post(g, &f->ret_type, f->where)) return false;
}
- return cgen_fn_args(g, f, instance, which_are_const);
+ return true;
}
@@ -748,6 +751,7 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents,
case EXPR_CAST:
case EXPR_NEW:
case EXPR_C:
+ case EXPR_BUILTIN:
case EXPR_TYPE:
case EXPR_PKG:
assert(0);
@@ -1151,6 +1155,18 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
cgen_write(g, ";");
cgen_nl(g);
break;
+ case EXPR_TUPLE:
+ arr_foreach(e->tuple, Expression, x)
+ if (!cgen_expr_pre(g, x)) return false;
+ break;
+ case EXPR_BUILTIN:
+ switch (e->builtin.which.val) {
+ case BUILTIN_STDOUT:
+ cgen_write(g, "extern void *stdout;");
+ cgen_nl(g);
+ break;
+ }
+ break;
case EXPR_LITERAL_INT:
case EXPR_LITERAL_FLOAT:
case EXPR_LITERAL_BOOL:
@@ -1162,10 +1178,6 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
case EXPR_TYPE:
case EXPR_PKG:
break;
- case EXPR_TUPLE:
- arr_foreach(e->tuple, Expression, x)
- if (!cgen_expr_pre(g, x)) return false;
- break;
}
return true;
}
@@ -1446,6 +1458,13 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_indent(g);
fwrite(code->val.slice.data, 1, (size_t)code->val.slice.n, cgen_writing_to(g));
} break;
+ case EXPR_BUILTIN:
+ switch (e->builtin.which.val) {
+ case BUILTIN_STDOUT:
+ cgen_write(g, "stdout");
+ break;
+ }
+ break;
case EXPR_CAST: {
Type *from = &e->cast.expr->type;
Type *to = &e->cast.type;
diff --git a/copy.c b/copy.c
index 0ad1adc..585e1de 100644
--- a/copy.c
+++ b/copy.c
@@ -152,6 +152,7 @@ static void copy_fn_expr(Copier *c, FnExpr *fout, FnExpr *fin, bool copy_body) {
copy_block(c, &fout->body, &fin->body);
}
+static Expression *copy_expr_(Copier *c, Expression *in);
static void copy_expr(Copier *c, Expression *out, Expression *in) {
Allocator *a = c->allocr;
*out = *in;
@@ -247,6 +248,9 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) {
case EXPR_C:
copy_expr(c, out->c.code = allocr_malloc(a, sizeof *out->c.code), in->c.code);
break;
+ case EXPR_BUILTIN:
+ out->builtin.which.expr = copy_expr_(c, in->builtin.which.expr);
+ break;
case EXPR_SLICE: {
SliceExpr *sin = &in->slice;
SliceExpr *sout = &out->slice;
@@ -257,7 +261,7 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) {
copy_expr(c, sout->to = allocr_malloc(a, sizeof *sout->to), sin->to);
} break;
case EXPR_PKG:
- copy_expr(c, out->pkg.name_expr = allocr_malloc(a, sizeof *out->pkg.name_expr), in->pkg.name_expr);
+ out->pkg.name_expr = copy_expr_(c, in->pkg.name_expr);
break;
case EXPR_TYPE:
copy_type(c, &out->typeval, &in->typeval);
@@ -268,6 +272,12 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) {
}
}
+static Expression *copy_expr_(Copier *c, Expression *in) {
+ Expression *out = allocr_malloc(c->allocr, sizeof *out);
+ copy_expr(c, out, in);
+ return out;
+}
+
static void copy_decl(Copier *c, Declaration *out, Declaration *in) {
*out = *in;
assert(!(in->flags & DECL_FOUND_TYPE));
diff --git a/decls_cgen.c b/decls_cgen.c
index 762a8cb..99ae190 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -143,12 +143,12 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
}
cgen_write(g, " ");
cgen_ident(g, ident);
+ if (!cgen_fn_args(g, f, 0, 0))
+ return false;
if (!out_param) {
if (!cgen_type_post(g, &f->ret_type, e->where))
return false;
}
- if (!cgen_fn_args(g, f, 0, 0))
- return false;
cgen_write(g, ";");
cgen_nl(g);
}
diff --git a/eval.c b/eval.c
index 49a2d32..bc97a3e 100644
--- a/eval.c
+++ b/eval.c
@@ -11,6 +11,7 @@ static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v);
static bool eval_expr(Evaluator *ev, Expression *e, Value *v);
static bool block_enter(Block *b, Statement *stmts, U16 flags);
static void block_exit(Block *b, Statement *stmts);
+static void get_builtin_val(BuiltinVal val, Value *v);
static void evalr_create(Evaluator *ev, Typer *tr, Allocator *allocr) {
ev->returning = NULL;
@@ -1421,6 +1422,9 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
case EXPR_C:
err_print(e->where, "Cannot run C code at compile time.");
return false;
+ case EXPR_BUILTIN:
+ get_builtin_val(e->builtin.which.val, v);
+ break;
case EXPR_NEW:
/* it's not strictly necessary to do the if here */
if (e->new.n) {
diff --git a/identifiers.c b/identifiers.c
index a17c002..5e0f531 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -200,11 +200,11 @@ static void idents_test(void) {
char *s = b;
idents_create(&ids);
Identifier i1 = ident_insert(&ids, &s);
- assert(strcmp(s, " bar") == 0);
+ assert(strs_equal(s, " bar"));
char b2[] = "foo_variable+6";
s = b2;
Identifier i2 = ident_insert(&ids, &s);
- assert(strcmp(s, "+6") == 0);
+ assert(strs_equal(s, "+6"));
assert(i1 == i2);
idents_free(&ids);
diff --git a/main.c b/main.c
index 5f69aa7..7f2dce3 100644
--- a/main.c
+++ b/main.c
@@ -18,17 +18,22 @@
/*
TODO:
-see NOTE in test.toc
-variadic fns
-#include
-constants in structs
#builtin values - accessed via, e.g. #builtin("sizeof(int)")
- sizeof(int) (size of C int type), sizeof(long), sizeof(size_t) etc.
- compiling - true if @ compile time, false otherwise
- stdout, stderr, stdin - pointers to C FILEs
+clean up copy_expr
+each=>for
+
+#C_int, #C_long, etc.
+
+#include
+constants in structs
#if
+variadic fns
+
---
X ::= newtype(int); or something
don't allow while {3; 5} (once break is added)
@@ -60,7 +65,7 @@ int main(int argc, char **argv) {
}
const char *out_filename = "out.c";
for (int i = 2; i < argc-1; ++i) {
- if (strcmp(argv[i], "-o") == 0)
+ if (strs_equal(argv[i], "-o"))
out_filename = argv[i+1];
}
diff --git a/misc.c b/misc.c
index 3bd06c6..497a94f 100644
--- a/misc.c
+++ b/misc.c
@@ -48,10 +48,12 @@ size_t str_copy(char *dest, size_t destsz, const char *src) {
return destsz-1;
}
-static U32 rand_u32(U32 seed) {
+static inline U32 rand_u32(U32 seed) {
U64 seed64 = (U64)seed;
return (U32)((seed64 * 0x832f0fda4e1a8642 + 0x41d49cd5459a2ab4) >> 32);
}
-
+static inline bool strs_equal(const char *a, const char *b) {
+ return strcmp(a, b) == 0;
+}
diff --git a/package.c b/package.c
index ae40160..32b3c8e 100644
--- a/package.c
+++ b/package.c
@@ -669,6 +669,15 @@ static bool export_expr(Exporter *ex, Expression *e) {
if (!export_expr(ex, e->c.code))
return false;
break;
+ case EXPR_BUILTIN:
+ if (found_type) {
+ possibly_static_assert(BUILTIN_VAL_COUNT <= 256);
+ export_u8(ex, e->builtin.which.val);
+ } else {
+ if (!export_expr(ex, e->builtin.which.expr))
+ return false;
+ }
+ break;
case EXPR_IDENT:
export_ident(ex, e->ident);
break;
@@ -833,6 +842,14 @@ static void import_expr(Importer *im, Expression *e) {
case EXPR_C:
e->c.code = import_expr_(im);
break;
+ case EXPR_BUILTIN:
+ if (found_type) {
+ possibly_static_assert(BUILTIN_VAL_COUNT <= 256);
+ e->builtin.which.val = import_u8(im);
+ } else {
+ e->builtin.which.expr = import_expr_(im);
+ }
+ break;
case EXPR_IDENT:
e->ident = import_ident(im);
break;
diff --git a/parse.c b/parse.c
index 1ac882e..4fe7008 100644
--- a/parse.c
+++ b/parse.c
@@ -35,7 +35,8 @@ static const char *expr_kind_to_str(ExprKind k) {
case EXPR_WHILE: return "while expression";
case EXPR_EACH: return "each expression";
case EXPR_CALL: return "function call";
- case EXPR_C: return "c code";
+ case EXPR_C: return "C code";
+ case EXPR_BUILTIN: return "#builtin value";
case EXPR_NEW: return "new expression";
case EXPR_CAST: return "cast expression";
case EXPR_UNARY_OP: return "unary operator";
@@ -912,7 +913,7 @@ static void fprint_expr(FILE *out, Expression *e);
#define NOT_AN_OP -1
/* cast/new aren't really operators since they operate on types, not exprs. */
-#define CAST_PRECEDENCE -10
+#define CAST_PRECEDENCE 2
#define NEW_PRECEDENCE 22
static int op_precedence(Keyword op) {
switch (op) {
@@ -1683,6 +1684,10 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
e->kind = EXPR_C;
single_arg = e->c.code = parser_new_expr(p);
break;
+ case DIRECT_BUILTIN:
+ e->kind = EXPR_BUILTIN;
+ single_arg = e->builtin.which.expr = parser_new_expr(p);
+ break;
case DIRECT_SIZEOF:
e->kind = EXPR_UNARY_OP;
e->unary.op = UNARY_DSIZEOF;
@@ -2278,6 +2283,15 @@ static void fprint_expr(FILE *out, Expression *e) {
fprint_expr(out, e->c.code);
fprintf(out, ")");
break;
+ case EXPR_BUILTIN:
+ fprintf(out, "#builtin(");
+ if (found_type) {
+ fprintf(out, "%s", builtin_val_names[e->builtin.which.val]);
+ } else {
+ fprint_expr(out, e->builtin.which.expr);
+ }
+ fprintf(out, ")");
+ break;
case EXPR_SLICE: {
SliceExpr *s = &e->slice;
fprint_expr(out, s->of);
@@ -2415,6 +2429,7 @@ static bool expr_is_definitely_const(Expression *e) {
case EXPR_IF:
case EXPR_WHILE:
case EXPR_C:
+ case EXPR_BUILTIN:
case EXPR_NEW:
case EXPR_CAST:
case EXPR_CALL:
diff --git a/test.toc b/test.toc
index 33cd6ad..38fc2df 100644
--- a/test.toc
+++ b/test.toc
@@ -1,11 +1,20 @@
-stdout :: &u8 = #foreign "stdout";
+getstdout ::= fn() &u8 {
+ #builtin("stdout")
+};
+
fwrite :: fn(&u8, u64, u64, &u8) = #foreign "fwrite";
puts ::= fn(x : []char) {
- fwrite(&x[0] as &u8 as &u16 as &u8, 1, x.len as u64, stdout);
+ fwrite(&x[0] as &u8 as &u16 as &u8, 1, x.len as u64, getstdout());
+};
+
+hw ::= fn() int {
+ hw();
+ 2
};
main ::= fn() {
- puts("Hello, world!\n");
+ hw();
+ x ::= hw();
};
diff --git a/tokenizer.c b/tokenizer.c
index 8c26769..103c534 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -20,7 +20,7 @@ static const char *const keywords[KW_COUNT] =
static inline const char *kw_to_str(Keyword k) { return keywords[k]; }
static const char *directives[DIRECT_COUNT] =
- {"C", "sizeof", "alignof", "export", "foreign"};
+ {"C", "sizeof", "alignof", "export", "foreign", "builtin"};
/* Returns KW_COUNT if it's not a keyword */
/* OPTIM: don't use strncmp so much */
diff --git a/types.c b/types.c
index 887c39b..22f8648 100644
--- a/types.c
+++ b/types.c
@@ -168,6 +168,7 @@ static bool expr_must_lval(Expression *e) {
case EXPR_EACH:
case EXPR_CALL:
case EXPR_C:
+ case EXPR_BUILTIN:
case EXPR_BLOCK:
case EXPR_SLICE:
case EXPR_TYPE:
@@ -925,6 +926,47 @@ static bool call_arg_param_order(Allocator *allocr, FnExpr *fn, Type *fn_type, A
return true;
}
+static void get_builtin_val(BuiltinVal val, Value *v) {
+ switch (val) {
+ case BUILTIN_STDOUT:
+ v->ptr = stdout;
+ break;
+ }
+}
+
+static void get_builtin_val_type(Allocator *a, BuiltinVal val, Type *t) {
+ t->flags = TYPE_IS_RESOLVED;
+ switch (val) {
+ case BUILTIN_STDOUT:
+ t->kind = TYPE_PTR;
+ t->ptr = allocr_calloc(a, 1, sizeof *t->ptr);
+ t->ptr->flags = TYPE_IS_RESOLVED;
+ t->ptr->kind = TYPE_BUILTIN;
+ t->ptr->builtin = BUILTIN_U8;
+ break;
+ }
+}
+
+/* returns NULL if an error occured */
+static char *eval_expr_as_cstr(Typer *tr, Expression *e, const char *what_is_this) {
+ Value e_val;
+ if (!types_expr(tr, e))
+ return NULL;
+ if (!type_is_slicechar(&e->type)) {
+ char *got = type_to_str(&e->type);
+ err_print(e->where, "Expected []char for %s, but got %s.", what_is_this, got);
+ free(got);
+ return NULL;
+ }
+ if (!eval_expr(tr->evalr, e, &e_val))
+ return NULL;
+ Slice e_slice = e_val.slice;
+ char *str = typer_malloc(tr, (size_t)e_slice.n + 1);
+ str[e_slice.n] = 0;
+ memcpy(str, e_slice.data, (size_t)e_slice.n);
+ return str;
+}
+
static bool types_expr(Typer *tr, Expression *e) {
if (e->flags & EXPR_FOUND_TYPE) return true;
Type *t = &e->type;
@@ -1645,6 +1687,23 @@ static bool types_expr(Typer *tr, Expression *e) {
code->kind = EXPR_VAL;
t->kind = TYPE_UNKNOWN;
} break;
+ case EXPR_BUILTIN: {
+ char *builtin_name = eval_expr_as_cstr(tr, e->builtin.which.expr, "#builtin value name");
+ if (!builtin_name) return false;
+ int which = -1;
+ for (BuiltinVal b = 0; b < BUILTIN_VAL_COUNT; b = b + 1) {
+ if (strs_equal(builtin_val_names[b], builtin_name)) {
+ which = b;
+ }
+ }
+ if (which == -1) {
+ err_print(e->where, "Unrecognized builtin value: %s.", builtin_name);
+ return false;
+ }
+ e->builtin.which.val = (BuiltinVal)which;
+ get_builtin_val_type(tr->allocr, e->builtin.which.val, t);
+ assert(t->flags & TYPE_IS_RESOLVED);
+ } break;
case EXPR_UNARY_OP: {
Expression *of = e->unary.of;
Type *of_type = &of->type;
@@ -2136,26 +2195,6 @@ static bool types_block(Typer *tr, Block *b) {
return success;
}
-/* returns NULL if an error occured */
-static char *eval_expr_as_cstr(Typer *tr, Expression *e, const char *what_is_this) {
- Value e_val;
- if (!types_expr(tr, e))
- return NULL;
- if (!type_is_slicechar(&e->type)) {
- char *got = type_to_str(&e->type);
- err_print(e->where, "Expected []char for %s, but got %s.", what_is_this, got);
- free(got);
- return NULL;
- }
- if (!eval_expr(tr->evalr, e, &e_val))
- return NULL;
- Slice e_slice = e_val.slice;
- char *str = typer_malloc(tr, (size_t)e_slice.n + 1);
- str[e_slice.n] = 0;
- memcpy(str, e_slice.data, (size_t)e_slice.n);
- return str;
-}
-
static bool types_decl(Typer *tr, Declaration *d) {
bool success = true;
if (d->flags & DECL_FOUND_TYPE) return true;
diff --git a/types.h b/types.h
index e6a3ff2..a32c9a0 100644
--- a/types.h
+++ b/types.h
@@ -241,6 +241,7 @@ typedef enum {
DIRECT_ALIGNOF,
DIRECT_EXPORT,
DIRECT_FOREIGN,
+ DIRECT_BUILTIN,
DIRECT_COUNT
} Directive;
@@ -505,6 +506,7 @@ typedef enum {
EXPR_BLOCK,
EXPR_TUPLE,
EXPR_C,
+ EXPR_BUILTIN,
EXPR_SLICE,
EXPR_TYPE,
EXPR_PKG,
@@ -670,6 +672,13 @@ typedef struct SliceExpr {
} c;
} SliceExpr;
+typedef enum {
+ BUILTIN_STDOUT
+#define BUILTIN_VAL_COUNT (BUILTIN_STDOUT+1)
+} BuiltinVal;
+
+const char *const builtin_val_names[BUILTIN_VAL_COUNT] = {"stdout"};
+
enum {
EXPR_FOUND_TYPE = 0x01
};
@@ -703,6 +712,12 @@ typedef struct Expression {
struct {
struct Expression *code;
} c;
+ struct {
+ union {
+ struct Expression *expr;
+ BuiltinVal val;
+ } which;
+ } builtin;
Identifier ident;
NewExpr new;
struct {