aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast.c1
-rw-r--r--ast.h4
-rw-r--r--compile.c21
-rw-r--r--parse.c9
-rw-r--r--typecheck.c1
5 files changed, 34 insertions, 2 deletions
diff --git a/ast.c b/ast.c
index 37ce837b..753066cf 100644
--- a/ast.c
+++ b/ast.c
@@ -94,6 +94,7 @@ CORD ast_to_cord(ast_t *ast)
T(Assign, "(targets=%r, values=%r)", ast_list_to_cord(data.targets), ast_list_to_cord(data.values))
T(BinaryOp, "(%r, %s, %r)", ast_to_cord(data.lhs), OP_NAMES[data.op], ast_to_cord(data.rhs))
T(UpdateAssign, "(%r, %s, %r)", ast_to_cord(data.lhs), OP_NAMES[data.op], ast_to_cord(data.rhs))
+ T(Length, "(%r)", ast_to_cord(data.value))
T(Negative, "(%r)", ast_to_cord(data.value))
T(Not, "(%r)", ast_to_cord(data.value))
T(HeapAllocate, "(%r)", ast_to_cord(data.value))
diff --git a/ast.h b/ast.h
index ab88aec5..4db7b38a 100644
--- a/ast.h
+++ b/ast.h
@@ -88,7 +88,7 @@ typedef enum {
StringLiteral, StringJoin,
Declare, Assign,
BinaryOp, UpdateAssign,
- Not, Negative, HeapAllocate, StackReference,
+ Length, Not, Negative, HeapAllocate, StackReference,
Min, Max,
Array, Table, TableEntry,
FunctionDef, Lambda,
@@ -150,7 +150,7 @@ struct ast_s {
} BinaryOp, UpdateAssign;
struct {
ast_t *value;
- } Not, Negative, HeapAllocate, StackReference;
+ } Length, Not, Negative, HeapAllocate, StackReference;
struct {
ast_t *lhs, *rhs, *key;
} Min, Max;
diff --git a/compile.c b/compile.c
index 665c6469..b41040fb 100644
--- a/compile.c
+++ b/compile.c
@@ -75,6 +75,27 @@ CORD compile(env_t *env, ast_t *ast)
char *buf = asprintfa(Match(ast, Num)->bits == 64 ? "%a" : "%af", Match(ast, Num)->n);
return CORD_from_char_star(buf);
}
+ case Length: {
+ ast_t *expr = Match(ast, Length)->value;
+ CORD code = compile(env, expr);
+ type_t *t = get_type(env, expr);
+ next_value:;
+ switch (t->tag) {
+ case PointerType: {
+ auto ptr = Match(t, PointerType);
+ if (ptr->is_optional)
+ code_err(ast, "You can't dereference this value, since it's not guaranteed to be non-null");
+ code = CORD_all("*(", code, ")");
+ t = ptr->pointed;
+ goto next_value;
+ }
+ case StringType: return CORD_all("CORD_len(", code, ")");
+ case ArrayType: return CORD_all("I64((", code, ").length)");
+ case TableType: return CORD_all("I64((", code, ").entries.length)");
+ default: code_err(ast, "Length is only supported for strings, arrays, and tables, not: %T", t);
+ }
+ break;
+ }
case Not: return CORD_asprintf("not(%r)", compile(env, Match(ast, Not)->value));
case Negative: return CORD_asprintf("-(%r)", compile(env, Match(ast, Negative)->value));
case HeapAllocate: return CORD_asprintf("$heap(%r)", compile(env, Match(ast, HeapAllocate)->value));
diff --git a/parse.c b/parse.c
index 571f5676..5c9520ea 100644
--- a/parse.c
+++ b/parse.c
@@ -839,6 +839,14 @@ PARSER(parse_while) {
return NewAST(ctx->file, start, pos, While, .condition=condition, .body=body);
}
+PARSER(parse_length) {
+ const char *start = pos;
+ if (!match(&pos, "#")) return NULL;
+ spaces(&pos);
+ ast_t *val = expect(ctx, start, &pos, parse_expr, "I expected an expression for this '#'");
+ return NewAST(ctx->file, start, pos, Length, .value=val);
+}
+
PARSER(parse_heap_alloc) {
const char *start = pos;
if (!match(&pos, "@")) return NULL;
@@ -1070,6 +1078,7 @@ PARSER(parse_term_no_suffix) {
|| (term=parse_nil(ctx, pos))
|| (term=parse_num(ctx, pos))
|| (term=parse_int(ctx, pos))
+ || (term=parse_length(ctx, pos))
|| (term=parse_negative(ctx, pos))
|| (term=parse_heap_alloc(ctx, pos))
|| (term=parse_stack_reference(ctx, pos))
diff --git a/typecheck.c b/typecheck.c
index ba72b74a..6f86f891 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -368,6 +368,7 @@ type_t *get_type(env_t *env, ast_t *ast)
return Type(AbortType);
}
case Pass: return Type(VoidType);
+ case Length: return Type(IntType, .bits=64);
case Negative: {
type_t *t = get_type(env, Match(ast, Negative)->value);
if (t->tag == IntType || t->tag == NumType)