diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-01 15:25:08 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-01 15:25:08 -0400 |
commit | 456ff7743aeed28a6837a7dbc9cc0ab28331931d (patch) | |
tree | 424b05bd695d6e18b0f4f318b867fe55b8110a58 | |
parent | 7f84a8f28c3d0f8d99d2d88373ee7c1595266d2d (diff) |
.len as an lvalue for slices
-rw-r--r-- | eval.c | 124 | ||||
-rw-r--r-- | main.c | 5 | ||||
-rw-r--r-- | test.toc | 46 | ||||
-rw-r--r-- | types.c | 15 |
4 files changed, 109 insertions, 81 deletions
@@ -675,6 +675,62 @@ static void *eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr) { return (char *)struc_data + dot_expr->binary.field->offset; } +static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) { + switch (e->kind) { + case EXPR_IDENT: { + IdentDecl *id = ident_decl(e->ident); + if (!(id->flags & IDECL_FLAG_HAS_VAL)) { + err_print(e->where, "Cannot take address of run time variable at compile time."); + return false; + } + if (e->type.kind == TYPE_ARR) + *ptr = id->val.arr; /* point directly to data */ + else if (e->type.kind == TYPE_STRUCT) + *ptr = id->val.struc; + else + *ptr = &id->val; + } break; + case EXPR_UNARY_OP: + switch (e->unary.op) { + case UNARY_DEREF: { + Value v; + if (!eval_expr(ev, e, &v)) return false; + *ptr = v.ptr; + } break; + case UNARY_LEN: { + Value slice; + if (!eval_expr(ev, e, &slice)) return false; + *ptr = &slice.slice.n; + } break; + default: assert(0); return false; + } + break; + case EXPR_BINARY_OP: + switch (e->binary.op) { + case BINARY_AT_INDEX: { + if (!eval_expr_ptr_at_index(ev, e, ptr, NULL)) + return false; + } break; + case BINARY_DOT: { + Value struc; + if (!eval_expr(ev, e->binary.lhs, &struc)) + return false; + *ptr = eval_ptr_to_struct_field(ev, e); + if (!*ptr) + return false; + return true; + } break; + default: assert(0); return false; + } + break; + default: + assert(0); + return false; + } + return true; +} + + static bool eval_set(Evaluator *ev, Expression *set, Value *to) { switch (set->kind) { case EXPR_IDENT: { @@ -692,6 +748,21 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) { if (!eval_expr(ev, set->unary.of, &ptr)) return false; eval_deref_set(ptr.ptr, to, &set->type); } break; + case UNARY_LEN: { + Type *of_type = &set->unary.of->type; + if (of_type->kind == TYPE_PTR) { + /* if it's a pointer, we can just eval it and set its length */ + Value of; + if (!eval_expr(ev, set->unary.of, &of)) return false; + ((Slice *)of.ptr)->n = to->i64; + } else { + /* otherwise, we need a pointer to the slice */ + void *p; + if (!eval_address_of(ev, set->unary.of, &p)) + return false; + ((Slice *)p)->n = to->i64; + } + } break; default: assert(0); break; } break; @@ -828,59 +899,14 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { if (o->type.kind == TYPE_TYPE) { if (!eval_expr(ev, e->unary.of, &of)) return false; /* "address" of type (pointer to type) */ - v->type = evalr_calloc(ev, 1, sizeof *v->type); /* TODO: this might be bad in the future; should free this at some point */ - /* v->type->flags = 0; */ + v->type = evalr_malloc(ev, sizeof *v->type); /* TODO: this might be bad in the future; should free this at some point */ + v->type->flags = 0; v->type->kind = TYPE_PTR; v->type->ptr = of.type; break; } - switch (o->kind) { - case EXPR_IDENT: { - IdentDecl *id = ident_decl(o->ident); - if (!(id->flags & IDECL_FLAG_HAS_VAL)) { - err_print(e->where, "Cannot take address of run time variable at compile time."); - return false; - } - if (o->type.kind == TYPE_ARR) - v->ptr = id->val.arr; /* point directly to data */ - else if (o->type.kind == TYPE_STRUCT) - v->ptr = id->val.struc; - else - v->ptr = &id->val; - } break; - case EXPR_UNARY_OP: - switch (o->unary.op) { - case UNARY_DEREF: { - Value ptr; - if (!eval_expr(ev, o, &ptr)) return false; - v->ptr = ptr.ptr; - } break; - default: assert(0); break; - } - break; - case EXPR_BINARY_OP: - switch (o->binary.op) { - case BINARY_AT_INDEX: { - void *ptr; - if (!eval_expr_ptr_at_index(ev, o, &ptr, NULL)) - return false; - v->ptr = ptr; - } break; - case BINARY_DOT: { - Value struc; - if (!eval_expr(ev, o->binary.lhs, &struc)) - return false; - v->ptr = eval_ptr_to_struct_field(ev, o); - if (!v->ptr) - return false; - } break; - default: assert(0); break; - } - break; - default: - assert(0); - break; - } + if (!eval_address_of(ev, o, &v->ptr)) + return false; } break; case UNARY_DEREF: eval_deref(v, of.ptr, &e->type); @@ -1,9 +1,10 @@ /* TODO: -length of slice/arr with .len -.len lvalue for slices verify size of struct, align of fields pointers to futurely-declared types +for ++=, -=, *=, /= +compile-time arguments don't allow while {3; 5} (once break is added) any odd number of "s for a string modifiable strings: @@ -3,37 +3,27 @@ puti @= fn(x: int) { "); }; -foo @= fn() int { - x:= new(int, 10).len; - x +total @= fn() int { + t := 0; + x := new(int,10); + i := 0; + while i < x.len { + x[i] = i; + i = i + 1; + } + + x.len = 5; + i = 0; + while i < x.len { + t = t + x[i]; + i = i + 1; + } + t }; -bar @= fn() int { - x := new(int,10); - (&x).len -}; - -baz @= fn() int { - x: [10]int; - x.len -}; - -quux @= fn() int { - x: [10]int; - (&x).len -}; main @= fn() { - puti(foo()); - X @= foo(); + puti(total()); + X @= total(); puti(X); - puti(bar()); - Y @= bar(); - puti(Y); - puti(baz()); - Z @= baz(); - puti(Z); - puti(quux()); - W @= quux(); - puti(W); }; @@ -163,14 +163,25 @@ static bool expr_must_lval(Expression *e) { } case EXPR_UNARY_OP: if (e->unary.op == UNARY_DEREF) return true; - break; + if (e->unary.op == UNARY_LEN) { + Type *of_type = &e->unary.of->type; + if (of_type->kind != TYPE_PTR && !expr_must_lval(e->unary.of)) { /* can't set length of a non-lvalue slice */ + return false; + } + + return of_type->kind == TYPE_SLICE + || (of_type->kind == TYPE_PTR + && of_type->kind == TYPE_SLICE); + } + err_print(e->where, "Cannot use operator %s as l-value.", unary_op_to_str(e->unary.op)); + return false; case EXPR_BINARY_OP: switch (e->binary.op) { case BINARY_AT_INDEX: return true; case BINARY_DOT: return true; default: break; } - err_print(e->where, "Cannot use operator %s as l-value", binary_op_to_str(e->binary.op)); + err_print(e->where, "Cannot use operator %s as l-value.", binary_op_to_str(e->binary.op)); return false; case EXPR_TUPLE: /* x, y is an lval, but 3, "hello" is not. */ |