summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-03-16 20:24:23 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-03-16 20:24:23 -0400
commit6855c6e752e4e4f2f37702477a3b461a51bbc614 (patch)
treeea3b8ea8f872139515009564a64afdee401441c0
parent970a379d5ee3e8a585a3138a64411ce80f31c8b7 (diff)
made new and del functions
-rw-r--r--cgen.c46
-rw-r--r--copy.c7
-rw-r--r--eval.c32
-rw-r--r--parse.c218
-rw-r--r--std/mem.toc23
-rw-r--r--test.toc49
-rw-r--r--types.c39
-rw-r--r--types.h7
8 files changed, 151 insertions, 270 deletions
diff --git a/cgen.c b/cgen.c
index f9138fe..70db8ff 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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);
diff --git a/copy.c b/copy.c
index e3d2076..f99d880 100644
--- a/copy.c
+++ b/copy.c
@@ -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;
diff --git a/eval.c b/eval.c
index 474e9ee..a0de141 100644
--- a/eval.c
+++ b/eval.c
@@ -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) {
diff --git a/parse.c b/parse.c
index 7d2628c..290bb5d 100644
--- a/parse.c
+++ b/parse.c
@@ -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
diff --git a/test.toc b/test.toc
index e030af4..8d884fd 100644
--- a/test.toc
+++ b/test.toc
@@ -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");
-};
diff --git a/types.c b/types.c
index eabb79d..25a6751 100644
--- a/types.c
+++ b/types.c
@@ -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);
diff --git a/types.h b/types.h
index 40165f5..b02a783 100644
--- a/types.h
+++ b/types.h
@@ -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,