From 38102f14c19f83ef1e0c13a824448bab4e80877e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:01:54 +0100 Subject: Add `#load(path) or_else default` in favour of `#load_or(path, default)` --- src/check_expr.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f6c94466b..ae459574c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -121,6 +121,28 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na bool is_diverging_expr(Ast *expr); + +enum LoadDirectiveResult { + LoadDirective_Success = 0, + LoadDirective_Error = 1, + LoadDirective_NotFound = 2, +}; + +bool is_load_directive_call(Ast *call) { + call = unparen_expr(call); + if (call->kind != Ast_CallExpr) { + return false; + } + ast_node(ce, CallExpr, call); + if (ce->proc->kind != Ast_BasicDirective) { + return false; + } + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + return name == "load"; +} +LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found); + void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); if (results.count != 0) { @@ -7407,9 +7429,54 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type String name = oe->token.string; Ast *arg = oe->x; Ast *default_value = oe->y; - Operand x = {}; Operand y = {}; + + // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default + if (is_load_directive_call(arg)) { + LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); + if (res == LoadDirective_Success) { + *o = x; + return Expr_Expr; + } + + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); + y.mode = Addressing_Invalid; + break; + } + + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } + + if (!y_is_diverging) { + check_assignment(c, &y, x.type, name); + } + + o->mode = y.mode; + o->type = y.type; + o->expr = node; + + return Expr_Expr; + } + check_multi_expr_with_type_hint(c, &x, arg, type_hint); if (x.mode == Addressing_Invalid) { o->mode = Addressing_Value; @@ -7417,7 +7484,6 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type o->expr = node; return Expr_Expr; } - bool y_is_diverging = false; check_expr_base(c, &y, default_value, x.type); switch (y.mode) { -- cgit v1.2.3 From 70dc0c15fd244bdc4a769b0d91b50ecc210bca65 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:43:35 +0100 Subject: Improve type hint for #load to allow for string types --- src/check_builtin.cpp | 8 ++++++-- src/check_expr.cpp | 14 ++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b0c7f8d4b..122d3a461 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1196,10 +1196,14 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As GB_ASSERT(o.value.kind == ExactValue_String); + operand->type = t_u8_slice; + if (type_hint && is_type_string(type_hint)) { + operand->type = type_hint; + } + operand->mode = Addressing_Constant; + LoadFileCache *cache = nullptr; if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) { - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; operand->value = exact_value_string(cache->data); return LoadDirective_Success; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ae459574c..076eaba73 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7435,10 +7435,6 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default if (is_load_directive_call(arg)) { LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); - if (res == LoadDirective_Success) { - *o = x; - return Expr_Expr; - } bool y_is_diverging = false; check_expr_base(c, &y, default_value, x.type); @@ -7468,10 +7464,16 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type if (!y_is_diverging) { check_assignment(c, &y, x.type, name); + if (y.mode != Addressing_Constant) { + error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + } } - o->mode = y.mode; - o->type = y.type; + if (res == LoadDirective_Success) { + *o = x; + } else { + *o = y; + } o->expr = node; return Expr_Expr; -- cgit v1.2.3 From cecadce86d8070ee31d193736d331926efec0fff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 14:42:29 +0100 Subject: Allow for chaining of '#load(path) or_else #load(path)' --- src/check_builtin.cpp | 56 ++++++++++++++++++++++++++------------------------- src/check_expr.cpp | 55 ++++++++++++++++++++++++++------------------------ 2 files changed, 58 insertions(+), 53 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 36c9ea001..687f1694b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1163,6 +1163,27 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi } +bool is_valid_type_for_load(Type *type) { + if (type == t_invalid) { + return false; + } else if (is_type_string(type)) { + return true; + } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { + Type *elem = nullptr; + Type *bt = base_type(type); + if (bt->kind == Type_Slice) { + elem = bt->Slice.elem; + } else if (bt->kind == Type_Array) { + elem = bt->Array.elem; + } else if (bt->kind == Type_EnumeratedArray) { + elem = bt->EnumeratedArray.elem; + } + GB_ASSERT(elem != nullptr); + return is_type_load_safe(elem); + } + return false; +} + LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); @@ -1198,42 +1219,23 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As operand->type = t_u8_slice; if (ce->args.count == 1) { - if (type_hint && is_type_string(type_hint)) { + if (type_hint && is_valid_type_for_load(type_hint)) { operand->type = type_hint; } } else if (ce->args.count == 2) { - bool failed = false; Ast *arg_type = ce->args[1]; Type *type = check_type(c, arg_type); - if (type != nullptr && type != t_invalid) { - if (is_type_string(type)) { + if (type != nullptr) { + if (is_valid_type_for_load(type)) { operand->type = type; - } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { - Type *elem = nullptr; - Type *bt = base_type(type); - if (bt->kind == Type_Slice) { - elem = bt->Slice.elem; - } else if (bt->kind == Type_Array) { - elem = bt->Array.elem; - } else if (bt->kind == Type_EnumeratedArray) { - elem = bt->EnumeratedArray.elem; - } - GB_ASSERT(elem != nullptr); - if (is_type_load_safe(elem)) { - operand->type = type; - } else { - failed = true; - } } else { - failed = true; + gbString type_str = type_to_string(type); + error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); + gb_string_free(type_str); } } - - if (failed) { - gbString type_str = type_to_string(type); - error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); - gb_string_free(type_str); - } + } else { + GB_PANIC("unreachable"); } operand->mode = Addressing_Constant; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 076eaba73..310874139 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7436,36 +7436,39 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type if (is_load_directive_call(arg)) { LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); - bool y_is_diverging = false; - check_expr_base(c, &y, default_value, x.type); - switch (y.mode) { - case Addressing_NoValue: - if (is_diverging_expr(y.expr)) { - // Allow - y.mode = Addressing_Value; - y_is_diverging = true; - } else { - error_operand_no_value(&y); + // Allow for chaining of '#load(path) or_else #load(path)' + if (!(is_load_directive_call(default_value) && res == LoadDirective_Success)) { + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); y.mode = Addressing_Invalid; + break; } - break; - case Addressing_Type: - error_operand_not_expression(&y); - y.mode = Addressing_Invalid; - break; - } - if (y.mode == Addressing_Invalid) { - o->mode = Addressing_Value; - o->type = t_invalid; - o->expr = node; - return Expr_Expr; - } + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } - if (!y_is_diverging) { - check_assignment(c, &y, x.type, name); - if (y.mode != Addressing_Constant) { - error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + if (!y_is_diverging) { + check_assignment(c, &y, x.type, name); + if (y.mode != Addressing_Constant) { + error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + } } } -- cgit v1.2.3