summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c55
-rw-r--r--decls_cgen.c5
-rw-r--r--eval.c103
-rw-r--r--main.c3
-rw-r--r--out.c29
-rw-r--r--parse.c82
-rw-r--r--test.toc28
-rw-r--r--types.c32
-rw-r--r--types.h13
9 files changed, 267 insertions, 83 deletions
diff --git a/cgen.c b/cgen.c
index 23e2e85..1fb0166 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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++;
diff --git a/eval.c b/eval.c
index 39eaf8a..aa17e5b 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
}
diff --git a/main.c b/main.c
index 75ac654..041eaf7 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/out.c b/out.c
index c1c1926..a4dc39f 100644
--- a/out.c
+++ b/out.c
@@ -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])));
}
diff --git a/parse.c b/parse.c
index 115883f..22473bc 100644
--- a/parse.c
+++ b/parse.c
@@ -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, ":");
diff --git a/test.toc b/test.toc
index b085a77..404b85f 100644
--- a/test.toc
+++ b/test.toc
@@ -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]);
};
diff --git a/types.c b/types.c
index 3e6d871..c96f5e6 100644
--- a/types.c
+++ b/types.c
@@ -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;
diff --git a/types.h b/types.h
index a73cfa9..f684c18 100644
--- a/types.h
+++ b/types.h
@@ -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;