summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-11-01 15:01:38 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-11-01 15:01:38 -0400
commit7f84a8f28c3d0f8d99d2d88373ee7c1595266d2d (patch)
treeb09d15501e88fa925537423f0cb983eaa3438045
parentbedd8ae2b1fead877438feb85ff57df3da21fb2b (diff)
arr/slice length with .len!
-rw-r--r--cgen.c33
-rw-r--r--eval.c31
-rw-r--r--main.c2
-rw-r--r--parse.c15
-rw-r--r--test.toc46
-rw-r--r--types.c59
-rw-r--r--types.h5
7 files changed, 152 insertions, 39 deletions
diff --git a/cgen.c b/cgen.c
index be35274..c28342f 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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, "};");
diff --git a/eval.c b/eval.c
index c7a6f43..b9797b3 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
diff --git a/main.c b/main.c
index 557d389..f2648de 100644
--- a/main.c
+++ b/main.c
@@ -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)
diff --git a/parse.c b/parse.c
index 6ea1362..4d38609 100644
--- a/parse.c
+++ b/parse.c
@@ -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! */
diff --git a/test.toc b/test.toc
index 08989ed..98c4b01 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
+};
diff --git a/types.c b/types.c
index 5f44db2..9cb10b7 100644
--- a/types.c
+++ b/types.c
@@ -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);
diff --git a/types.h b/types.h
index 388727c..d1c5bf5 100644
--- a/types.h
+++ b/types.h
@@ -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 {