diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-01 15:01:38 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-01 15:01:38 -0400 |
commit | 7f84a8f28c3d0f8d99d2d88373ee7c1595266d2d (patch) | |
tree | b09d15501e88fa925537423f0cb983eaa3438045 | |
parent | bedd8ae2b1fead877438feb85ff57df3da21fb2b (diff) |
arr/slice length with .len!
-rw-r--r-- | cgen.c | 33 | ||||
-rw-r--r-- | eval.c | 31 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | parse.c | 15 | ||||
-rw-r--r-- | test.toc | 46 | ||||
-rw-r--r-- | types.c | 59 | ||||
-rw-r--r-- | types.h | 5 |
7 files changed, 152 insertions, 39 deletions
@@ -856,7 +856,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, "("); cgen_expr(g, e->binary.lhs); bool is_ptr = type_inner(&e->binary.lhs->type)->kind == TYPE_PTR; - cgen_write(g, is_ptr ? "->" : "."); + cgen_write(g, is_ptr ? "->" :"."); cgen_ident(g, e->binary.field->name); cgen_write(g, ")"); handled = true; @@ -874,6 +874,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) { case EXPR_UNARY_OP: { const char *s = ""; bool handled = false; + Type *of_type = &e->unary.of->type; switch (e->unary.op) { case UNARY_MINUS: s = "-"; break; @@ -887,11 +888,29 @@ static bool cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, "free("); if (!cgen_expr(g, e->unary.of)) return false; - if (e->unary.of->type.kind == TYPE_SLICE) + 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) { + of_type = of_type->ptr; + } + switch (of_type->kind) { + case TYPE_SLICE: + if (!cgen_expr(g, e->unary.of)) + return false; + cgen_write(g, "%sn", is_ptr ? "->" : "."); + break; + case TYPE_ARR: + cgen_write(g, "%lu", (unsigned long)of_type->arr.n); + break; + default: assert(0); break; + } + handled = true; + } break; } if (handled) break; cgen_write(g, "("); @@ -961,7 +980,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) { if (!eval_expr(g->evalr, &e->direct.args[0], &val)) return false; cgen_indent(g); - fwrite(val.slice.data, 1, val.slice.n, cgen_writing_to(g)); + fwrite(val.slice.data, 1, (size_t)val.slice.n, cgen_writing_to(g)); } break; case DIRECT_COUNT: assert(0); break; } @@ -1111,17 +1130,17 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { switch (t->kind) { case TYPE_SLICE: { Slice *s = (Slice *)v; - for (U64 i = 0; i < s->n; i++) { - if (!cgen_val_ptr_pre(g, (char *)s->data + i * compiler_sizeof(t->slice), t->slice, where)) + for (I64 i = 0; i < s->n; i++) { + if (!cgen_val_ptr_pre(g, (char *)s->data + (U64)i * compiler_sizeof(t->slice), t->slice, where)) return false; } if (!cgen_type_pre(g, t->slice, where)) return false; cgen_write(g, "(d%p_[])", v); /* TODO: improve this somehow? */ if (!cgen_type_post(g, t->slice, where)) return false; cgen_write(g, " = {"); - for (U64 i = 0; i < s->n; i++) { + for (I64 i = 0; i < s->n; i++) { if (i) cgen_write(g, ", "); - if (!cgen_val_ptr(g, (char *)s->data + i * compiler_sizeof(t->slice), t->slice, where)) + if (!cgen_val_ptr(g, (char *)s->data + (U64)i * compiler_sizeof(t->slice), t->slice, where)) return false; } cgen_write(g, "};"); @@ -620,7 +620,7 @@ static bool eval_val_ptr_at_index(Evaluator *ev, Location where, Value *arr, U64 if (type) *type = arr_type->arr.of; } break; case TYPE_SLICE: { - U64 slice_sz = arr->slice.n; + U64 slice_sz = (U64)arr->slice.n; if (i >= slice_sz) { err_print(where, "Slice out of bounds (%lu, slice size = %lu)\n", (unsigned long)i, (unsigned long)slice_sz); return false; @@ -821,6 +821,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { if (e->unary.op != UNARY_ADDRESS) { if (!eval_expr(ev, e->unary.of, &of)) return false; } + Type *of_type = &e->unary.of->type; switch (e->unary.op) { case UNARY_ADDRESS: { Expression *o = e->unary.of; @@ -893,13 +894,29 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { v->boolv = !val_truthiness(v, &e->unary.of->type); break; case UNARY_DEL: - if (e->unary.of->type.kind == TYPE_PTR) + if (of_type->kind == TYPE_PTR) free(of.ptr); else { - assert(e->unary.of->type.kind == TYPE_SLICE); + assert(of_type->kind == TYPE_SLICE); free(of.slice.data); } break; + case UNARY_LEN: + if (of_type->kind == TYPE_PTR) { + /* dereference of */ + eval_deref(&of, of.ptr, of_type->ptr); + of_type = of_type->ptr; + } + switch (of_type->kind) { + case TYPE_SLICE: + v->i64 = of.slice.n; + break; + case TYPE_ARR: + v->i64 = (I64)of_type->arr.n; + break; + default: assert(0); break; + } + break; } } break; case EXPR_BINARY_OP: { @@ -1011,7 +1028,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { break; case EXPR_LITERAL_STR: v->slice.data = e->strl.str; - v->slice.n = e->strl.len; + v->slice.n = (I64)e->strl.len; break; case EXPR_CAST: { Value casted; @@ -1084,7 +1101,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { 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 = n64; + v->slice.n = (I64)n64; } else { v->ptr = err_calloc(1, compiler_sizeof(&e->new.type)); } @@ -1135,7 +1152,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { Type *of_type = &s->of->type; if (!eval_expr(ev, s->of, &ofv)) return false; - U64 n = of_type->kind == TYPE_ARR ? of_type->arr.n : ofv.slice.n; + U64 n = of_type->kind == TYPE_ARR ? of_type->arr.n : (U64)ofv.slice.n; U64 from, to; if (s->from) { Value fromv; @@ -1167,7 +1184,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { if (!eval_val_ptr_at_index(ev, e->where, &ofv, to, of_type, &s->to->type, &ptr2, NULL)) return false; v->slice.data = ptr1; - v->slice.n = to - from; + v->slice.n = (I64)(to - from); } else { v->slice.data = NULL; v->slice.n = 0; @@ -1,7 +1,7 @@ /* TODO: -using dot with pointers length of slice/arr with .len +.len lvalue for slices verify size of struct, align of fields pointers to futurely-declared types don't allow while {3; 5} (once break is added) @@ -36,6 +36,7 @@ static const char *unary_op_to_str(UnaryOp u) { case UNARY_DEREF: return "*"; case UNARY_NOT: return "!"; case UNARY_DEL: return "del"; + case UNARY_LEN: return "len"; } assert(0); return ""; @@ -1205,7 +1206,11 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { err_print(e->where, "You cannot new a tuple."); return false; } - return true; + if (t->token == end) + return true; + /* 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 */ @@ -1327,6 +1332,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { } return true; } else { + not_an_op:; /* function calls, array accesses, etc. */ /* try a function call or array access */ @@ -1343,6 +1349,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { } /* which opening bracket starts the call/array access */ Token *opening_bracket = NULL; + Token *closing_bracket = NULL; for (; token < end; token++) { if (token->kind == TOKEN_KW) { switch (token->kw) { @@ -1361,9 +1368,13 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { break; case KW_RPAREN: paren_level--; + if (opening_bracket && token_is_kw(opening_bracket, KW_LPAREN) && square_level == 0 && paren_level == 0 && brace_level == 0) + closing_bracket = token; break; case KW_RSQUARE: square_level--; + if (opening_bracket && token_is_kw(opening_bracket, KW_LSQUARE) && square_level == 0 && paren_level == 0 && brace_level == 0) + closing_bracket = token; break; case KW_LBRACE: brace_level++; @@ -1386,7 +1397,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { break; } } - if (opening_bracket) { + if (opening_bracket && closing_bracket && closing_bracket + 1 == end /* make sure there's nothing after the closing bracket */) { switch (opening_bracket->kw) { case KW_LPAREN: { /* it's a function call! */ @@ -1,27 +1,39 @@ - - - puti @= fn(x: int) { #C("printf(\"%ld\\n\", (long)x); "); }; -main @= fn() { -puti(somesum()); -foo @= somesum(); -puti(foo); +foo @= fn() int { + x:= new(int, 10).len; + x }; -Point @= struct { - x, y : int; + +bar @= fn() int { + x := new(int,10); + (&x).len }; -sum @= fn(p: &Point) int { - p.x + p.y + +baz @= fn() int { + x: [10]int; + x.len }; -somesum @= fn() int { - p : Point; - p.x = 12389; - p.y = 29404; - total := sum(&p); - total + +quux @= fn() int { + x: [10]int; + (&x).len }; +main @= fn() { + puti(foo()); + X @= foo(); + puti(X); + puti(bar()); + Y @= bar(); + puti(Y); + puti(baz()); + Z @= baz(); + puti(Z); + puti(quux()); + W @= quux(); + puti(W); +}; @@ -945,6 +945,18 @@ static bool types_expr(Typer *tr, Expression *e) { } t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_BOOL; + break; + case UNARY_LEN: + /* in theory, this shouldn't happen right now, because typing generates len operators */ + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_I64; + if (of_type->kind != TYPE_SLICE || of_type->kind != TYPE_ARR) { + char *s = type_to_str(of_type); + err_print(e->where, "Cannot get length of non-array, non-slice type %s.", s); + free(s); + return false; + } + break; } } break; case EXPR_BINARY_OP: { @@ -1104,7 +1116,17 @@ static bool types_expr(Typer *tr, Expression *e) { Value field_name; if (!types_expr(tr, rhs)) return false; if (rhs_type->kind != TYPE_SLICE || !type_is_builtin(rhs_type->slice, BUILTIN_CHAR)) { - err_print(e->where, "Invalid field of type %s."); + char *struct_typestr = type_to_str(lhs_type); + if (rhs->kind == EXPR_IDENT) { + char *fstr = ident_to_str(rhs->ident); + err_print(e->where, "%s is not a field of structure %s.", fstr, struct_typestr); + free(fstr); + } else { + char *field_typestr = type_to_str(rhs_type); + err_print(e->where, "Invalid type %s for field of structure %s .", rhs_type, struct_typestr); + free(field_typestr); + } + free(struct_typestr); return false; } @@ -1117,8 +1139,8 @@ static bool types_expr(Typer *tr, Expression *e) { } } if (!is_field) { - char *fstr = err_malloc(field_name.slice.n + 1); - memcpy(fstr, field_name.slice.data, field_name.slice.n); + char *fstr = err_malloc((size_t)(field_name.slice.n + 1)); + memcpy(fstr, field_name.slice.data, (size_t)field_name.slice.n); fstr[field_name.slice.n] = 0; /* null-terminate */ char *typestr = type_to_str(lhs_type); err_print(e->where, "%s is not a field of structure %s.", fstr, typestr); @@ -1126,6 +1148,37 @@ static bool types_expr(Typer *tr, Expression *e) { return false; } } + } else if (struct_type->kind == TYPE_SLICE || struct_type->kind == TYPE_ARR) { + if (!(rhs->kind == EXPR_IDENT && ident_eq_str(rhs->ident, "len"))) { + + Value field_name; + if (!types_expr(tr, rhs)) return false; + if (rhs_type->kind != TYPE_SLICE || !type_is_builtin(rhs_type->slice, BUILTIN_CHAR)) { + err_print(e->where, "Invalid field of type %s."); + return false; + + } + if (!eval_expr(tr->evalr, rhs, &field_name)) return false; + char *str = field_name.slice.data; + if (field_name.slice.n != 3 || strcmp(str, "len") != 0) { + char *fstr = err_malloc((size_t)(field_name.slice.n + 1)); + memcpy(fstr, field_name.slice.data, (size_t)field_name.slice.n); + fstr[field_name.slice.n] = 0; /* null-terminate */ + char *typestr = type_to_str(lhs_type); + err_print(e->where, "%s is not a field of type %s.", fstr, typestr); + free(fstr); free(typestr); + return false; + } + } + + /* length of slice/arr */ + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_I64; + /* change expr to UNARY_LEN */ + e->kind = EXPR_UNARY_OP; + Expression *of = lhs; + e->unary.op = UNARY_LEN; + e->unary.of = of; } else { char *s = type_to_str(lhs_type); err_print(e->where, "Operator . applied to type %s, which is not a structure or pointer to structure.", s); @@ -68,7 +68,7 @@ typedef struct { } BlockArr; typedef struct { - U64 n; + I64 n; void *data; } Slice; @@ -347,7 +347,8 @@ typedef enum { UNARY_ADDRESS, /* &x */ UNARY_DEREF, /* *x */ UNARY_NOT, /* !x */ - UNARY_DEL + UNARY_DEL, /* del x */ + UNARY_LEN /* x.len ; replaces BINARY_DOT len when typing */ } UnaryOp; typedef enum { |