diff options
-rw-r--r-- | allocator.c | 23 | ||||
-rw-r--r-- | cgen.c | 29 | ||||
-rw-r--r-- | copy.c | 12 | ||||
-rw-r--r-- | decls_cgen.c | 4 | ||||
-rw-r--r-- | eval.c | 4 | ||||
-rw-r--r-- | identifiers.c | 4 | ||||
-rw-r--r-- | main.c | 15 | ||||
-rw-r--r-- | misc.c | 6 | ||||
-rw-r--r-- | package.c | 17 | ||||
-rw-r--r-- | parse.c | 19 | ||||
-rw-r--r-- | test.toc | 15 | ||||
-rw-r--r-- | tokenizer.c | 2 | ||||
-rw-r--r-- | types.c | 79 | ||||
-rw-r--r-- | types.h | 15 |
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); @@ -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; @@ -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); } @@ -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); @@ -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]; } @@ -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; +} @@ -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; @@ -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: @@ -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 */ @@ -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; @@ -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 { |