Add lexing, parsing and some semantic checking for constant buffers.

This commit is contained in:
2024-06-14 19:56:28 +02:00
parent b1dceb298f
commit a9a67e3fac
45 changed files with 1275 additions and 1119 deletions

View File

@@ -829,8 +829,11 @@ proper_type_to_string :: (checker : *Semantic_Checker, var : Type_Variable, allo
proper_type_to_string(*builder, checker, var);
return builder_to_string(*builder,, allocator);
}
case .Struct; {
return var.typename;
}
}
return "______not proper type______";
}
@@ -916,12 +919,25 @@ declare_struct :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variab
return declare_struct(checker, node, node.name);
}
PROPERTIES_BUFFER_INDEX : u32 : 0;
META_BUFFER_INDEX : u32 : PROPERTIES_BUFFER_INDEX + 1;
current_custom_buffer_index : u32 = META_BUFFER_INDEX + 1;
declare_properties :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle {
name := ifx node.name.count == 0 then "properties" else node.name;
type_var := declare_struct(checker, node, name);
var := h2tv(checker, type_var);
var.typename = "properties";
var.buffer_index = 0;
var.buffer_index = PROPERTIES_BUFFER_INDEX;
return type_var;
}
declare_cbuffer :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle {
type_var := declare_struct(checker, node);
var := h2tv(checker, type_var);
var.typename = "constant_buffer";
current_custom_buffer_index += 1;
var.buffer_index = current_custom_buffer_index;
return type_var;
}
@@ -930,7 +946,7 @@ declare_meta :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable
type_var := declare_struct(checker, node, name);
var := h2tv(checker, type_var);
var.typename = name;
var.buffer_index = 0;
var.buffer_index = META_BUFFER_INDEX;
return type_var;
}
@@ -1204,7 +1220,7 @@ create_variable :: (checker : *Semantic_Checker, node : *AST_Node, field_parent
field_access_on_primitive_type(checker, node, find_result.type_variable);
return 0;
} else {
lookup_name : string;
lookup_name : string = variable.typename;
if variable.typename == "properties" {
lookup_name = variable.name;
}
@@ -1306,6 +1322,34 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
overload_found := false;
arg_node : *AST_Node = null;
Result :: struct {
var : Type_Variable_Handle;
node : *AST_Node;
}
arg_vars : [..]Result;
// @incomplete(niels): Should be some kind of scratch allocator instead probably?
arg_vars.allocator = temp;
arg_count := 0;
for child : node.children {
if child.kind == {
case .ArgList; {
arg_count = child.children.count;
for arg_child : child.children {
arg_var := check_node(checker, arg_child);
if arg_var != 0 {
array_add(*arg_vars, .{ arg_var, arg_child });
}
}
}
}
}
if arg_vars.count != arg_count {
return;
}
for *func : find_result.functions {
if overload_found {
break;
@@ -1313,6 +1357,10 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
function := h2tv(checker, func.type_variable);
if arg_count != function.child_count {
continue;
}
if function.return_var > 0 {
return_var := h2tv(checker, function.return_var);
constrained_var := h2tv(checker, type_var);
@@ -1327,39 +1375,27 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
all_args_match : bool = true;
for child : node.children {
if child.kind == {
case .ArgList; {
if child.children.count != function.child_count {
// mismatched_arguments(checker, node, func, child.children.count, function.child_count);
break;
}
for arg : arg_vars {
function_param := function.children[it_index];
for arg_child : child.children {
arg_var := check_node(checker, arg_child);
function_param := function.children[it_index];
// @Incomplete(nb): Improve the error handling of this constraint.
// The usage site might be the call, but really the usage site
// is the variable, with the call around it.
// We could probably expand source locations to always include the whole line
// That is unlikely to be annoying now that I think about it.
// So maybe we just always do that? Then we always have the complete information
// and the actual token we want to focus on is just the one we have?
// @Update(nb): We actually do this now for a bunch of places, but not all.
// Error reporting in this case is still not great, since it doesn't properly mark the
// faulty variable.
create_equivalence_constraint(checker, arg_var, function_param, arg_child);
if !types_compatible(checker, arg_var, function_param) {
if all_args_match {
arg_node = arg_child;
}
all_args_match = false;
} else {
overload_found = all_args_match;
}
}
// @Incomplete(nb): Improve the error handling of this constraint.
// The usage site might be the call, but really the usage site
// is the variable, with the call around it.
// We could probably expand source locations to always include the whole line
// That is unlikely to be annoying now that I think about it.
// So maybe we just always do that? Then we always have the complete information
// and the actual token we want to focus on is just the one we have?
// @Update(nb): We actually do this now for a bunch of places, but not all.
// Error reporting in this case is still not great, since it doesn't properly mark the
// faulty variable.
create_equivalence_constraint(checker, arg.var, function_param, arg.node);
if !types_compatible(checker, arg.var, function_param) {
if all_args_match {
arg_node = arg.node;
}
all_args_match = false;
} else {
overload_found = all_args_match;
}
}
}
@@ -1478,6 +1514,8 @@ traverse :: (checker : *Semantic_Checker, root : *AST_Node) {
declare_struct(checker, declaration);
} else if declaration.kind == .Meta {
declare_meta(checker, declaration);
} else if declaration.kind == .CBuffer {
declare_cbuffer(checker, declaration);
}
}