diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5bf3e45a1..d8081cc14 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -311,8 +311,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->value = exact_value_string(result); } else if (name == "load_or") { - if (ce->args.count != 1) { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + if (ce->args.count != 2) { + error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count); return false; } @@ -320,13 +320,28 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Operand o = {}; check_expr(c, &o, arg); if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); + error(arg, "'#load_or' expected a constant string argument"); return false; } if (!is_type_string(o.type)) { gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); + error(arg, "'#load_or' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + Ast *default_arg = ce->args[1]; + Operand default_op = {}; + check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice); + if (default_op.mode != Addressing_Constant) { + error(arg, "'#load_or' expected a constant '[]byte' argument"); + return false; + } + + if (!are_types_identical(base_type(default_op.type), t_u8_slice)) { + gbString str = type_to_string(default_op.type); + error(arg, "'#load_or' expected a constant '[]byte', got %s", str); gb_string_free(str); return false; } @@ -350,36 +365,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 gbFile f = {}; gbFileError file_err = gb_file_open(&f, c_str); defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - + operand->type = t_u8_slice; operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); + if (file_err == gbFileError_None) { + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->value = exact_value_string(result); + } else { + operand->value = default_op.value; + } } else if (name == "assert") { if (ce->args.count != 1) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 08be7b7bc..13643b283 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5865,7 +5865,15 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, proc); String name = bd->name.string; - if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "config" || name == "load") { + if ( + name == "location" || + name == "assert" || + name == "panic" || + name == "defined" || + name == "config" || + name == "load" || + name == "load_or" + ) { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; operand->expr = proc; @@ -6619,10 +6627,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type o->type = t_source_code_location; o->mode = Addressing_Value; } else if ( - name == "load" || name == "assert" || name == "defined" || - name == "config" + name == "config" || + name == "load" || + name == "load_or" ) { error(node, "'#%.*s' must be used as a call", LIT(name)); o->type = t_invalid;