aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2022-02-17 23:15:38 +0000
committerGitHub <noreply@github.com>2022-02-17 23:15:38 +0000
commit8f13724a4b9782d7ac8e6a8037d0a44cfd41e240 (patch)
treeaed1e727a6c53cc6704f927fe118f740bbdf4a29 /src
parent89b7a3f7ac1388ea9e8752f9445843aa58b157be (diff)
parent746d5fc322a410625435fd05bb847481919a918f (diff)
Merge pull request #1504 from odin-lang/directx-packages
DirectX Package Support
Diffstat (limited to 'src')
-rw-r--r--src/check_builtin.cpp49
-rw-r--r--src/check_expr.cpp3
-rw-r--r--src/check_type.cpp18
-rw-r--r--src/checker_builtin_procs.hpp6
-rw-r--r--src/entity.cpp5
-rw-r--r--src/llvm_backend_proc.cpp71
-rw-r--r--src/parser.cpp4
-rw-r--r--src/parser.hpp3
-rw-r--r--src/types.cpp12
9 files changed, 145 insertions, 26 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index c7ada8e03..1535f6644 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -223,31 +223,28 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
map_set(&c->info->objc_msgSend_types, call, data);
mutex_unlock(&c->info->objc_types_mutex);
- add_package_dependency(c, "runtime", "objc_lookUpClass");
- add_package_dependency(c, "runtime", "sel_registerName");
- add_package_dependency(c, "runtime", "objc_allocateClassPair");
-
add_package_dependency(c, "runtime", "objc_msgSend");
add_package_dependency(c, "runtime", "objc_msgSend_fpret");
add_package_dependency(c, "runtime", "objc_msgSend_fp2ret");
add_package_dependency(c, "runtime", "objc_msgSend_stret");
}
+bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
+ Operand op = {};
+ check_expr(c, &op, expr);
+ if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
+ if (name_) *name_ = op.value.value_string;
+ return true;
+ }
+ gbString e = expr_to_string(op.expr);
+ gbString t = type_to_string(op.type);
+ error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
+ gb_string_free(t);
+ gb_string_free(e);
+ return false;
+}
+
bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
- auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool {
- Operand op = {};
- check_expr(c, &op, expr);
- if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
- if (name_) *name_ = op.value.value_string;
- return true;
- }
- gbString e = expr_to_string(op.expr);
- gbString t = type_to_string(op.type);
- error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
- gb_string_free(t);
- gb_string_free(e);
- return false;
- };
String builtin_name = builtin_procs[id].name;
if (build_context.metrics.os != TargetOs_darwin) {
@@ -371,6 +368,10 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
}
operand->mode = Addressing_Value;
+
+ add_package_dependency(c, "runtime", "objc_lookUpClass");
+ add_package_dependency(c, "runtime", "sel_registerName");
+ add_package_dependency(c, "runtime", "objc_allocateClassPair");
return true;
} break;
}
@@ -4086,6 +4087,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
+ case BuiltinProc_constant_utf16_cstring:
+ {
+ String value = {};
+ if (!is_constant_string(c, builtin_name, ce->args[0], &value)) {
+ return false;
+ }
+ operand->mode = Addressing_Value;
+ operand->type = alloc_type_multi_pointer(t_u16);
+ operand->value = {};
+ break;
+ }
+
}
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 7fb0e44f2..884f1bb9f 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -9774,6 +9774,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
if (f->flags&FieldFlag_const) {
str = gb_string_appendc(str, "#const ");
}
+ if (f->flags&FieldFlag_subtype) {
+ str = gb_string_appendc(str, "#subtype ");
+ }
for_array(i, f->names) {
Ast *name = f->names[i];
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 976bb7f42..64fb67723 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -144,6 +144,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
}
bool is_using = (p->flags&FieldFlag_using) != 0;
+ bool is_subtype = (p->flags&FieldFlag_subtype) != 0;
for_array(j, p->names) {
Ast *name = p->names[j];
@@ -158,6 +159,9 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
add_entity(ctx, ctx->scope, name, field);
field->Variable.field_group_index = field_group_index;
+ if (is_subtype) {
+ field->flags |= EntityFlag_Subtype;
+ }
if (j == 0) {
field->Variable.docs = docs;
@@ -194,6 +198,20 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
populate_using_entity_scope(ctx, node, p, type);
}
+
+ if (is_subtype && p->names.count > 0) {
+ Type *first_type = fields_array[fields_array.count-1]->type;
+ Type *t = base_type(type_deref(first_type));
+
+ if (!does_field_type_allow_using(t) &&
+ p->names.count >= 1 &&
+ p->names[0]->kind == Ast_Ident) {
+ Token name_token = p->names[0]->Ident.token;
+ gbString type_str = type_to_string(first_type);
+ error(name_token, "'subtype' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
+ gb_string_free(type_str);
+ }
+ }
}
*fields = slice_from_array(fields_array);
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 19fa94ee6..cba952ddf 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -258,6 +258,9 @@ BuiltinProc__type_end,
BuiltinProc_objc_register_selector,
BuiltinProc_objc_register_class,
+ BuiltinProc_constant_utf16_cstring,
+
+
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -517,4 +520,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
+ {STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
};
diff --git a/src/entity.cpp b/src/entity.cpp
index df8ee3faa..f5720293f 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -74,6 +74,7 @@ enum EntityFlag : u64 {
EntityFlag_Test = 1ull<<30,
EntityFlag_Init = 1ull<<31,
+ EntityFlag_Subtype = 1ull<<32,
EntityFlag_CustomLinkName = 1ull<<40,
EntityFlag_CustomLinkage_Internal = 1ull<<41,
@@ -86,6 +87,10 @@ enum EntityFlag : u64 {
EntityFlag_Overridden = 1ull<<63,
};
+enum : u64 {
+ EntityFlags_IsSubtype = EntityFlag_Using|EntityFlag_Subtype,
+};
+
enum EntityState : u32 {
EntityState_Unresolved = 0,
EntityState_InProgress = 1,
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 261e2819c..7bc7fb61f 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -2122,6 +2122,77 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr);
case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr);
case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr);
+
+
+ case BuiltinProc_constant_utf16_cstring:
+ {
+ auto const encode_surrogate_pair = [](Rune r, u16 *r1, u16 *r2) {
+ if (r < 0x10000 || r > 0x10ffff) {
+ *r1 = 0xfffd;
+ *r2 = 0xfffd;
+ } else {
+ r -= 0x10000;
+ *r1 = 0xd800 + ((r>>10)&0x3ff);
+ *r2 = 0xdc00 + (r&0x3ff);
+ }
+ };
+
+ lbModule *m = p->module;
+
+ auto tav = type_and_value_of_expr(ce->args[0]);
+ GB_ASSERT(tav.value.kind == ExactValue_String);
+ String value = tav.value.value_string;
+
+ LLVMTypeRef llvm_u16 = lb_type(m, t_u16);
+
+ isize max_len = value.len*2 + 1;
+ LLVMValueRef *buffer = gb_alloc_array(temporary_allocator(), LLVMValueRef, max_len);
+ isize n = 0;
+ while (value.len > 0) {
+ Rune r = 0;
+ isize w = gb_utf8_decode(value.text, value.len, &r);
+ value.text += w;
+ value.len -= w;
+ if ((0 <= r && r < 0xd800) || (0xe000 <= r && r < 0x10000)) {
+ buffer[n++] = LLVMConstInt(llvm_u16, cast(u16)r, false);
+ } else if (0x10000 <= r && r <= 0x10ffff) {
+ u16 r1, r2;
+ encode_surrogate_pair(r, &r1, &r2);
+ buffer[n++] = LLVMConstInt(llvm_u16, r1, false);
+ buffer[n++] = LLVMConstInt(llvm_u16, r2, false);
+ } else {
+ buffer[n++] = LLVMConstInt(llvm_u16, 0xfffd, false);
+ }
+ }
+
+ buffer[n++] = LLVMConstInt(llvm_u16, 0, false);
+
+ LLVMValueRef array = LLVMConstArray(llvm_u16, buffer, cast(unsigned int)n);
+
+ 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;
+ }
+ LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name);
+ LLVMSetInitializer(global_data, array);
+ LLVMSetLinkage(global_data, LLVMInternalLinkage);
+
+
+
+ LLVMValueRef indices[] = {
+ LLVMConstInt(lb_type(m, t_u32), 0, false),
+ LLVMConstInt(lb_type(m, t_u32), 0, false),
+ };
+ lbValue res = {};
+ res.type = tv.type;
+ res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), "");
+ return res;
+
+ }
}
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
diff --git a/src/parser.cpp b/src/parser.cpp
index bd0e55b7f..7309d9769 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -3510,12 +3510,13 @@ enum FieldPrefixKind : i32 {
FieldPrefix_Unknown = -1,
FieldPrefix_Invalid = 0,
- FieldPrefix_using,
+ FieldPrefix_using, // implies #subtype
FieldPrefix_const,
FieldPrefix_no_alias,
FieldPrefix_c_vararg,
FieldPrefix_auto_cast,
FieldPrefix_any_int,
+ FieldPrefix_subtype, // does not imply `using` semantics
};
struct ParseFieldPrefixMapping {
@@ -3532,6 +3533,7 @@ gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = {
{str_lit("c_vararg"), Token_Hash, FieldPrefix_c_vararg, FieldFlag_c_vararg},
{str_lit("const"), Token_Hash, FieldPrefix_const, FieldFlag_const},
{str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int},
+ {str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype},
};
diff --git a/src/parser.hpp b/src/parser.hpp
index 9e93f4b26..83c755553 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -300,6 +300,7 @@ enum FieldFlag : u32 {
FieldFlag_auto_cast = 1<<4,
FieldFlag_const = 1<<5,
FieldFlag_any_int = 1<<6,
+ FieldFlag_subtype = 1<<7,
// Internal use by the parser only
FieldFlag_Tags = 1<<10,
@@ -307,7 +308,7 @@ enum FieldFlag : u32 {
// Parameter List Restrictions
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int,
- FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
+ FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
};
enum StmtAllowFlag {
diff --git a/src/types.cpp b/src/types.cpp
index 78958146b..2c1e6162f 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -2334,7 +2334,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
GB_ASSERT(is_type_struct(src) || is_type_union(src));
for_array(i, src->Struct.fields) {
Entity *f = src->Struct.fields[i];
- if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) {
+ if (f->kind == Entity_Variable && f->flags & EntityFlags_IsSubtype) {
if (are_types_identical(dst, f->type)) {
return f->token.string;
}
@@ -2343,7 +2343,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
return f->token.string;
}
}
- if (is_type_struct(f->type)) {
+ if ((f->flags & EntityFlag_Using) != 0 && is_type_struct(f->type)) {
String name = lookup_subtype_polymorphic_field(dst, f->type);
if (name.len > 0) {
return name;
@@ -2489,9 +2489,9 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) {
if (xf->token.string != yf->token.string) {
return false;
}
- bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
- bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
- if (xf_is_using ^ yf_is_using) {
+ u64 xf_flags = (xf->flags&EntityFlags_IsSubtype);
+ u64 yf_flags = (yf->flags&EntityFlags_IsSubtype);
+ if (xf_flags != yf_flags) {
return false;
}
}
@@ -3813,7 +3813,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0
for_array(i, src->Struct.fields) {
Entity *f = src->Struct.fields[i];
- if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
+ if (f->kind != Entity_Variable || (f->flags&EntityFlags_IsSubtype) == 0) {
continue;
}