diff options
-rw-r--r-- | cgen.c | 55 | ||||
-rw-r--r-- | decls_cgen.c | 5 | ||||
-rw-r--r-- | eval.c | 103 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | out.c | 29 | ||||
-rw-r--r-- | parse.c | 82 | ||||
-rw-r--r-- | test.toc | 28 | ||||
-rw-r--r-- | types.c | 32 | ||||
-rw-r--r-- | types.h | 13 |
9 files changed, 267 insertions, 83 deletions
@@ -485,6 +485,7 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, cgen_write(g, "; "); } break; + case EXPR_SLICE: case EXPR_IDENT: case EXPR_LITERAL_INT: case EXPR_LITERAL_CHAR: @@ -663,6 +664,57 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { cgen_write(g, ";"); } break; + case EXPR_SLICE: { + SliceExpr *s = &e->slice; + IdentID s_id = e->slice.c.id = g->ident_counter++; + IdentID from_id = g->ident_counter++; + if (!cgen_expr_pre(g, s->of)) + return false; + if (s->from && !cgen_expr_pre(g, s->from)) + return false; + if (s->to && !cgen_expr_pre(g, s->to)) + return false; + cgen_write(g, "u64 "); + cgen_ident_id(g, from_id); + cgen_write(g, " = "); + if (s->from) { + if (!cgen_expr(g, s->from)) + return false; + } else { + cgen_write(g, "0"); + } + cgen_write(g, "; slice_ "); + cgen_ident_id(g, s_id); + cgen_write(g, "; "); + cgen_ident_id(g, s_id); + cgen_write(g, ".data = ("); + if (!cgen_type_pre(g, e->type.slice, e->where)) + return false; + cgen_write(g, "(*)"); + if (!cgen_type_post(g, e->type.slice, e->where)) + return false; + cgen_write(g, ")("); + if (!cgen_expr(g, s->of)) + return false; + if (s->of->type.kind == TYPE_SLICE) { + cgen_write(g, ".data"); + } + cgen_write(g, ") + "); + cgen_ident_id(g, from_id); + cgen_write(g, "; "); + cgen_ident_id(g, s_id); + cgen_write(g, ".n = "); + if (s->to) { + if (!cgen_expr(g, s->to)) + return false; + } else { + /* TODO */ + } + cgen_write(g, " - "); + cgen_ident_id(g, from_id); + cgen_write(g, ";"); + cgen_nl(g); + } break; case EXPR_LITERAL_INT: case EXPR_LITERAL_FLOAT: case EXPR_LITERAL_BOOL: @@ -883,6 +935,9 @@ static bool cgen_expr(CGenerator *g, Expression *e) { } cgen_fn_name(g, &e->fn); } break; + case EXPR_SLICE: + cgen_ident_id(g, e->slice.c.id); + break; } return true; } diff --git a/decls_cgen.c b/decls_cgen.c index 189b032..0ef0451 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -49,6 +49,11 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) { if (!cgen_decls_expr(g, x)) return false; break; + case EXPR_SLICE: + if (!cgen_decls_expr(g, e->slice.of)) return false; + if (e->slice.from && !cgen_decls_expr(g, e->slice.from)) return false; + if (e->slice.to && !cgen_decls_expr(g, e->slice.to)) return false; + break; case EXPR_FN: e->fn.c.name = NULL; e->fn.c.id = g->ident_counter++; @@ -405,14 +405,39 @@ static void eval_deref_set(void *set, Value *to, Type *type) { } } -static bool eval_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Type **type) { +static bool eval_val_ptr_at_index(Evaluator *ev, Location where, Value *arr, U64 i, Type *arr_type, Type *idx_type, void **ptr, Type **type) { + switch (arr_type->kind) { + case TYPE_ARR: { + U64 arr_sz = arr_type->arr.n; + if (i >= arr_sz) { + err_print(where, "Array out of bounds (%lu, array size = %lu)\n", (unsigned long)i, (unsigned long)arr_sz); + return false; + } + *ptr = (char *)arr->arr + compiler_sizeof(arr_type->arr.of) * i; + if (type) *type = arr_type->arr.of; + } break; + case TYPE_SLICE: { + U64 slice_sz = 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; + } + *ptr = (char *)arr->slice.data + compiler_sizeof(arr_type->slice) * i; + if (type) *type = arr_type->slice; + } break; + default: assert(0); break; + } + return true; +} + +static bool eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Type **type) { Value arr; if (!eval_expr(ev, e->binary.lhs, &arr)) return false; Value index; if (!eval_expr(ev, e->binary.rhs, &index)) return false; - U64 i; Type *ltype = &e->binary.lhs->type; Type *rtype = &e->binary.rhs->type; + U64 i; assert(rtype->kind == TYPE_BUILTIN); if (rtype->builtin == BUILTIN_U64) { i = index.u64; @@ -424,28 +449,7 @@ static bool eval_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Type **t } i = (U64)signed_index; } - switch (ltype->kind) { - case TYPE_ARR: { - U64 arr_sz = ltype->arr.n; - if (i >= arr_sz) { - err_print(e->where, "Array out of bounds (%lu, array size = %lu)\n", (unsigned long)i, (unsigned long)arr_sz); - return false; - } - *ptr = (char *)arr.arr + compiler_sizeof(ltype->arr.of) * i; - *type = ltype->arr.of; - } break; - case TYPE_SLICE: { - U64 slice_sz = arr.slice.n; - if (i >= slice_sz) { - err_print(e->where, "Slice out of bounds (%lu, slice size = %lu)\n", (unsigned long)i, (unsigned long)slice_sz); - return false; - } - *ptr = (char *)arr.slice.data + compiler_sizeof(ltype->slice) * i; - *type = ltype->slice; - } break; - default: assert(0); break; - } - return true; + return eval_val_ptr_at_index(ev, e->where, &arr, i, ltype, rtype, ptr, type); } static bool eval_set(Evaluator *ev, Expression *set, Value *to) { @@ -473,7 +477,7 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) { case BINARY_AT_INDEX: { void *ptr; Type *type; - if (!eval_ptr_at_index(ev, set, &ptr, &type)) + if (!eval_expr_ptr_at_index(ev, set, &ptr, &type)) return false; eval_deref_set(ptr, to, type); } break; @@ -606,8 +610,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { switch (o->binary.op) { case BINARY_AT_INDEX: { void *ptr; - Type *type; - if (!eval_ptr_at_index(ev, o, &ptr, &type)) + if (!eval_expr_ptr_at_index(ev, o, &ptr, NULL)) return false; v->ptr = ptr; } break; @@ -674,7 +677,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { case BINARY_AT_INDEX: { void *ptr; Type *type; - eval_ptr_at_index(ev, e, &ptr, &type); + eval_expr_ptr_at_index(ev, e, &ptr, &type); eval_deref(v, ptr, type); } break; } @@ -836,6 +839,50 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { } fn_exit(fn); } break; + case EXPR_SLICE: { + SliceExpr *s = &e->slice; + Value ofv; + 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 from, to; + if (s->from) { + Value fromv; + if (!eval_expr(ev, s->from, &fromv)) + return false; + assert(s->from->type.kind == TYPE_BUILTIN); + from = val_to_u64(&fromv, s->from->type.builtin); + } else { + from = 0; + } + if (s->to) { + Value tov; + if (!eval_expr(ev, s->to, &tov)) + return false; + assert(s->to->type.kind == TYPE_BUILTIN); + to = val_to_u64(&tov, s->to->type.builtin); + } else { + to = n - 1; + } + /* TODO: is this the best check? (Go also checks if from > to) */ + if (to > n) { + err_print(e->where, "Slice index out of bounds (to = %lu, length = %lu).", (unsigned long)to, (unsigned long)n); + return false; + } + void *ptr1, *ptr2; + if (to < from) { + if (!eval_val_ptr_at_index(ev, e->where, &ofv, from, of_type, &s->from->type, &ptr1, NULL)) + return false; + 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; + } else { + v->slice.data = NULL; + v->slice.n = 0; + } + } break; } return true; } @@ -1,7 +1,8 @@ /* TODO: slice notation (x[a:b]) -bf interpreter +fix constants +bf interpreter (& other tests) error on failed calloc in output unicode variable names make sure initializers for global variables are compile-time constants @@ -18,7 +18,6 @@ typedef struct { void *data; u64 n; } slice_; /* declarations */ void puti(i64 x); -i64 factorial(i64 x); void main__(void); /* code */ int main() { @@ -34,32 +33,20 @@ void puti(i64 x) { } -i64 factorial(i64 x) { +void main__(void) { + i64 N; { + i64 expr__; expr__ = 10;N = expr__;} slice_ numbers; { - slice_ expr__; slice_ a0_; a0_.data = calloc(x, sizeof(i64)); a0_.n = x;expr__ = a0_;numbers = expr__;} + slice_ expr__; slice_ a0_; a0_.data = calloc(N, sizeof(i64)); a0_.n = N;expr__ = a0_;numbers = expr__;} i64 i; { i64 expr__; expr__ = 0;i = expr__;} - while ((i<x)) { - (((i64(*))(numbers.data))[i]) = (i+1);; - i = (i+1);; - }; - i64 product; { - i64 expr__; expr__ = 1;product = expr__;} - i = 0;; - while ((i<x)) { - product = (product*(((i64(*))(numbers.data))[i]));; + while ((i<N)) { + (((i64(*))(numbers.data))[i]) = i;; i = (i+1);; }; - free(numbers.data); - return product; -} - - -void main__(void) { - - i64( a342[120]) = {0}; - (puti((factorial(10)))); + u64 a3_ = 0; slice_ a2_; a2_.data = (i64(*))(numbers.data) + a3_; a2_.n = 8 - a3_; + (puti((((i64(*))(a2_.data))[0]))); } @@ -22,6 +22,7 @@ static const char *expr_kind_to_str(ExprKind k) { case EXPR_TUPLE: return "tuple"; case EXPR_BLOCK: return "block"; case EXPR_IDENT: return "identifier"; + case EXPR_SLICE: return "slice"; } assert(0); return ""; @@ -234,7 +235,7 @@ static inline Expression *parser_new_expr(Parser *p) { #define EXPR_CAN_END_WITH_COMMA 0x01 /* a comma could end the expression */ #define EXPR_CAN_END_WITH_LBRACE 0x02 - +#define EXPR_CAN_END_WITH_COLON 0x04 /* is_vbs can be NULL */ static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) { Tokenizer *t = p->tokr; @@ -290,6 +291,10 @@ static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) { return token; could_be_vbs = true; break; + case KW_COLON: + if ((flags & EXPR_CAN_END_WITH_COLON) + && brace_level == 0 && square_level == 0 && paren_level == 0) + return token; default: break; } if (token->kw != KW_RBRACE && token->kw != KW_SEMICOLON && token->kw != KW_LBRACE) @@ -1169,18 +1174,66 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { return parse_args(p, &e->call.args); } case KW_LSQUARE: { - /* it's an array access */ - e->kind = EXPR_BINARY_OP; - e->binary.op = BINARY_AT_INDEX; - e->binary.lhs = parser_new_expr(p); - e->binary.rhs = parser_new_expr(p); + Expression *arr = parser_new_expr(p); + /* it's an array access or slice */ /* parse array */ - if (!parse_expr(p, e->binary.lhs, opening_bracket)) return false; - /* parse index */ + if (!parse_expr(p, arr, opening_bracket)) return false; + t->token = opening_bracket + 1; - Token *index_end = expr_find_end(p, 0, NULL); - if (!parse_expr(p, e->binary.rhs, index_end)) + Token *iend = NULL; + if (token_is_kw(t->token, KW_COLON)) { + /* slice */ + goto expr_is_slice; + } + iend = expr_find_end(p, EXPR_CAN_END_WITH_COLON, NULL); + if (iend->kind != TOKEN_KW) { + err_print(iend->where, "Expected ] or : after index."); return false; + } + switch (iend->kw) { + case KW_RSQUARE: + /* array access */ + e->kind = EXPR_BINARY_OP; + e->binary.op = BINARY_AT_INDEX; + e->binary.lhs = arr; + e->binary.rhs = parser_new_expr(p); + if (!parse_expr(p, e->binary.rhs, iend)) + return false; + break; + expr_is_slice: + case KW_COLON: { + /* slice */ + SliceExpr *s = &e->slice; + e->kind = EXPR_SLICE; + s->of = arr; + if (iend) { + s->from = parser_new_expr(p); + if (!parse_expr(p, s->from, iend)) + return false; + } else { + /* e.g. x[:5] */ + s->from = NULL; + } + assert(token_is_kw(t->token, KW_COLON)); + t->token++; + if (token_is_kw(t->token, KW_RSQUARE)) { + /* e.g. x[5:] */ + s->to = NULL; + } else { + s->to = parser_new_expr(p); + Token *to_end = expr_find_end(p, 0, NULL); + if (!token_is_kw(to_end, KW_RSQUARE)) { + err_print(iend->where, "Expected ] at end of slice."); + return false; + } + if (!parse_expr(p, s->to, to_end)) + return false; + } + } break; + default: + err_print(iend->where, "Expected ] or : after index."); + return false; + } t->token++; /* move past ] */ return true; } @@ -1601,6 +1654,15 @@ static void fprint_expr(FILE *out, Expression *e) { fprintf(out, "%s", directives[e->direct.which]); fprint_arg_exprs(out, e->direct.args); break; + case EXPR_SLICE: { + SliceExpr *s = &e->slice; + fprint_expr(out, s->of); + fprintf(out, "["); + if (s->from) fprint_expr(out, s->from); + fprintf(out, ":"); + if (s->from) fprint_expr(out, s->to); + fprintf(out, "]"); + } break; } if (parse_printing_after_types) { fprintf(out, ":"); @@ -5,25 +5,13 @@ puti @= fn(x: int) { #C("printf(\"%ld\\n\", (long)x)"); }; - -factorial @= fn(x: int) int { - numbers := new(int, x); - i := 0; - while i < x { - numbers[i] = i+1; - i = i + 1; - } - product := 1; - i = 0; - while i < x{ - product = product * numbers[i]; - i = i + 1; - } - del(numbers); - product -}; - main @= fn() { - a342 : [factorial(5)]int; - puti(factorial(10)); + N := 10; + numbers := new(int, N); + i := 0; + while i < N { + numbers[i] = i; + i = i + 1; + } + puti(numbers[:8][0]); }; @@ -84,7 +84,7 @@ static bool type_must_eq(Location where, Type *expected, Type *got) { /* -this expression, which is an array, must be mutable (otherwise print an error, +this expression, which is an array (or slice), must be mutable (otherwise print an error, return false)! */ static bool expr_arr_must_mut(Expression *e) { @@ -106,6 +106,8 @@ static bool expr_arr_must_mut(Expression *e) { case EXPR_NEW: case EXPR_UNARY_OP: return true; + case EXPR_SLICE: + return expr_arr_must_mut(e->slice.of); case EXPR_WHILE: assert(e->while_.body.ret_expr); return expr_arr_must_mut(e->while_.body.ret_expr); @@ -187,7 +189,8 @@ static bool expr_must_lval(Expression *e) { case EXPR_WHILE: case EXPR_CALL: case EXPR_DIRECT: - case EXPR_BLOCK: { + case EXPR_BLOCK: + case EXPR_SLICE: { err_print(e->where, "Cannot use %s as l-value.", expr_kind_to_str(e->kind)); return false; } @@ -1005,6 +1008,31 @@ static bool types_expr(Typer *tr, Expression *e) { *x_type = x->type; } break; + case EXPR_SLICE: { + t->kind = TYPE_SLICE; + SliceExpr *s = &e->slice; + if (!types_expr(tr, s->of)) + return false; + if (e->slice.from && !types_expr(tr, s->from)) + return false; + if (e->slice.to && !types_expr(tr, s->to)) + return false; + switch (s->of->type.kind) { + case TYPE_ARR: + t->slice = s->of->type.arr.of; + break; + case TYPE_SLICE: + t->slice = s->of->type.slice; + break; + default: { + char *str = type_to_str(&s->of->type); + err_print(e->where, "Cannot take slice of non-array, non-slice type %s.", str); + free(str); + return false; + } + } + break; + } } e->type.flags |= TYPE_FLAG_RESOLVED; return true; @@ -308,7 +308,8 @@ typedef enum { EXPR_CALL, EXPR_BLOCK, EXPR_TUPLE, - EXPR_DIRECT + EXPR_DIRECT, + EXPR_SLICE } ExprKind; typedef enum { @@ -390,6 +391,15 @@ typedef struct { } c; } NewExpr; +typedef struct { + struct Expression *of; + struct Expression *from; + struct Expression *to; + struct { + IdentID id; + } c; +} SliceExpr; + #define EXPR_FLAG_FOUND_TYPE 0x01 typedef struct Expression { @@ -424,6 +434,7 @@ typedef struct Expression { WhileExpr while_; FnExpr fn; CastExpr cast; + SliceExpr slice; struct { Block block; IdentID block_ret_id; |