aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2022-08-15 10:27:53 +0100
committerGitHub <noreply@github.com>2022-08-15 10:27:53 +0100
commitd30198c99af7b3346ee6305e6306c379ddd2ffa2 (patch)
treefff75340799d1f94509f429807b5600a20eb6df0 /src/check_expr.cpp
parenta460d140fefd91c76e55f735e180bf663c48f2da (diff)
parentcecadce86d8070ee31d193736d331926efec0fff (diff)
Merge pull request #1944 from odin-lang/load-improvements
Improvements to `#load`
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp75
1 files changed, 73 insertions, 2 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index f6c94466b..310874139 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,59 @@ 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);
+
+ // 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;
+ }
+
+ 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 (res == LoadDirective_Success) {
+ *o = x;
+ } else {
+ *o = y;
+ }
+ 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 +7489,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) {