diff --git a/AST.jai b/AST.jai index 918e98a..ff1efb1 100644 --- a/AST.jai +++ b/AST.jai @@ -356,6 +356,29 @@ pretty_print_node :: (node : *AST_Node, indentation : int, builder : *String_Bui case .If; { 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 { + append(builder, "\n"); + pretty_print_node(node.children[2], indentation + 4, builder); + } + + append(builder, ")"); + } case .For; { pretty_print_for(node, indentation, builder, skip_indent); } @@ -479,9 +502,26 @@ pretty_print_declaration :: (declaration : *AST_Node, indentation : int, builder pretty_print_node(declaration.children[0], 0, builder); append(builder, "\n"); 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 { 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); } } diff --git a/Semantic_Analysis.jai b/Check.jai similarity index 85% rename from Semantic_Analysis.jai rename to Check.jai index a6083dc..b0a8a58 100644 --- a/Semantic_Analysis.jai +++ b/Check.jai @@ -135,7 +135,7 @@ Checker_State :: enum { Adding_Builtins; } -Semantic_Checker :: struct { +Checker :: struct { program_root : *AST_Node; path : string; @@ -152,17 +152,17 @@ Semantic_Checker :: struct { 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[0] = 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); } -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 '%': @@ -184,7 +184,7 @@ symbol_redeclaration :: (checker : *Semantic_Checker, redeclared_node : *AST_Nod cyan(*builder); 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); 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); 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); 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); } -symbol_undeclared :: (checker : *Semantic_Checker, node : *AST_Node) { +symbol_undeclared :: (checker : *Checker, node : *AST_Node) { /* Use of undeclard symbol '%'. b = f; @@ -231,7 +231,7 @@ Use of undeclard symbol '%'. cyan(*builder); 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); 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); } -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; init_string_builder(*builder,, temp); @@ -250,7 +250,7 @@ no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, ov indent(*builder, 1); append(*builder, "found:\n"); 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); print_token_pointer(*builder, call.source_location.main_token); newline(*builder); @@ -275,7 +275,7 @@ no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, ov cyan(*builder); 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); print_token_pointer(*builder, arg_node.source_location.main_token); 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; indent(*builder, 2); + if func.builtin { + 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); + } // @Incomplete(niels): We need a way to properly save the path of the declaration - print_to_builder(*builder, "% (%:%)\n", print_from_source_location(func_location), checker.path, - func_location.main_token.line); + if !arg_node { 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; init_string_builder(*builder,, temp); @@ -328,7 +333,7 @@ not_all_control_paths_return_value :: (checker : *Semantic_Checker, node : *AST_ 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); 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); } -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; init_string_builder(*builder,, temp); @@ -364,7 +369,7 @@ Too many arguments: Expected %, got %. indent(*builder, 1); append(*builder, "found:\n"); 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); print_token_pointer(*builder, call.source_location.main_token); append(*builder, "\n\n"); @@ -372,7 +377,7 @@ Too many arguments: Expected %, got %. append(*builder, "expected:\n"); 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[0] = call.source_location; @@ -381,7 +386,7 @@ Too many arguments: Expected %, got %. 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'. @@ -395,7 +400,7 @@ Error: Undeclared identifier 'name'. print_to_builder(*builder, "Attempt to call undeclared function '%'.\n\n", node.name); cyan(*builder); 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); print_token_pointer(*builder, node.source_location.main_token); newline(*builder); @@ -404,7 +409,7 @@ Error: Undeclared identifier 'name'. 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 '%'. b.t = f; @@ -423,7 +428,7 @@ Field '%' is not defined in struct '%'. cyan(*builder); 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); print_token_pointer(*builder, node.source_location.main_token); newline(*builder); @@ -431,13 +436,13 @@ Field '%' is not defined in struct '%'. indent(*builder, 1); 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); 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 '%'. x.d = 5; @@ -451,11 +456,11 @@ Attempting to access a field on a primitive type '%'. init_string_builder(*builder,, temp); 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); 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); 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"); 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); record_error(checker, message, node.source_location, false); @@ -479,7 +484,7 @@ Attempting to access a field on a primitive type '%'. 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. if 100.0 @@ -499,7 +504,7 @@ if_condition_has_to_be_boolean_type :: (checker : *Semantic_Checker, usage_site 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); 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_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); 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); } -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); got_var := from_handle(checker, got); @@ -545,7 +550,7 @@ type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_no indent(*builder, 1); append(*builder, "found:\n"); 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); 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); print_to_builder(*builder, "expected:\n"); 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"); // indent(*builder, 2); @@ -572,14 +577,14 @@ type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_no 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); 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.message_kind = .Error; error.report_source_location = report_source_location; @@ -607,7 +612,7 @@ is_proper :: (var : Type_Variable) -> bool { 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); previous_scope := checker.current_scope; checker.current_scope = handle; @@ -615,7 +620,7 @@ use_scope :: (checker : *Semantic_Checker, handle : Scope_Handle) -> Scope_Handl 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; 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; } -pop_scope :: (checker : *Semantic_Checker) -> Scope_Handle { +pop_scope :: (checker : *Checker) -> Scope_Handle { scope := get_scope(checker, checker.current_scope); if !scope.parent { return 0; @@ -652,7 +657,7 @@ pop_scope :: (checker : *Semantic_Checker) -> Scope_Handle { 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 { return null, 0; } @@ -662,7 +667,7 @@ peek_scope :: (checker : *Semantic_Checker) -> *Scope, Scope_Handle { return scope, xx count; } -get_current_scope :: (checker : *Semantic_Checker) -> *Scope { +get_current_scope :: (checker : *Checker) -> *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]; } -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); } @@ -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); } -new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Variable_Handle { +new_type_variable :: (checker : *Checker) -> *Type_Variable, Type_Variable_Handle { variable : Type_Variable; handle := cast(Type_Variable_Handle)checker.ctx.type_variables.count + 1; 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; } -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.name = name; @@ -720,7 +725,7 @@ Arg :: struct { 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); 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; } -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); 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.source_node = builtin_node; function.type_variable = handle; - + function.builtin = true; find_result := find_symbol(checker, name, checker.current_scope); if !find_result { @@ -822,13 +827,13 @@ add_child :: (variable : *Type_Variable, child : Type_Variable_Handle) { // 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); assert(variable.children.count < Type_Variable.MAX_TYPE_VARIABLE_CHILDREN); 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_sampler_index = 0; checker.current_texture_index = 0; @@ -864,11 +869,11 @@ find_symbol :: (scope_stack : Scope_Stack, name : string, current_scope : Scope_ 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); } -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); } @@ -877,11 +882,11 @@ from_handle :: (variables : []Type_Variable, handle : Type_Variable_Handle) -> * 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); } -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 == { case .Int; #through; case .Half; #through; @@ -900,7 +905,7 @@ proper_type_to_string :: (builder : *String_Builder, variables : []Type_Variable if child.kind == .FieldList { for field : child.children { var := field.type_variable; - print_type_variable(builder, variables, var); + print_type_variable(ctx, builder, variables, var); if it_index != child.children.count - 1 { append(builder, ", "); @@ -915,10 +920,10 @@ proper_type_to_string :: (builder : *String_Builder, variables : []Type_Variable append(builder, " -> ", ); return_var := from_handle(variables, var.return_type_variable); if is_proper(return_var) { - proper_type_to_string(builder, variables, return_var); + proper_type_to_string(ctx, builder, variables, return_var); } else { append(builder, "[["); - print_type_variable(builder, variables, var.return_type_variable); + print_type_variable(ctx, builder, variables, var.return_type_variable); append(builder, "]]", ); } } 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 == { case .Int; #through; case .Half; #through; @@ -943,7 +948,7 @@ proper_type_to_string :: (variables : []Type_Variable, var : Type_Variable, allo builder : String_Builder; 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); } case .Struct; { @@ -954,7 +959,7 @@ proper_type_to_string :: (variables : []Type_Variable, var : Type_Variable, allo 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 == { case Typenames[Type_Kind.Int]; return .Int; case Typenames[Type_Kind.Half]; return .Half; @@ -980,18 +985,18 @@ lookup_type :: (checker : *Semantic_Checker, scope : Scope_Handle, type_string : 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; 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 { 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.type = .Struct; variable.source_kind = .Declaration; @@ -1034,11 +1039,11 @@ declare_struct :: (checker : *Semantic_Checker, node : *AST_Node, name : string) 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); } -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; if node.name.count > 0 { @@ -1053,7 +1058,7 @@ declare_properties :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Va 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); var := from_handle(checker, type_var); var.type = .CBuffer; @@ -1073,11 +1078,11 @@ get_actual_function_name :: (node : *AST_Node) -> string { 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); } -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) { invalid_symbol_name(checker, node, "function"); return 0; @@ -1204,7 +1209,7 @@ declare_function :: (checker : *Semantic_Checker, node : *AST_Node, builtin : bo 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); find_result := find_symbol(checker, name_to_check, checker.current_scope); @@ -1238,6 +1243,10 @@ check_function :: (checker : *Semantic_Checker, node : *AST_Node) { stm := from_handle(checker, result_var); add_child(variable, result_var); } + + if statement.kind == .If_Directive { + break; + } } } } @@ -1251,7 +1260,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); // x : int; // x.d = 5; @@ -1296,7 +1305,7 @@ check_variable :: (checker : *Semantic_Checker, node : *AST_Node, struct_field_p return 0; } -can_declare :: (checker : *Semantic_Checker, name : string) -> bool { +can_declare :: (checker : *Checker, name : string) -> bool { max_value := Type_Kind.Max_Builtin; for i : 0..max_value - 1 { @@ -1309,7 +1318,7 @@ can_declare :: (checker : *Semantic_Checker, name : string) -> bool { } //@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.name = node.name; typename : string; @@ -1393,7 +1402,7 @@ check_field :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_ 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); if !find_result { @@ -1505,7 +1514,7 @@ check_call :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Va 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 == { case .Function; { check_function(checker, node); @@ -1645,8 +1654,7 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H } } case .If_Directive; { - cond_var := check_node(checker, node.children[0]); - assert(false, "Not implemented yet\n"); + check_if_directive(checker, node); } case .Variable; { return check_variable(checker, node); @@ -1686,22 +1694,106 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H return 0; } -traverse :: (checker : *Semantic_Checker, root : *AST_Node) { +is_valid_define :: (checker : *Checker, def : string) -> bool { + for env_def : checker.ctx.environment.defines { + 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.foreign_declaration { + fun_handle := declare_foreign_function(checker, declaration); + } else { + fun_handle := declare_function(checker, declaration); + } + } else if declaration.kind == .Properties { + declare_properties(checker, declaration); + } else if declaration.kind == .Struct { + declare_struct(checker, declaration); + } else if declaration.kind == .CBuffer { + 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 { - if declaration.kind == .Function { - if declaration.foreign_declaration { - fun_handle := declare_foreign_function(checker, declaration); - } else { - fun_handle := declare_function(checker, declaration); - } - } else if declaration.kind == .Properties { - declare_properties(checker, declaration); - } else if declaration.kind == .Struct { - declare_struct(checker, declaration); - } else if declaration.kind == .CBuffer { - declare_cbuffer(checker, declaration); - } + check_declaration(checker, declaration); } if checker.had_error { @@ -1709,15 +1801,19 @@ traverse :: (checker : *Semantic_Checker, root : *AST_Node) { } for declaration : declarations { + if declaration.kind == .If_Directive { + continue; + } + check_node(checker, declaration); } } -traverse :: (checker : *Semantic_Checker) { +traverse :: (checker : *Checker) { 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); rhs_var := from_handle(checker, rhs); @@ -1797,7 +1893,7 @@ types_compatible :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rh return false; } -add_builtins_new :: (checker : *Semantic_Checker) { +add_builtins_new :: (checker : *Checker) { checker.state = .Adding_Builtins; float_name := Typenames[Type_Kind.Float]; @@ -2065,7 +2161,7 @@ add_builtins_new :: (checker : *Semantic_Checker) { checker.state = .Type_Checking; } -add_builtins :: (checker : *Semantic_Checker) { +add_builtins :: (checker : *Checker) { source_location := #location().fully_pathed_filename; path_array := split(source_location, "/"); @@ -2084,7 +2180,7 @@ add_builtins :: (checker : *Semantic_Checker) { if !ok { messages : [..]Compiler_Message; internal_error_message(*messages, "Error loading builtin functions.", checker.path); - print("%\n", report_messages(messages)); + print("%\n", report_messages(checker.ctx, messages)); assert(false); return; } @@ -2123,7 +2219,7 @@ add_builtins :: (checker : *Semantic_Checker) { checker.ctx.tokens = prev_tokens; } -type_check :: (checker : *Semantic_Checker, root : *AST_Node) { +type_check :: (checker : *Checker, root : *AST_Node) { traverse(checker, root); } @@ -2138,7 +2234,7 @@ check :: (ctx : *Compiler_Context, allocator : Allocator = temp) { init_context_allocators(); defer clear_context_allocators(); - checker : Semantic_Checker; + checker : Checker; checker.current_buffer_index = 0; checker.current_sampler_index = 0; @@ -2255,7 +2351,7 @@ pretty_print_struct :: (scope_stack : *Scope_Stack, current_scope : Scope_Handle 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 { return; } @@ -2291,7 +2387,7 @@ pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack, if type_variable.typename.count > 0 && type_variable.source_kind != .Declaration { indent(builder, indentation + 1); 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"); // print_to_builder(builder, "%\n", type_variable.typename); } else { @@ -2334,7 +2430,7 @@ pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack, for child : scope.children { 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 { @@ -2343,7 +2439,7 @@ pretty_print_scope :: (current_scope : Scope_Handle, scope_stack : Scope_Stack, 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.type != .Function || variable.type != .Struct { print_to_builder(builder, "%", type_to_string(variable)); @@ -2391,13 +2487,13 @@ print_type_variable :: (builder : *String_Builder, variables : []Type_Variable, source_location.end = right_most.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; { if variable.return_type_variable{ assert(false); 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); @@ -2406,7 +2502,7 @@ print_type_variable :: (builder : *String_Builder, variables : []Type_Variable, for child : node.children { if child.kind == .ArgList { 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 { append(builder, ", "); @@ -2418,23 +2514,23 @@ print_type_variable :: (builder : *String_Builder, variables : []Type_Variable, append(builder, ")"); } 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); - 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; 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); } @@ -2444,7 +2540,7 @@ pretty_print_symbol_table :: (ctx : *Compiler_Context, allocator : Allocator) -> init_string_builder(*builder,, allocator); 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); } diff --git a/Codegen.jai b/Codegen.jai index 8dbe59d..092d8bd 100644 --- a/Codegen.jai +++ b/Codegen.jai @@ -11,16 +11,13 @@ Output_Language :: enum { HLSL; GLSL; // @Incomplete MLSL; // @Incomplete + // SPIRV; // @Incomplete: Should we do this? } Codegen_State :: struct { path : string; - // scope_stack : Scope_Stack; current_scope : Scope_Handle; - - // type_variables : []Type_Variable; - // root : *AST_Node; output_language : Output_Language; @@ -29,14 +26,6 @@ Codegen_State :: struct { 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.[ "texture", "sampler", @@ -131,27 +120,24 @@ emit_field :: (state : *Codegen_State, node : *AST_Node, indentation : int) { child := node.children[0]; print_to_builder(*state.builder, " = "); - emit_node(state, child, 0); - + emit_node(state, child, 0); } if node.parent.kind == .Block { append(*state.builder, ";"); } - for i :0..field.children.count - 1 { child := from_handle(state.result.type_variables, field.children[i]); emit_node(state, child.source_node, 0); } for hint : node.hint_tokens { - if hint.ident_value == "position" { - // @Incomplete(nb): Should be a lookup table somewhere + if lookup_hint(hint.ident_value) == .Position { append(*state.builder, " : POSITION"); - } else if hint.ident_value == "uv" { + } else if lookup_hint(hint.ident_value) == .UV { append(*state.builder, " : TEXCOORD0"); - } else if hint.ident_value == "outposition" { + } else if lookup_hint(hint.ident_value) == .Output_Position { append(*state.builder, " : SV_POSITION"); } } diff --git a/Error.jai b/Error.jai index 3559a72..6feb05b 100644 --- a/Error.jai +++ b/Error.jai @@ -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; init_string_builder(*builder); for message : messages { - report_message(*builder, message); + report_message(ctx, *builder, message); } return builder_to_string(*builder); } -report_message :: (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 : *Compiler_Context, builder : *String_Builder, message : Compiler_Message) { + 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"); if path.count > 0 { print_to_builder(builder, "%:", path); @@ -140,7 +140,7 @@ report_message :: (builder : *String_Builder, path : string, message : string, s if report_source_location { for location : source_locations { append(builder, "\t"); - print_from_source_location(builder, location); + print_from_source_location(ctx, builder, location); append(builder, "\n\t"); begin := location.begin; diff --git a/Ink.jai b/Ink.jai index b833087..f744cec 100644 --- a/Ink.jai +++ b/Ink.jai @@ -18,13 +18,13 @@ #load "module.jai"; -GOLDEN_EXTENSION :: "golden"; -LEXER_FOLDER :: "lex"; -PARSER_FOLDER :: "parse"; -CODEGEN_FOLDER :: "codegen"; -COMPILED_FOLDER :: "compiled"; -SEMANTIC_ANALYSIS_FOLDER :: "semant"; -TESTS_FOLDER :: "test"; +GOLDEN_EXTENSION :: "golden"; +LEXER_FOLDER :: "lex"; +PARSER_FOLDER :: "parse"; +CODEGEN_FOLDER :: "codegen"; +COMPILED_FOLDER :: "compiled"; +CHECK_FOLDER :: "check"; +TESTS_FOLDER :: "test"; SHADER_EXTENSION :: "ink"; SUITE_EXTENSION :: "suite"; @@ -32,7 +32,7 @@ SUITE_EXTENSION :: "suite"; Stage_Flags :: enum_flags u16 { Lexer :: 0x1; Parser :: 0x2; - Semantic_Analysis :: 0x4; + Check :: 0x4; Codegen :: 0x8; Compile :: 0x10; } @@ -97,10 +97,10 @@ get_golden_path :: (file_path : string, stage : Stage_Flags) -> string { make_directory_if_it_does_not_exist(dir); array_add(*path.words, PARSER_FOLDER); } - case .Semantic_Analysis; { - dir := tprint("%/%", TESTS_FOLDER, SEMANTIC_ANALYSIS_FOLDER); + case .Check; { + dir := tprint("%/%", TESTS_FOLDER, CHECK_FOLDER); make_directory_if_it_does_not_exist(dir); - array_add(*path.words, SEMANTIC_ANALYSIS_FOLDER); + array_add(*path.words, CHECK_FOLDER); } case .Codegen; { 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 { result.type = .Failed; - result_text = report_messages(ctx.messages); + result_text = report_messages(ctx, ctx.messages); return result; } @@ -261,7 +261,7 @@ run_lexer_test :: (file_path : string, ctx : *Compiler_Context, output_type : Ou lex(ctx); if ctx.had_error { result.type = .Failed; - result_text = report_messages(ctx.messages); + result_text = report_messages(ctx, ctx.messages); } else { result_text = pretty_print_tokens(ctx.tokens, context.allocator); } @@ -300,7 +300,7 @@ run_parser_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) -> R if ctx.had_error { result.type = .Failed; - result_text = report_messages(ctx.messages); + result_text = report_messages(ctx, ctx.messages); } else { result_text = pretty_print_ast(ctx.root, context.allocator); } @@ -316,7 +316,7 @@ run_parser_test :: (ctx : *Compiler_Context, output_type : Output_Type = 0) -> R 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.path = ctx.file.path; result_text : string; @@ -325,7 +325,7 @@ run_semantic_analysis_test :: (ctx : *Compiler_Context, output_type : Output_Typ if ctx.had_error { result.type = .Failed; - result_text = report_messages(ctx.messages); + result_text = report_messages(ctx, ctx.messages); } else { result_text = pretty_print_symbol_table(ctx, context.allocator); } @@ -336,12 +336,12 @@ run_semantic_analysis_test :: (ctx : *Compiler_Context, output_type : Output_Typ 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); 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.path = file_path; @@ -352,7 +352,7 @@ run_semantic_analysis_test :: (file_path : string, ctx : *Compiler_Context, outp return result; } - result = run_semantic_analysis_test(ctx, output_type); + result = run_check_test(ctx, output_type); return result; } @@ -389,17 +389,17 @@ run_test_new :: (file_path : string, stage_flags : Stage_Flags, results : *[..]R record_result(results, result); } - if stage_flags & .Semantic_Analysis { + if stage_flags & .Check { 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 { - result = run_semantic_analysis_test(file_path, *ctx, output_type); + result = run_check_test(file_path, *ctx, output_type); } record_result(results, result); } 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); } else { result = run_codegen_test(file_path, *ctx, output_type); @@ -554,8 +554,8 @@ read_suite :: (file_path : string, suite : *Test_Suite, allocator := temp) -> bo stage_flags |= .Lexer; } else if equal(trimmed, "parse") { stage_flags |= .Parser; - } else if equal(trimmed, "semant") { - stage_flags |= .Semantic_Analysis; + } else if equal(trimmed, "check") { + stage_flags |= .Check; } else if equal(trimmed, "codegen") { stage_flags |= .Codegen; } else if equal(trimmed, "compile") { @@ -577,7 +577,7 @@ stage_to_string :: (stage : Stage_Flags) -> string { if #complete stage == { case .Lexer; return "lexing"; case .Parser; return "parsing"; - case .Semantic_Analysis; return "semantic checking"; + case .Check; return "checking"; case .Codegen; return "codegen"; case .Compile; return "compiled"; case; return ""; @@ -671,8 +671,8 @@ main :: () { current_suite.test_cases[cases - 1].stage_flags |= .Lexer; } else if arg == "-parse" { current_suite.test_cases[cases - 1].stage_flags |= .Parser; - } else if arg == "-semant" { - current_suite.test_cases[cases - 1].stage_flags |= .Semantic_Analysis; + } else if arg == "-check" { + current_suite.test_cases[cases - 1].stage_flags |= .Check; } else if arg == "-codegen" { current_suite.test_cases[cases - 1].stage_flags |= .Codegen; } else if arg == "-compile" { diff --git a/Lexing.jai b/Lexing.jai index 9afd815..996a60a 100644 --- a/Lexing.jai +++ b/Lexing.jai @@ -11,6 +11,7 @@ Lexer :: struct { } Token_Kind :: enum { + TOKEN_INVALID :: 0; TOKEN_FLOATLITERAL; TOKEN_INTLITERAL; @@ -129,7 +130,7 @@ Token :: struct { // This could all be derived on demand line : int; length : int; - column : int; + column : int; index : int; error : string; @@ -386,7 +387,12 @@ make_directive :: (lexer : *Lexer) -> *Token { for tok : ctx.tokens { 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; } @@ -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; begin := source_location.begin; 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; token_string : string; 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(); defer scratch_end(sc); builder : String_Builder; 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); } diff --git a/Parsing.jai b/Parsing.jai index e83e6ce..fe79755 100644 --- a/Parsing.jai +++ b/Parsing.jai @@ -186,7 +186,7 @@ unexpected_token :: (state : *Parse_State, token : Token, message : string) { indent(*builder, 1); 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); print_token_pointer(*builder, token); @@ -207,7 +207,7 @@ else_if_without_if :: (state : *Parse_State) { indent(*builder, 1); 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); print_token_pointer(*builder, token); @@ -229,7 +229,7 @@ else_without_if :: (state : *Parse_State) { indent(*builder, 1); 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); print_token_pointer(*builder, token); @@ -249,7 +249,7 @@ unable_to_parse_statement :: (state : *Parse_State, token : Token, message : str indent(*builder, 1); 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); @@ -269,7 +269,7 @@ expected_expression :: (state : *Parse_State, token : Token, message : string) { indent(*builder, 1); 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); print_token_pointer(*builder, token); @@ -288,7 +288,7 @@ missing_type_specifier :: (state : *Parse_State, token : Token, message : string indent(*builder, 1); 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; @@ -312,7 +312,7 @@ empty_block :: (state : *Parse_State, token : Token, message : string) { indent(*builder, 1); 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; @@ -336,7 +336,26 @@ unable_to_open_file :: (state : *Parse_State, path : string, token : Token) { indent(*builder, 1); 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); loc := location.begin; @@ -383,28 +402,13 @@ make_node :: (parse_state : *Parse_State, kind : AST_Kind) -> *AST_Node { return make_node(*parse_state.ctx.nodes, kind); } -// new_builtin_node :: (nodes : *[..]AST_Node, kind : AST_Kind) -> *AST_Node { -// 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 { +make_builtin_token :: (tokens : *[..]Token, kind : Token_Kind, text : string, col : *int, line : *int) -> *Token { tok : Token; tok.kind = kind; start := 0; - buffer := get_current_buffer(builder); - - if buffer { - start := buffer.count; - } tok.column = col.*; - - print_to_builder(builder, "%", text); - buffer = get_current_buffer(builder); - end := buffer.count; for c : text { if c == #char "\n" { @@ -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.builtin = true; + tok.source = text.data; + tok.ident_value = text; 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 { sc := get_scratch(context.allocator); 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); source_location : Source_Range; @@ -439,17 +442,13 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : [] 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; source_location.begin = ident_token; - append(*builder, " "); - make_builtin_token(*ctx.tokens, *builder, .TOKEN_DOUBLECOLON, "::", *col, *line); - append(*builder, " "); - 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"); + make_builtin_token(*ctx.tokens, .TOKEN_DOUBLECOLON, " :: ", *col, *line); + make_builtin_token(*ctx.tokens, .TOKEN_STRUCT, "struct ", *col, *line); + make_builtin_token(*ctx.tokens, .TOKEN_LEFTBRACE, "{\n\t", *col, *line); line += 1; col = 0; @@ -460,18 +459,14 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : [] field := make_node(*ctx.nodes, .Field); field_source_loc : Source_Range; - indent(*builder, 1); - field_ident := make_builtin_token(*ctx.tokens, *builder, .TOKEN_IDENTIFIER, tprint("%", member.name), *col, *line); + field_ident := make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, member.name, *col, *line); field_source_loc.begin = field_ident; field.token = field_ident; field.name = member.name; - append(*builder, " "); - make_builtin_token(*ctx.tokens, *builder, .TOKEN_COLON, ":", *col, *line); - append(*builder, " "); - 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"); + make_builtin_token(*ctx.tokens, .TOKEN_COLON, ": ", *col, *line); + make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, member.typename, *col, *line); + semicolon_tok := make_builtin_token(*ctx.tokens, .TOKEN_SEMICOLON, ";", *col, *line); col = 0; line += 1; @@ -481,26 +476,9 @@ new_builtin_struct_node :: (ctx : *Compiler_Context, name : string, members : [] add_child(field_list, field); } - brace_token := make_builtin_token(*ctx.tokens, *builder, .TOKEN_RIGHTBRACE, "}", *col, *line); - append(*builder, "\n"); + brace_token := make_builtin_token(*ctx.tokens, .TOKEN_RIGHTBRACE, "\n}", *col, *line); 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; @@ -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 { sc := get_scratch(context.allocator); 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); @@ -522,13 +498,11 @@ new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members : 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; - append(*builder, " "); - make_builtin_token(*ctx.tokens, *builder, .TOKEN_DOUBLECOLON, "::", *col, *line); - append(*builder, " "); - make_builtin_token(*ctx.tokens, *builder, .TOKEN_LEFTPAREN, "(", *col, *line); + make_builtin_token(*ctx.tokens, .TOKEN_DOUBLECOLON, " :: ", *col, *line); + make_builtin_token(*ctx.tokens, .TOKEN_LEFTPAREN, "(", *col, *line); field_list := make_node(*ctx.nodes, .FieldList); 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_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, *builder, .TOKEN_IDENTIFIER, tprint("%", member.typename), *col, *line); + type_tok := make_builtin_token(*ctx.tokens, .TOKEN_IDENTIFIER, member.typename, *col, *line); field_source_loc.begin = type_tok; field.token = type_tok; if it_index < members.count - 1 { - make_builtin_token(*ctx.tokens, *builder, .TOKEN_COMMA, ",", *col, *line); - append(*builder, " "); + make_builtin_token(*ctx.tokens, .TOKEN_COMMA, ", ", *col, *line); } field_source_loc.end = type_tok; @@ -552,26 +524,10 @@ new_builtin_function_node :: (ctx : *Compiler_Context, name : string, members : add_child(field_list, field); } - make_builtin_token(*ctx.tokens, *builder, .TOKEN_RIGHTPAREN, ")", *col, *line); - semicolon_tok := make_builtin_token(*ctx.tokens, *builder, .TOKEN_SEMICOLON, ";", *col, *line); + make_builtin_token(*ctx.tokens, .TOKEN_RIGHTPAREN, ")", *col, *line); + semicolon_tok := make_builtin_token(*ctx.tokens, .TOKEN_SEMICOLON, ";", *col, *line); 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; @@ -838,16 +794,28 @@ directive :: (state : *Parse_State) -> *AST_Node { if_directive := make_node(state, .If_Directive); 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); cond := expression(state); add_child(if_directive, cond); + source_location.end = state.previous; + advance_to_sync_point(state); + if_body := block(state); 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; return if_directive; @@ -1256,13 +1224,15 @@ statement :: (parse_state : *Parse_State) -> *AST_Node { else_statement :: (parse_state : *Parse_State) -> *AST_Node { if check(parse_state, .TOKEN_IF) { 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); } block :: (parse_state : *Parse_State) -> *AST_Node { node : *AST_Node = make_node(parse_state, .Block); - array_reserve(*node.children, 1024); + array_reserve(*node.children, 32); source_location : Source_Range; @@ -1361,10 +1331,22 @@ function_declaration :: (parse_state : *Parse_State, identifier_token : *Token, case .Vertex; { node.vertex_entry_point = true; 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; { node.pixel_entry_point = true; 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, ""); + // } } } diff --git a/module.jai b/module.jai index 89d69fd..8cd9cab 100644 --- a/module.jai +++ b/module.jai @@ -1,11 +1,20 @@ #load "Lexing.jai"; #load "Error.jai"; #load "Parsing.jai"; -#load "Semantic_Analysis.jai"; +#load "Check.jai"; #load "Codegen.jai"; #import "File_Utilities"; +/* TODO +- [ ] 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 +- [ ] Support #if + +*/ + add_define :: (env : *Environment, key : string) { for define : env.defines { if define == key { @@ -55,10 +64,33 @@ Hint_Kind :: enum { Position; UV; Target; + Output_Position; 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 { kind : Hint_Kind; @@ -99,21 +131,11 @@ Constant_Buffer :: struct { fields : Static_Array(Property_Field, 16); - // hints : Field_Hint; // optional hint... hints : [..]Field_Hint; 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 { source : string; path : string; @@ -149,7 +171,7 @@ Compiler_Context :: struct { return_value : Field; } - properties : Properties; //@Note(niels): We'll deprecate this in favor of just marking a constant buffer how you'd want to use it + 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; @@ -159,7 +181,7 @@ Compiler_Context :: struct { messages : [..]Compiler_Message; } - #add_context scratch_allocators : [2]Allocator; +#add_context scratch_allocators : [2]Allocator; #add_context scratch_id : int = 0; init_context_allocators :: () { @@ -294,7 +316,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)); } @@ -349,13 +371,11 @@ type_variable_to_field :: (type_variables : []Type_Variable, scope_stack : Scope for hint : variable.source_node.hint_tokens { field_hint : Field_Hint; - if hint.ident_value == "position" { - // @Incomplete(nb): Should be a lookup table somewhere + if lookup_hint(hint.ident_value) == .Position { field_hint.kind = .Position; - } else if hint.ident_value == "uv" { + } else if lookup_hint(hint.ident_value) == .UV { field_hint.kind = .UV; - } else if starts_with(hint.ident_value, "target") { - // @Incomplete(nb): Should be a lookup table somewhere + } else if lookup_hint(hint.ident_value) == .Target { index_str : string; index_str.data = *hint.ident_value.data[7]; index_str.count = 1; @@ -381,7 +401,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)); } -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); } @@ -445,38 +465,36 @@ generate_output_data :: (ctx : *Compiler_Context) { ctx.properties.buffer_index = property_variable.resource_index; } - if ctx.pixel_entry_point.node { 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); assert(type_variable.type == .Function); - field := type_variable_to_field(ctx.type_variables, ctx.scope_stack, type_variable.return_type_variable); - for hint : type_variable.source_node.hint_tokens { - field_hint : Field_Hint; + if type_variable.return_type_variable > 0 { + field := type_variable_to_field(ctx.type_variables, ctx.scope_stack, type_variable.return_type_variable); + for hint : type_variable.source_node.hint_tokens { + field_hint : Field_Hint; - if hint.ident_value == "position" { - // @Incomplete(nb): Should be a lookup table somewhere - field_hint.kind = .Position; - } else if starts_with(hint.ident_value, "target") { - // @Incomplete(nb): Should be a lookup table somewhere - index_str : string; - index_str.data = *hint.ident_value.data[7]; - index_str.count = 1; - - result, ok, remainder := string_to_int(index_str); - if ok { - field_hint.target_index = result; + if lookup_hint(hint.ident_value) == .Position { + field_hint.kind = .Position; + } else if lookup_hint(hint.ident_value) == .Target { + index_str : string; + index_str.data = *hint.ident_value.data[7]; + index_str.count = 1; + + result, ok, remainder := string_to_int(index_str); + if ok { + field_hint.target_index = result; + } + field_hint.kind = .Target; + } else { + // @Incomplete(nb): custom hints } - field_hint.kind = .Target; - } else { - // @Incomplete(nb): custom hints + 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; + } } } diff --git a/test/semant/assign_arithmetic_expression.golden b/test/check/assign_arithmetic_expression.golden similarity index 100% rename from test/semant/assign_arithmetic_expression.golden rename to test/check/assign_arithmetic_expression.golden diff --git a/test/semant/basic_property_and_return_value.golden b/test/check/basic_property_and_return_value.golden similarity index 100% rename from test/semant/basic_property_and_return_value.golden rename to test/check/basic_property_and_return_value.golden diff --git a/test/semant/builtin_types.golden b/test/check/builtin_types.golden similarity index 100% rename from test/semant/builtin_types.golden rename to test/check/builtin_types.golden diff --git a/test/semant/complicated_computation.golden b/test/check/complicated_computation.golden similarity index 100% rename from test/semant/complicated_computation.golden rename to test/check/complicated_computation.golden diff --git a/test/semant/constant_buffer.golden b/test/check/constant_buffer.golden similarity index 100% rename from test/semant/constant_buffer.golden rename to test/check/constant_buffer.golden diff --git a/test/semant/custom_hint.golden b/test/check/custom_hint.golden similarity index 100% rename from test/semant/custom_hint.golden rename to test/check/custom_hint.golden diff --git a/test/semant/empty_struct.golden b/test/check/empty_struct.golden similarity index 100% rename from test/semant/empty_struct.golden rename to test/check/empty_struct.golden diff --git a/test/semant/empty_vertex_main.golden b/test/check/empty_vertex_main.golden similarity index 100% rename from test/semant/empty_vertex_main.golden rename to test/check/empty_vertex_main.golden diff --git a/test/semant/empty_vertex_main_with_position_parameter.golden b/test/check/empty_vertex_main_with_position_parameter.golden similarity index 100% rename from test/semant/empty_vertex_main_with_position_parameter.golden rename to test/check/empty_vertex_main_with_position_parameter.golden diff --git a/test/semant/field_assignment.golden b/test/check/field_assignment.golden similarity index 100% rename from test/semant/field_assignment.golden rename to test/check/field_assignment.golden diff --git a/test/semant/field_without_type_specifier.golden b/test/check/field_without_type_specifier.golden similarity index 100% rename from test/semant/field_without_type_specifier.golden rename to test/check/field_without_type_specifier.golden diff --git a/test/semant/float_if_cond.golden b/test/check/float_if_cond.golden similarity index 100% rename from test/semant/float_if_cond.golden rename to test/check/float_if_cond.golden diff --git a/test/semant/float_suffix.golden b/test/check/float_suffix.golden similarity index 100% rename from test/semant/float_suffix.golden rename to test/check/float_suffix.golden diff --git a/test/semant/for_i_loop.golden b/test/check/for_i_loop.golden similarity index 100% rename from test/semant/for_i_loop.golden rename to test/check/for_i_loop.golden diff --git a/test/semant/function_call.golden b/test/check/function_call.golden similarity index 100% rename from test/semant/function_call.golden rename to test/check/function_call.golden diff --git a/test/semant/function_call_out_of_order_declaration.golden b/test/check/function_call_out_of_order_declaration.golden similarity index 100% rename from test/semant/function_call_out_of_order_declaration.golden rename to test/check/function_call_out_of_order_declaration.golden diff --git a/test/semant/function_call_return.golden b/test/check/function_call_return.golden similarity index 100% rename from test/semant/function_call_return.golden rename to test/check/function_call_return.golden diff --git a/test/semant/function_with_int_return.golden b/test/check/function_with_int_return.golden similarity index 100% rename from test/semant/function_with_int_return.golden rename to test/check/function_with_int_return.golden diff --git a/test/semant/functions_with_same_name.golden b/test/check/functions_with_same_name.golden similarity index 100% rename from test/semant/functions_with_same_name.golden rename to test/check/functions_with_same_name.golden diff --git a/test/semant/if_cond_assign.golden b/test/check/if_cond_assign.golden similarity index 100% rename from test/semant/if_cond_assign.golden rename to test/check/if_cond_assign.golden diff --git a/test/semant/inferred_types.golden b/test/check/inferred_types.golden similarity index 100% rename from test/semant/inferred_types.golden rename to test/check/inferred_types.golden diff --git a/test/semant/meta_block.golden b/test/check/meta_block.golden similarity index 100% rename from test/semant/meta_block.golden rename to test/check/meta_block.golden diff --git a/test/semant/multiple_functions.golden b/test/check/multiple_functions.golden similarity index 100% rename from test/semant/multiple_functions.golden rename to test/check/multiple_functions.golden diff --git a/test/semant/multiple_semicolons_everywhere.golden b/test/check/multiple_semicolons_everywhere.golden similarity index 100% rename from test/semant/multiple_semicolons_everywhere.golden rename to test/check/multiple_semicolons_everywhere.golden diff --git a/test/semant/nested_if.golden b/test/check/nested_if.golden similarity index 100% rename from test/semant/nested_if.golden rename to test/check/nested_if.golden diff --git a/test/semant/non_bool_cond.golden b/test/check/non_bool_cond.golden similarity index 100% rename from test/semant/non_bool_cond.golden rename to test/check/non_bool_cond.golden diff --git a/test/semant/pass_and_access_struct_fields_in_functions.golden b/test/check/pass_and_access_struct_fields_in_functions.golden similarity index 100% rename from test/semant/pass_and_access_struct_fields_in_functions.golden rename to test/check/pass_and_access_struct_fields_in_functions.golden diff --git a/test/semant/passthrough.golden b/test/check/passthrough.golden similarity index 100% rename from test/semant/passthrough.golden rename to test/check/passthrough.golden diff --git a/test/semant/precedence_test.golden b/test/check/precedence_test.golden similarity index 100% rename from test/semant/precedence_test.golden rename to test/check/precedence_test.golden diff --git a/test/semant/property_rename.golden b/test/check/property_rename.golden similarity index 100% rename from test/semant/property_rename.golden rename to test/check/property_rename.golden diff --git a/test/semant/redeclared_variable.golden b/test/check/redeclared_variable.golden similarity index 100% rename from test/semant/redeclared_variable.golden rename to test/check/redeclared_variable.golden diff --git a/test/semant/simple_else_if.golden b/test/check/simple_else_if.golden similarity index 100% rename from test/semant/simple_else_if.golden rename to test/check/simple_else_if.golden diff --git a/test/semant/simple_if.golden b/test/check/simple_if.golden similarity index 100% rename from test/semant/simple_if.golden rename to test/check/simple_if.golden diff --git a/test/semant/simple_if_else.golden b/test/check/simple_if_else.golden similarity index 100% rename from test/semant/simple_if_else.golden rename to test/check/simple_if_else.golden diff --git a/test/semant/simple_struct_access.golden b/test/check/simple_struct_access.golden similarity index 100% rename from test/semant/simple_struct_access.golden rename to test/check/simple_struct_access.golden diff --git a/test/semant/struct_access_primitive_type.golden b/test/check/struct_access_primitive_type.golden similarity index 100% rename from test/semant/struct_access_primitive_type.golden rename to test/check/struct_access_primitive_type.golden diff --git a/test/semant/struct_within_struct.golden b/test/check/struct_within_struct.golden similarity index 100% rename from test/semant/struct_within_struct.golden rename to test/check/struct_within_struct.golden diff --git a/test/semant/type_as_function_name.golden b/test/check/type_as_function_name.golden similarity index 100% rename from test/semant/type_as_function_name.golden rename to test/check/type_as_function_name.golden diff --git a/test/semant/type_as_variable_name.golden b/test/check/type_as_variable_name.golden similarity index 100% rename from test/semant/type_as_variable_name.golden rename to test/check/type_as_variable_name.golden diff --git a/test/semant/unary.golden b/test/check/unary.golden similarity index 100% rename from test/semant/unary.golden rename to test/check/unary.golden diff --git a/test/semant/undeclared_function.golden b/test/check/undeclared_function.golden similarity index 100% rename from test/semant/undeclared_function.golden rename to test/check/undeclared_function.golden diff --git a/test/semant/undeclared_symbol.golden b/test/check/undeclared_symbol.golden similarity index 100% rename from test/semant/undeclared_symbol.golden rename to test/check/undeclared_symbol.golden diff --git a/test/semant/unknown_overload.golden b/test/check/unknown_overload.golden similarity index 100% rename from test/semant/unknown_overload.golden rename to test/check/unknown_overload.golden diff --git a/test/semant/use_builtin_functions.golden b/test/check/use_builtin_functions.golden similarity index 100% rename from test/semant/use_builtin_functions.golden rename to test/check/use_builtin_functions.golden diff --git a/test/semant/wrong_argument_count.golden b/test/check/wrong_argument_count.golden similarity index 100% rename from test/semant/wrong_argument_count.golden rename to test/check/wrong_argument_count.golden diff --git a/test/semant/wrong_multiply.golden b/test/check/wrong_multiply.golden similarity index 53% rename from test/semant/wrong_multiply.golden rename to test/check/wrong_multiply.golden index 1e10581..1312d16 100644 --- a/test/semant/wrong_multiply.golden +++ b/test/check/wrong_multiply.golden @@ -7,15 +7,15 @@  result : float4 = float4(1.0, foo * res, 0.0, 1.0); ^  Possible overloads: - float4 :: (float, float, float, float); (test/wrong_multiply.ink:0) - float4 :: (float2, float2); (test/wrong_multiply.ink:0) - float4 :: (float2, float, float); (test/wrong_multiply.ink:0) - float4 :: (float, float2, float); (test/wrong_multiply.ink:0) - float4 :: (float, float, float2); (test/wrong_multiply.ink:0) - float4 :: (float, float3); (test/wrong_multiply.ink:0) - float4 :: (float3, float); (test/wrong_multiply.ink:0) - float4 :: (float4); (test/wrong_multiply.ink:0) - float4 :: (float); (test/wrong_multiply.ink:0) + 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_multiply.ink:4,34: error: Type mismatch. Expected float got float2  found: diff --git a/test/check/wrong_type_for_function.golden b/test/check/wrong_type_for_function.golden new file mode 100644 index 0000000..5406253 --- /dev/null +++ b/test/check/wrong_type_for_function.golden @@ -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() + + \ No newline at end of file diff --git a/test/check_all.suite b/test/check_all.suite new file mode 100644 index 0000000..bf66c02 --- /dev/null +++ b/test/check_all.suite @@ -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 diff --git a/test/codegen/if_def_block.golden b/test/codegen/if_def_block.golden new file mode 100644 index 0000000..83e1fba --- /dev/null +++ b/test/codegen/if_def_block.golden @@ -0,0 +1,7 @@ +void ps_main() +{ + + float4 color = float4(1, 0, 0, 1); + float f = 2.0f; +} + diff --git a/test/codegen_all.suite b/test/codegen_all.suite index 4c8f5e4..04e3ee9 100644 --- a/test/codegen_all.suite +++ b/test/codegen_all.suite @@ -10,6 +10,9 @@ test/field_assignment.ink codegen test/function_call.ink codegen test/function_call_out_of_order_declaration.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/meta_block.ink codegen test/multiple_functions.ink codegen diff --git a/test/compile_all.suite b/test/compile_all.suite index 2bb5618..d227386 100644 --- a/test/compile_all.suite +++ b/test/compile_all.suite @@ -11,6 +11,9 @@ test/function_call.ink compile test/function_call_out_of_order_declaration.ink compile test/function_call_return.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/meta_block.ink compile test/multiple_functions.ink compile diff --git a/test/if_def_block.ink b/test/if_def_block.ink new file mode 100644 index 0000000..730171e --- /dev/null +++ b/test/if_def_block.ink @@ -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; +} +} diff --git a/test/if_def_expression.ink b/test/if_def_expression.ink new file mode 100644 index 0000000..9060df9 --- /dev/null +++ b/test/if_def_expression.ink @@ -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 :: () { + + } +} diff --git a/test/ifdefs.ink b/test/ifdefs.ink index 04f1612..16f1866 100644 --- a/test/ifdefs.ink +++ b/test/ifdefs.ink @@ -1,5 +1,17 @@ -#if Defines.Skinning { - vertex main :: () { - // Stub +//#add_define Skinning +#add_define UV + + +#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 :: () { + +} diff --git a/test/lex/if_def_block.golden b/test/lex/if_def_block.golden new file mode 100644 index 0000000..df791c6 --- /dev/null +++ b/test/lex/if_def_block.golden @@ -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 =''; } diff --git a/test/lex/if_def_expression.golden b/test/lex/if_def_expression.golden new file mode 100644 index 0000000..3a0cccd --- /dev/null +++ b/test/lex/if_def_expression.golden @@ -0,0 +1,34 @@ +{kind = TOKEN_DIRECTIVE; ; index = 62 ; length = 2 line = 5 ; column = 0 ; value ='if'; } +{kind = TOKEN_LEFTPAREN; ; index = 65 ; length = 1 line = 5 ; column = 3 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 66 ; length = 3 line = 5 ; column = 4 ; value ='Env'; } +{kind = TOKEN_DOT; ; index = 69 ; length = 1 line = 5 ; column = 7 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 70 ; length = 3 line = 5 ; column = 8 ; value ='PS5'; } +{kind = TOKEN_LOGICALAND; ; index = 74 ; length = 2 line = 5 ; column = 12 ; value ='&&'; } +{kind = TOKEN_IDENTIFIER; ; index = 77 ; length = 3 line = 5 ; column = 15 ; value ='Env'; } +{kind = TOKEN_DOT; ; index = 80 ; length = 1 line = 5 ; column = 18 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 81 ; length = 3 line = 5 ; column = 19 ; value ='XSX'; } +{kind = TOKEN_RIGHTPAREN; ; index = 84 ; length = 1 line = 5 ; column = 22 ; value =')'; } +{kind = TOKEN_LOGICALOR; ; index = 86 ; length = 2 line = 5 ; column = 24 ; value ='||'; } +{kind = TOKEN_IDENTIFIER; ; index = 89 ; length = 3 line = 5 ; column = 27 ; value ='Env'; } +{kind = TOKEN_DOT; ; index = 92 ; length = 1 line = 5 ; column = 30 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 93 ; length = 7 line = 5 ; column = 31 ; value ='Switch2'; } +{kind = TOKEN_LEFTBRACE; ; index = 101 ; length = 1 line = 5 ; column = 39 ; value ='{'; } +{kind = TOKEN_VERTEX; ; index = 105 ; length = 6 line = 6 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 112 ; length = 12 line = 6 ; column = 7 ; value ='console_main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 125 ; length = 2 line = 6 ; column = 20 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 128 ; length = 1 line = 6 ; column = 23 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 129 ; length = 1 line = 6 ; column = 24 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 131 ; length = 1 line = 6 ; column = 26 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 137 ; length = 1 line = 8 ; column = 0 ; value ='}'; } +{kind = TOKEN_RIGHTBRACE; ; index = 140 ; length = 1 line = 9 ; column = 0 ; value ='}'; } +{kind = TOKEN_ELSE; ; index = 142 ; length = 4 line = 9 ; column = 2 ; value ='else'; } +{kind = TOKEN_LEFTBRACE; ; index = 147 ; length = 1 line = 9 ; column = 7 ; value ='{'; } +{kind = TOKEN_VERTEX; ; index = 151 ; length = 6 line = 10 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 158 ; length = 12 line = 10 ; column = 7 ; value ='windows_main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 171 ; length = 2 line = 10 ; column = 20 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 174 ; length = 1 line = 10 ; column = 23 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 175 ; length = 1 line = 10 ; column = 24 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 177 ; length = 1 line = 10 ; column = 26 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 183 ; length = 1 line = 12 ; column = 0 ; value ='}'; } +{kind = TOKEN_RIGHTBRACE; ; index = 186 ; length = 1 line = 13 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 189 ; length = 0 line = 14 ; column = 0 ; value =''; } diff --git a/test/lex/ifdefs.golden b/test/lex/ifdefs.golden new file mode 100644 index 0000000..3722b9c --- /dev/null +++ b/test/lex/ifdefs.golden @@ -0,0 +1,52 @@ +{kind = TOKEN_DIRECTIVE; ; index = 45 ; length = 2 line = 5 ; column = 0 ; value ='if'; } +{kind = TOKEN_IDENTIFIER; ; index = 48 ; length = 3 line = 5 ; column = 3 ; value ='Env'; } +{kind = TOKEN_DOT; ; index = 51 ; length = 1 line = 5 ; column = 6 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 52 ; length = 8 line = 5 ; column = 7 ; value ='Skinning'; } +{kind = TOKEN_LEFTBRACE; ; index = 61 ; length = 1 line = 5 ; column = 16 ; value ='{'; } +{kind = TOKEN_VERTEX; ; index = 65 ; length = 6 line = 6 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 72 ; length = 13 line = 6 ; column = 7 ; value ='skinning_main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 86 ; length = 2 line = 6 ; column = 21 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 89 ; length = 1 line = 6 ; column = 24 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 90 ; length = 1 line = 6 ; column = 25 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 92 ; length = 1 line = 6 ; column = 27 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 97 ; length = 1 line = 7 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 99 ; length = 1 line = 7 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 101 ; length = 5 line = 7 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 107 ; length = 1 line = 7 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 109 ; length = 3 line = 7 ; column = 12 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 112 ; length = 1 line = 7 ; column = 15 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 116 ; length = 1 line = 8 ; column = 0 ; value ='}'; } +{kind = TOKEN_RIGHTBRACE; ; index = 119 ; length = 1 line = 9 ; column = 0 ; value ='}'; } +{kind = TOKEN_ELSE; ; index = 121 ; length = 4 line = 9 ; column = 2 ; value ='else'; } +{kind = TOKEN_DIRECTIVE; ; index = 127 ; length = 2 line = 9 ; column = 7 ; value ='if'; } +{kind = TOKEN_IDENTIFIER; ; index = 130 ; length = 3 line = 9 ; column = 10 ; value ='Env'; } +{kind = TOKEN_DOT; ; index = 133 ; length = 1 line = 9 ; column = 13 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 134 ; length = 2 line = 9 ; column = 14 ; value ='UV'; } +{kind = TOKEN_LEFTBRACE; ; index = 137 ; length = 1 line = 9 ; column = 17 ; value ='{'; } +{kind = TOKEN_VERTEX; ; index = 141 ; length = 6 line = 10 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 148 ; length = 20 line = 10 ; column = 7 ; value ='texture_mapping_main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 169 ; length = 2 line = 10 ; column = 28 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 172 ; length = 1 line = 10 ; column = 31 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 173 ; length = 1 line = 10 ; column = 32 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 175 ; length = 1 line = 10 ; column = 34 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 180 ; length = 1 line = 11 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 182 ; length = 1 line = 11 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 184 ; length = 6 line = 11 ; column = 4 ; value ='float2'; } +{kind = TOKEN_ASSIGN; ; index = 191 ; length = 1 line = 11 ; column = 11 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 193 ; length = 6 line = 11 ; column = 13 ; value ='float2'; } +{kind = TOKEN_LEFTPAREN; ; index = 199 ; length = 1 line = 11 ; column = 19 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 200 ; length = 3 line = 11 ; column = 20 ; value ='2'; } +{kind = TOKEN_COMMA; ; index = 203 ; length = 1 line = 11 ; column = 23 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 205 ; length = 3 line = 11 ; column = 25 ; value ='2'; } +{kind = TOKEN_RIGHTPAREN; ; index = 208 ; length = 1 line = 11 ; column = 28 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 209 ; length = 1 line = 11 ; column = 29 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 213 ; length = 1 line = 12 ; column = 0 ; value ='}'; } +{kind = TOKEN_RIGHTBRACE; ; index = 216 ; length = 1 line = 13 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 221 ; length = 5 line = 15 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 227 ; length = 4 line = 15 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 232 ; length = 2 line = 15 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 235 ; length = 1 line = 15 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 236 ; length = 1 line = 15 ; column = 15 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 238 ; length = 1 line = 15 ; column = 17 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 243 ; length = 1 line = 17 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 246 ; length = 0 line = 18 ; column = 0 ; value =''; } diff --git a/test/lex_all.suite b/test/lex_all.suite index 9655939..61d642e 100644 --- a/test/lex_all.suite +++ b/test/lex_all.suite @@ -20,6 +20,9 @@ test/function_call_return.ink lex test/functions_with_same_name.ink lex test/function_with_int_return.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/inferred_types.ink lex test/large_block.ink lex diff --git a/test/parse/if_def_block.golden b/test/parse/if_def_block.golden new file mode 100644 index 0000000..772ccd1 --- /dev/null +++ b/test/parse/if_def_block.golden @@ -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)))) \ No newline at end of file diff --git a/test/parse/if_def_expression.golden b/test/parse/if_def_expression.golden new file mode 100644 index 0000000..e5f5179 --- /dev/null +++ b/test/parse/if_def_expression.golden @@ -0,0 +1,6 @@ +(program + (#if (|| (&& Env.PS5 Env.XSX) Env.Switch2) + (fun vertex vs_console_main + []) + (fun vertex vs_windows_main + []))) \ No newline at end of file diff --git a/test/parse_all.suite b/test/parse_all.suite index 0fa32a8..5303a19 100644 --- a/test/parse_all.suite +++ b/test/parse_all.suite @@ -20,6 +20,9 @@ test/function_call_return.ink parse test/functions_with_same_name.ink parse test/function_with_int_return.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/inferred_types.ink parse test/large_block.ink parse diff --git a/test/semant/wrong_type_for_function.golden b/test/semant/wrong_type_for_function.golden deleted file mode 100644 index 0adc791..0000000 --- a/test/semant/wrong_type_for_function.golden +++ /dev/null @@ -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() - - \ No newline at end of file diff --git a/test/semant_all.suite b/test/semant_all.suite deleted file mode 100644 index 593aea7..0000000 --- a/test/semant_all.suite +++ /dev/null @@ -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