From eb87eb1987857e4eee9889ec4f0595e2c98ebc75 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 5 Dec 2022 15:42:24 +0100 Subject: [PATCH] Allow an expression list be an lvalue if the last value is an lvalue. Fix indexing from back for [] overloads. --- lib/std/list.c3 | 28 ++++++++++++++-------------- src/compiler/compiler_internal.h | 3 ++- src/compiler/expr.c | 20 ++++++++++++++++++++ src/compiler/sema_expr.c | 31 ++++++++++++++++++++++++++++++- src/version.h | 2 +- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/lib/std/list.c3 b/lib/std/list.c3 index f139f8087..a3f38d972 100644 --- a/lib/std/list.c3 +++ b/lib/std/list.c3 @@ -36,7 +36,7 @@ fn void List.tinit(List* list, usz initial_capacity = 16) list.init(initial_capacity, mem::temp_allocator()) @inline; } -fn void List.push(List *list, Type element) @inline +fn void List.push(List* list, Type element) @inline { list.append(element); } @@ -58,14 +58,14 @@ fn Type List.pop(List* list) /** * @require list.size > 0 */ -fn Type List.pop_first(List *list) +fn Type List.pop_first(List* list) { Type value = list.entries[0]; list.remove_at(0); return value; } -fn void List.remove_at(List *list, usz index) +fn void List.remove_at(List* list, usz index) { for (usz i = index + 1; i < list.size; i++) { @@ -74,7 +74,7 @@ fn void List.remove_at(List *list, usz index) list.size--; } -fn void List.push_front(List *list, Type type) @inline +fn void List.push_front(List* list, Type type) @inline { list.insert_at(0, type); } @@ -95,37 +95,37 @@ fn void List.remove_last(List* list) list.size--; } -fn void List.remove_first(List *list) +fn void List.remove_first(List* list) { list.remove_at(0); } -fn Type* List.first(List *list) +fn Type* List.first(List* list) { return list.size ? &list.entries[0] : null; } -fn Type* List.last(List *list) +fn Type* List.last(List* list) { return list.size ? &list.entries[list.size - 1] : null; } -fn bool List.is_empty(List *list) +fn bool List.is_empty(List* list) { return !list.size; } -fn usz List.len(List *list) @operator(len) +fn usz List.len(List* list) @operator(len) { return list.size; } -fn Type List.get(List *list, usz index) +fn Type List.get(List* list, usz index) { return list.entries[index]; } -fn void List.free(List *list) +fn void List.free(List* list) { if (!list.allocator) return; list.allocator.free_aligned(list.entries)!!; @@ -134,7 +134,7 @@ fn void List.free(List *list) list.entries = null; } -fn void List.swap(List *list, usz i, usz j) +fn void List.swap(List* list, usz i, usz j) { @swap(list.entries[i], list.entries[j]); } @@ -142,7 +142,7 @@ fn void List.swap(List *list, usz i, usz j) /** * Reserve at least min_capacity **/ -fn void List.reserve(List *list, usz min_capacity) +fn void List.reserve(List* list, usz min_capacity) { if (!min_capacity) return; if (list.capacity >= min_capacity) return; @@ -163,7 +163,7 @@ macro Type* List.@item_ref(List &list, usz index) @operator(&[]) } -private fn void List.ensure_capacity(List *list) @inline +private fn void List.ensure_capacity(List* list) @inline { if (list.capacity == list.size) { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 8cb7bcf96..05a470a38 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2137,6 +2137,8 @@ void expr_rewrite_to_builtin_access(Expr *expr, Expr *parent, BuiltinAccessKind void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string); void expr_rewrite_to_const_zero(Expr *expr, Type *type); bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index); +void expr_rewrite_to_variable(Expr *expr, Decl *decl); +void expr_rewrite_to_binary(Expr *expr_to_rewrite, Expr *left, Expr *right, BinaryOp op); bool expr_const_in_range(const ExprConst *left, const ExprConst *right, const ExprConst *right_to); bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op); @@ -3050,7 +3052,6 @@ INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type) expr->resolve_status = RESOLVE_DONE; } - INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v, bool narrowable) { expr->expr_kind = EXPR_CONST; diff --git a/src/compiler/expr.c b/src/compiler/expr.c index fcea7fa52..7d61e90fc 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -883,6 +883,20 @@ Expr *expr_variable(Decl *decl) return expr; } +void expr_rewrite_to_variable(Expr *expr, Decl *decl) +{ + expr->expr_kind = EXPR_IDENTIFIER; + if (decl->resolve_status == RESOLVE_DONE) + { + expr->identifier_expr.decl = decl; + expr->resolve_status = RESOLVE_DONE; + expr->type = decl->type; + return; + } + expr->identifier_expr.ident = decl->name; + expr->resolve_status = RESOLVE_NOT_DONE; +} + void expr_rewrite_insert_deref(Expr *original) { // Assume *(&x) => x @@ -921,3 +935,9 @@ void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string) expr_to_rewrite->resolve_status = RESOLVE_DONE; expr_to_rewrite->type = type_get_ptr(type_get_array(type_char, len)); } + +void expr_rewrite_to_binary(Expr *expr_to_rewrite, Expr *left, Expr *right, BinaryOp op) +{ + expr_to_rewrite->binary_expr = (ExprBinary) { .operator = op, .left = exprid(left), .right = exprid(right) }; + expr_to_rewrite->expr_kind = EXPR_BINARY; +} diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 18a23c922..d7b09f7a7 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -426,6 +426,9 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr) case EXPR_HASH_IDENT: SEMA_ERROR(top_expr, "You cannot assign to an unevaluated expression."); return false; + case EXPR_EXPRESSION_LIST: + if (!vec_size(expr->expression_list)) return false; + return sema_binary_is_expr_lvalue(top_expr, VECLAST(expr->expression_list)); case EXPR_POISONED: case EXPR_ARGV_TO_SUBARRAY: case EXPR_ASM: @@ -448,7 +451,6 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr) case EXPR_DECL: case EXPR_DESIGNATED_INITIALIZER_LIST: case EXPR_DESIGNATOR: - case EXPR_EXPRESSION_LIST: case EXPR_EXPR_BLOCK: case EXPR_FAILABLE: case EXPR_FLATPATH: @@ -2386,6 +2388,33 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } if (overload) { + if (start_from_end) + { + Decl *len = sema_find_operator(context, current_expr, OVERLOAD_LEN); + if (!len) + { + SEMA_ERROR(subscripted, "Cannot index '%s' from the end, since there is no 'len' overload.", type_to_error_string(subscripted->type)); + return false; + } + if (!sema_analyse_expr(context, current_expr)) return false; + Decl *temp = decl_new_generated_var(current_expr->type, VARDECL_PARAM, current_expr->span); + Expr *decl = expr_generate_decl(temp, expr_copy(current_expr)); + current_expr->expr_kind = EXPR_EXPRESSION_LIST; + current_expr->expression_list = NULL; + vec_add(current_expr->expression_list, decl); + vec_add(current_expr->expression_list, expr_variable(temp)); + if (!sema_analyse_expr(context, current_expr)) return false; + Expr *var_for_len = expr_variable(temp); + Expr *len_expr = expr_new(EXPR_CALL, expr->span); + if (!sema_insert_method_call(context, len_expr, len, var_for_len, NULL)) return false; + if (!sema_analyse_expr(context, len_expr)) return false; + Expr *index_copy = expr_copy(index); + if (!sema_analyse_expr(context, index_copy)) return false; + if (!cast(index_copy, len_expr->type)) return false; + expr_rewrite_to_binary(index, len_expr, index_copy, BINARYOP_SUB); + index->resolve_status = RESOLVE_NOT_DONE; + if (!sema_analyse_expr(context, index)) return false; + } if (eval_type == SUBSCRIPT_EVAL_ASSIGN) { expr->expr_kind = EXPR_SUBSCRIPT_ASSIGN; diff --git a/src/version.h b/src/version.h index 2178fbbc1..3c5126f2f 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.104" \ No newline at end of file +#define COMPILER_VERSION "0.3.105" \ No newline at end of file