Compare commits

..

3 Commits

82 changed files with 859 additions and 444 deletions

44
AST.jai
View File

@@ -356,6 +356,29 @@ pretty_print_node :: (node : *AST_Node, indentation : int, builder : *String_Bui
case .If; { case .If; {
pretty_print_if(node, indentation, builder, skip_indent); pretty_print_if(node, indentation, builder, skip_indent);
} }
case .If_Directive; {
if !skip_indent {
indent(builder, indentation);
}
append(builder, "(#if ");
condition := node.children[0];
pretty_print_node(condition, 0, builder);
append(builder, "\n");
body := node.children[1];
// indent(builder,indentation + 4);
// append(builder, "(");
pretty_print_node(body, indentation + 4, builder);
// append(builder, ")");
if node.children.count == 3 { //@Note: Else branch
append(builder, "\n");
pretty_print_node(node.children[2], indentation + 4, builder);
}
append(builder, ")");
}
case .For; { case .For; {
pretty_print_for(node, indentation, builder, skip_indent); pretty_print_for(node, indentation, builder, skip_indent);
} }
@@ -462,8 +485,10 @@ pretty_print_declaration :: (declaration : *AST_Node, indentation : int, builder
} else if declaration.kind == .CBuffer { } else if declaration.kind == .CBuffer {
append(builder, "constant_buffer "); append(builder, "constant_buffer ");
} }
if declaration.kind != .If_Directive {
print_to_builder(builder, "%", declaration.name); print_to_builder(builder, "%", declaration.name);
} }
}
if declaration.kind == .Function && declaration.token.kind == .TOKEN_IDENTIFIER{ if declaration.kind == .Function && declaration.token.kind == .TOKEN_IDENTIFIER{
print_to_builder(builder, " -> %", declaration.token.ident_value); print_to_builder(builder, " -> %", declaration.token.ident_value);
@@ -479,9 +504,26 @@ pretty_print_declaration :: (declaration : *AST_Node, indentation : int, builder
pretty_print_node(declaration.children[0], 0, builder); pretty_print_node(declaration.children[0], 0, builder);
append(builder, "\n"); append(builder, "\n");
pretty_print_node(declaration.children[1], indentation + 5, builder); pretty_print_node(declaration.children[1], indentation + 5, builder);
if declaration.children.count > 2 {
append(builder, "\n");
if declaration.children[2].kind == .If_Directive {
pretty_print_declaration(declaration.children[2], indentation + 5, builder);
} else {
pretty_print_node(declaration.children[2], indentation + 5, builder);
}
}
} else { } else {
print_to_builder(builder, "\n"); print_to_builder(builder, "\n");
pretty_print_children(declaration, indentation + 1, builder, flags = .NewLine);
flags := Children_Print_Flags.NewLine;
if declaration.parent && declaration.parent.parent {
if declaration.parent.parent.kind == .If_Directive {
indent(builder, indentation - 1); //@Note: Hack the indent for now... Wow this is stupid, but it works!
}
}
pretty_print_children(declaration, indentation + 1, builder, flags = flags);
} }
} }

View File

@@ -135,7 +135,7 @@ Checker_State :: enum {
Adding_Builtins; Adding_Builtins;
} }
Semantic_Checker :: struct { Checker :: struct {
program_root : *AST_Node; program_root : *AST_Node;
path : string; path : string;
@@ -152,17 +152,17 @@ Semantic_Checker :: struct {
had_error : bool; had_error : bool;
} }
record_error :: (checker : *Semantic_Checker, message : string, source_location : Source_Range, report_source_location : bool = true) { record_error :: (checker : *Checker, message : string, source_location : Source_Range, report_source_location : bool = true) {
locations : [1]Source_Range; locations : [1]Source_Range;
locations[0] = source_location; locations[0] = source_location;
record_error(checker, message, locations, report_source_location); record_error(checker, message, locations, report_source_location);
} }
invalid_symbol_name :: (checker : *Semantic_Checker, node : *AST_Node, type : string) { invalid_symbol_name :: (checker : *Checker, node : *AST_Node, type : string) {
record_error(checker, tprint("Invalid % name '%'", type, node.name), node.source_location); record_error(checker, tprint("Invalid % name '%'", type, node.name), node.source_location);
} }
symbol_redeclaration :: (checker : *Semantic_Checker, redeclared_node : *AST_Node, symbol : *Defined_Symbol) { symbol_redeclaration :: (checker : *Checker, redeclared_node : *AST_Node, symbol : *Defined_Symbol) {
/* /*
Redeclaration of '%': Redeclaration of '%':
@@ -184,7 +184,7 @@ symbol_redeclaration :: (checker : *Semantic_Checker, redeclared_node : *AST_Nod
cyan(*builder); cyan(*builder);
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "%\n", print_from_source_location(redeclared_node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, redeclared_node.source_location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, redeclared_node.source_location.main_token); print_token_pointer(*builder, redeclared_node.source_location.main_token);
@@ -205,7 +205,7 @@ symbol_redeclaration :: (checker : *Semantic_Checker, redeclared_node : *AST_Nod
cyan(*builder); cyan(*builder);
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, symbol.source_node.source_location.main_token); print_token_pointer(*builder, symbol.source_node.source_location.main_token);
} }
@@ -216,7 +216,7 @@ symbol_redeclaration :: (checker : *Semantic_Checker, redeclared_node : *AST_Nod
record_error(checker, message, redeclared_node.source_location, false); record_error(checker, message, redeclared_node.source_location, false);
} }
symbol_undeclared :: (checker : *Semantic_Checker, node : *AST_Node) { symbol_undeclared :: (checker : *Checker, node : *AST_Node) {
/* /*
Use of undeclard symbol '%'. Use of undeclard symbol '%'.
b = f; b = f;
@@ -231,7 +231,7 @@ Use of undeclard symbol '%'.
cyan(*builder); cyan(*builder);
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, node.source_location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, node.source_location.main_token); print_token_pointer(*builder, node.source_location.main_token);
@@ -240,7 +240,7 @@ Use of undeclard symbol '%'.
record_error(checker, message, node.source_location, false); record_error(checker, message, node.source_location, false);
} }
no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, overloads : *Defined_Symbol, arg_node : *AST_Node = null) { no_matching_overload_found :: (checker : *Checker, call : *AST_Node, overloads : *Defined_Symbol, arg_node : *AST_Node = null) {
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder,, temp); init_string_builder(*builder,, temp);
@@ -250,7 +250,7 @@ no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, ov
indent(*builder, 1); indent(*builder, 1);
append(*builder, "found:\n"); append(*builder, "found:\n");
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%\n", print_from_source_location(call.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, call.source_location));
indent(*builder, 2); indent(*builder, 2);
print_token_pointer(*builder, call.source_location.main_token); print_token_pointer(*builder, call.source_location.main_token);
newline(*builder); newline(*builder);
@@ -275,7 +275,7 @@ no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, ov
cyan(*builder); cyan(*builder);
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, location));
indent(*builder, 2); indent(*builder, 2);
print_token_pointer(*builder, arg_node.source_location.main_token); print_token_pointer(*builder, arg_node.source_location.main_token);
newline(*builder); newline(*builder);
@@ -293,9 +293,14 @@ no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, ov
func_location := func_var.source_node.source_location; func_location := func_var.source_node.source_location;
indent(*builder, 2); indent(*builder, 2);
// @Incomplete(niels): We need a way to properly save the path of the declaration if func.builtin {
print_to_builder(*builder, "% (%:%)\n", print_from_source_location(func_location), checker.path, print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, func_location));
} else {
print_to_builder(*builder, "% (%:%)\n", print_from_source_location(checker.ctx, func_location), checker.path,
func_location.main_token.line); func_location.main_token.line);
}
// @Incomplete(niels): We need a way to properly save the path of the declaration
if !arg_node { if !arg_node {
white(*builder); white(*builder);
@@ -318,7 +323,7 @@ no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, ov
} }
not_all_control_paths_return_value :: (checker : *Semantic_Checker, node : *AST_Node) { not_all_control_paths_return_value :: (checker : *Checker, node : *AST_Node) {
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder,, temp); init_string_builder(*builder,, temp);
@@ -328,7 +333,7 @@ not_all_control_paths_return_value :: (checker : *Semantic_Checker, node : *AST_
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, node.source_location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, node.token); print_token_pointer(*builder, node.token);
@@ -339,7 +344,7 @@ not_all_control_paths_return_value :: (checker : *Semantic_Checker, node : *AST_
record_error(checker, message, node.source_location, false); record_error(checker, message, node.source_location, false);
} }
mismatched_arguments :: (checker : *Semantic_Checker, call : *AST_Node, symbol : *Defined_Symbol, args_call : int, args_def : int) { mismatched_arguments :: (checker : *Checker, call : *AST_Node, symbol : *Defined_Symbol, args_call : int, args_def : int) {
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder,, temp); init_string_builder(*builder,, temp);
@@ -364,7 +369,7 @@ Too many arguments: Expected %, got %.
indent(*builder, 1); indent(*builder, 1);
append(*builder, "found:\n"); append(*builder, "found:\n");
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%\n", print_from_source_location(call.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, call.source_location));
indent(*builder, 2); indent(*builder, 2);
print_token_pointer(*builder, call.source_location.main_token); print_token_pointer(*builder, call.source_location.main_token);
append(*builder, "\n\n"); append(*builder, "\n\n");
@@ -372,7 +377,7 @@ Too many arguments: Expected %, got %.
append(*builder, "expected:\n"); append(*builder, "expected:\n");
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%\n", print_from_source_location(symbol.source_node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, symbol.source_node.source_location));
locations : [1]Source_Range; locations : [1]Source_Range;
locations[0] = call.source_location; locations[0] = call.source_location;
@@ -381,7 +386,7 @@ Too many arguments: Expected %, got %.
record_error(checker, message, locations, false); record_error(checker, message, locations, false);
} }
function_undeclared :: (checker : *Semantic_Checker, node : *AST_Node) { function_undeclared :: (checker : *Checker, node : *AST_Node) {
/* /*
Error: Undeclared identifier 'name'. Error: Undeclared identifier 'name'.
@@ -395,7 +400,7 @@ Error: Undeclared identifier 'name'.
print_to_builder(*builder, "Attempt to call undeclared function '%'.\n\n", node.name); print_to_builder(*builder, "Attempt to call undeclared function '%'.\n\n", node.name);
cyan(*builder); cyan(*builder);
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, node.source_location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, node.source_location.main_token); print_token_pointer(*builder, node.source_location.main_token);
newline(*builder); newline(*builder);
@@ -404,7 +409,7 @@ Error: Undeclared identifier 'name'.
record_error(checker, message, node.source_location, false); record_error(checker, message, node.source_location, false);
} }
field_not_defined_on_struct :: (checker : *Semantic_Checker, node : *AST_Node, struct_symbol : *Defined_Symbol) { field_not_defined_on_struct :: (checker : *Checker, node : *AST_Node, struct_symbol : *Defined_Symbol) {
/* /*
Field '%' is not defined in struct '%'. Field '%' is not defined in struct '%'.
b.t = f; b.t = f;
@@ -423,7 +428,7 @@ Field '%' is not defined in struct '%'.
cyan(*builder); cyan(*builder);
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, node.source_location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, node.source_location.main_token); print_token_pointer(*builder, node.source_location.main_token);
newline(*builder); newline(*builder);
@@ -431,13 +436,13 @@ Field '%' is not defined in struct '%'.
indent(*builder, 1); indent(*builder, 1);
append(*builder, "declaration:\n"); append(*builder, "declaration:\n");
print_from_source_location(*builder, struct_symbol.source_node.source_location, 2); print_from_source_location(checker.ctx, *builder, struct_symbol.source_node.source_location, 2);
message := builder_to_string(*builder); message := builder_to_string(*builder);
record_error(checker, message, node.source_location, false); record_error(checker, message, node.source_location, false);
} }
field_access_on_primitive_type :: (checker : *Semantic_Checker, node : *AST_Node, handle : Type_Variable_Handle) { field_access_on_primitive_type :: (checker : *Checker, node : *AST_Node, handle : Type_Variable_Handle) {
/* /*
Attempting to access a field on a primitive type '%'. Attempting to access a field on a primitive type '%'.
x.d = 5; x.d = 5;
@@ -451,11 +456,11 @@ Attempting to access a field on a primitive type '%'.
init_string_builder(*builder,, temp); init_string_builder(*builder,, temp);
variable := from_handle(checker, handle); variable := from_handle(checker, handle);
print_to_builder(*builder, "Attempting to access a field on a primitive type '%'.\n", proper_type_to_string(checker.ctx.type_variables, variable)); print_to_builder(*builder, "Attempting to access a field on a primitive type '%'.\n", proper_type_to_string(checker.ctx, checker.ctx.type_variables, variable));
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, node.source_location));
indent(*builder, 1); indent(*builder, 1);
node_variable := from_handle(checker, node.type_variable); node_variable := from_handle(checker, node.type_variable);
@@ -471,7 +476,7 @@ Attempting to access a field on a primitive type '%'.
append(*builder, "declaration:\n"); append(*builder, "declaration:\n");
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%", print_from_source_location(variable.source_node.source_location)); print_to_builder(*builder, "%", print_from_source_location(checker.ctx, variable.source_node.source_location));
message := builder_to_string(*builder,, temp); message := builder_to_string(*builder,, temp);
record_error(checker, message, node.source_location, false); record_error(checker, message, node.source_location, false);
@@ -479,7 +484,7 @@ Attempting to access a field on a primitive type '%'.
white(*builder); white(*builder);
} }
if_condition_has_to_be_boolean_type :: (checker : *Semantic_Checker, usage_site : *AST_Node, handle : Type_Variable_Handle) { if_condition_has_to_be_boolean_type :: (checker : *Checker, usage_site : *AST_Node, handle : Type_Variable_Handle) {
/* /*
Type of expression in if condition has to be bool. Type of expression in if condition has to be bool.
if 100.0 if 100.0
@@ -499,7 +504,7 @@ if_condition_has_to_be_boolean_type :: (checker : *Semantic_Checker, usage_site
location := usage_site.source_location; location := usage_site.source_location;
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, usage_site.children[0].source_location.begin); print_token_pointer(*builder, usage_site.children[0].source_location.begin);
@@ -512,7 +517,7 @@ if_condition_has_to_be_boolean_type :: (checker : *Semantic_Checker, usage_site
usage_child := usage_site.children[0]; usage_child := usage_site.children[0];
usage_loc := usage_child.source_location; usage_loc := usage_child.source_location;
print_to_builder(*builder, "% has type %\n", print_from_source_location(*usage_loc), proper_type_to_string(checker.ctx.type_variables, var)); print_to_builder(*builder, "% has type %\n", print_from_source_location(checker.ctx, *usage_loc), proper_type_to_string(checker.ctx, checker.ctx.type_variables, var));
message := builder_to_string(*builder,, temp); message := builder_to_string(*builder,, temp);
record_error(checker, message, usage_site.source_location, false); record_error(checker, message, usage_site.source_location, false);
@@ -520,7 +525,7 @@ if_condition_has_to_be_boolean_type :: (checker : *Semantic_Checker, usage_site
white(*builder); white(*builder);
} }
type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_node : *AST_Node, expect : Type_Variable_Handle, got : Type_Variable_Handle) { type_mismatch :: (checker : *Checker, usage_site : *AST_Node, expect_node : *AST_Node, expect : Type_Variable_Handle, got : Type_Variable_Handle) {
expect_var := from_handle(checker, expect); expect_var := from_handle(checker, expect);
got_var := from_handle(checker, got); got_var := from_handle(checker, got);
@@ -545,7 +550,7 @@ type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_no
indent(*builder, 1); indent(*builder, 1);
append(*builder, "found:\n"); append(*builder, "found:\n");
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, location));
indent(*builder, 2); indent(*builder, 2);
print_token_pointer(*builder, location.main_token); print_token_pointer(*builder, location.main_token);
@@ -554,7 +559,7 @@ type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_no
indent(*builder, 1); indent(*builder, 1);
print_to_builder(*builder, "expected:\n"); print_to_builder(*builder, "expected:\n");
indent(*builder, 2); indent(*builder, 2);
proper_type_to_string(*builder, checker.ctx.type_variables, expect_var); proper_type_to_string(checker.ctx, *builder, checker.ctx.type_variables, expect_var);
append(*builder, "\n"); append(*builder, "\n");
// indent(*builder, 2); // indent(*builder, 2);
@@ -572,14 +577,14 @@ type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_no
indent(*builder, 2); indent(*builder, 2);
print_to_builder(*builder, "%\n", print_from_source_location(got_var.source_node.source_location)); print_to_builder(*builder, "%\n", print_from_source_location(checker.ctx, got_var.source_node.source_location));
message := builder_to_string(*builder); message := builder_to_string(*builder);
record_error(checker, message, Source_Range.[usage_site.source_location], false); record_error(checker, message, Source_Range.[usage_site.source_location], false);
} }
record_error :: (checker : *Semantic_Checker, error_string : string, locations : []Source_Range, report_source_location : bool = true) { record_error :: (checker : *Checker, error_string : string, locations : []Source_Range, report_source_location : bool = true) {
error : Compiler_Message; error : Compiler_Message;
error.message_kind = .Error; error.message_kind = .Error;
error.report_source_location = report_source_location; error.report_source_location = report_source_location;
@@ -607,7 +612,7 @@ is_proper :: (var : Type_Variable) -> bool {
return false; return false;
} }
use_scope :: (checker : *Semantic_Checker, handle : Scope_Handle) -> Scope_Handle { use_scope :: (checker : *Checker, handle : Scope_Handle) -> Scope_Handle {
assert(handle > 0, "Invalid scope handle: %", handle); assert(handle > 0, "Invalid scope handle: %", handle);
previous_scope := checker.current_scope; previous_scope := checker.current_scope;
checker.current_scope = handle; checker.current_scope = handle;
@@ -615,7 +620,7 @@ use_scope :: (checker : *Semantic_Checker, handle : Scope_Handle) -> Scope_Handl
return previous_scope; return previous_scope;
} }
push_scope :: (checker : *Semantic_Checker, name := "", kind : Scope_Kind = .Global) -> *Scope, Scope_Handle { push_scope :: (checker : *Checker, name := "", kind : Scope_Kind = .Global) -> *Scope, Scope_Handle {
new_scope : Scope; new_scope : Scope;
array_add(*checker.ctx.scope_stack.stack, new_scope); array_add(*checker.ctx.scope_stack.stack, new_scope);
@@ -641,7 +646,7 @@ push_scope :: (checker : *Semantic_Checker, name := "", kind : Scope_Kind = .Glo
return scope, xx count; return scope, xx count;
} }
pop_scope :: (checker : *Semantic_Checker) -> Scope_Handle { pop_scope :: (checker : *Checker) -> Scope_Handle {
scope := get_scope(checker, checker.current_scope); scope := get_scope(checker, checker.current_scope);
if !scope.parent { if !scope.parent {
return 0; return 0;
@@ -652,7 +657,7 @@ pop_scope :: (checker : *Semantic_Checker) -> Scope_Handle {
return checker.current_scope; return checker.current_scope;
} }
peek_scope :: (checker : *Semantic_Checker) -> *Scope, Scope_Handle { peek_scope :: (checker : *Checker) -> *Scope, Scope_Handle {
if checker.ctx.scope_stack.stack.count == 0 { if checker.ctx.scope_stack.stack.count == 0 {
return null, 0; return null, 0;
} }
@@ -662,7 +667,7 @@ peek_scope :: (checker : *Semantic_Checker) -> *Scope, Scope_Handle {
return scope, xx count; return scope, xx count;
} }
get_current_scope :: (checker : *Semantic_Checker) -> *Scope { get_current_scope :: (checker : *Checker) -> *Scope {
return get_scope(checker, checker.current_scope); return get_scope(checker, checker.current_scope);
} }
@@ -674,7 +679,7 @@ get_scope :: (scope_stack : Scope_Stack, handle : Scope_Handle) -> *Scope {
return *scope_stack.stack[handle - 1]; return *scope_stack.stack[handle - 1];
} }
get_scope :: (checker : *Semantic_Checker, handle : Scope_Handle) -> *Scope { get_scope :: (checker : *Checker, handle : Scope_Handle) -> *Scope {
return get_scope(*checker.ctx.scope_stack, handle); return get_scope(*checker.ctx.scope_stack, handle);
} }
@@ -695,7 +700,7 @@ add_symbol_to_scope :: (state : Checker_State, scope_stack : *Scope_Stack, scope
return table_set(*scope.table, name, symbol_to_add); return table_set(*scope.table, name, symbol_to_add);
} }
new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Variable_Handle { new_type_variable :: (checker : *Checker) -> *Type_Variable, Type_Variable_Handle {
variable : Type_Variable; variable : Type_Variable;
handle := cast(Type_Variable_Handle)checker.ctx.type_variables.count + 1; handle := cast(Type_Variable_Handle)checker.ctx.type_variables.count + 1;
array_add(*checker.ctx.type_variables, variable); array_add(*checker.ctx.type_variables, variable);
@@ -703,7 +708,7 @@ new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Varia
return from_handle(checker, handle), handle; return from_handle(checker, handle), handle;
} }
new_builtin_type_variable :: (checker : *Semantic_Checker, type : Type_Kind, source : Source_Kind, name : string, typename : string = "") -> *Type_Variable, Type_Variable_Handle { new_builtin_type_variable :: (checker : *Checker, type : Type_Kind, source : Source_Kind, name : string, typename : string = "") -> *Type_Variable, Type_Variable_Handle {
tv, handle := new_type_variable(checker); tv, handle := new_type_variable(checker);
tv.name = name; tv.name = name;
@@ -720,7 +725,7 @@ Arg :: struct {
typename : string; typename : string;
} }
new_builtin_struct :: (checker : *Semantic_Checker, name : string, members : []Arg) -> *Type_Variable, Type_Variable_Handle { new_builtin_struct :: (checker : *Checker, name : string, members : []Arg) -> *Type_Variable, Type_Variable_Handle {
tv, handle := new_builtin_type_variable(checker, .Struct, .Declaration, name, name); tv, handle := new_builtin_type_variable(checker, .Struct, .Declaration, name, name);
builtin_node := new_builtin_struct_node(checker.ctx, name, members); builtin_node := new_builtin_struct_node(checker.ctx, name, members);
@@ -762,7 +767,7 @@ new_builtin_struct :: (checker : *Semantic_Checker, name : string, members : []A
return from_handle(checker, handle), handle; return from_handle(checker, handle), handle;
} }
new_builtin_function :: (checker : *Semantic_Checker, name : string, args : []Arg, return_arg : Arg) -> *Type_Variable, Type_Variable_Handle { new_builtin_function :: (checker : *Checker, name : string, args : []Arg, return_arg : Arg) -> *Type_Variable, Type_Variable_Handle {
tv, handle := new_builtin_type_variable(checker, .Function, .Declaration, name); tv, handle := new_builtin_type_variable(checker, .Function, .Declaration, name);
builtin_node := new_builtin_function_node(checker.ctx, name, args, return_arg); builtin_node := new_builtin_function_node(checker.ctx, name, args, return_arg);
@@ -771,7 +776,7 @@ new_builtin_function :: (checker : *Semantic_Checker, name : string, args : []Ar
function.name = name; function.name = name;
function.source_node = builtin_node; function.source_node = builtin_node;
function.type_variable = handle; function.type_variable = handle;
function.builtin = true;
find_result := find_symbol(checker, name, checker.current_scope); find_result := find_symbol(checker, name, checker.current_scope);
if !find_result { if !find_result {
@@ -822,13 +827,13 @@ add_child :: (variable : *Type_Variable, child : Type_Variable_Handle) {
// variable.children.count += 1; // variable.children.count += 1;
} }
add_child :: (checker : *Semantic_Checker, handle : Type_Variable_Handle, child : Type_Variable_Handle) { add_child :: (checker : *Checker, handle : Type_Variable_Handle, child : Type_Variable_Handle) {
variable := from_handle(checker, handle); variable := from_handle(checker, handle);
assert(variable.children.count < Type_Variable.MAX_TYPE_VARIABLE_CHILDREN); assert(variable.children.count < Type_Variable.MAX_TYPE_VARIABLE_CHILDREN);
array_add(*variable.children, child); array_add(*variable.children, child);
} }
init_semantic_checker :: (checker : *Semantic_Checker, root : *AST_Node, path : string) { init_semantic_checker :: (checker : *Checker, root : *AST_Node, path : string) {
checker.current_buffer_index = 0; checker.current_buffer_index = 0;
checker.current_sampler_index = 0; checker.current_sampler_index = 0;
checker.current_texture_index = 0; checker.current_texture_index = 0;
@@ -864,11 +869,11 @@ find_symbol :: (scope_stack : Scope_Stack, name : string, current_scope : Scope_
return null; return null;
} }
find_symbol :: (checker : *Semantic_Checker, name : string, current_scope : Scope_Handle, containing_scope : *Scope_Handle = null) -> *Defined_Symbol { find_symbol :: (checker : *Checker, name : string, current_scope : Scope_Handle, containing_scope : *Scope_Handle = null) -> *Defined_Symbol {
return find_symbol(checker.ctx.scope_stack, name, current_scope, containing_scope); return find_symbol(checker.ctx.scope_stack, name, current_scope, containing_scope);
} }
find_symbol :: (name : string, checker : *Semantic_Checker, containing_scope : *Scope_Handle = null) -> *Defined_Symbol { find_symbol :: (name : string, checker : *Checker, containing_scope : *Scope_Handle = null) -> *Defined_Symbol {
return find_symbol(checker, name, checker.current_scope, containing_scope); return find_symbol(checker, name, checker.current_scope, containing_scope);
} }
@@ -877,11 +882,11 @@ from_handle :: (variables : []Type_Variable, handle : Type_Variable_Handle) -> *
return *variables[handle - 1]; return *variables[handle - 1];
} }
from_handle :: (checker : *Semantic_Checker, handle : Type_Variable_Handle) -> *Type_Variable { from_handle :: (checker : *Checker, handle : Type_Variable_Handle) -> *Type_Variable {
return from_handle(checker.ctx.type_variables, handle); return from_handle(checker.ctx.type_variables, handle);
} }
proper_type_to_string :: (builder : *String_Builder, variables : []Type_Variable, var : Type_Variable) { proper_type_to_string :: (ctx : *Compiler_Context, builder : *String_Builder, variables : []Type_Variable, var : Type_Variable) {
if var.type == { if var.type == {
case .Int; #through; case .Int; #through;
case .Half; #through; case .Half; #through;
@@ -900,7 +905,7 @@ proper_type_to_string :: (builder : *String_Builder, variables : []Type_Variable
if child.kind == .FieldList { if child.kind == .FieldList {
for field : child.children { for field : child.children {
var := field.type_variable; var := field.type_variable;
print_type_variable(builder, variables, var); print_type_variable(ctx, builder, variables, var);
if it_index != child.children.count - 1 { if it_index != child.children.count - 1 {
append(builder, ", "); append(builder, ", ");
@@ -915,10 +920,10 @@ proper_type_to_string :: (builder : *String_Builder, variables : []Type_Variable
append(builder, " -> ", ); append(builder, " -> ", );
return_var := from_handle(variables, var.return_type_variable); return_var := from_handle(variables, var.return_type_variable);
if is_proper(return_var) { if is_proper(return_var) {
proper_type_to_string(builder, variables, return_var); proper_type_to_string(ctx, builder, variables, return_var);
} else { } else {
append(builder, "[["); append(builder, "[[");
print_type_variable(builder, variables, var.return_type_variable); print_type_variable(ctx, builder, variables, var.return_type_variable);
append(builder, "]]", ); append(builder, "]]", );
} }
} else { } else {
@@ -931,7 +936,7 @@ proper_type_to_string :: (builder : *String_Builder, variables : []Type_Variable
} }
} }
proper_type_to_string :: (variables : []Type_Variable, var : Type_Variable, allocator := context.allocator) -> string { proper_type_to_string :: (ctx : *Compiler_Context, variables : []Type_Variable, var : Type_Variable, allocator := context.allocator) -> string {
if var.type == { if var.type == {
case .Int; #through; case .Int; #through;
case .Half; #through; case .Half; #through;
@@ -943,7 +948,7 @@ proper_type_to_string :: (variables : []Type_Variable, var : Type_Variable, allo
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder,, allocator); init_string_builder(*builder,, allocator);
proper_type_to_string(*builder, variables, var); proper_type_to_string(ctx, *builder, variables, var);
return builder_to_string(*builder,, allocator); return builder_to_string(*builder,, allocator);
} }
case .Struct; { case .Struct; {
@@ -954,7 +959,7 @@ proper_type_to_string :: (variables : []Type_Variable, var : Type_Variable, allo
return "______not proper type______"; return "______not proper type______";
} }
lookup_type :: (checker : *Semantic_Checker, scope : Scope_Handle, type_string : string, typename : *string = null) -> Type_Kind { lookup_type :: (checker : *Checker, scope : Scope_Handle, type_string : string, typename : *string = null) -> Type_Kind {
if type_string == { if type_string == {
case Typenames[Type_Kind.Int]; return .Int; case Typenames[Type_Kind.Int]; return .Int;
case Typenames[Type_Kind.Half]; return .Half; case Typenames[Type_Kind.Half]; return .Half;
@@ -980,18 +985,18 @@ lookup_type :: (checker : *Semantic_Checker, scope : Scope_Handle, type_string :
return .Invalid; return .Invalid;
} }
lookup_type :: (checker : *Semantic_Checker, scope : Scope_Handle, node : *AST_Node, typename : *string = null) -> Type_Kind { lookup_type :: (checker : *Checker, scope : Scope_Handle, node : *AST_Node, typename : *string = null) -> Type_Kind {
type_string := node.token.ident_value; type_string := node.token.ident_value;
return lookup_type(checker, scope, type_string, typename); return lookup_type(checker, scope, type_string, typename);
} }
check_block :: (checker : *Semantic_Checker, node : *AST_Node) { check_block :: (checker : *Checker, node : *AST_Node) {
for child : node.children { for child : node.children {
check_node(checker, child); check_node(checker, child);
} }
} }
declare_struct :: (checker : *Semantic_Checker, node : *AST_Node, name : string) -> Type_Variable_Handle { declare_struct :: (checker : *Checker, node : *AST_Node, name : string) -> Type_Variable_Handle {
variable, handle := new_type_variable(checker); variable, handle := new_type_variable(checker);
variable.type = .Struct; variable.type = .Struct;
variable.source_kind = .Declaration; variable.source_kind = .Declaration;
@@ -1034,15 +1039,17 @@ declare_struct :: (checker : *Semantic_Checker, node : *AST_Node, name : string)
return handle; return handle;
} }
declare_struct :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { declare_struct :: (checker : *Checker, node : *AST_Node) -> Type_Variable_Handle {
return declare_struct(checker, node, node.name); return declare_struct(checker, node, node.name);
} }
declare_properties :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { declare_properties :: (checker : *Checker, node : *AST_Node) -> Type_Variable_Handle {
name := ifx node.name.count == 0 then "properties" else node.name; name := ifx node.name.count == 0 then "properties" else node.name;
if node.name.count > 0 { if node.name.count > 0 {
checker.ctx.property_name = name; checker.ctx.property_name = name;
} else {
checker.ctx.property_name = "properties";
} }
type_var := declare_struct(checker, node, name); type_var := declare_struct(checker, node, name);
var := from_handle(checker, type_var); var := from_handle(checker, type_var);
@@ -1053,7 +1060,7 @@ declare_properties :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Va
return type_var; return type_var;
} }
declare_cbuffer :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { declare_cbuffer :: (checker : *Checker, node : *AST_Node) -> Type_Variable_Handle {
type_var := declare_struct(checker, node); type_var := declare_struct(checker, node);
var := from_handle(checker, type_var); var := from_handle(checker, type_var);
var.type = .CBuffer; var.type = .CBuffer;
@@ -1073,11 +1080,11 @@ get_actual_function_name :: (node : *AST_Node) -> string {
return name_to_check; return name_to_check;
} }
declare_foreign_function :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { declare_foreign_function :: (checker : *Checker, node : *AST_Node) -> Type_Variable_Handle {
return declare_function(checker, node, true); return declare_function(checker, node, true);
} }
declare_function :: (checker : *Semantic_Checker, node : *AST_Node, builtin : bool = false) -> Type_Variable_Handle { declare_function :: (checker : *Checker, node : *AST_Node, builtin : bool = false) -> Type_Variable_Handle {
if !node.foreign_declaration && !can_declare(checker, node.name) { if !node.foreign_declaration && !can_declare(checker, node.name) {
invalid_symbol_name(checker, node, "function"); invalid_symbol_name(checker, node, "function");
return 0; return 0;
@@ -1204,7 +1211,7 @@ declare_function :: (checker : *Semantic_Checker, node : *AST_Node, builtin : bo
return handle; return handle;
} }
check_function :: (checker : *Semantic_Checker, node : *AST_Node) { check_function :: (checker : *Checker, node : *AST_Node) {
name_to_check := get_actual_function_name(node); name_to_check := get_actual_function_name(node);
find_result := find_symbol(checker, name_to_check, checker.current_scope); find_result := find_symbol(checker, name_to_check, checker.current_scope);
@@ -1238,6 +1245,10 @@ check_function :: (checker : *Semantic_Checker, node : *AST_Node) {
stm := from_handle(checker, result_var); stm := from_handle(checker, result_var);
add_child(variable, result_var); add_child(variable, result_var);
} }
if statement.kind == .If_Directive {
break;
}
} }
} }
} }
@@ -1251,7 +1262,7 @@ check_function :: (checker : *Semantic_Checker, node : *AST_Node) {
} }
} }
check_variable :: (checker : *Semantic_Checker, node : *AST_Node, struct_field_parent : *AST_Node = null) -> Type_Variable_Handle { check_variable :: (checker : *Checker, node : *AST_Node, struct_field_parent : *AST_Node = null) -> Type_Variable_Handle {
find_result := find_symbol(checker, node.name, checker.current_scope); find_result := find_symbol(checker, node.name, checker.current_scope);
// x : int; // x : int;
// x.d = 5; // x.d = 5;
@@ -1296,7 +1307,7 @@ check_variable :: (checker : *Semantic_Checker, node : *AST_Node, struct_field_p
return 0; return 0;
} }
can_declare :: (checker : *Semantic_Checker, name : string) -> bool { can_declare :: (checker : *Checker, name : string) -> bool {
max_value := Type_Kind.Max_Builtin; max_value := Type_Kind.Max_Builtin;
for i : 0..max_value - 1 { for i : 0..max_value - 1 {
@@ -1309,7 +1320,7 @@ can_declare :: (checker : *Semantic_Checker, name : string) -> bool {
} }
//@Incomplete(niels): Handle meta stuff here //@Incomplete(niels): Handle meta stuff here
check_field :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { check_field :: (checker : *Checker, node : *AST_Node) -> Type_Variable_Handle {
variable, handle := new_type_variable(checker); variable, handle := new_type_variable(checker);
variable.name = node.name; variable.name = node.name;
typename : string; typename : string;
@@ -1393,7 +1404,7 @@ check_field :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_
return handle; return handle;
} }
check_call :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Variable_Handle) -> error : bool { check_call :: (checker : *Checker, node : *AST_Node, type_var : Type_Variable_Handle) -> error : bool {
find_result := find_symbol(checker, node.name, checker.current_scope); find_result := find_symbol(checker, node.name, checker.current_scope);
if !find_result { if !find_result {
@@ -1505,7 +1516,7 @@ check_call :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Va
return false; return false;
} }
check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { check_node :: (checker : *Checker, node : *AST_Node) -> Type_Variable_Handle {
if node.kind == { if node.kind == {
case .Function; { case .Function; {
check_function(checker, node); check_function(checker, node);
@@ -1645,8 +1656,7 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
} }
} }
case .If_Directive; { case .If_Directive; {
cond_var := check_node(checker, node.children[0]); check_if_directive(checker, node);
assert(false, "Not implemented yet\n");
} }
case .Variable; { case .Variable; {
return check_variable(checker, node); return check_variable(checker, node);
@@ -1686,9 +1696,85 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
return 0; return 0;
} }
traverse :: (checker : *Semantic_Checker, root : *AST_Node) { is_valid_define :: (checker : *Checker, def : string) -> bool {
declarations := root.children; for env_def : checker.ctx.environment.defines {
for declaration : declarations { if env_def == def {
return true;
}
}
return false;
}
check_env_expression :: (checker : *Checker, expr : *AST_Node, directive : *AST_Node) -> bool {
if expr.kind == .Binary {
lhs := expr.children[0];
rhs := expr.children[1];
lhs_valid := check_env_expression(checker, lhs, directive);
rhs_valid := check_env_expression(checker, rhs, directive);
if expr.token.kind == .TOKEN_LOGICALOR {
return lhs_valid || rhs_valid;
} else if expr.token.kind == .TOKEN_LOGICALAND {
return lhs_valid && rhs_valid;
}
} else if expr.kind == .Variable {
if expr.name == "Env" {
child := expr.children[0]; // The variable in the environment
return is_valid_define(checker, child.name);
}
}
return false;
}
check_if_directive :: (checker : *Checker, directive : *AST_Node) {
cond := directive.children[0];
is_valid := check_env_expression(checker, cond, directive);
if is_valid {
parent := directive.parent;
first_child : *AST_Node = directive.children[1];
if checker.current_scope == 1 {
traverse(checker, first_child);
} else {
check_block(checker, first_child);
}
for child : directive.children[1].children {
add_child(parent, child);
}
if directive.children.count > 2 {
directive.children.count = 0;
}
} else if directive.children.count > 2 {
parent := directive.parent;
else_branch := directive.children[2];
if else_branch.kind == .If_Directive {
check_if_directive(checker, else_branch);
} else {
for child : else_branch.children {
add_child(parent, child);
}
if checker.current_scope == 1 {
if else_branch.kind == .If_Directive {
check_declaration(checker, else_branch);
} else {
traverse(checker, else_branch);
}
}
}
directive.children.count = 0;
}
}
check_declaration :: (checker : *Checker, declaration : *AST_Node) {
if declaration.kind == .Function { if declaration.kind == .Function {
if declaration.foreign_declaration { if declaration.foreign_declaration {
fun_handle := declare_foreign_function(checker, declaration); fun_handle := declare_foreign_function(checker, declaration);
@@ -1701,23 +1787,35 @@ traverse :: (checker : *Semantic_Checker, root : *AST_Node) {
declare_struct(checker, declaration); declare_struct(checker, declaration);
} else if declaration.kind == .CBuffer { } else if declaration.kind == .CBuffer {
declare_cbuffer(checker, declaration); declare_cbuffer(checker, declaration);
} else if declaration.kind == .If_Directive {
check_if_directive(checker, declaration);
} }
} }
traverse :: (checker : *Checker, root : *AST_Node) {
declarations := root.children;
for declaration : declarations {
check_declaration(checker, declaration);
}
if checker.had_error { if checker.had_error {
return; return;
} }
for declaration : declarations { for declaration : declarations {
if declaration.kind == .If_Directive {
continue;
}
check_node(checker, declaration); check_node(checker, declaration);
} }
} }
traverse :: (checker : *Semantic_Checker) { traverse :: (checker : *Checker) {
traverse(checker, checker.program_root); traverse(checker, checker.program_root);
} }
types_compatible :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rhs : Type_Variable_Handle, param_matching : bool = false) -> bool { types_compatible :: (checker : *Checker, lhs : Type_Variable_Handle, rhs : Type_Variable_Handle, param_matching : bool = false) -> bool {
lhs_var := from_handle(checker, lhs); lhs_var := from_handle(checker, lhs);
rhs_var := from_handle(checker, rhs); rhs_var := from_handle(checker, rhs);
@@ -1797,7 +1895,7 @@ types_compatible :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rh
return false; return false;
} }
add_builtins_new :: (checker : *Semantic_Checker) { add_builtins_new :: (checker : *Checker) {
checker.state = .Adding_Builtins; checker.state = .Adding_Builtins;
float_name := Typenames[Type_Kind.Float]; float_name := Typenames[Type_Kind.Float];
@@ -2065,7 +2163,7 @@ add_builtins_new :: (checker : *Semantic_Checker) {
checker.state = .Type_Checking; checker.state = .Type_Checking;
} }
add_builtins :: (checker : *Semantic_Checker) { add_builtins :: (checker : *Checker) {
source_location := #location().fully_pathed_filename; source_location := #location().fully_pathed_filename;
path_array := split(source_location, "/"); path_array := split(source_location, "/");
@@ -2084,7 +2182,7 @@ add_builtins :: (checker : *Semantic_Checker) {
if !ok { if !ok {
messages : [..]Compiler_Message; messages : [..]Compiler_Message;
internal_error_message(*messages, "Error loading builtin functions.", checker.path); internal_error_message(*messages, "Error loading builtin functions.", checker.path);
print("%\n", report_messages(messages)); print("%\n", report_messages(checker.ctx, messages));
assert(false); assert(false);
return; return;
} }
@@ -2123,7 +2221,7 @@ add_builtins :: (checker : *Semantic_Checker) {
checker.ctx.tokens = prev_tokens; checker.ctx.tokens = prev_tokens;
} }
type_check :: (checker : *Semantic_Checker, root : *AST_Node) { type_check :: (checker : *Checker, root : *AST_Node) {
traverse(checker, root); traverse(checker, root);
} }
@@ -2138,7 +2236,7 @@ check :: (ctx : *Compiler_Context, allocator : Allocator = temp) {
init_context_allocators(); init_context_allocators();
defer clear_context_allocators(); defer clear_context_allocators();
checker : Semantic_Checker; checker : Checker;
checker.current_buffer_index = 0; checker.current_buffer_index = 0;
checker.current_sampler_index = 0; checker.current_sampler_index = 0;
@@ -2255,7 +2353,7 @@ pretty_print_struct :: (scope_stack : *Scope_Stack, current_scope : Scope_Handle
append(builder, "}\n"); append(builder, "}\n");
} }
pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack, variables : []Type_Variable, scope : *Scope, builder : *String_Builder, indentation : int = 0) { pretty_print_scope :: (ctx : *Compiler_Context, current_scope : Scope_Handle, scope_stack : Scope_Stack, variables : []Type_Variable, scope : *Scope, builder : *String_Builder, indentation : int = 0) {
if scope.builtin { if scope.builtin {
return; return;
} }
@@ -2291,7 +2389,7 @@ pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack,
if type_variable.typename.count > 0 && type_variable.source_kind != .Declaration { if type_variable.typename.count > 0 && type_variable.source_kind != .Declaration {
indent(builder, indentation + 1); indent(builder, indentation + 1);
print_key(*scope_stack, current_scope, builder, key); print_key(*scope_stack, current_scope, builder, key);
print_type_variable(builder, variables, type_variable); print_type_variable(ctx, builder, variables, type_variable);
append(builder, "\n"); append(builder, "\n");
// print_to_builder(builder, "%\n", type_variable.typename); // print_to_builder(builder, "%\n", type_variable.typename);
} else { } else {
@@ -2334,7 +2432,7 @@ pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack,
for child : scope.children { for child : scope.children {
child_scope := *scope_stack.stack[child - 1]; child_scope := *scope_stack.stack[child - 1];
pretty_print_scope(current_scope, *scope_stack, variables, child_scope, builder, indentation + 1); pretty_print_scope(ctx, current_scope, *scope_stack, variables, child_scope, builder, indentation + 1);
} }
if scope.table.count > 0 { if scope.table.count > 0 {
@@ -2343,7 +2441,7 @@ pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack,
append(builder, "]\n"); append(builder, "]\n");
} }
print_type_variable :: (builder : *String_Builder, variables : []Type_Variable, variable : Type_Variable) { print_type_variable :: (ctx : *Compiler_Context, builder : *String_Builder, variables : []Type_Variable, variable : Type_Variable) {
if variable.builtin { if variable.builtin {
if variable.type != .Function || variable.type != .Struct { if variable.type != .Function || variable.type != .Struct {
print_to_builder(builder, "%", type_to_string(variable)); print_to_builder(builder, "%", type_to_string(variable));
@@ -2391,13 +2489,13 @@ print_type_variable :: (builder : *String_Builder, variables : []Type_Variable,
source_location.end = right_most.source_location.main_token; source_location.end = right_most.source_location.main_token;
source_location.main_token = node.source_location.main_token; source_location.main_token = node.source_location.main_token;
print("%\n", print_from_source_location(builder, source_location,, temp)); print("%\n", print_from_source_location(ctx, builder, source_location,, temp));
} }
case .Call; { case .Call; {
if variable.return_type_variable{ if variable.return_type_variable{
assert(false); assert(false);
print_to_builder(builder, "%", variable.typename); print_to_builder(builder, "%", variable.typename);
print_type_variable(builder, variables, variable.return_type_variable); print_type_variable(ctx, builder, variables, variable.return_type_variable);
} }
print_to_builder(builder, "%(", node.name); print_to_builder(builder, "%(", node.name);
@@ -2406,7 +2504,7 @@ print_type_variable :: (builder : *String_Builder, variables : []Type_Variable,
for child : node.children { for child : node.children {
if child.kind == .ArgList { if child.kind == .ArgList {
for arg : child.children { for arg : child.children {
print_type_variable(builder, variables, arg.type_variable); print_type_variable(ctx, builder, variables, arg.type_variable);
if it_index < child.children.count - 1 { if it_index < child.children.count - 1 {
append(builder, ", "); append(builder, ", ");
@@ -2418,23 +2516,23 @@ print_type_variable :: (builder : *String_Builder, variables : []Type_Variable,
append(builder, ")"); append(builder, ")");
} }
case; { case; {
print("%\n", print_from_source_location(builder, node.source_location,, temp)); print("%\n", print_from_source_location(ctx, builder, node.source_location,, temp));
} }
} }
} }
} }
} }
print_type_variable :: (builder : *String_Builder, variables : []Type_Variable, handle : Type_Variable_Handle) { print_type_variable :: (ctx : *Compiler_Context, builder : *String_Builder, variables : []Type_Variable, handle : Type_Variable_Handle) {
variable := from_handle(variables, handle); variable := from_handle(variables, handle);
print_type_variable(builder, variables, variable); print_type_variable(ctx, builder, variables, variable);
} }
pretty_print_symbol_table :: (checker : *Semantic_Checker, allocator : Allocator) -> string { pretty_print_symbol_table :: (checker : *Checker, allocator : Allocator) -> string {
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder,, allocator); init_string_builder(*builder,, allocator);
pretty_print_scope(xx checker.current_scope, checker.ctx.scope_stack, checker.ctx.type_variables, *checker.ctx.scope_stack.stack[0], *builder); pretty_print_scope(checker.ctx, xx checker.current_scope, checker.ctx.scope_stack, checker.ctx.type_variables, *checker.ctx.scope_stack.stack[0], *builder);
return builder_to_string(*builder,, allocator); return builder_to_string(*builder,, allocator);
} }
@@ -2444,7 +2542,7 @@ pretty_print_symbol_table :: (ctx : *Compiler_Context, allocator : Allocator) ->
init_string_builder(*builder,, allocator); init_string_builder(*builder,, allocator);
current_scope := cast(Scope_Handle)1; current_scope := cast(Scope_Handle)1;
pretty_print_scope(current_scope, ctx.scope_stack, ctx.type_variables, *ctx.scope_stack.stack[0], *builder); pretty_print_scope(ctx, current_scope, ctx.scope_stack, ctx.type_variables, *ctx.scope_stack.stack[0], *builder);
return builder_to_string(*builder,, allocator); return builder_to_string(*builder,, allocator);
} }

View File

@@ -11,17 +11,14 @@ Output_Language :: enum {
HLSL; HLSL;
GLSL; // @Incomplete GLSL; // @Incomplete
MLSL; // @Incomplete MLSL; // @Incomplete
// SPIRV; // @Incomplete: Should we do this?
} }
Codegen_State :: struct { Codegen_State :: struct {
path : string; path : string;
// scope_stack : Scope_Stack;
current_scope : Scope_Handle; current_scope : Scope_Handle;
// type_variables : []Type_Variable;
// root : *AST_Node;
output_language : Output_Language; output_language : Output_Language;
builder : String_Builder; builder : String_Builder;
@@ -29,14 +26,6 @@ Codegen_State :: struct {
result : *Compiler_Context; result : *Compiler_Context;
} }
// Codegen_Result :: struct {
// messages : [..]Compiler_Message;
// had_error : bool;
// result_text : string; // @Incomplete(nb): Result for now, should likely be far more sophisticated.
// }
Reserved_HLSL_Words :: string.[ Reserved_HLSL_Words :: string.[
"texture", "texture",
"sampler", "sampler",
@@ -132,26 +121,23 @@ emit_field :: (state : *Codegen_State, node : *AST_Node, indentation : int) {
print_to_builder(*state.builder, " = "); print_to_builder(*state.builder, " = ");
emit_node(state, child, 0); emit_node(state, child, 0);
} }
if node.parent.kind == .Block { if node.parent.kind == .Block {
append(*state.builder, ";"); append(*state.builder, ";");
} }
for i :0..field.children.count - 1 { for i :0..field.children.count - 1 {
child := from_handle(state.result.type_variables, field.children[i]); child := from_handle(state.result.type_variables, field.children[i]);
emit_node(state, child.source_node, 0); emit_node(state, child.source_node, 0);
} }
for hint : node.hint_tokens { for hint : node.hint_tokens {
if hint.ident_value == "position" { if lookup_hint(hint.ident_value) == .Position {
// @Incomplete(nb): Should be a lookup table somewhere
append(*state.builder, " : POSITION"); append(*state.builder, " : POSITION");
} else if hint.ident_value == "uv" { } else if lookup_hint(hint.ident_value) == .UV {
append(*state.builder, " : TEXCOORD0"); append(*state.builder, " : TEXCOORD0");
} else if hint.ident_value == "outposition" { } else if lookup_hint(hint.ident_value) == .Output_Position {
append(*state.builder, " : SV_POSITION"); append(*state.builder, " : SV_POSITION");
} }
} }

View File

@@ -102,20 +102,20 @@ copy_messages :: (source : []Compiler_Message, dest : *[..]Compiler_Message) {
} }
} }
report_messages :: (messages : []Compiler_Message) -> string { report_messages :: (ctx : *Compiler_Context, messages : []Compiler_Message) -> string {
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder); init_string_builder(*builder);
for message : messages { for message : messages {
report_message(*builder, message); report_message(ctx, *builder, message);
} }
return builder_to_string(*builder); return builder_to_string(*builder);
} }
report_message :: (builder : *String_Builder, message : Compiler_Message) { report_message :: (ctx : *Compiler_Context, builder : *String_Builder, message : Compiler_Message) {
report_message(builder, message.path, message.message, message.source_locations, message.message_kind, message.report_source_location); report_message(ctx, builder, message.path, message.message, message.source_locations, message.message_kind, message.report_source_location);
} }
report_message :: (builder : *String_Builder, path : string, message : string, source_locations : []Source_Range, kind : Message_Kind, report_source_location : bool = false) { report_message :: (ctx : *Compiler_Context, builder : *String_Builder, path : string, message : string, source_locations : []Source_Range, kind : Message_Kind, report_source_location : bool = false) {
append(builder, "\x1b[1;37m"); append(builder, "\x1b[1;37m");
if path.count > 0 { if path.count > 0 {
print_to_builder(builder, "%:", path); print_to_builder(builder, "%:", path);
@@ -140,7 +140,7 @@ report_message :: (builder : *String_Builder, path : string, message : string, s
if report_source_location { if report_source_location {
for location : source_locations { for location : source_locations {
append(builder, "\t"); append(builder, "\t");
print_from_source_location(builder, location); print_from_source_location(ctx, builder, location);
append(builder, "\n\t"); append(builder, "\n\t");
begin := location.begin; begin := location.begin;

60
Ink.jai
View File

@@ -23,7 +23,7 @@ LEXER_FOLDER :: "lex";
PARSER_FOLDER :: "parse"; PARSER_FOLDER :: "parse";
CODEGEN_FOLDER :: "codegen"; CODEGEN_FOLDER :: "codegen";
COMPILED_FOLDER :: "compiled"; COMPILED_FOLDER :: "compiled";
SEMANTIC_ANALYSIS_FOLDER :: "semant"; CHECK_FOLDER :: "check";
TESTS_FOLDER :: "test"; TESTS_FOLDER :: "test";
SHADER_EXTENSION :: "ink"; SHADER_EXTENSION :: "ink";
@@ -32,7 +32,7 @@ SUITE_EXTENSION :: "suite";
Stage_Flags :: enum_flags u16 { Stage_Flags :: enum_flags u16 {
Lexer :: 0x1; Lexer :: 0x1;
Parser :: 0x2; Parser :: 0x2;
Semantic_Analysis :: 0x4; Check :: 0x4;
Codegen :: 0x8; Codegen :: 0x8;
Compile :: 0x10; Compile :: 0x10;
} }
@@ -97,10 +97,10 @@ get_golden_path :: (file_path : string, stage : Stage_Flags) -> string {
make_directory_if_it_does_not_exist(dir); make_directory_if_it_does_not_exist(dir);
array_add(*path.words, PARSER_FOLDER); array_add(*path.words, PARSER_FOLDER);
} }
case .Semantic_Analysis; { case .Check; {
dir := tprint("%/%", TESTS_FOLDER, SEMANTIC_ANALYSIS_FOLDER); dir := tprint("%/%", TESTS_FOLDER, CHECK_FOLDER);
make_directory_if_it_does_not_exist(dir); make_directory_if_it_does_not_exist(dir);
array_add(*path.words, SEMANTIC_ANALYSIS_FOLDER); array_add(*path.words, CHECK_FOLDER);
} }
case .Codegen; { case .Codegen; {
dir := tprint("%/%", TESTS_FOLDER, CODEGEN_FOLDER); dir := tprint("%/%", TESTS_FOLDER, CODEGEN_FOLDER);
@@ -189,7 +189,7 @@ run_codegen_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) ->
if ctx.had_error { if ctx.had_error {
result.type = .Failed; result.type = .Failed;
result_text = report_messages(ctx.messages); result_text = report_messages(ctx, ctx.messages);
return result; return result;
} }
@@ -227,6 +227,22 @@ run_compile_test :: (path : string, output_type : Output_Type = 0) -> Result, Co
print_to_builder(*sb, "[pixel entry point] - %\n", ctx.pixel_entry_point.name); print_to_builder(*sb, "[pixel entry point] - %\n", ctx.pixel_entry_point.name);
} }
if ctx.properties.fields.count > 0{
props := ctx.properties;
append(*sb, "[");
if ctx.property_name.count > 0 {
print_to_builder(*sb, "% :: ", ctx.property_name);
}
print_to_builder(*sb, "properties] - %\n", props.buffer_index);
indent(*sb, 1);
for field : props.fields {
append(*sb, "[field] - ");
pretty_print_field(*sb, *field.base_field);
}
}
for cb : ctx.cbuffers { for cb : ctx.cbuffers {
print_to_builder(*sb, "[constant_buffer] - % - %\n", cb.name, cb.buffer_index); print_to_builder(*sb, "[constant_buffer] - % - %\n", cb.name, cb.buffer_index);
@@ -261,7 +277,7 @@ run_lexer_test :: (file_path : string, ctx : *Compiler_Context, output_type : Ou
lex(ctx); lex(ctx);
if ctx.had_error { if ctx.had_error {
result.type = .Failed; result.type = .Failed;
result_text = report_messages(ctx.messages); result_text = report_messages(ctx, ctx.messages);
} else { } else {
result_text = pretty_print_tokens(ctx.tokens, context.allocator); result_text = pretty_print_tokens(ctx.tokens, context.allocator);
} }
@@ -300,7 +316,7 @@ run_parser_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) -> R
if ctx.had_error { if ctx.had_error {
result.type = .Failed; result.type = .Failed;
result_text = report_messages(ctx.messages); result_text = report_messages(ctx, ctx.messages);
} else { } else {
result_text = pretty_print_ast(ctx.root, context.allocator); result_text = pretty_print_ast(ctx.root, context.allocator);
} }
@@ -316,7 +332,7 @@ run_parser_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) -> R
return result; return result;
} }
run_semantic_analysis_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) -> Result { run_check_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) -> Result {
result : Result; result : Result;
result.path = ctx.file.path; result.path = ctx.file.path;
result_text : string; result_text : string;
@@ -325,7 +341,7 @@ run_semantic_analysis_test :: (ctx : *Compiler_Context, output_type : Output_Typ
if ctx.had_error { if ctx.had_error {
result.type = .Failed; result.type = .Failed;
result_text = report_messages(ctx.messages); result_text = report_messages(ctx, ctx.messages);
} else { } else {
result_text = pretty_print_symbol_table(ctx, context.allocator); result_text = pretty_print_symbol_table(ctx, context.allocator);
} }
@@ -336,12 +352,12 @@ run_semantic_analysis_test :: (ctx : *Compiler_Context, output_type : Output_Typ
return result; return result;
} }
golden_path := get_golden_path(ctx.file.path, .Semantic_Analysis); golden_path := get_golden_path(ctx.file.path, .Check);
do_golden_comparison(golden_path, result_text, *result, output_type); do_golden_comparison(golden_path, result_text, *result, output_type);
return result; return result;
} }
run_semantic_analysis_test :: (file_path : string, ctx : *Compiler_Context, output_type : Output_Type = 0) -> Result { run_check_test :: (file_path : string, ctx : *Compiler_Context, output_type : Output_Type = 0) -> Result {
result : Result; result : Result;
result.path = file_path; result.path = file_path;
@@ -352,7 +368,7 @@ run_semantic_analysis_test :: (file_path : string, ctx : *Compiler_Context, outp
return result; return result;
} }
result = run_semantic_analysis_test(ctx, output_type); result = run_check_test(ctx, output_type);
return result; return result;
} }
@@ -389,17 +405,17 @@ run_test_new :: (file_path : string, stage_flags : Stage_Flags, results : *[..]R
record_result(results, result); record_result(results, result);
} }
if stage_flags & .Semantic_Analysis { if stage_flags & .Check {
if stage_flags & .Parser && (result.type == .Passed || result.type == .Golden_Output) { if stage_flags & .Parser && (result.type == .Passed || result.type == .Golden_Output) {
result = run_semantic_analysis_test(*ctx, output_type); result = run_check_test(*ctx, output_type);
} else { } else {
result = run_semantic_analysis_test(file_path, *ctx, output_type); result = run_check_test(file_path, *ctx, output_type);
} }
record_result(results, result); record_result(results, result);
} }
if stage_flags & .Codegen { if stage_flags & .Codegen {
if stage_flags & .Semantic_Analysis && (result.type == .Passed || result.type == .Golden_Output) { if stage_flags & .Check && (result.type == .Passed || result.type == .Golden_Output) {
result = run_codegen_test(*ctx, output_type); result = run_codegen_test(*ctx, output_type);
} else { } else {
result = run_codegen_test(file_path, *ctx, output_type); result = run_codegen_test(file_path, *ctx, output_type);
@@ -554,8 +570,8 @@ read_suite :: (file_path : string, suite : *Test_Suite, allocator := temp) -> bo
stage_flags |= .Lexer; stage_flags |= .Lexer;
} else if equal(trimmed, "parse") { } else if equal(trimmed, "parse") {
stage_flags |= .Parser; stage_flags |= .Parser;
} else if equal(trimmed, "semant") { } else if equal(trimmed, "check") {
stage_flags |= .Semantic_Analysis; stage_flags |= .Check;
} else if equal(trimmed, "codegen") { } else if equal(trimmed, "codegen") {
stage_flags |= .Codegen; stage_flags |= .Codegen;
} else if equal(trimmed, "compile") { } else if equal(trimmed, "compile") {
@@ -577,7 +593,7 @@ stage_to_string :: (stage : Stage_Flags) -> string {
if #complete stage == { if #complete stage == {
case .Lexer; return "lexing"; case .Lexer; return "lexing";
case .Parser; return "parsing"; case .Parser; return "parsing";
case .Semantic_Analysis; return "semantic checking"; case .Check; return "checking";
case .Codegen; return "codegen"; case .Codegen; return "codegen";
case .Compile; return "compiled"; case .Compile; return "compiled";
case; return ""; case; return "";
@@ -671,8 +687,8 @@ main :: () {
current_suite.test_cases[cases - 1].stage_flags |= .Lexer; current_suite.test_cases[cases - 1].stage_flags |= .Lexer;
} else if arg == "-parse" { } else if arg == "-parse" {
current_suite.test_cases[cases - 1].stage_flags |= .Parser; current_suite.test_cases[cases - 1].stage_flags |= .Parser;
} else if arg == "-semant" { } else if arg == "-check" {
current_suite.test_cases[cases - 1].stage_flags |= .Semantic_Analysis; current_suite.test_cases[cases - 1].stage_flags |= .Check;
} else if arg == "-codegen" { } else if arg == "-codegen" {
current_suite.test_cases[cases - 1].stage_flags |= .Codegen; current_suite.test_cases[cases - 1].stage_flags |= .Codegen;
} else if arg == "-compile" { } else if arg == "-compile" {

View File

@@ -11,6 +11,7 @@ Lexer :: struct {
} }
Token_Kind :: enum { Token_Kind :: enum {
TOKEN_INVALID :: 0;
TOKEN_FLOATLITERAL; TOKEN_FLOATLITERAL;
TOKEN_INTLITERAL; TOKEN_INTLITERAL;
@@ -386,7 +387,12 @@ make_directive :: (lexer : *Lexer) -> *Token {
for tok : ctx.tokens { for tok : ctx.tokens {
lexer.ctx.tokens[it_index] = tok; lexer.ctx.tokens[it_index] = tok;
} }
return scan_next_token(lexer);; return scan_next_token(lexer);
} else if ident.ident_value == "add_define" {
new_define := scan_next_token(lexer);
add_define(*lexer.ctx.environment, new_define.ident_value);
lexer.ctx.tokens.count -= 2;
return scan_next_token(lexer);
} }
return ident; return ident;
} }
@@ -739,10 +745,25 @@ print_token_pointer :: (builder : *String_Builder, token : Token) {
} }
} }
print_from_source_location :: (builder : *String_Builder, source_location : Source_Range, indentation : int = 0) { print_from_source_location :: (ctx : *Compiler_Context, builder : *String_Builder, source_location : Source_Range, indentation : int = 0) {
current := source_location.begin; current := source_location.begin;
begin := source_location.begin; begin := source_location.begin;
end := source_location.end; end := source_location.end;
if begin.builtin {
for i : begin.index..end.index - 1 {
tok := ctx.tokens[i];
text : string;
text.data = tok.source;
text.count = tok.length;
print_to_builder(builder, "%", text);
}
return;
} else {
}
begin_pos := 0; begin_pos := 0;
token_string : string; token_string : string;
count := end.index - begin.index + end.length; count := end.index - begin.index + end.length;
@@ -769,12 +790,12 @@ print_from_source_location :: (builder : *String_Builder, source_location : Sour
} }
} }
print_from_source_location :: (source_location : Source_Range, allocator := context.allocator, indentation : int = 0) -> string { print_from_source_location :: (ctx : *Compiler_Context, source_location : Source_Range, allocator := context.allocator, indentation : int = 0) -> string {
sc := get_scratch(); sc := get_scratch();
defer scratch_end(sc); defer scratch_end(sc);
builder : String_Builder; builder : String_Builder;
init_string_builder(*builder,, sc.allocator); init_string_builder(*builder,, sc.allocator);
print_from_source_location(*builder, source_location,, sc.allocator); print_from_source_location(ctx, *builder, source_location,, sc.allocator);
return builder_to_string(*builder,, allocator); return builder_to_string(*builder,, allocator);
} }

View File

@@ -186,7 +186,7 @@ unexpected_token :: (state : *Parse_State, token : Token, message : string) {
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, token); print_token_pointer(*builder, token);
@@ -207,7 +207,7 @@ else_if_without_if :: (state : *Parse_State) {
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, token); print_token_pointer(*builder, token);
@@ -229,7 +229,7 @@ else_without_if :: (state : *Parse_State) {
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, token); print_token_pointer(*builder, token);
@@ -249,7 +249,7 @@ unable_to_parse_statement :: (state : *Parse_State, token : Token, message : str
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
@@ -269,7 +269,7 @@ expected_expression :: (state : *Parse_State, token : Token, message : string) {
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
print_token_pointer(*builder, token); print_token_pointer(*builder, token);
@@ -288,7 +288,7 @@ missing_type_specifier :: (state : *Parse_State, token : Token, message : string
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
loc := location.begin; loc := location.begin;
@@ -312,7 +312,7 @@ empty_block :: (state : *Parse_State, token : Token, message : string) {
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
loc := location.begin; loc := location.begin;
@@ -336,7 +336,26 @@ unable_to_open_file :: (state : *Parse_State, path : string, token : Token) {
indent(*builder, 1); indent(*builder, 1);
cyan(*builder); cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(location)); print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1);
loc := location.begin;
print_token_pointer(*builder, loc);
final_message := builder_to_string(*builder);
record_error(state, token, final_message, false);
}
entry_point_requires_return_value :: (state : *Parse_State, token : Token) {
builder : String_Builder;
init_string_builder(*builder,, temp);
print_to_builder(*builder, "Entry point '%' requires return value\n\n", token.ident_value);
location := generate_source_location_from_token(state, token);
indent(*builder, 1);
cyan(*builder);
print_to_builder(*builder, "%\n", print_from_source_location(state.ctx, location));
indent(*builder, 1); indent(*builder, 1);
loc := location.begin; loc := location.begin;
@@ -383,29 +402,14 @@ make_node :: (parse_state : *Parse_State, kind : AST_Kind) -> *AST_Node {
return make_node(*parse_state.ctx.nodes, kind); return make_node(*parse_state.ctx.nodes, kind);
} }
// new_builtin_node :: (nodes : *[..]AST_Node, kind : AST_Kind) -> *AST_Node { make_builtin_token :: (tokens : *[..]Token, kind : Token_Kind, text : string, col : *int, line : *int) -> *Token {
// node := make_node(parse_state, kind);
// node.builtin = true;
// return node;
// }
make_builtin_token :: (tokens : *[..]Token, builder : *String_Builder, kind : Token_Kind, text : string, col : *int, line : *int) -> *Token {
tok : Token; tok : Token;
tok.kind = kind; tok.kind = kind;
start := 0; start := 0;
buffer := get_current_buffer(builder);
if buffer {
start := buffer.count;
}
tok.column = col.*; tok.column = col.*;
print_to_builder(builder, "%", text);
buffer = get_current_buffer(builder);
end := buffer.count;
for c : text { for c : text {
if c == #char "\n" { if c == #char "\n" {
line.* ++ 1; line.* ++ 1;
@@ -415,9 +419,11 @@ make_builtin_token :: (tokens : *[..]Token, builder : *String_Builder, kind : To
} }
} }
tok.index = buffer.count - text.count; tok.index = tokens.count;
tok.length = text.count; tok.length = text.count;
tok.builtin = true; tok.builtin = true;
tok.source = text.data;
tok.ident_value = text;
array_add(tokens, tok); array_add(tokens, tok);
@@ -427,9 +433,6 @@ make_builtin_token :: (tokens : *[..]Token, builder : *String_Builder, kind : To
new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : []Arg) -> *AST_Node { new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : []Arg) -> *AST_Node {
sc := get_scratch(context.allocator); sc := get_scratch(context.allocator);
defer scratch_end(sc); defer scratch_end(sc);
builder : String_Builder;
builder.allocator = sc.allocator; // I want to find a good way to use scratch here...
node := make_node(*ctx.nodes, .Struct); node := make_node(*ctx.nodes, .Struct);
source_location : Source_Range; source_location : Source_Range;
@@ -439,17 +442,13 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : []
tok_index := ctx.tokens.count; tok_index := ctx.tokens.count;
ident_token := make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", name), *col, *line); ident_token := make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, name, *col, *line);
ident_token.ident_value = name; ident_token.ident_value = name;
source_location.begin = ident_token; source_location.begin = ident_token;
append(*builder, " "); make_builtin_token(*ctx.tokens, .TOKEN_DOUBLECOLON, " :: ", *col, *line);
make_builtin_token(*ctx.tokens, *builder, .TOKEN_DOUBLECOLON, "::", *col, *line); make_builtin_token(*ctx.tokens, .TOKEN_STRUCT, "struct ", *col, *line);
append(*builder, " "); make_builtin_token(*ctx.tokens, .TOKEN_LEFTBRACE, "{\n\t", *col, *line);
make_builtin_token(*ctx.tokens, *builder, .TOKEN_STRUCT, "struct", *col, *line);
append(*builder, " ");
make_builtin_token(*ctx.tokens, *builder, .TOKEN_LEFTBRACE, "{", *col, *line);
append(*builder, "\n");
line += 1; line += 1;
col = 0; col = 0;
@@ -460,18 +459,14 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : []
field := make_node(*ctx.nodes, .Field); field := make_node(*ctx.nodes, .Field);
field_source_loc : Source_Range; field_source_loc : Source_Range;
indent(*builder, 1); field_ident := make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, member.name, *col, *line);
field_ident := make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", member.name), *col, *line);
field_source_loc.begin = field_ident; field_source_loc.begin = field_ident;
field.token = field_ident; field.token = field_ident;
field.name = member.name; field.name = member.name;
append(*builder, " "); make_builtin_token(*ctx.tokens, .TOKEN_COLON, ": ", *col, *line);
make_builtin_token(*ctx.tokens, *builder, .TOKEN_COLON, ":", *col, *line); make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, member.typename, *col, *line);
append(*builder, " "); semicolon_tok := make_builtin_token(*ctx.tokens, .TOKEN_SEMICOLON, ";", *col, *line);
make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", member.typename), *col, *line);
semicolon_tok := make_builtin_token(*ctx.tokens, *builder, .TOKEN_SEMICOLON, ";", *col, *line);
append(*builder, "\n");
col = 0; col = 0;
line += 1; line += 1;
@@ -481,27 +476,10 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : []
add_child(field_list, field); add_child(field_list, field);
} }
brace_token := make_builtin_token(*ctx.tokens, *builder, .TOKEN_RIGHTBRACE, "}", *col, *line); brace_token := make_builtin_token(*ctx.tokens, .TOKEN_RIGHTBRACE, "\n}", *col, *line);
append(*builder, "\n");
source_location.end = brace_token; source_location.end = brace_token;
source := builder_to_string(*builder,, context.allocator);
source_location.begin.source = *source.data[source_location.begin.column];
source_location.end.source = *source.data[source_location.end.column];
for i : tok_index..ctx.tokens.count - 1 {
tok := ctx.tokens[i];
tok.source = *source.data[tok.column];
}
for field : field_list.children {
field.source_location.begin.source = *source.data[field.source_location.begin.column];
field.source_location.end.source = *source.data[field.source_location.end.column];
// field.source_location.main_token.source = *source.data[tok.column];
}
node.source_location = source_location; node.source_location = source_location;
return node; return node;
@@ -510,8 +488,6 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : []
new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members : []Arg, return_var : Arg) -> *AST_Node { new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members : []Arg, return_var : Arg) -> *AST_Node {
sc := get_scratch(context.allocator); sc := get_scratch(context.allocator);
defer scratch_end(sc); defer scratch_end(sc);
builder : String_Builder;
builder.allocator = sc.allocator; // I want to find a good way to use scratch here...
node := make_node(*ctx.nodes, .Function); node := make_node(*ctx.nodes, .Function);
@@ -522,13 +498,11 @@ new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members :
tok_index := ctx.tokens.count; tok_index := ctx.tokens.count;
ident_token := make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", name), *col, *line); ident_token := make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, name, *col, *line);
source_location.begin = ident_token; source_location.begin = ident_token;
append(*builder, " "); make_builtin_token(*ctx.tokens, .TOKEN_DOUBLECOLON, " :: ", *col, *line);
make_builtin_token(*ctx.tokens, *builder, .TOKEN_DOUBLECOLON, "::", *col, *line); make_builtin_token(*ctx.tokens, .TOKEN_LEFTPAREN, "(", *col, *line);
append(*builder, " ");
make_builtin_token(*ctx.tokens, *builder, .TOKEN_LEFTPAREN, "(", *col, *line);
field_list := make_node(*ctx.nodes, .FieldList); field_list := make_node(*ctx.nodes, .FieldList);
add_child(node, field_list); add_child(node, field_list);
@@ -536,14 +510,12 @@ new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members :
field := make_node(*ctx.nodes, .Field); field := make_node(*ctx.nodes, .Field);
field_source_loc : Source_Range; field_source_loc : Source_Range;
// field_ident := make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", member.name), *col, *line); type_tok := make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, member.typename, *col, *line);
type_tok := make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", member.typename), *col, *line);
field_source_loc.begin = type_tok; field_source_loc.begin = type_tok;
field.token = type_tok; field.token = type_tok;
if it_index < members.count - 1 { if it_index < members.count - 1 {
make_builtin_token(*ctx.tokens, *builder, .TOKEN_COMMA, ",", *col, *line); make_builtin_token(*ctx.tokens, .TOKEN_COMMA, ", ", *col, *line);
append(*builder, " ");
} }
field_source_loc.end = type_tok; field_source_loc.end = type_tok;
@@ -552,27 +524,11 @@ new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members :
add_child(field_list, field); add_child(field_list, field);
} }
make_builtin_token(*ctx.tokens, *builder, .TOKEN_RIGHTPAREN, ")", *col, *line); make_builtin_token(*ctx.tokens, .TOKEN_RIGHTPAREN, ")", *col, *line);
semicolon_tok := make_builtin_token(*ctx.tokens, *builder, .TOKEN_SEMICOLON, ";", *col, *line); semicolon_tok := make_builtin_token(*ctx.tokens, .TOKEN_SEMICOLON, ";", *col, *line);
source_location.end = semicolon_tok; source_location.end = semicolon_tok;
source := builder_to_string(*builder,, context.allocator);
source_location.begin.source = *source.data[source_location.begin.column];
source_location.end.source = *source.data[source_location.end.column];
for i : tok_index..ctx.tokens.count - 1 {
tok := ctx.tokens[i];
tok.source = *source.data[tok.column];
}
for field : field_list.children {
field.source_location.begin.source = *source.data[field.source_location.begin.column];
field.source_location.end.source = *source.data[field.source_location.end.column];
// field.source_location.main_token.source = *source.data[tok.column];
}
node.source_location = source_location; node.source_location = source_location;
return node; return node;
@@ -838,16 +794,28 @@ directive :: (state : *Parse_State) -> *AST_Node {
if_directive := make_node(state, .If_Directive); if_directive := make_node(state, .If_Directive);
source_location : Source_Range; source_location : Source_Range;
// source_location.begin = state.previous; if state.previous {
source_location.begin = state.previous;
} else {
source_location.begin = state.current;
}
advance(state); advance(state);
cond := expression(state); cond := expression(state);
add_child(if_directive, cond); add_child(if_directive, cond);
source_location.end = state.previous;
advance_to_sync_point(state);
if_body := block(state); if_body := block(state);
add_child(if_directive, if_body); add_child(if_directive, if_body);
if match(state, .TOKEN_ELSE) {
else_node := else_statement(state);
add_child(if_directive, else_node);
}
if_directive.source_location = source_location; if_directive.source_location = source_location;
return if_directive; return if_directive;
@@ -1256,13 +1224,15 @@ statement :: (parse_state : *Parse_State) -> *AST_Node {
else_statement :: (parse_state : *Parse_State) -> *AST_Node { else_statement :: (parse_state : *Parse_State) -> *AST_Node {
if check(parse_state, .TOKEN_IF) { if check(parse_state, .TOKEN_IF) {
return statement(parse_state); return statement(parse_state);
} else if check(parse_state, .TOKEN_DIRECTIVE) && parse_state.current.ident_value == "if" {
return directive(parse_state);
} }
return block(parse_state); return block(parse_state);
} }
block :: (parse_state : *Parse_State) -> *AST_Node { block :: (parse_state : *Parse_State) -> *AST_Node {
node : *AST_Node = make_node(parse_state, .Block); node : *AST_Node = make_node(parse_state, .Block);
array_reserve(*node.children, 1024); array_reserve(*node.children, 32);
source_location : Source_Range; source_location : Source_Range;
@@ -1361,10 +1331,22 @@ function_declaration :: (parse_state : *Parse_State, identifier_token : *Token,
case .Vertex; { case .Vertex; {
node.vertex_entry_point = true; node.vertex_entry_point = true;
name = sprint("vs_%", function_name_token.ident_value); name = sprint("vs_%", function_name_token.ident_value);
// if return_type_token.kind == .TOKEN_INVALID {
// entry_point_requires_return_value(parse_state, function_name_token);
// advance_to_sync_point(parse_state);
// return error_node(parse_state, "");
// }
} }
case .Pixel; { case .Pixel; {
node.pixel_entry_point = true; node.pixel_entry_point = true;
name = sprint("ps_%", function_name_token.ident_value); name = sprint("ps_%", function_name_token.ident_value);
// if return_type_token.kind == .TOKEN_INVALID {
// entry_point_requires_return_value(parse_state, function_name_token);
// advance_to_sync_point(parse_state);
// return error_node(parse_state, "");
// }
} }
} }

View File

@@ -20,15 +20,15 @@ There is basic support for most HLSL built-in math functions for the following t
- Vector types: float2, float3, float4, int2, int3, int4 - Vector types: float2, float3, float4, int2, int3, int4
- Matrices: float4x4 - Matrices: float4x4
All of the above can be constructed with their namesake constructors i.e. `float4(x, y, z, w);`. All of the above can be constructed with their namesake constructors i.e. `float4(x, y, z, w);`.
We don't yet support textures and samplers. We also support Samplers and Texture2D
If you want to declare and use variables you can do it as follows If you want to declare and use variables you can do it as follows
```hlsl ```hlsl
x : float = 2.0; // no 'f' suffix required or even supported (it gives an error) x : float = 2.0; // no 'f' suffix required or even supported (it gives an error)
y : float = 4.0; y : float = 4.0;
v : float2 = float2(x, y); v : float2 = float2(x, y);
v2 := float2(x, y);
``` ```
For now it is required to specify the type of the variable (no type inference).
You can also do arithmetic as you would expect You can also do arithmetic as you would expect
``` ```
@@ -43,6 +43,7 @@ Camera_Data :: struct {
} }
``` ```
And there is a special struct called `properties`, which is used for custom data you want to pass in. And there is a special struct called `properties`, which is used for custom data you want to pass in.
#### ** Note: Properties will likely be deprecated, since the language now supports `@` hints to easily mark buffers and values with metadata.**
```hlsl ```hlsl
properties { properties {
projection : float4x4; projection : float4x4;
@@ -53,13 +54,14 @@ which will be exposed in the compiled result. `properties` can be renamed to a c
``` ```
p :: properties { p :: properties {
... ...
}
``` ```
You can also define constant buffers You can also define constant buffers
``` ```
camera :: Constant_Buffer { camera :: constant_buffer {
projection : float4x4; projection : float4x4;
view : float4x4; view : float4x4;
} }
@@ -70,69 +72,68 @@ camera :: Constant_Buffer {
To compile a shader and use the result, you can do the following in jai To compile a shader and use the result, you can do the following in jai
```jai ```jai
parse_shader :: (path : string, allocator : Allocator) -> Compilation_Result {
// In the future, you can pass environment defines to the compiler. // In the future, you can pass environment defines to the compiler.
compiler : Shader_Compiler; ctx : Compiler_Context;
compile_file(*compiler, "shader.shd", allocator);
return compile_file(*compiler, path,, allocator); if ctx.had_error {
} log_error("%\n", report_messages(ctx.messages),, temp);
result := parse_shader("shader.shd", allocator);
if result.had_error {
log_error("%\n", report_messages(result.messages),, temp);
return; return;
} }
collection := result.collection; // The ctx now contains all the needed information like the source text, entry points, constant buffers etc.
variant := collection.variants[0];
}
``` ```
When parsing a shader you get the following struct as a result When parsing a shader you get the following struct as a result
``` ```
Compilation_Result :: struct { Compiler_Context :: struct {
messages : [..]Compiler_Message; file : Input_File;
had_error : bool; environment : Environment;
collection : Shader_Variant_Collection; tokens : [..]Token;;
} root : *AST_Node;
``` nodes : [..]AST_Node;
A `Shader_Variant_Collection` looks as follows codegen_result_text : string;
```
Shader_Variant_Collection :: struct {
properties : Properties;
max_constant_buffers :: 16; constant_buffers : Static_Array(Type_Variable_Handle, 16);
cbuffers : Static_Array(Constant_Buffer, max_constant_buffers);
variants : [..]Shader_Variant; scope_stack : Scope_Stack;
} type_variables : [..]Type_Variable;
Shader_Variant :: struct { property_name : string;
text : string;
vertex_entry_point : struct { vertex_entry_point : struct {
node : *AST_Node;
name : string; name : string;
input : [..]Field; input : [..]Field;
} }
pixel_entry_point : struct { pixel_entry_point : struct {
node : *AST_Node;
name : string; name : string;
return_value : Field; return_value : Field;
} }
properties : Properties;
max_constant_buffers :: 16;
cbuffers : Static_Array(Constant_Buffer, max_constant_buffers);
had_error : bool;
messages : [..]Compiler_Message;
} }
Constant_Buffer :: struct { Constant_Buffer :: struct {
register : int;
name : string; name : string;
fields : Static_Array(Property_Field, 16); fields : Static_Array(Property_Field, 16);
// hints : Field_Hint; // optional hint...
hints : [..]Field_Hint;
buffer_index : u32; buffer_index : u32;
} }
@@ -192,11 +193,10 @@ Hint_Kind :: enum {
## Notable missing features ## Notable missing features
- Control flow: if/else, for, while, switch etc. - While
- Arrays - Arrays
- Textures and samplers
- Multiple render targets - Multiple render targets
- Custom buffers/structured buffers - Custom buffers/structured buffers
- Interpolation specifiers - Interpolation specifiers
- Proper variant handling with environment defines - Proper variant handling with environment defines
- Include/importing files such as shared utils etc. - Importing files such as shared utils etc. with something other than textual `#load`

View File

@@ -1,11 +1,29 @@
#load "Lexing.jai"; #load "Lexing.jai";
#load "Error.jai"; #load "Error.jai";
#load "Parsing.jai"; #load "Parsing.jai";
#load "Semantic_Analysis.jai"; #load "Check.jai";
#load "Codegen.jai"; #load "Codegen.jai";
#import "File_Utilities"; #import "File_Utilities";
/* TODO
- [x] Remove builtin stringbuilding and replace it with ad-hoc string building when error reporting. In that case we are already building a string anyway, so we can just pass in the string builder
- [ ] Support structured buffers (ro, rw, w)
- [ ] Support mesh and amplification shaders
- [ ] Support compute shaders
- [x] Support #if at top level
- [x] Support #if at block level
- [ ] Remove properties block and just use hinted constant buffers instead
```
props :: constant_buffer @properties {
[...]
}
```
- [ ] while loops
- [ ] for-each loops
- [ ]
*/
add_define :: (env : *Environment, key : string) { add_define :: (env : *Environment, key : string) {
for define : env.defines { for define : env.defines {
if define == key { if define == key {
@@ -55,10 +73,33 @@ Hint_Kind :: enum {
Position; Position;
UV; UV;
Target; Target;
Output_Position;
Custom; Custom;
} }
Hint_Names :: #run -> [(cast(int)Hint_Kind.Target) + 1]string {
names : [(cast(int)Hint_Kind.Target) + 1]string;
names[Hint_Kind.Position] = "position";
names[Hint_Kind.UV] = "uv";
names[Hint_Kind.Target] = "target";
return names;
}
lookup_hint :: (name : string) -> Hint_Kind {
if name == "position" {
return Hint_Kind.Position;
} else if name == "uv" {
return Hint_Kind.UV;
} else if starts_with(name, "target") {
return Hint_Kind.Target;
} else if name == "outposition" {
return Hint_Kind.Output_Position;
}
return .None;
}
Field_Hint :: struct { Field_Hint :: struct {
kind : Hint_Kind; kind : Hint_Kind;
@@ -81,22 +122,6 @@ Entry_Point :: struct {
return_value : Field; return_value : Field;
} }
Shader_Variant :: struct {
text : string;
vertex_entry_point : struct {
name : string;
input : [..]Field;
}
pixel_entry_point : struct {
name : string;
return_value : Field;
}
}
Property_Field :: struct { Property_Field :: struct {
base_field : Field; base_field : Field;
@@ -111,27 +136,15 @@ Properties :: struct {
} }
Constant_Buffer :: struct { Constant_Buffer :: struct {
register : int;
name : string; name : string;
fields : Static_Array(Property_Field, 16); fields : Static_Array(Property_Field, 16);
// hints : Field_Hint; // optional hint...
hints : [..]Field_Hint; hints : [..]Field_Hint;
buffer_index : u32; buffer_index : u32;
} }
Shader_Variant_Collection :: struct {
properties : Properties;
max_constant_buffers :: 16;
cbuffers : Static_Array(Constant_Buffer, max_constant_buffers);
variants : [..]Shader_Variant;
}
Input_File :: struct { Input_File :: struct {
source : string; source : string;
path : string; path : string;
@@ -167,7 +180,7 @@ Compiler_Context :: struct {
return_value : Field; return_value : Field;
} }
properties : Properties; properties : Properties; //@Note(niels): We'll deprecate this in favor of just marking a constant buffer with a hint on how you'd want to use it
max_constant_buffers :: 16; max_constant_buffers :: 16;
@@ -312,7 +325,7 @@ pretty_print_field :: (builder : *String_Builder, field : *Field) {
} }
} }
type_variable_to_field :: (checker : *Semantic_Checker, variable : Type_Variable_Handle) -> Field { type_variable_to_field :: (checker : *Checker, variable : Type_Variable_Handle) -> Field {
return type_variable_to_field(checker, from_handle(checker, variable)); return type_variable_to_field(checker, from_handle(checker, variable));
} }
@@ -367,13 +380,11 @@ type_variable_to_field :: (type_variables : []Type_Variable, scope_stack : Scope
for hint : variable.source_node.hint_tokens { for hint : variable.source_node.hint_tokens {
field_hint : Field_Hint; field_hint : Field_Hint;
if hint.ident_value == "position" { if lookup_hint(hint.ident_value) == .Position {
// @Incomplete(nb): Should be a lookup table somewhere
field_hint.kind = .Position; field_hint.kind = .Position;
} else if hint.ident_value == "uv" { } else if lookup_hint(hint.ident_value) == .UV {
field_hint.kind = .UV; field_hint.kind = .UV;
} else if starts_with(hint.ident_value, "target") { } else if lookup_hint(hint.ident_value) == .Target {
// @Incomplete(nb): Should be a lookup table somewhere
index_str : string; index_str : string;
index_str.data = *hint.ident_value.data[7]; index_str.data = *hint.ident_value.data[7];
index_str.count = 1; index_str.count = 1;
@@ -399,7 +410,7 @@ type_variable_to_field :: (type_variables : []Type_Variable, scope_stack : Scope
return type_variable_to_field(type_variables, scope_stack, from_handle(type_variables, variable)); return type_variable_to_field(type_variables, scope_stack, from_handle(type_variables, variable));
} }
type_variable_to_field :: (checker : *Semantic_Checker, variable : *Type_Variable) -> Field { type_variable_to_field :: (checker : *Checker, variable : *Type_Variable) -> Field {
return type_variable_to_field(checker.ctx.type_variables, checker.ctx.scope_stack, variable); return type_variable_to_field(checker.ctx.type_variables, checker.ctx.scope_stack, variable);
} }
@@ -451,6 +462,7 @@ generate_output_data :: (ctx : *Compiler_Context) {
find_result := find_symbol(*ctx.scope_stack, ctx.property_name, xx 1); find_result := find_symbol(*ctx.scope_stack, ctx.property_name, xx 1);
if find_result { if find_result {
property_variable := from_handle(ctx.type_variables, find_result.type_variable); property_variable := from_handle(ctx.type_variables, find_result.type_variable);
for i : 0..property_variable.children.count - 1 { for i : 0..property_variable.children.count - 1 {
@@ -463,22 +475,20 @@ generate_output_data :: (ctx : *Compiler_Context) {
ctx.properties.buffer_index = property_variable.resource_index; ctx.properties.buffer_index = property_variable.resource_index;
} }
if ctx.pixel_entry_point.node { if ctx.pixel_entry_point.node {
ctx.pixel_entry_point.name = ctx.pixel_entry_point.node.name; ctx.pixel_entry_point.name = ctx.pixel_entry_point.node.name;
type_variable := from_handle(ctx.type_variables, ctx.pixel_entry_point.node.type_variable); type_variable := from_handle(ctx.type_variables, ctx.pixel_entry_point.node.type_variable);
assert(type_variable.type == .Function); assert(type_variable.type == .Function);
if type_variable.return_type_variable > 0 {
field := type_variable_to_field(ctx.type_variables, ctx.scope_stack, type_variable.return_type_variable); field := type_variable_to_field(ctx.type_variables, ctx.scope_stack, type_variable.return_type_variable);
for hint : type_variable.source_node.hint_tokens { for hint : type_variable.source_node.hint_tokens {
field_hint : Field_Hint; field_hint : Field_Hint;
if hint.ident_value == "position" { if lookup_hint(hint.ident_value) == .Position {
// @Incomplete(nb): Should be a lookup table somewhere
field_hint.kind = .Position; field_hint.kind = .Position;
} else if starts_with(hint.ident_value, "target") { } else if lookup_hint(hint.ident_value) == .Target {
// @Incomplete(nb): Should be a lookup table somewhere
index_str : string; index_str : string;
index_str.data = *hint.ident_value.data[7]; index_str.data = *hint.ident_value.data[7];
index_str.count = 1; index_str.count = 1;
@@ -493,10 +503,10 @@ generate_output_data :: (ctx : *Compiler_Context) {
} }
array_add(*field.hints, field_hint); array_add(*field.hints, field_hint);
} }
ctx.pixel_entry_point.return_value = field; ctx.pixel_entry_point.return_value = field;
} }
} }
}
compile_file :: (ctx : *Compiler_Context, path : string, allocator : Allocator = temp) { compile_file :: (ctx : *Compiler_Context, path : string, allocator : Allocator = temp) {
new_context := context; new_context := context;

View File

@@ -0,0 +1,7 @@
scope (global) [
[pixel__ps_main] : ()
scope (pixel__ps_main) [
[alpha_color] : float4
[f] : float
]
]

View File

@@ -0,0 +1,4 @@
scope (global) [
[vertex__vs_console_main] : ()
scope (vertex__vs_console_main) []
]

8
test/check/ifdefs.golden Normal file
View File

@@ -0,0 +1,8 @@
scope (global) [
[vertex__vs_skinning_main] : ()
[pixel__ps_main] : ()
scope (vertex__vs_skinning_main) [
[x] : float
]
scope (pixel__ps_main) []
]

View File

@@ -7,15 +7,15 @@
 result : float4 = float4(1.0, foo * res, 0.0, 1.0);  result : float4 = float4(1.0, foo * res, 0.0, 1.0);
^ ^
 Possible overloads:  Possible overloads:
 float4 :: (float, float, float, float); (test/wrong_multiply.ink:0)  float4 :: (float, float, float, float)
 float4 :: (float2, float2); (test/wrong_multiply.ink:0)  float4 :: (float2, float2)
 float4 :: (float2, float, float); (test/wrong_multiply.ink:0)  float4 :: (float2, float, float)
 float4 :: (float, float2, float); (test/wrong_multiply.ink:0)  float4 :: (float, float2, float)
 float4 :: (float, float, float2); (test/wrong_multiply.ink:0)  float4 :: (float, float, float2)
 float4 :: (float, float3); (test/wrong_multiply.ink:0)  float4 :: (float, float3)
 float4 :: (float3, float); (test/wrong_multiply.ink:0)  float4 :: (float3, float)
 float4 :: (float4); (test/wrong_multiply.ink:0)  float4 :: (float4)
 float4 :: (float); (test/wrong_multiply.ink:0)  float4 :: (float)
test/wrong_multiply.ink:4,34: error: Type mismatch. Expected float got float2 test/wrong_multiply.ink:4,34: error: Type mismatch. Expected float got float2
 found:  found:

View File

@@ -0,0 +1,30 @@
test/wrong_type_for_function.ink:11,17: error: Procedure call did not match any of the possible overloads for 'float4'
 found:
color : float4 = float4(y, 1.0, 1.0, 1.0);
^^^^^^
 While matching argument 1 in function call.
 color : float4 = float4(y, 1.0, 1.0, 1.0);
^
 Possible overloads:
 float4 :: (float, float, float, float)
 float4 :: (float2, float2)
 float4 :: (float2, float, float)
 float4 :: (float, float2, float)
 float4 :: (float, float, float2)
 float4 :: (float, float3)
 float4 :: (float3, float)
 float4 :: (float4)
 float4 :: (float)
test/wrong_type_for_function.ink:11,24: error: Type mismatch. Expected float got float2
 found:
color : float4 = float4(y, 1.0, 1.0, 1.0);
^
expected:
float
got:
y : float2 = foo()


43
test/check_all.suite Normal file
View File

@@ -0,0 +1,43 @@
test/assign_arithmetic_expression.ink check
test/basic_property_and_return_value.ink check
test/builtin_types.ink check
test/complicated_computation.ink check
test/constant_buffer.ink check
test/empty_struct.ink check
test/empty_vertex_main.ink check
test/empty_vertex_main_with_position_parameter.ink check
test/field_assignment.ink check
test/for_i_loop.ink check
test/function_call.ink check
test/function_call_out_of_order_declaration.ink check
test/function_call_return.ink check
test/functions_with_same_name.ink check
test/function_with_int_return.ink check
test/if_cond_assign.ink check
test/ifdefs.ink check
test/if_def_block.ink check
test/if_def_expression.ink check
test/inferred_types.ink check
test/multiple_functions.ink check
test/multiple_semicolons_everywhere.ink check
test/nested_if.ink check
test/non_bool_cond.ink check
test/pass_and_access_struct_fields_in_functions.ink check
test/passthrough.ink check
test/property_rename.ink check
test/redeclared_variable.ink check
test/simple_else_if.ink check
test/simple_if_else.ink check
test/simple_if.ink check
test/simple_struct_access.ink check
test/struct_access_primitive_type.ink check
test/struct_within_struct.ink check
test/type_as_variable_name.ink check
test/unary.ink check
test/undeclared_function.ink check
test/undeclared_symbol.ink check
test/unknown_overload.ink check
test/use_builtin_functions.ink check
test/wrong_argument_count.ink check
test/wrong_multiply.ink check
test/wrong_type_for_function.ink check

View File

@@ -0,0 +1,7 @@
void ps_main()
{
float4 alpha_color = float4(1, 0, 0, 1);
float f = 2.0f;
}

View File

@@ -0,0 +1,4 @@
void vs_console_main()
{
}

View File

@@ -0,0 +1,9 @@
void ps_main()
{
}
void vs_skinning_main()
{
float x = 5.0f;
}

View File

@@ -10,6 +10,9 @@ test/field_assignment.ink codegen
test/function_call.ink codegen test/function_call.ink codegen
test/function_call_out_of_order_declaration.ink codegen test/function_call_out_of_order_declaration.ink codegen
test/function_call_return.ink codegen test/function_call_return.ink codegen
test/ifdefs.ink codegen
test/if_def_block.ink codegen
test/if_def_expression.ink codegen
test/inferred_types.ink codegen test/inferred_types.ink codegen
test/meta_block.ink codegen test/meta_block.ink codegen
test/multiple_functions.ink codegen test/multiple_functions.ink codegen

View File

@@ -11,6 +11,9 @@ test/function_call.ink compile
test/function_call_out_of_order_declaration.ink compile test/function_call_out_of_order_declaration.ink compile
test/function_call_return.ink compile test/function_call_return.ink compile
test/functions_with_same_name.ink compile test/functions_with_same_name.ink compile
test/ifdefs.ink compile
test/if_def_block.ink compile
test/if_def_expression.ink compile
test/inferred_types.ink compile test/inferred_types.ink compile
test/meta_block.ink compile test/meta_block.ink compile
test/multiple_functions.ink compile test/multiple_functions.ink compile

View File

@@ -0,0 +1 @@
[vertex entry point] - vs_main

View File

@@ -0,0 +1 @@
[pixel entry point] - ps_main

View File

@@ -0,0 +1 @@
[vertex entry point] - vs_console_main

View File

@@ -0,0 +1,2 @@
[vertex entry point] - vs_skinning_main
[pixel entry point] - ps_main

11
test/if_def_block.ink Normal file
View File

@@ -0,0 +1,11 @@
#add_define Alpha
pixel main :: () {
#if Env.Alpha {
alpha_color := float4(1, 0, 0, 1);
f := 2.0;
} else {
color := float3(0, 0, 0);
g := 5.0;
}
}

View File

@@ -0,0 +1,13 @@
#add_define PS5
#add_define XSX
#add_define Switch2
#if (Env.PS5 && Env.XSX) || Env.Switch2 {
vertex console_main :: () {
}
} else {
vertex windows_main :: () {
}
}

View File

@@ -1,5 +1,17 @@
#if Defines.Skinning { #add_define Skinning
vertex main :: () { #add_define UV
// Stub
#if Env.Skinning {
vertex skinning_main :: () {
x : float = 5.0;
}
} else #if Env.UV {
vertex texture_mapping_main :: () {
x : float2 = float2(2.0, 2.0);
} }
} }
pixel main :: () {
}

View File

@@ -0,0 +1,53 @@
{kind = TOKEN_PIXEL; ; index = 21 ; length = 5 line = 3 ; column = 0 ; value ='pixel'; }
{kind = TOKEN_IDENTIFIER; ; index = 27 ; length = 4 line = 3 ; column = 6 ; value ='main'; }
{kind = TOKEN_DOUBLECOLON; ; index = 32 ; length = 2 line = 3 ; column = 11 ; value ='::'; }
{kind = TOKEN_LEFTPAREN; ; index = 35 ; length = 1 line = 3 ; column = 14 ; value ='('; }
{kind = TOKEN_RIGHTPAREN; ; index = 36 ; length = 1 line = 3 ; column = 15 ; value =')'; }
{kind = TOKEN_LEFTBRACE; ; index = 38 ; length = 1 line = 3 ; column = 17 ; value ='{'; }
{kind = TOKEN_DIRECTIVE; ; index = 42 ; length = 2 line = 4 ; column = 0 ; value ='if'; }
{kind = TOKEN_IDENTIFIER; ; index = 45 ; length = 3 line = 4 ; column = 3 ; value ='Env'; }
{kind = TOKEN_DOT; ; index = 48 ; length = 1 line = 4 ; column = 6 ; value ='.'; }
{kind = TOKEN_IDENTIFIER; ; index = 49 ; length = 5 line = 4 ; column = 7 ; value ='Alpha'; }
{kind = TOKEN_LEFTBRACE; ; index = 55 ; length = 1 line = 4 ; column = 13 ; value ='{'; }
{kind = TOKEN_IDENTIFIER; ; index = 59 ; length = 11 line = 5 ; column = 0 ; value ='alpha_color'; }
{kind = TOKEN_COLON; ; index = 71 ; length = 1 line = 5 ; column = 12 ; value =':'; }
{kind = TOKEN_ASSIGN; ; index = 72 ; length = 1 line = 5 ; column = 13 ; value ='='; }
{kind = TOKEN_IDENTIFIER; ; index = 74 ; length = 6 line = 5 ; column = 15 ; value ='float4'; }
{kind = TOKEN_LEFTPAREN; ; index = 80 ; length = 1 line = 5 ; column = 21 ; value ='('; }
{kind = TOKEN_INTLITERAL; ; index = 81 ; length = 1 line = 5 ; column = 22 ; value ='1'; }
{kind = TOKEN_COMMA; ; index = 82 ; length = 1 line = 5 ; column = 23 ; value =','; }
{kind = TOKEN_INTLITERAL; ; index = 84 ; length = 1 line = 5 ; column = 25 ; value ='0'; }
{kind = TOKEN_COMMA; ; index = 85 ; length = 1 line = 5 ; column = 26 ; value =','; }
{kind = TOKEN_INTLITERAL; ; index = 87 ; length = 1 line = 5 ; column = 28 ; value ='0'; }
{kind = TOKEN_COMMA; ; index = 88 ; length = 1 line = 5 ; column = 29 ; value =','; }
{kind = TOKEN_INTLITERAL; ; index = 90 ; length = 1 line = 5 ; column = 31 ; value ='1'; }
{kind = TOKEN_RIGHTPAREN; ; index = 91 ; length = 1 line = 5 ; column = 32 ; value =')'; }
{kind = TOKEN_SEMICOLON; ; index = 92 ; length = 1 line = 5 ; column = 33 ; value =';'; }
{kind = TOKEN_IDENTIFIER; ; index = 96 ; length = 1 line = 6 ; column = 0 ; value ='f'; }
{kind = TOKEN_COLON; ; index = 98 ; length = 1 line = 6 ; column = 2 ; value =':'; }
{kind = TOKEN_ASSIGN; ; index = 99 ; length = 1 line = 6 ; column = 3 ; value ='='; }
{kind = TOKEN_FLOATLITERAL; ; index = 101 ; length = 3 line = 6 ; column = 5 ; value ='2'; }
{kind = TOKEN_SEMICOLON; ; index = 104 ; length = 1 line = 6 ; column = 8 ; value =';'; }
{kind = TOKEN_RIGHTBRACE; ; index = 107 ; length = 1 line = 7 ; column = 0 ; value ='}'; }
{kind = TOKEN_ELSE; ; index = 109 ; length = 4 line = 7 ; column = 2 ; value ='else'; }
{kind = TOKEN_LEFTBRACE; ; index = 114 ; length = 1 line = 7 ; column = 7 ; value ='{'; }
{kind = TOKEN_IDENTIFIER; ; index = 118 ; length = 5 line = 8 ; column = 0 ; value ='color'; }
{kind = TOKEN_COLON; ; index = 124 ; length = 1 line = 8 ; column = 6 ; value =':'; }
{kind = TOKEN_ASSIGN; ; index = 125 ; length = 1 line = 8 ; column = 7 ; value ='='; }
{kind = TOKEN_IDENTIFIER; ; index = 127 ; length = 6 line = 8 ; column = 9 ; value ='float3'; }
{kind = TOKEN_LEFTPAREN; ; index = 133 ; length = 1 line = 8 ; column = 15 ; value ='('; }
{kind = TOKEN_INTLITERAL; ; index = 134 ; length = 1 line = 8 ; column = 16 ; value ='0'; }
{kind = TOKEN_COMMA; ; index = 135 ; length = 1 line = 8 ; column = 17 ; value =','; }
{kind = TOKEN_INTLITERAL; ; index = 137 ; length = 1 line = 8 ; column = 19 ; value ='0'; }
{kind = TOKEN_COMMA; ; index = 138 ; length = 1 line = 8 ; column = 20 ; value =','; }
{kind = TOKEN_INTLITERAL; ; index = 140 ; length = 1 line = 8 ; column = 22 ; value ='0'; }
{kind = TOKEN_RIGHTPAREN; ; index = 141 ; length = 1 line = 8 ; column = 23 ; value =')'; }
{kind = TOKEN_SEMICOLON; ; index = 142 ; length = 1 line = 8 ; column = 24 ; value =';'; }
{kind = TOKEN_IDENTIFIER; ; index = 146 ; length = 1 line = 9 ; column = 0 ; value ='g'; }
{kind = TOKEN_COLON; ; index = 148 ; length = 1 line = 9 ; column = 2 ; value =':'; }
{kind = TOKEN_ASSIGN; ; index = 149 ; length = 1 line = 9 ; column = 3 ; value ='='; }
{kind = TOKEN_FLOATLITERAL; ; index = 151 ; length = 3 line = 9 ; column = 5 ; value ='5'; }
{kind = TOKEN_SEMICOLON; ; index = 154 ; length = 1 line = 9 ; column = 8 ; value =';'; }
{kind = TOKEN_RIGHTBRACE; ; index = 157 ; length = 1 line = 10 ; column = 0 ; value ='}'; }
{kind = TOKEN_RIGHTBRACE; ; index = 160 ; length = 1 line = 11 ; column = 0 ; value ='}'; }
{kind = TOKEN_EOF; ; index = 163 ; length = 0 line = 12 ; column = 0 ; value =''; }

View File

@@ -0,0 +1,34 @@
{kind = TOKEN_DIRECTIVE; ; index = 58 ; length = 2 line = 5 ; column = 0 ; value ='if'; }
{kind = TOKEN_LEFTPAREN; ; index = 61 ; length = 1 line = 5 ; column = 3 ; value ='('; }
{kind = TOKEN_IDENTIFIER; ; index = 62 ; length = 3 line = 5 ; column = 4 ; value ='Env'; }
{kind = TOKEN_DOT; ; index = 65 ; length = 1 line = 5 ; column = 7 ; value ='.'; }
{kind = TOKEN_IDENTIFIER; ; index = 66 ; length = 3 line = 5 ; column = 8 ; value ='PS5'; }
{kind = TOKEN_LOGICALAND; ; index = 70 ; length = 2 line = 5 ; column = 12 ; value ='&&'; }
{kind = TOKEN_IDENTIFIER; ; index = 73 ; length = 3 line = 5 ; column = 15 ; value ='Env'; }
{kind = TOKEN_DOT; ; index = 76 ; length = 1 line = 5 ; column = 18 ; value ='.'; }
{kind = TOKEN_IDENTIFIER; ; index = 77 ; length = 3 line = 5 ; column = 19 ; value ='XSX'; }
{kind = TOKEN_RIGHTPAREN; ; index = 80 ; length = 1 line = 5 ; column = 22 ; value =')'; }
{kind = TOKEN_LOGICALOR; ; index = 82 ; length = 2 line = 5 ; column = 24 ; value ='||'; }
{kind = TOKEN_IDENTIFIER; ; index = 85 ; length = 3 line = 5 ; column = 27 ; value ='Env'; }
{kind = TOKEN_DOT; ; index = 88 ; length = 1 line = 5 ; column = 30 ; value ='.'; }
{kind = TOKEN_IDENTIFIER; ; index = 89 ; length = 7 line = 5 ; column = 31 ; value ='Switch2'; }
{kind = TOKEN_LEFTBRACE; ; index = 97 ; length = 1 line = 5 ; column = 39 ; value ='{'; }
{kind = TOKEN_VERTEX; ; index = 101 ; length = 6 line = 6 ; column = 0 ; value ='vertex'; }
{kind = TOKEN_IDENTIFIER; ; index = 108 ; length = 12 line = 6 ; column = 7 ; value ='console_main'; }
{kind = TOKEN_DOUBLECOLON; ; index = 121 ; length = 2 line = 6 ; column = 20 ; value ='::'; }
{kind = TOKEN_LEFTPAREN; ; index = 124 ; length = 1 line = 6 ; column = 23 ; value ='('; }
{kind = TOKEN_RIGHTPAREN; ; index = 125 ; length = 1 line = 6 ; column = 24 ; value =')'; }
{kind = TOKEN_LEFTBRACE; ; index = 127 ; length = 1 line = 6 ; column = 26 ; value ='{'; }
{kind = TOKEN_RIGHTBRACE; ; index = 133 ; length = 1 line = 8 ; column = 0 ; value ='}'; }
{kind = TOKEN_RIGHTBRACE; ; index = 136 ; length = 1 line = 9 ; column = 0 ; value ='}'; }
{kind = TOKEN_ELSE; ; index = 138 ; length = 4 line = 9 ; column = 2 ; value ='else'; }
{kind = TOKEN_LEFTBRACE; ; index = 143 ; length = 1 line = 9 ; column = 7 ; value ='{'; }
{kind = TOKEN_VERTEX; ; index = 147 ; length = 6 line = 10 ; column = 0 ; value ='vertex'; }
{kind = TOKEN_IDENTIFIER; ; index = 154 ; length = 12 line = 10 ; column = 7 ; value ='windows_main'; }
{kind = TOKEN_DOUBLECOLON; ; index = 167 ; length = 2 line = 10 ; column = 20 ; value ='::'; }
{kind = TOKEN_LEFTPAREN; ; index = 170 ; length = 1 line = 10 ; column = 23 ; value ='('; }
{kind = TOKEN_RIGHTPAREN; ; index = 171 ; length = 1 line = 10 ; column = 24 ; value =')'; }
{kind = TOKEN_LEFTBRACE; ; index = 173 ; length = 1 line = 10 ; column = 26 ; value ='{'; }
{kind = TOKEN_RIGHTBRACE; ; index = 179 ; length = 1 line = 12 ; column = 0 ; value ='}'; }
{kind = TOKEN_RIGHTBRACE; ; index = 182 ; length = 1 line = 13 ; column = 0 ; value ='}'; }
{kind = TOKEN_EOF; ; index = 185 ; length = 0 line = 14 ; column = 0 ; value =''; }

52
test/lex/ifdefs.golden Normal file
View File

@@ -0,0 +1,52 @@
{kind = TOKEN_DIRECTIVE; ; index = 43 ; length = 2 line = 5 ; column = 0 ; value ='if'; }
{kind = TOKEN_IDENTIFIER; ; index = 46 ; length = 3 line = 5 ; column = 3 ; value ='Env'; }
{kind = TOKEN_DOT; ; index = 49 ; length = 1 line = 5 ; column = 6 ; value ='.'; }
{kind = TOKEN_IDENTIFIER; ; index = 50 ; length = 8 line = 5 ; column = 7 ; value ='Skinning'; }
{kind = TOKEN_LEFTBRACE; ; index = 59 ; length = 1 line = 5 ; column = 16 ; value ='{'; }
{kind = TOKEN_VERTEX; ; index = 63 ; length = 6 line = 6 ; column = 0 ; value ='vertex'; }
{kind = TOKEN_IDENTIFIER; ; index = 70 ; length = 13 line = 6 ; column = 7 ; value ='skinning_main'; }
{kind = TOKEN_DOUBLECOLON; ; index = 84 ; length = 2 line = 6 ; column = 21 ; value ='::'; }
{kind = TOKEN_LEFTPAREN; ; index = 87 ; length = 1 line = 6 ; column = 24 ; value ='('; }
{kind = TOKEN_RIGHTPAREN; ; index = 88 ; length = 1 line = 6 ; column = 25 ; value =')'; }
{kind = TOKEN_LEFTBRACE; ; index = 90 ; length = 1 line = 6 ; column = 27 ; value ='{'; }
{kind = TOKEN_IDENTIFIER; ; index = 95 ; length = 1 line = 7 ; column = 0 ; value ='x'; }
{kind = TOKEN_COLON; ; index = 97 ; length = 1 line = 7 ; column = 2 ; value =':'; }
{kind = TOKEN_IDENTIFIER; ; index = 99 ; length = 5 line = 7 ; column = 4 ; value ='float'; }
{kind = TOKEN_ASSIGN; ; index = 105 ; length = 1 line = 7 ; column = 10 ; value ='='; }
{kind = TOKEN_FLOATLITERAL; ; index = 107 ; length = 3 line = 7 ; column = 12 ; value ='5'; }
{kind = TOKEN_SEMICOLON; ; index = 110 ; length = 1 line = 7 ; column = 15 ; value =';'; }
{kind = TOKEN_RIGHTBRACE; ; index = 114 ; length = 1 line = 8 ; column = 0 ; value ='}'; }
{kind = TOKEN_RIGHTBRACE; ; index = 117 ; length = 1 line = 9 ; column = 0 ; value ='}'; }
{kind = TOKEN_ELSE; ; index = 119 ; length = 4 line = 9 ; column = 2 ; value ='else'; }
{kind = TOKEN_DIRECTIVE; ; index = 125 ; length = 2 line = 9 ; column = 7 ; value ='if'; }
{kind = TOKEN_IDENTIFIER; ; index = 128 ; length = 3 line = 9 ; column = 10 ; value ='Env'; }
{kind = TOKEN_DOT; ; index = 131 ; length = 1 line = 9 ; column = 13 ; value ='.'; }
{kind = TOKEN_IDENTIFIER; ; index = 132 ; length = 2 line = 9 ; column = 14 ; value ='UV'; }
{kind = TOKEN_LEFTBRACE; ; index = 135 ; length = 1 line = 9 ; column = 17 ; value ='{'; }
{kind = TOKEN_VERTEX; ; index = 139 ; length = 6 line = 10 ; column = 0 ; value ='vertex'; }
{kind = TOKEN_IDENTIFIER; ; index = 146 ; length = 20 line = 10 ; column = 7 ; value ='texture_mapping_main'; }
{kind = TOKEN_DOUBLECOLON; ; index = 167 ; length = 2 line = 10 ; column = 28 ; value ='::'; }
{kind = TOKEN_LEFTPAREN; ; index = 170 ; length = 1 line = 10 ; column = 31 ; value ='('; }
{kind = TOKEN_RIGHTPAREN; ; index = 171 ; length = 1 line = 10 ; column = 32 ; value =')'; }
{kind = TOKEN_LEFTBRACE; ; index = 173 ; length = 1 line = 10 ; column = 34 ; value ='{'; }
{kind = TOKEN_IDENTIFIER; ; index = 178 ; length = 1 line = 11 ; column = 0 ; value ='x'; }
{kind = TOKEN_COLON; ; index = 180 ; length = 1 line = 11 ; column = 2 ; value =':'; }
{kind = TOKEN_IDENTIFIER; ; index = 182 ; length = 6 line = 11 ; column = 4 ; value ='float2'; }
{kind = TOKEN_ASSIGN; ; index = 189 ; length = 1 line = 11 ; column = 11 ; value ='='; }
{kind = TOKEN_IDENTIFIER; ; index = 191 ; length = 6 line = 11 ; column = 13 ; value ='float2'; }
{kind = TOKEN_LEFTPAREN; ; index = 197 ; length = 1 line = 11 ; column = 19 ; value ='('; }
{kind = TOKEN_FLOATLITERAL; ; index = 198 ; length = 3 line = 11 ; column = 20 ; value ='2'; }
{kind = TOKEN_COMMA; ; index = 201 ; length = 1 line = 11 ; column = 23 ; value =','; }
{kind = TOKEN_FLOATLITERAL; ; index = 203 ; length = 3 line = 11 ; column = 25 ; value ='2'; }
{kind = TOKEN_RIGHTPAREN; ; index = 206 ; length = 1 line = 11 ; column = 28 ; value =')'; }
{kind = TOKEN_SEMICOLON; ; index = 207 ; length = 1 line = 11 ; column = 29 ; value =';'; }
{kind = TOKEN_RIGHTBRACE; ; index = 211 ; length = 1 line = 12 ; column = 0 ; value ='}'; }
{kind = TOKEN_RIGHTBRACE; ; index = 214 ; length = 1 line = 13 ; column = 0 ; value ='}'; }
{kind = TOKEN_PIXEL; ; index = 219 ; length = 5 line = 15 ; column = 0 ; value ='pixel'; }
{kind = TOKEN_IDENTIFIER; ; index = 225 ; length = 4 line = 15 ; column = 6 ; value ='main'; }
{kind = TOKEN_DOUBLECOLON; ; index = 230 ; length = 2 line = 15 ; column = 11 ; value ='::'; }
{kind = TOKEN_LEFTPAREN; ; index = 233 ; length = 1 line = 15 ; column = 14 ; value ='('; }
{kind = TOKEN_RIGHTPAREN; ; index = 234 ; length = 1 line = 15 ; column = 15 ; value =')'; }
{kind = TOKEN_LEFTBRACE; ; index = 236 ; length = 1 line = 15 ; column = 17 ; value ='{'; }
{kind = TOKEN_RIGHTBRACE; ; index = 241 ; length = 1 line = 17 ; column = 0 ; value ='}'; }
{kind = TOKEN_EOF; ; index = 244 ; length = 0 line = 18 ; column = 0 ; value =''; }

View File

@@ -20,6 +20,9 @@ test/function_call_return.ink lex
test/functions_with_same_name.ink lex test/functions_with_same_name.ink lex
test/function_with_int_return.ink lex test/function_with_int_return.ink lex
test/if_cond_assign.ink lex test/if_cond_assign.ink lex
test/ifdefs.ink lex
test/if_def_block.ink lex
test/if_def_expression.ink lex
test/if_if_if.ink lex test/if_if_if.ink lex
test/inferred_types.ink lex test/inferred_types.ink lex
test/large_block.ink lex test/large_block.ink lex

View File

@@ -0,0 +1,8 @@
(program
(fun pixel ps_main
[]
(#if Env.Alpha
(:= alpha_color (float4 1 0 0 1))
(:= f 2)
(:= color (float3 0 0 0))
(:= g 5))))

View File

@@ -0,0 +1,6 @@
(program
(#if (|| (&& Env.PS5 Env.XSX) Env.Switch2)
(fun vertex vs_console_main
[])
(fun vertex vs_windows_main
[])))

12
test/parse/ifdefs.golden Normal file
View File

@@ -0,0 +1,12 @@
(program
(#if Env.Skinning
(fun vertex vs_skinning_main
[]
(:= x float 5))
(#if Env.UV
(fun vertex vs_texture_mapping_main
[]
(:= x float2 (float2 2 2)))))
(fun pixel ps_main
[]))

View File

@@ -20,6 +20,9 @@ test/function_call_return.ink parse
test/functions_with_same_name.ink parse test/functions_with_same_name.ink parse
test/function_with_int_return.ink parse test/function_with_int_return.ink parse
test/if_cond_assign.ink parse test/if_cond_assign.ink parse
test/ifdefs.ink parse
test/if_def_block.ink parse
test/if_def_expression.ink parse
test/if_if_if.ink parse test/if_if_if.ink parse
test/inferred_types.ink parse test/inferred_types.ink parse
test/large_block.ink parse test/large_block.ink parse

View File

@@ -1,30 +0,0 @@
test/wrong_type_for_function.ink:11,17: error: Procedure call did not match any of the possible overloads for 'float4'
 found:
color : float4 = float4(y, 1.0, 1.0, 1.0);
^^^^^^
 While matching argument 1 in function call.
 color : float4 = float4(y, 1.0, 1.0, 1.0);
^
 Possible overloads:
 float4 :: (float, float, float, float); (test/wrong_type_for_function.ink:0)
 float4 :: (float2, float2); (test/wrong_type_for_function.ink:0)
 float4 :: (float2, float, float); (test/wrong_type_for_function.ink:0)
 float4 :: (float, float2, float); (test/wrong_type_for_function.ink:0)
 float4 :: (float, float, float2); (test/wrong_type_for_function.ink:0)
 float4 :: (float, float3); (test/wrong_type_for_function.ink:0)
 float4 :: (float3, float); (test/wrong_type_for_function.ink:0)
 float4 :: (float4); (test/wrong_type_for_function.ink:0)
 float4 :: (float); (test/wrong_type_for_function.ink:0)
test/wrong_type_for_function.ink:11,24: error: Type mismatch. Expected float got float2
 found:
color : float4 = float4(y, 1.0, 1.0, 1.0);
^
expected:
float
got:
y : float2 = foo()


View File

@@ -1,40 +0,0 @@
test/assign_arithmetic_expression.ink semant
test/basic_property_and_return_value.ink semant
test/builtin_types.ink semant
test/complicated_computation.ink semant
test/constant_buffer.ink semant
test/empty_struct.ink semant
test/empty_vertex_main.ink semant
test/empty_vertex_main_with_position_parameter.ink semant
test/field_assignment.ink semant
test/for_i_loop.ink semant
test/function_call.ink semant
test/function_call_out_of_order_declaration.ink semant
test/function_call_return.ink semant
test/functions_with_same_name.ink semant
test/function_with_int_return.ink semant
test/if_cond_assign.ink semant
test/inferred_types.ink semant
test/multiple_functions.ink semant
test/multiple_semicolons_everywhere.ink semant
test/nested_if.ink semant
test/non_bool_cond.ink semant
test/pass_and_access_struct_fields_in_functions.ink semant
test/passthrough.ink semant
test/property_rename.ink semant
test/redeclared_variable.ink semant
test/simple_else_if.ink semant
test/simple_if_else.ink semant
test/simple_if.ink semant
test/simple_struct_access.ink semant
test/struct_access_primitive_type.ink semant
test/struct_within_struct.ink semant
test/type_as_variable_name.ink semant
test/unary.ink semant
test/undeclared_function.ink semant
test/undeclared_symbol.ink semant
test/unknown_overload.ink semant
test/use_builtin_functions.ink semant
test/wrong_argument_count.ink semant
test/wrong_multiply.ink semant
test/wrong_type_for_function.ink semant