|
|
|
|
@@ -77,52 +77,10 @@ Type_Variable :: struct {
|
|
|
|
|
//@Note(niels): For constant buffers
|
|
|
|
|
resource_index : u32;
|
|
|
|
|
|
|
|
|
|
uf_parent : Type_Variable_Handle;
|
|
|
|
|
|
|
|
|
|
source_node : *AST_Node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Type_Variable_Handle :: #type, distinct u32;
|
|
|
|
|
Type_Constraint_Handle :: #type, distinct u32;
|
|
|
|
|
|
|
|
|
|
Type_Constraint_Kind :: enum {
|
|
|
|
|
Int_Literal; // [[I]] = int
|
|
|
|
|
Float_Literal; // [[F]] = float
|
|
|
|
|
Equivalence; // [[X]] = int/float
|
|
|
|
|
Equality; // E1 == E2: [[E1]] = [[E2]] && [[E1 == E2]] = bool
|
|
|
|
|
Function_Decl; // X(X1, ..., Xn) { return E; }: [[X]] = ([[X1]], ..., [[Xn]]) -> [[E]]
|
|
|
|
|
Function_Call; // E(E1, ..., En): [[E]] = ([[E1]], ..., [[En]]) -> [[E(E1, ..., En)]]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Type_Constraint :: struct {
|
|
|
|
|
kind : Type_Constraint_Kind;
|
|
|
|
|
|
|
|
|
|
union {
|
|
|
|
|
literal : struct {
|
|
|
|
|
type_variable : Type_Variable_Handle;
|
|
|
|
|
union {
|
|
|
|
|
i : int;
|
|
|
|
|
f : float;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
equivalence : struct {
|
|
|
|
|
lhs : Type_Variable_Handle;
|
|
|
|
|
rhs : Type_Variable_Handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function : struct {
|
|
|
|
|
symbol_variable : Type_Variable_Handle;
|
|
|
|
|
return_variable : Type_Variable_Handle;
|
|
|
|
|
arguments : [16]Type_Variable_Handle;
|
|
|
|
|
argument_count : int;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usage_site : *AST_Node;
|
|
|
|
|
|
|
|
|
|
binary_operator : Token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Scope_Stack :: struct {
|
|
|
|
|
allocator : Allocator;
|
|
|
|
|
@@ -199,7 +157,6 @@ Semantic_Checker :: struct {
|
|
|
|
|
current_scope : Scope_Handle;
|
|
|
|
|
|
|
|
|
|
// type_variables : [..]Type_Variable;
|
|
|
|
|
constraints : [..]Type_Constraint;
|
|
|
|
|
|
|
|
|
|
current_buffer_index : u32 = 0;
|
|
|
|
|
current_sampler_index : u32 = 0;
|
|
|
|
|
@@ -708,7 +665,6 @@ add_symbol_to_scope :: (checker : *Semantic_Checker, scope_handle : Scope_Handle
|
|
|
|
|
new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Variable_Handle {
|
|
|
|
|
variable : Type_Variable;
|
|
|
|
|
handle := cast(Type_Variable_Handle)checker.result.type_variables.count + 1;
|
|
|
|
|
variable.uf_parent = handle;
|
|
|
|
|
array_add(*checker.result.type_variables, variable);
|
|
|
|
|
|
|
|
|
|
return h2tv(checker, handle), handle;
|
|
|
|
|
@@ -1103,7 +1059,7 @@ declare_function :: (checker : *Semantic_Checker, node : *AST_Node, builtin : bo
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) {
|
|
|
|
|
create_function :: (checker : *Semantic_Checker, node : *AST_Node) {
|
|
|
|
|
name_to_check := get_actual_function_name(node);
|
|
|
|
|
find_result := find_symbol(checker, name_to_check, checker.current_scope);
|
|
|
|
|
|
|
|
|
|
@@ -1123,27 +1079,13 @@ create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) {
|
|
|
|
|
|
|
|
|
|
previous_scope := use_scope(checker, variable.scope);
|
|
|
|
|
|
|
|
|
|
constraint : Type_Constraint;
|
|
|
|
|
constraint.kind = .Function_Decl;
|
|
|
|
|
constraint.function.symbol_variable = function.type_variable;
|
|
|
|
|
|
|
|
|
|
for i : 0..variable.children.count - 1 {
|
|
|
|
|
arg_var := variable.children[i];
|
|
|
|
|
|
|
|
|
|
if arg_var > 0 {
|
|
|
|
|
constraint.function.arguments[constraint.function.argument_count] = arg_var;
|
|
|
|
|
constraint.function.argument_count += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for child : node.children {
|
|
|
|
|
if child.kind == .Block {
|
|
|
|
|
for statement : child.children {
|
|
|
|
|
if statement.kind == .Return {
|
|
|
|
|
result_var := check_node(checker, statement);
|
|
|
|
|
if result_var > 0 {
|
|
|
|
|
variable.return_type_variable= result_var;
|
|
|
|
|
constraint.function.return_variable = variable.return_type_variable;
|
|
|
|
|
variable.return_type_variable = result_var;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result_var := check_node(checker, statement);
|
|
|
|
|
@@ -1160,44 +1102,10 @@ create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) {
|
|
|
|
|
not_all_control_paths_return_value(checker, node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array_add(*checker.constraints, constraint);
|
|
|
|
|
|
|
|
|
|
use_scope(checker, previous_scope);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create_literal_constraint :: (checker : *Semantic_Checker, value : int, type_variable : Type_Variable_Handle) {
|
|
|
|
|
constraint : Type_Constraint;
|
|
|
|
|
constraint.kind = .Int_Literal;
|
|
|
|
|
constraint.literal.i = value;
|
|
|
|
|
constraint.literal.type_variable = type_variable;
|
|
|
|
|
|
|
|
|
|
array_add(*checker.constraints, constraint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create_literal_constraint :: (checker : *Semantic_Checker, value : float, type_variable : Type_Variable_Handle) -> Type_Constraint_Handle {
|
|
|
|
|
constraint : Type_Constraint;
|
|
|
|
|
constraint.kind = .Float_Literal;
|
|
|
|
|
constraint.literal.f = value;
|
|
|
|
|
constraint.literal.type_variable = type_variable;
|
|
|
|
|
|
|
|
|
|
array_add(*checker.constraints, constraint);
|
|
|
|
|
|
|
|
|
|
return cast(Type_Constraint_Handle)checker.constraints.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create_equivalence_constraint :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rhs : Type_Variable_Handle, usage_site : *AST_Node = null) -> Type_Constraint_Handle {
|
|
|
|
|
constraint : Type_Constraint;
|
|
|
|
|
constraint.kind = .Equivalence;
|
|
|
|
|
constraint.equivalence.lhs = lhs;
|
|
|
|
|
constraint.equivalence.rhs = rhs;
|
|
|
|
|
constraint.usage_site = usage_site;
|
|
|
|
|
|
|
|
|
|
array_add(*checker.constraints, constraint);
|
|
|
|
|
|
|
|
|
|
return cast(Type_Constraint_Handle)checker.constraints.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create_variable :: (checker : *Semantic_Checker, node : *AST_Node, struct_field_parent : *AST_Node = null) -> Type_Variable_Handle {
|
|
|
|
|
find_result := find_symbol(checker, node.name, checker.current_scope);
|
|
|
|
|
// x : int;
|
|
|
|
|
@@ -1317,18 +1225,30 @@ create_field :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable
|
|
|
|
|
for child : node.children {
|
|
|
|
|
rhs = check_node(checker, child);
|
|
|
|
|
}
|
|
|
|
|
create_equivalence_constraint(checker, handle, rhs, node);
|
|
|
|
|
|
|
|
|
|
if handle == 0 || rhs == 0 {
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l := h2tv(checker, handle);
|
|
|
|
|
r := h2tv(checker, rhs);
|
|
|
|
|
assert(l.type != .Unresolved_Expression && r.type != .Unresolved_Expression);
|
|
|
|
|
|
|
|
|
|
if !types_compatible(checker, handle, rhs) {
|
|
|
|
|
type_mismatch(checker, l.source_node, r.source_node, rhs, handle);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Variable_Handle) {
|
|
|
|
|
check_call :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Variable_Handle) -> error : bool {
|
|
|
|
|
find_result := find_symbol(checker, node.name, checker.current_scope);
|
|
|
|
|
|
|
|
|
|
if !find_result {
|
|
|
|
|
function_undeclared(checker, node);
|
|
|
|
|
return;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
overload_found := false;
|
|
|
|
|
@@ -1359,7 +1279,7 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if arg_vars.count != arg_count {
|
|
|
|
|
return;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Type_Mismatch_Data :: struct {
|
|
|
|
|
@@ -1383,6 +1303,9 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
|
|
|
|
|
|
|
|
|
|
if node.children.count == 0 && function.children.count == 0 {
|
|
|
|
|
overload_found = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if overload_found && function.return_type_variable == 0 {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1409,7 +1332,7 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if overload_found {
|
|
|
|
|
if function.return_type_variable> 0 {
|
|
|
|
|
if function.return_type_variable > 0 {
|
|
|
|
|
return_var := h2tv(checker, function.return_type_variable);
|
|
|
|
|
constrained_var := h2tv(checker, type_var);
|
|
|
|
|
constrained_var.type = return_var.type;
|
|
|
|
|
@@ -1424,13 +1347,17 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
|
|
|
|
|
for mismatch : mismatches {
|
|
|
|
|
type_mismatch(checker, mismatch.lhs.node, mismatch.rhs.node, mismatch.rhs.var, mismatch.lhs.var);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle {
|
|
|
|
|
if node.kind == {
|
|
|
|
|
case .Function; {
|
|
|
|
|
create_function_constraint(checker, node);
|
|
|
|
|
create_function(checker, node);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
case. Field; {
|
|
|
|
|
@@ -1466,19 +1393,17 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
|
|
|
|
|
case .TOKEN_MINUS; #through;
|
|
|
|
|
case .TOKEN_STAR; #through;
|
|
|
|
|
case .TOKEN_SLASH; {
|
|
|
|
|
create_equivalence_constraint(checker, rhs_var, lhs_var, node);
|
|
|
|
|
|
|
|
|
|
proper_variable, rhs_handle := new_type_variable(checker);
|
|
|
|
|
lhs_type_var := h2tv(checker, lhs_var);
|
|
|
|
|
proper_variable.type = lhs_type_var.type;
|
|
|
|
|
proper_variable.typename = lhs_type_var.typename;
|
|
|
|
|
proper_variable.source_node = h2tv(checker, lhs_var).source_node;
|
|
|
|
|
proper_variable.struct_field_parent = h2tv(checker, lhs_var).struct_field_parent;
|
|
|
|
|
|
|
|
|
|
create_equivalence_constraint(checker, handle, rhs_handle, node);
|
|
|
|
|
if !types_compatible(checker, lhs_var, rhs_var, true) {
|
|
|
|
|
type_mismatch(checker, node, node.children[1], lhs_var, rhs_var);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case .TOKEN_ASSIGN; {
|
|
|
|
|
create_equivalence_constraint(checker, lhs_var, rhs_var, node);
|
|
|
|
|
|
|
|
|
|
if !types_compatible(checker, lhs_var, rhs_var, true) {
|
|
|
|
|
type_mismatch(checker, node.parent, node.children[1], lhs_var, rhs_var);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return handle;
|
|
|
|
|
@@ -1494,7 +1419,6 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
|
|
|
|
|
type_variable.type = .Int;
|
|
|
|
|
type_variable.source_node = node;
|
|
|
|
|
node.type_variable = handle;
|
|
|
|
|
type_constraint := create_literal_constraint(checker, node.integer_value, handle);
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
@@ -1503,7 +1427,6 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
|
|
|
|
|
type_variable.type = .Float;
|
|
|
|
|
type_variable.source_node = node;
|
|
|
|
|
node.type_variable = handle;
|
|
|
|
|
type_constraint := create_literal_constraint(checker, node.float_value, handle);
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
@@ -1516,7 +1439,9 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
|
|
|
|
|
type_variable.source_node = node;
|
|
|
|
|
node.type_variable = handle;
|
|
|
|
|
|
|
|
|
|
create_call_constraint(checker, node, handle);
|
|
|
|
|
if check_call(checker, node, handle) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
@@ -1555,16 +1480,16 @@ traverse :: (checker : *Semantic_Checker) {
|
|
|
|
|
traverse(checker, checker.program_root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
find :: (checker : *Semantic_Checker, root_handle : Type_Variable_Handle) -> Type_Variable_Handle {
|
|
|
|
|
assert(root_handle > 0);
|
|
|
|
|
root := h2tv(checker, root_handle);
|
|
|
|
|
// find :: (checker : *Semantic_Checker, root_handle : Type_Variable_Handle) -> Type_Variable_Handle {
|
|
|
|
|
// assert(root_handle > 0);
|
|
|
|
|
// root := h2tv(checker, root_handle);
|
|
|
|
|
|
|
|
|
|
if root.uf_parent != root_handle {
|
|
|
|
|
root.uf_parent = find(checker, root.uf_parent);
|
|
|
|
|
}
|
|
|
|
|
// // if root.uf_parent != root_handle {
|
|
|
|
|
// // root.uf_parent = find(checker, root.uf_parent);
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
return root.uf_parent;
|
|
|
|
|
}
|
|
|
|
|
// return root.uf_parent;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
Unification_Result :: enum {
|
|
|
|
|
Unification_Success;
|
|
|
|
|
@@ -1653,78 +1578,6 @@ types_compatible :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rh
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
union_terms :: (checker : *Semantic_Checker, lhs_handle : Type_Variable_Handle, rhs_handle : Type_Variable_Handle, usage_site : *AST_Node) {
|
|
|
|
|
|
|
|
|
|
if !types_compatible(checker, lhs_handle, rhs_handle) {
|
|
|
|
|
lhs_var := h2tv(checker, lhs_handle);
|
|
|
|
|
rhs_var := h2tv(checker, rhs_handle);
|
|
|
|
|
|
|
|
|
|
if usage_site {
|
|
|
|
|
type_mismatch(checker, usage_site, rhs_var.source_node.parent, rhs_handle, lhs_handle);
|
|
|
|
|
} else {
|
|
|
|
|
type_mismatch(checker, lhs_var.source_node.parent, rhs_var.source_node.parent, rhs_handle, lhs_handle);
|
|
|
|
|
}
|
|
|
|
|
} else if lhs_handle != rhs_handle {
|
|
|
|
|
lhs := h2tv(checker, lhs_handle);
|
|
|
|
|
lhs.uf_parent = rhs_handle;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unify :: (checker : *Semantic_Checker, lhs_handle : Type_Variable_Handle, rhs_handle : Type_Variable_Handle, usage_site : *AST_Node = null) -> Unification_Result {
|
|
|
|
|
rep_lhs := find(checker, lhs_handle);
|
|
|
|
|
rep_rhs := find(checker, rhs_handle);
|
|
|
|
|
|
|
|
|
|
if rep_lhs != rep_rhs {
|
|
|
|
|
lhs := h2tv(checker, rep_lhs);
|
|
|
|
|
rhs := h2tv(checker, rep_rhs);
|
|
|
|
|
if !is_proper(lhs) && !is_proper(rhs) {
|
|
|
|
|
union_terms(checker, rep_lhs, rep_rhs, usage_site);
|
|
|
|
|
} else if !is_proper(lhs) && is_proper(rhs) {
|
|
|
|
|
union_terms(checker, rep_lhs, rep_rhs, usage_site);
|
|
|
|
|
} else if is_proper(lhs) && !is_proper(rhs) {
|
|
|
|
|
union_terms(checker, rep_rhs, rep_lhs, usage_site);
|
|
|
|
|
} else if is_proper(lhs) && is_proper(rhs) {
|
|
|
|
|
union_terms(checker, rep_lhs, rep_rhs, usage_site);
|
|
|
|
|
|
|
|
|
|
//@Incomplete(niels): Evaluate sub-terms for functions.
|
|
|
|
|
} else {
|
|
|
|
|
return .Unification_Failure;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return .Unification_Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
union_find :: (checker : *Semantic_Checker) -> bool {
|
|
|
|
|
for constraint : checker.constraints {
|
|
|
|
|
if constraint.kind == {
|
|
|
|
|
case .Int_Literal; {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
case .Float_Literal; {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
case .Equivalence; {
|
|
|
|
|
if !constraint.equivalence.lhs || !constraint.equivalence.rhs {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handle_lhs := find(checker, constraint.equivalence.lhs);
|
|
|
|
|
handle_rhs := find(checker, constraint.equivalence.rhs);
|
|
|
|
|
|
|
|
|
|
unification_result := unify(checker, handle_lhs, handle_rhs, constraint.usage_site);
|
|
|
|
|
if unification_result == .Unification_Failure {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case .Function_Decl; {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HLSL_BUILTIN :: #run -> string {
|
|
|
|
|
// T := #load "hlsl_builtin.jai";
|
|
|
|
|
|
|
|
|
|
@@ -1796,24 +1649,6 @@ add_hlsl_builtins :: (checker : *Semantic_Checker) {
|
|
|
|
|
|
|
|
|
|
type_check :: (checker : *Semantic_Checker, root : *AST_Node) {
|
|
|
|
|
traverse(checker, root);
|
|
|
|
|
|
|
|
|
|
// if checker.result.had_error {
|
|
|
|
|
// //@Incomplete(niels): handle error...
|
|
|
|
|
// return checker.result;
|
|
|
|
|
// }
|
|
|
|
|
uf_result := union_find(checker);
|
|
|
|
|
|
|
|
|
|
if !uf_result {
|
|
|
|
|
//@Incomplete(niels): handle error...
|
|
|
|
|
// return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for *type_variable : checker.result.type_variables {
|
|
|
|
|
if type_variable.type == .Unresolved_Variable {
|
|
|
|
|
rep := h2tv(checker, type_variable.uf_parent);
|
|
|
|
|
type_variable.type = rep.type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check :: (checker : *Semantic_Checker, root : *AST_Node) -> Semantic_Check_Result {
|
|
|
|
|
@@ -1821,7 +1656,6 @@ check :: (checker : *Semantic_Checker, root : *AST_Node) -> Semantic_Check_Resul
|
|
|
|
|
checker.current_sampler_index = 0;
|
|
|
|
|
checker.current_texture_index = 0;
|
|
|
|
|
array_reserve(*checker.result.messages, 16);
|
|
|
|
|
array_reserve(*checker.constraints, 1024);
|
|
|
|
|
add_hlsl_builtins(checker);
|
|
|
|
|
|
|
|
|
|
type_check(checker, root);
|
|
|
|
|
@@ -2019,64 +1853,6 @@ pretty_print_scope :: (checker : *Semantic_Checker, scope : *Scope, builder : *S
|
|
|
|
|
append(builder, "]\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pretty_print_constraint :: (checker : *Semantic_Checker, constraint : Type_Constraint, builder : *String_Builder) {
|
|
|
|
|
if constraint.kind == {
|
|
|
|
|
case .Int_Literal; {
|
|
|
|
|
print_to_builder(builder, "[[%]] = int\n", constraint.literal.i);
|
|
|
|
|
}
|
|
|
|
|
case .Float_Literal; {
|
|
|
|
|
print_to_builder(builder, "[[%]] = float\n", constraint.literal.f);
|
|
|
|
|
}
|
|
|
|
|
case .Equivalence; {
|
|
|
|
|
lhs_var := h2tv(checker, constraint.equivalence.lhs);
|
|
|
|
|
rhs_var := h2tv(checker, constraint.equivalence.rhs);
|
|
|
|
|
|
|
|
|
|
append(builder, "[[");
|
|
|
|
|
print_type_variable(builder, lhs_var, checker);
|
|
|
|
|
append(builder, "]] = ");
|
|
|
|
|
if rhs_var.source_node {
|
|
|
|
|
append(builder, "[[");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_type_variable(builder, rhs_var, checker);
|
|
|
|
|
if rhs_var.source_node {
|
|
|
|
|
append(builder, "]]");
|
|
|
|
|
}
|
|
|
|
|
append(builder, "\n");
|
|
|
|
|
}
|
|
|
|
|
case .Function_Decl; {
|
|
|
|
|
sym := h2tv(checker, constraint.function.symbol_variable);
|
|
|
|
|
print_to_builder(builder, "[[%]] =", sym.name);
|
|
|
|
|
append(builder, " (");
|
|
|
|
|
if constraint.function.argument_count > 0 {
|
|
|
|
|
for i : 0..constraint.function.argument_count - 1 {
|
|
|
|
|
arg := h2tv(checker, constraint.function.arguments[i]);
|
|
|
|
|
print_to_builder(builder, "[[%]]", arg.name);
|
|
|
|
|
|
|
|
|
|
if i < constraint.function.argument_count - 1 {
|
|
|
|
|
append(builder, ", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
append(builder, ")");
|
|
|
|
|
|
|
|
|
|
if constraint.function.return_variable > 0 {
|
|
|
|
|
return_var := h2tv(checker, constraint.function.return_variable);
|
|
|
|
|
|
|
|
|
|
append(builder, " -> ");
|
|
|
|
|
append(builder, "[[");
|
|
|
|
|
|
|
|
|
|
print_type_variable(builder, return_var, checker);
|
|
|
|
|
|
|
|
|
|
append(builder, "]]", );
|
|
|
|
|
append(builder, "\n");
|
|
|
|
|
} else {
|
|
|
|
|
append(builder, " -> unit\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_type_variable :: (builder : *String_Builder, variable : Type_Variable, checker : *Semantic_Checker) {
|
|
|
|
|
if variable.builtin {
|
|
|
|
|
if variable.type != .Function || variable.type != .Struct {
|
|
|
|
|
@@ -2173,68 +1949,6 @@ pretty_print_symbol_table :: (checker : *Semantic_Checker, allocator : Allocator
|
|
|
|
|
return builder_to_string(*builder,, allocator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pretty_print_type_variable :: (checker : *Semantic_Checker, type_variable : *Type_Variable, builder : *String_Builder) {
|
|
|
|
|
rep := type_variable.uf_parent;
|
|
|
|
|
if type_variable.name.count > 0 {
|
|
|
|
|
append(builder, "[[");
|
|
|
|
|
print_type_variable(builder, type_variable, checker);
|
|
|
|
|
append(builder, "]] = ");
|
|
|
|
|
rep_var := h2tv(checker, rep);
|
|
|
|
|
if is_proper(type_variable) {
|
|
|
|
|
print_to_builder(builder, proper_type_to_string(checker, type_variable, temp));
|
|
|
|
|
} else if type_variable.type == .Struct || type_variable.type == .Properties ||
|
|
|
|
|
type_variable.type == .CBuffer {
|
|
|
|
|
if type_variable.kind == .Declaration {
|
|
|
|
|
append(builder, "{");
|
|
|
|
|
|
|
|
|
|
for 0..type_variable.children.count - 1 {
|
|
|
|
|
child_handle := type_variable.children[it];
|
|
|
|
|
child := h2tv(checker, child_handle);
|
|
|
|
|
print_to_builder(builder, child.name);
|
|
|
|
|
append(builder, " : ");
|
|
|
|
|
print_to_builder(builder, type_to_string(child));
|
|
|
|
|
|
|
|
|
|
if it < type_variable.children.count - 1 {
|
|
|
|
|
append(builder, ", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
append(builder, "}");
|
|
|
|
|
} else if type_variable.typename.count > 0 {
|
|
|
|
|
print_to_builder(builder, "%", type_variable.typename);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
print_from_source_location(builder, rep_var.source_node.source_location);
|
|
|
|
|
}
|
|
|
|
|
append(builder, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pretty_print_type_variables :: (checker : *Semantic_Checker, allocator : Allocator) -> string {
|
|
|
|
|
builder : String_Builder;
|
|
|
|
|
|
|
|
|
|
init_string_builder(*builder,, allocator);
|
|
|
|
|
|
|
|
|
|
for *type_variable : checker.result.type_variables {
|
|
|
|
|
if type_variable.builtin continue;
|
|
|
|
|
|
|
|
|
|
pretty_print_type_variable(checker, type_variable, *builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return builder_to_string(*builder,, allocator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pretty_print_type_constraints :: (checker : *Semantic_Checker, allocator : Allocator) -> string {
|
|
|
|
|
builder : String_Builder;
|
|
|
|
|
init_string_builder(*builder,, allocator);
|
|
|
|
|
|
|
|
|
|
for *constraint : checker.constraints {
|
|
|
|
|
pretty_print_constraint(checker, constraint, *builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return builder_to_string(*builder,, allocator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#scope_module
|
|
|
|
|
|
|
|
|
|
#import "ncore";
|
|
|
|
|
|