From eabff011ea552a4fecc13de129e0a205b77bc289 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 18 Feb 2024 01:27:25 -0500 Subject: [PATCH] Add in '#' operator for length --- ast.c | 1 + ast.h | 4 ++-- compile.c | 21 +++++++++++++++++++++ parse.c | 9 +++++++++ typecheck.c | 1 + 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ast.c b/ast.c index 37ce837..753066c 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 ab88aec..4db7b38 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 665c646..b41040f 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 571f567..5c9520e 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 ba72b74..6f86f89 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)