mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-17 19:32:23 -07:00
#load(path, type)
where `type` can be `string` or `[]T` where `T` is a simple type
This commit is contained in:
+42
-7
@@ -1169,11 +1169,11 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
|
||||
String name = bd->name.string;
|
||||
GB_ASSERT(name == "load");
|
||||
|
||||
if (ce->args.count != 1) {
|
||||
if (ce->args.count != 1 && ce->args.count != 2) {
|
||||
if (ce->args.count == 0) {
|
||||
error(ce->close, "'#load' expects 1 argument, got 0");
|
||||
error(ce->close, "'#%.*s' expects 1 or 2 arguments, got 0", LIT(name));
|
||||
} else {
|
||||
error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count);
|
||||
error(ce->args[0], "'#%.*s' expects 1 or 2 arguments, got %td", LIT(name), ce->args.count);
|
||||
}
|
||||
|
||||
return LoadDirective_Error;
|
||||
@@ -1183,13 +1183,13 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
|
||||
Operand o = {};
|
||||
check_expr(c, &o, arg);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
error(arg, "'#load' expected a constant string argument");
|
||||
error(arg, "'#%.*s' expected a constant string argument", LIT(name));
|
||||
return LoadDirective_Error;
|
||||
}
|
||||
|
||||
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, "'#%.*s' expected a constant string, got %s", LIT(name), str);
|
||||
gb_string_free(str);
|
||||
return LoadDirective_Error;
|
||||
}
|
||||
@@ -1197,8 +1197,43 @@ 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;
|
||||
if (ce->args.count == 1) {
|
||||
if (type_hint && is_type_string(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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
operand->mode = Addressing_Constant;
|
||||
|
||||
|
||||
@@ -391,8 +391,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
|
||||
|
||||
if (is_type_slice(type)) {
|
||||
if (value.kind == ExactValue_String) {
|
||||
GB_ASSERT(is_type_u8_slice(type));
|
||||
res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value;
|
||||
GB_ASSERT(is_type_slice(type));
|
||||
res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value;
|
||||
return res;
|
||||
} else {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
|
||||
@@ -2523,8 +2523,56 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
|
||||
res.type = t_u8_slice;
|
||||
return res;
|
||||
}
|
||||
lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) {
|
||||
GB_ASSERT(is_type_slice(slice_type));
|
||||
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
|
||||
LLVMValueRef data = LLVMConstStringInContext(m->ctx,
|
||||
cast(char const *)str.text,
|
||||
cast(unsigned)str.len,
|
||||
false);
|
||||
|
||||
|
||||
char *name = nullptr;
|
||||
{
|
||||
isize max_len = 7+8+1;
|
||||
name = gb_alloc_array(permanent_allocator(), char, max_len);
|
||||
u32 id = m->gen->global_array_index.fetch_add(1);
|
||||
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
|
||||
len -= 1;
|
||||
}
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
i64 data_len = str.len;
|
||||
LLVMValueRef ptr = nullptr;
|
||||
if (data_len != 0) {
|
||||
ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
|
||||
} else {
|
||||
ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
|
||||
}
|
||||
if (!is_type_u8_slice(slice_type)) {
|
||||
Type *bt = base_type(slice_type);
|
||||
Type *elem = bt->Slice.elem;
|
||||
i64 sz = type_size_of(elem);
|
||||
GB_ASSERT(sz > 0);
|
||||
ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem)));
|
||||
data_len /= sz;
|
||||
}
|
||||
|
||||
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true);
|
||||
LLVMValueRef values[2] = {ptr, len};
|
||||
|
||||
lbValue res = {};
|
||||
res.value = llvm_const_named_struct(m, slice_type, values, 2);
|
||||
res.type = slice_type;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) {
|
||||
|
||||
@@ -2398,6 +2398,57 @@ bool is_type_simple_compare(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_type_load_safe(Type *type) {
|
||||
GB_ASSERT(type != nullptr);
|
||||
type = core_type(core_array_type(type));
|
||||
switch (type->kind) {
|
||||
case Type_Basic:
|
||||
return (type->Basic.flags & (BasicFlag_Boolean|BasicFlag_Numeric|BasicFlag_Rune)) != 0;
|
||||
|
||||
case Type_BitSet:
|
||||
if (type->BitSet.underlying) {
|
||||
return is_type_load_safe(type->BitSet.underlying);
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_RelativePointer:
|
||||
case Type_RelativeSlice:
|
||||
return true;
|
||||
|
||||
case Type_Pointer:
|
||||
case Type_MultiPointer:
|
||||
case Type_Slice:
|
||||
case Type_DynamicArray:
|
||||
case Type_Proc:
|
||||
case Type_SoaPointer:
|
||||
return false;
|
||||
|
||||
case Type_Enum:
|
||||
case Type_EnumeratedArray:
|
||||
case Type_Array:
|
||||
case Type_SimdVector:
|
||||
case Type_Matrix:
|
||||
GB_PANIC("should never be hit");
|
||||
return false;
|
||||
|
||||
case Type_Struct:
|
||||
for_array(i, type->Struct.fields) {
|
||||
if (!is_type_load_safe(type->Struct.fields[i]->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return type_size_of(type) > 0;
|
||||
case Type_Union:
|
||||
for_array(i, type->Union.variants) {
|
||||
if (!is_type_load_safe(type->Union.variants[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return type_size_of(type) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
|
||||
Type *prev_src = src;
|
||||
// Type *prev_dst = dst;
|
||||
|
||||
Reference in New Issue
Block a user