From f7d403c35849758d68e3a0ca9a9777bfce7da0b7 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 25 Feb 2024 13:04:35 -0500 Subject: WIP on stackrefs --- builtins/array.h | 18 +++++++++--------- compile.c | 10 +++++----- typecheck.c | 29 ++++++++++++++++++++++++++++- typecheck.h | 1 + 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/builtins/array.h b/builtins/array.h index 9e74c41d..59245ffe 100644 --- a/builtins/array.h +++ b/builtins/array.h @@ -8,15 +8,15 @@ #include "types.h" // Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1 -#define $Array_get(type, x, i, filename, start, end) ({ \ - const array_t *$arr = x; int64_t $index = (int64_t)(i); \ - int64_t $off = $index + ($index < 0) * ($arr->length + 1) - 1; \ - if (__builtin_expect($off < 0 || $off >= $arr->length, 0)) \ - fail_source(filename, start, end, "Invalid array index: %r (array has length %ld)\n", Int64__as_str(&$index, USE_COLOR, NULL), $arr->length); \ - *(type*)($arr->data + $arr->stride * $off);}) -#define $Array_get_unchecked(type, x, i) ({ const array_t *$arr = x; int64_t $index = (int64_t)(i); \ - int64_t $off = $index + ($index < 0) * ($arr->length + 1) - 1; \ - *(type*)($arr->data + $arr->stride * $off);}) +#define $Array_get(type, x, i, filename, start, end) *({ \ + const array_t $arr = x; int64_t $index = (int64_t)(i); \ + int64_t $off = $index + ($index < 0) * ($arr.length + 1) - 1; \ + if (__builtin_expect($off < 0 || $off >= $arr.length, 0)) \ + fail_source(filename, start, end, "Invalid array index: %r (array has length %ld)\n", Int64__as_str(&$index, USE_COLOR, NULL), $arr.length); \ + (type*)($arr.data + $arr.stride * $off);}) +#define $Array_get_unchecked(type, x, i) *({ const array_t $arr = x; int64_t $index = (int64_t)(i); \ + int64_t $off = $index + ($index < 0) * ($arr.length + 1) - 1; \ + (type*)($arr.data + $arr.stride * $off);}) #define $is_atomic(x) _Generic(x, bool: true, int8_t: true, int16_t: true, int32_t: true, int64_t: true, float: true, double: true, default: false) #define $Array(x, ...) ({ __typeof(x) $items[] = {x, __VA_ARGS__}; \ (array_t){.length=sizeof($items)/sizeof($items[0]), \ diff --git a/compile.c b/compile.c index 455f13f4..4163a202 100644 --- a/compile.c +++ b/compile.c @@ -176,10 +176,10 @@ CORD compile(env_t *env, ast_t *ast) 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)); case StackReference: { - ast_t *value = Match(ast, StackReference)->value; - if (value->tag == Var) - return CORD_cat("&", compile(env, Match(ast, StackReference)->value)); - return CORD_all("$stack(", compile(env, Match(ast, StackReference)->value), ")"); + ast_t *subject = Match(ast, StackReference)->value; + if (can_be_mutated(env, subject)) + return CORD_cat("&", compile(env, subject)); + return CORD_all("$stack(", compile(env, subject), ")"); } case BinaryOp: { auto binop = Match(ast, BinaryOp); @@ -886,7 +886,7 @@ CORD compile(env_t *env, ast_t *ast) if (index_t->tag != IntType) code_err(indexing->index, "Arrays can only be indexed by integers, not %T", index_t); type_t *item_type = Match(container_t, ArrayType)->item_type; - CORD arr = compile_to_pointer_depth(env, indexing->indexed, 1, false); + CORD arr = compile_to_pointer_depth(env, indexing->indexed, 0, false); CORD index = compile(env, indexing->index); file_t *f = indexing->index->file; if (indexing->unchecked) diff --git a/typecheck.c b/typecheck.c index ce3c9d08..a5153512 100644 --- a/typecheck.c +++ b/typecheck.c @@ -203,6 +203,7 @@ type_t *get_type(env_t *env, ast_t *ast) ast_t *value = Match(ast, StackReference)->value; type_t *pointed_t = get_type(env, Match(ast, StackReference)->value); bool is_stack = true; + bool is_readonly = !can_be_mutated(env, value); // References to heap members/indexes are heap pointers, e.g. v := @Vec{1,2}; &v.x switch (value->tag) { case FieldAccess: { @@ -217,7 +218,7 @@ type_t *get_type(env_t *env, ast_t *ast) } default: break; } - return Type(PointerType, .pointed=pointed_t, .is_stack=is_stack); + return Type(PointerType, .pointed=pointed_t, .is_stack=is_stack, .is_readonly=is_readonly); } case StringJoin: case StringLiteral: { return Type(StringType); @@ -711,4 +712,30 @@ type_t *get_arg_type(env_t *env, arg_t *arg) return get_type(env, arg->default_val); } +bool can_be_mutated(env_t *env, ast_t *ast) +{ + switch (ast->tag) { + case Var: return true; + case FieldAccess: { + auto access = Match(ast, FieldAccess); + type_t *fielded_type = get_type(env, access->fielded); + if (fielded_type->tag == PointerType) { + auto ptr = Match(fielded_type, PointerType); + return !ptr->is_readonly; + } + return can_be_mutated(env, access->fielded); + } + case Index: { + auto index = Match(ast, Index); + type_t *indexed_type = get_type(env, index->indexed); + if (indexed_type->tag == PointerType) { + auto ptr = Match(indexed_type, PointerType); + return !ptr->is_readonly; + } + return false; + } + default: return false; + } +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/typecheck.h b/typecheck.h index a44e658b..bb6ed397 100644 --- a/typecheck.h +++ b/typecheck.h @@ -17,5 +17,6 @@ type_t *get_file_type(env_t *env, const char *path); type_t *get_function_def_type(env_t *env, ast_t *ast); type_t *get_arg_type(env_t *env, arg_t *arg); type_t *get_arg_ast_type(env_t *env, arg_ast_t *arg); +bool can_be_mutated(env_t *env, ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 -- cgit v1.2.3