diff options
-rw-r--r-- | cgen.c | 46 | ||||
-rw-r--r-- | copy.c | 7 | ||||
-rw-r--r-- | eval.c | 32 | ||||
-rw-r--r-- | parse.c | 218 | ||||
-rw-r--r-- | std/mem.toc | 23 | ||||
-rw-r--r-- | test.toc | 49 | ||||
-rw-r--r-- | types.c | 39 | ||||
-rw-r--r-- | types.h | 7 |
8 files changed, 151 insertions, 270 deletions
@@ -135,9 +135,6 @@ static void cgen_defs_decl(CGenerator *g, Declaration *d); cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f); \ } \ } break; \ - case EXPR_NEW: \ - if (e->new.n) f(g, e->new.n); \ - break; \ } @@ -880,7 +877,6 @@ static void cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, case EXPR_BINARY_OP: case EXPR_FN: case EXPR_CAST: - case EXPR_NEW: case EXPR_C: case EXPR_BUILTIN: case EXPR_TYPE: @@ -1275,9 +1271,6 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { cgen_write(g, "; }"); cgen_nl(g); } break; - case EXPR_NEW: - if (e->new.n) cgen_expr_pre(g, e->new.n); - break; case EXPR_VAL: /* TODO: don't make a variable for this if it's not needed */ if (type_is_compileonly(&e->type)) @@ -1474,6 +1467,12 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, is_ptr ? "->" :"."); cgen_ident_simple(g, e->binary.dot.field->name); cgen_write(g, ")"); + } else if (struct_type->kind == TYPE_SLICE) { + /* access slice data */ + cgen_expr(g, lhs); + bool is_ptr = lhs->type.kind == TYPE_PTR; + cgen_write(g, is_ptr ? "->" :"."); + cgen_write(g, "data"); } else { assert(type_is_builtin(struct_type, BUILTIN_NMS)); char *prefix = lhs->val.nms->c.prefix; @@ -1512,14 +1511,6 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, ")"); handled = true; break; - case UNARY_DEL: - cgen_write(g, "free_("); - cgen_expr(g, e->unary.of); - if (of_type->kind == TYPE_SLICE) - cgen_write(g, ".data"); - cgen_write(g, ")"); - handled = true; - break; case UNARY_LEN: { bool is_ptr = of_type->kind == TYPE_PTR; if (is_ptr) { @@ -1549,27 +1540,6 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_expr(g, e->unary.of); cgen_write(g, ")"); } break; - case EXPR_NEW: { - if (e->new.n) { - cgen_write(g, "mkslice_(ecalloc_("); - cgen_expr(g, e->new.n); - cgen_write(g, ", (i64)sizeof("); - cgen_type_pre(g, &e->new.type); - cgen_type_post(g, &e->new.type); - cgen_write(g, ")), "); - cgen_expr(g, e->new.n); - cgen_write(g, ")"); - } else { - Type *t = &e->new.type; - cgen_write(g, "(("); - cgen_type_pre(g, &e->type); - cgen_type_post(g, &e->type); - cgen_write(g, ")ecalloc_(1, sizeof("); - cgen_type_pre(g, t); - cgen_type_post(g, t); - cgen_write(g, ")))"); - } - } break; case EXPR_IF: case EXPR_WHILE: case EXPR_BLOCK: @@ -2131,9 +2101,7 @@ static void cgen_file(CGenerator *g, ParsedFile *f) { "typedef struct { void *data; i64 n; } slice_;\n" "#define false ((bool)0)\n" "#define true ((bool)1)\n" - "static slice_ mkslice_(void *data, i64 n) { slice_ ret; ret.data = data; ret.n = n; return ret; }\n" - "static void free_(void *data) { extern void free(void *data); free(data); }\n" /* don't introduce free to global namespace */ - "static void *ecalloc_(size_t n, size_t sz) { extern void *calloc(size_t n, size_t size); extern void abort(void); extern int printf(const char *fmt, ...); void *ret = calloc(n, sz); if (n && sz && !ret) { printf(\"Out of memory.\\n\"); abort(); } return ret; }\n\n\n"); + "static slice_ mkslice_(void *data, i64 n) { slice_ ret; ret.data = data; ret.n = n; return ret; }\n"); cgen_sdecls_file(g, f); cgen_decls_file(g, f); @@ -322,13 +322,6 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) { copy_type(c, &cout->type, &cin->type); cout->expr = copy_expr_(c, cin->expr); } break; - case EXPR_NEW: { - NewExpr *nin = &in->new; - NewExpr *nout = &out->new; - copy_type(c, &nout->type, &nin->type); - if (nin->n) - nout->n = copy_expr_(c, nin->n); - } break; case EXPR_CALL: { CallExpr *cin = &in->call; CallExpr *cout = &out->call; @@ -9,6 +9,7 @@ static Status types_decl(Typer *tr, Declaration *d); static Status type_resolve(Typer *tr, Type *t, Location where); static Status eval_block(Evaluator *ev, Block *b, Value *v); static Status eval_expr(Evaluator *ev, Expression *e, Value *v); +static Status eval_address_of(Evaluator *ev, Expression *e, void **ptr); static Value get_builtin_val(BuiltinVal val); static void evalr_create(Evaluator *ev, Typer *tr, Allocator *allocr) { @@ -742,6 +743,14 @@ static Status eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr, void struc_data = struc.struc; } *p = (char *)struc_data + dot_expr->binary.dot.field->offset; + } else if (struct_type->kind == TYPE_SLICE) { + void *ptr; + if (!eval_address_of(ev, dot_expr->binary.lhs, &ptr)) + return false; + /* access struct data */ + Identifier ident = dot_expr->binary.rhs->ident; + assert(ident_eq_str(ident, "data")); + *p = &((Slice *)ptr)->data; } else { void *ptr; Identifier ident = dot_expr->binary.rhs->ident; @@ -848,7 +857,7 @@ static Status eval_set(Evaluator *ev, Expression *set, Value *to) { void *ptr; if (!eval_ptr_to_struct_field(ev, set, &ptr)) return false; - eval_deref_set(ptr, to, &set->binary.dot.field->type); + eval_deref_set(ptr, to, &set->type); } break; default: assert(0); break; } @@ -1128,14 +1137,6 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { case UNARY_NOT: v->boolv = !val_truthiness(of, &e->unary.of->type); break; - case UNARY_DEL: - if (of_type->kind == TYPE_PTR) - free(of.ptr); - else { - assert(of_type->kind == TYPE_SLICE); - free(of.slice.data); - } - break; case UNARY_LEN: if (of_type->kind == TYPE_PTR) { /* dereference of */ @@ -1432,19 +1433,6 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { case EXPR_BUILTIN: *v = get_builtin_val(e->builtin.which.val); break; - case EXPR_NEW: - /* it's not strictly necessary to do the if here */ - if (e->new.n) { - Value n; - if (!eval_expr(ev, e->new.n, &n)) - return false; - U64 n64 = val_to_u64(n, e->new.n->type.builtin); - v->slice.data = err_calloc(n64, compiler_sizeof(&e->new.type)); - v->slice.n = (I64)n64; - } else { - v->ptr = err_calloc(1, compiler_sizeof(&e->new.type)); - } - break; case EXPR_CALL: { FnExpr *fn; if (e->call.instance) { @@ -37,7 +37,6 @@ static const char *expr_kind_to_str(ExprKind k) { case EXPR_CALL: return "function call"; 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"; case EXPR_BINARY_OP: return "binary operator"; @@ -60,7 +59,6 @@ static const char *unary_op_to_str(UnaryOp u) { case UNARY_ADDRESS: return "&"; case UNARY_DEREF: return "*"; case UNARY_NOT: return "!"; - case UNARY_DEL: return "del"; case UNARY_LEN: return "len"; case UNARY_DSIZEOF: return "#sizeof"; case UNARY_DALIGNOF: return "#alignof"; @@ -1019,9 +1017,8 @@ 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. */ +/* cast isn't really an operator since it operates on types, not exprs. */ #define CAST_PRECEDENCE 2 -#define NEW_PRECEDENCE 22 #define DSIZEOF_PRECEDENCE 5 #define DALIGNOF_PRECEDENCE 5 static int op_precedence(Keyword op) { @@ -1052,7 +1049,6 @@ static int op_precedence(Keyword op) { case KW_SLASH: return 40; case KW_PERCENT: return 45; case KW_EXCLAMATION: return 50; - case KW_DEL: return 1000; default: return NOT_AN_OP; } } @@ -1564,7 +1560,88 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { } default: break; } - + if (token_is_direct(t->token, DIRECT_FOREIGN)) { + e->kind = EXPR_FN; + FnExpr *fn = e->fn = parser_calloc(p, 1, sizeof *e->fn); + fn->flags |= FN_EXPR_FOREIGN; + fn->foreign.fn_ptr = 0; + fn->where.start = t->token; + fn->where.file = p->file; + ++t->token; + if (!token_is_kw(t->token, KW_LPAREN)) { + tokr_err(t, "Expected ( following #foreign."); + return false; + } + ++t->token; + Type *fn_t = &fn->foreign.type; + fn_t->kind = TYPE_FN; + FnType *fn_type = &fn_t->fn; + fn_type->constness = NULL; + fn_type->types = NULL; + Type *ret_type = parser_arr_add(p, &fn_type->types); + CType *ret_ctype = parser_arr_add(p, &fn->foreign.ctypes); + Expression *name = fn->foreign.name_expr = parser_new_expr(p); + + if (!parse_expr(p, name, expr_find_end(p, EXPR_CAN_END_WITH_COMMA))) + return false; + if (token_is_kw(t->token, KW_RPAREN)) { + fn->foreign.lib_expr = NULL; + } else { + if (!token_is_kw(t->token, KW_COMMA)) { + tokr_err(t, "Expected , to follow #foreign name."); + return false; + } + ++t->token; + Expression *lib = fn->foreign.lib_expr = parser_new_expr(p); + if (!parse_expr(p, lib, expr_find_end(p, 0))) + return false; + if (!token_is_kw(t->token, KW_RPAREN)) { + tokr_err(t, "Expected ) to follow #foreign lib."); + return false; + } + } + ++t->token; + + + if (!token_is_kw(t->token, KW_FN)) { + tokr_err(t, "Expected fn to follow #foreign."); + return false; + } + ++t->token; + if (!token_is_kw(t->token, KW_LPAREN)) { + tokr_err(t, "Expected ( after #foreign fn"); + return false; + } + ++t->token; + while (!token_is_kw(t->token, KW_RPAREN)) { + Type *type = parser_arr_add(p, &fn_type->types); + CType *ctype = parser_arr_add(p, &fn->foreign.ctypes); + if (!parse_c_type(p, ctype, type)) { + return false; + } + if (token_is_kw(t->token, KW_COMMA)) { + ++t->token; + } else if (token_is_kw(t->token, KW_RPAREN)) { + ++t->token; + break; + } else { + tokr_err(t, "Expected , or ) following #foreign fn type."); + return false; + } + } + if (t->token == end) { + /* void */ + ret_ctype->kind = CTYPE_NONE; + ret_type->kind = TYPE_VOID; + ret_type->flags = 0; + ret_type->was_expr = NULL; + } else { + if (!parse_c_type(p, ret_ctype, ret_type)) + return false; + } + fn->where.end = t->token; + return true; + } /* NOTE: the . operator is not handled here, but further down, in order to allow some_struct.fn_member() */ Token *dot = NULL; /* this keeps track of it for later */ @@ -1629,7 +1706,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { if (token->kind == TOKEN_KW) { switch (token->kw) { case KW_AS: precedence = CAST_PRECEDENCE; break; - case KW_NEW: precedence = NEW_PRECEDENCE; break; default: precedence = op_precedence(token->kw); break; } } else if (token->kind == TOKEN_DIRECT) { @@ -1724,45 +1800,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { case KW_ALIGNOF: op = UNARY_ALIGNOF; break; - case KW_NEW: - e->kind = EXPR_NEW; - ++t->token; - if (!token_is_kw(t->token, KW_LPAREN)) { - tokr_err(t, "Expected ( to follow new."); - return false; - } - ++t->token; - if (!parse_type(p, &e->new.type, NULL)) return false; - if (token_is_kw(t->token, KW_COMMA)) { - /* new(int, 5) */ - ++t->token; - Token *n_end = expr_find_end(p, 0); - e->new.n = parser_new_expr(p); - if (!parse_expr(p, e->new.n, n_end)) - return false; - } else e->new.n = NULL; - if (!token_is_kw(t->token, KW_RPAREN)) { - tokr_err(t, "Expected )."); - return false; - } - ++t->token; - if (e->new.type.kind == TYPE_TUPLE) { - err_print(e->where, "You cannot new a tuple."); - return false; - } - if (t->token == end) - goto success; - /* otherwise, there's more stuff after the new (e.g. new(int, 5).len)*/ - t->token = start; - goto not_an_op; - case KW_DEL: - if (!token_is_kw(t->token + 1, KW_LPAREN)) { - /* for the future, when del could be a function */ - err_print(e->where, "Expected ( after del."); - return false; - } - op = UNARY_DEL; - break; case KW_TYPEOF: op = UNARY_TYPEOF; break; @@ -1918,7 +1955,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { } goto success; } else { - not_an_op:; /* function calls, array accesses, etc. */ if (t->token->kind == TOKEN_DIRECT) { @@ -1937,89 +1973,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { e->kind = EXPR_BUILTIN; single_arg = e->builtin.which.expr = parser_new_expr(p); break; - case DIRECT_FOREIGN: { - - e->kind = EXPR_FN; - FnExpr *fn = e->fn = parser_calloc(p, 1, sizeof *e->fn); - fn->flags |= FN_EXPR_FOREIGN; - fn->foreign.fn_ptr = 0; - fn->where.start = t->token; - fn->where.file = p->file; - ++t->token; - if (!token_is_kw(t->token, KW_LPAREN)) { - tokr_err(t, "Expected ( following #foreign."); - return false; - } - ++t->token; - Type *fn_t = &fn->foreign.type; - fn_t->kind = TYPE_FN; - FnType *fn_type = &fn_t->fn; - fn_type->constness = NULL; - fn_type->types = NULL; - Type *ret_type = parser_arr_add(p, &fn_type->types); - CType *ret_ctype = parser_arr_add(p, &fn->foreign.ctypes); - Expression *name = fn->foreign.name_expr = parser_new_expr(p); - - if (!parse_expr(p, name, expr_find_end(p, EXPR_CAN_END_WITH_COMMA))) - return false; - if (token_is_kw(t->token, KW_RPAREN)) { - fn->foreign.lib_expr = NULL; - } else { - if (!token_is_kw(t->token, KW_COMMA)) { - tokr_err(t, "Expected , to follow #foreign name."); - return false; - } - ++t->token; - Expression *lib = fn->foreign.lib_expr = parser_new_expr(p); - if (!parse_expr(p, lib, expr_find_end(p, 0))) - return false; - if (!token_is_kw(t->token, KW_RPAREN)) { - tokr_err(t, "Expected ) to follow #foreign lib."); - return false; - } - } - ++t->token; - - - if (!token_is_kw(t->token, KW_FN)) { - tokr_err(t, "Expected fn to follow #foreign."); - return false; - } - ++t->token; - if (!token_is_kw(t->token, KW_LPAREN)) { - tokr_err(t, "Expected ( after #foreign fn"); - return false; - } - ++t->token; - while (!token_is_kw(t->token, KW_RPAREN)) { - Type *type = parser_arr_add(p, &fn_type->types); - CType *ctype = parser_arr_add(p, &fn->foreign.ctypes); - if (!parse_c_type(p, ctype, type)) { - return false; - } - if (token_is_kw(t->token, KW_COMMA)) { - ++t->token; - } else if (token_is_kw(t->token, KW_RPAREN)) { - ++t->token; - break; - } else { - tokr_err(t, "Expected , or ) following #foreign fn type."); - return false; - } - } - if (t->token == end) { - /* void */ - ret_ctype->kind = CTYPE_NONE; - ret_type->kind = TYPE_VOID; - ret_type->flags = 0; - ret_type->was_expr = NULL; - } else { - if (!parse_c_type(p, ret_ctype, ret_type)) - return false; - } - fn->where.end = t->token; - return true; - } default: tokr_err(t, "Unrecognized expression."); return false; @@ -2782,10 +2735,6 @@ static void fprint_expr(FILE *out, Expression *e) { fprint_type(out, &e->cast.type); fprintf(out, ")"); break; - case EXPR_NEW: - fprintf(out, "new "); - fprint_type(out, &e->new.type); - break; case EXPR_IF: { IfExpr *i = e->if_; if (i->cond) { @@ -3043,7 +2992,6 @@ static bool expr_is_definitely_const(Expression *e) { case EXPR_WHILE: case EXPR_C: case EXPR_BUILTIN: - case EXPR_NEW: case EXPR_CAST: case EXPR_CALL: case EXPR_BLOCK: diff --git a/std/mem.toc b/std/mem.toc new file mode 100644 index 0000000..06890b5 --- /dev/null +++ b/std/mem.toc @@ -0,0 +1,23 @@ +// TODO: check for failed malloc +malloc ::= #foreign("malloc", "libc.so.6") fn(#C size_t) #C &"void"; +free ::= #foreign("free", "libc.so.6") fn(#C &"void"); + +new ::= fn(t :: Type) &t { + malloc((sizeof t) as u64) +} + +news ::= fn(t :: Type, n :: int) []t { + s: []t; + s.data = malloc((n * sizeof t) as u64); + s.len = n; + s +} + +// TODO(eventually): use type information to make this just one function +del ::= fn(t::=, x: &t) { + free(x); +} + +dels ::= fn(t::=, x: []t) { + free(x.data); +}
\ No newline at end of file @@ -1,37 +1,18 @@ -printf ::= #foreign("printf","libc.so.6") fn(#C &"const char", #C ..) #C int; - - -// NOTE: this doesn't work (e.g. "%%%") -tprintf_valid ::= fn(fmt :: []char, nargs: int) bool { - if fmt[fmt.len-1] != '\0' { - return false; - } - count := 0; - for x, i := fmt { - if x == '%' { - if i == fmt.len-1 { - count += 1; - } elif fmt[i+1] != '%' { - count += 1; - } else { - count -= 1; - } - } +#include "std/mem.toc", mem; +#include "std/io.toc", io; +main ::= fn() { + i := mem.new(int); + *i = 3; + io.puti(*i); + ns := mem.news(int, 10); + for n, i := &ns { + *n = i; } - count == nargs -}; - - -tprintf ::= fn(fmt :: []char, args: ..) { - #if !tprintf_valid(fmt, args.len) { - #error "Invalid printf format"; + for n := ns { + io.puti(n); } - f := fmt; - printf(&f[0], args); -}; + mem.del(i); + mem.dels(ns); +} +main(); -main ::= fn() { - tprintf("%d %d%%\n\0", 3, 4); - tprintf("%d %d %d%%\n\0", 3, 4, 5); - tprintf("Hello!\n\0"); -}; @@ -1690,6 +1690,10 @@ static Status types_expr(Typer *tr, Expression *e) { } /* fallthrough */ default: { + if (fo->of->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored) { + /* silently fail */ + goto for_fail; + } char *s = type_to_str(&fo->of->type); err_print(e->where, "Cannot iterate over non-array non-slice type %s.", s); free(s); @@ -1766,24 +1770,6 @@ static Status types_expr(Typer *tr, Expression *e) { } *t = c->type; } break; - case EXPR_NEW: - if (!type_resolve(tr, &e->new.type, e->where)) - return false; - if (e->new.n) { - if (!types_expr(tr, e->new.n)) return false; - if (e->new.n->type.kind != TYPE_BUILTIN || !type_builtin_is_int(e->new.n->type.builtin)) { - char *got = type_to_str(&e->new.n->type); - err_print(e->where, "Expected integer as second argument to new, but got %s.", got); - free(got); - return false; - } - t->kind = TYPE_SLICE; - t->slice = &e->new.type; - } else { - t->kind = TYPE_PTR; - t->ptr = &e->new.type; - } - break; case EXPR_IF: { IfExpr *i = e->if_; IfExpr *curr = i; @@ -2565,15 +2551,6 @@ static Status types_expr(Typer *tr, Expression *e) { *t = *of_type->ptr; break; - case UNARY_DEL: - if (of_type->kind != TYPE_PTR && of_type->kind != TYPE_SLICE) { - char *s = type_to_str(of_type); - err_print(e->where, "Cannot delete non-pointer, non-slice type %s.", s); - free(s); - return false; - } - t->kind = TYPE_VOID; - break; case UNARY_NOT: if (!type_can_be_truthy(of_type)) { char *s = type_to_str(of_type); @@ -2926,6 +2903,14 @@ static Status types_expr(Typer *tr, Expression *e) { break; } } else if (struct_type->kind == TYPE_SLICE || struct_type->kind == TYPE_ARR || type_is_builtin(struct_type, BUILTIN_VARARGS)) { + if (ident_eq_str(rhs->ident, "data") && struct_type->kind == TYPE_SLICE) { + /* allow access of slice pointer */ + t->kind = TYPE_PTR; + t->ptr = typer_calloc(tr, 1, sizeof *t->ptr); + t->ptr->kind = TYPE_VOID; + t->ptr->flags = TYPE_IS_RESOLVED; + break; + } if (!ident_eq_str(rhs->ident, "len")) { char *s = type_to_str(struct_type); err_print(rhs->where, "Field of %s must be .len", s); @@ -300,8 +300,6 @@ typedef enum { KW_CONTINUE, KW_FN, KW_AS, - KW_NEW, - KW_DEL, KW_STRUCT, KW_INT, KW_I8, @@ -335,8 +333,7 @@ static const char *const keywords[KW_COUNT] = "+", "-", "*", "!", "&", "/", "%", "..", ".", "=", "if", "elif", "else", "while", "for", "return", "break", - "continue", "fn", "as", - "new", "del", "struct", + "continue", "fn", "as", "struct", "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "f32", "f64", "Type", "Namespace", @@ -557,7 +554,6 @@ typedef enum { EXPR_FOR, EXPR_FN, EXPR_CAST, - EXPR_NEW, EXPR_CALL, EXPR_BLOCK, EXPR_TUPLE, @@ -579,7 +575,6 @@ typedef enum { UNARY_ADDRESS, /* &x */ UNARY_DEREF, /* *x */ UNARY_NOT, /* !x */ - UNARY_DEL, /* del x */ UNARY_TYPEOF, /* typeof x */ UNARY_LEN, /* x.len ; replaces BINARY_DOT len when typing */ UNARY_DSIZEOF, |