From b81c0af596ded102bd1fd76698d4c58db29ff226 Mon Sep 17 00:00:00 2001 From: Niels Bross Date: Sun, 9 Jun 2024 21:34:23 +0200 Subject: [PATCH] init commit --- .gitignore | 5 + AST.jai | 369 +++ Codegen.jai | 403 ++++ Error.jai | 150 ++ Lexing.jai | 695 ++++++ Parsing.jai | 1001 ++++++++ Semantic_Analysis.jai | 2118 +++++++++++++++++ Test.jai | 762 ++++++ build.bat | 3 + example.shd | 29 + hlsl_builtin.jai | 252 ++ module.jai | 408 ++++ test/all.suite | 12 + test/assign_arithmetic_expression.shd | 3 + test/basic_property_and_return_value.shd | 11 + .../assign_arithmetic_expression.golden | 5 + .../basic_property_and_return_value.golden | 15 + test/codegen/complicated_computation.golden | 7 + test/codegen/empty_struct.golden | 4 + test/codegen/empty_vertex_main.golden | 4 + ...vertex_main_with_position_parameter.golden | 5 + test/codegen/field_assignment.golden | 7 + test/codegen/function_call.golden | 12 + ...ction_call_out_of_order_declaration.golden | 11 + test/codegen/function_call_return.golden | 9 + test/codegen/meta_block.golden | 15 + test/codegen/multiple_functions.golden | 19 + .../multiple_semicolons_everywhere.golden | 19 + ...d_access_struct_fields_in_functions.golden | 21 + test/codegen/passthrough.golden | 10 + test/codegen/precedence_test.golden | 8 + test/codegen/simple_struct_access.golden | 13 + test/codegen/struct_within_struct.golden | 20 + test/codegen/use_builtin_functions.golden | 5 + test/codegen_all.suite | 19 + test/compile_all.suite | 20 + test/complicated_computation.shd | 6 + test/empty_struct.shd | 3 + test/empty_vertex_main.shd | 3 + ...ty_vertex_main_with_position_parameter.shd | 3 + test/field_assignment.shd | 6 + test/field_without_type_specifier.shd | 3 + test/float_suffix.shd | 3 + test/function_call.shd | 7 + ...function_call_out_of_order_declaration.shd | 7 + test/function_call_return.shd | 7 + test/function_with_int_return.shd | 3 + test/functions_with_same_name.shd | 7 + test/lex/assign_arithmetic_expression.golden | 16 + .../basic_property_and_return_value.golden | 43 + test/lex/complicated_computation.golden | 30 + test/lex/empty_struct.golden | 6 + test/lex/empty_vertex_main.golden | 8 + ...vertex_main_with_position_parameter.golden | 18 + test/lex/field_assignment.golden | 30 + test/lex/field_without_type_specifier.golden | 13 + test/lex/float_suffix.golden | 4 + test/lex/foreign_function.golden | 40 + test/lex/foreign_overload.golden | 96 + test/lex/function_call.golden | 23 + ...ction_call_out_of_order_declaration.golden | 18 + test/lex/function_call_return.golden | 31 + test/lex/function_with_int_return.golden | 13 + test/lex/functions_with_same_name.golden | 26 + test/lex/meta_block.golden | 60 + test/lex/multiple_functions.golden | 48 + .../lex/multiple_semicolons_everywhere.golden | 77 + ...d_access_struct_fields_in_functions.golden | 54 + test/lex/passthrough.golden | 43 + test/lex/precedence_test.golden | 50 + test/lex/property_rename.golden | 45 + test/lex/redeclared_variable.golden | 20 + test/lex/simple_struct_access.golden | 29 + test/lex/struct_access_primitive_type.golden | 20 + test/lex/struct_field_access_test.golden | 167 ++ test/lex/struct_within_struct.golden | 40 + test/lex/type_as_function_name.golden | 7 + test/lex/type_as_variable_name.golden | 14 + test/lex/undeclared_function.golden | 12 + test/lex/undeclared_symbol.golden | 14 + test/lex/unknown_overload.golden | 51 + test/lex/use_builtin_functions.golden | 23 + test/lex/wrong_argument_count.golden | 73 + test/lex/wrong_multiply.golden | 54 + test/lex/wrong_type_for_function.golden | 73 + test/lex_all.suite | 32 + test/meta_block.shd | 16 + test/multiple_functions.shd | 12 + test/multiple_semicolons_everywhere.shd | 14 + .../parse/assign_arithmetic_expression.golden | 4 + .../basic_property_and_return_value.golden | 11 + test/parse/complicated_computation.golden | 6 + test/parse/empty_struct.golden | 3 + test/parse/empty_vertex_main.golden | 3 + ...vertex_main_with_position_parameter.golden | 4 + test/parse/field_assignment.golden | 5 + .../parse/field_without_type_specifier.golden | 4 + test/parse/foreign_function.golden | 15 + test/parse/foreign_overload.golden | 26 + test/parse/function_call.golden | 8 + ...ction_call_out_of_order_declaration.golden | 7 + test/parse/function_call_return.golden | 7 + test/parse/function_with_int_return.golden | 3 + test/parse/functions_with_same_name.golden | 12 + test/parse/meta_block.golden | 16 + test/parse/multiple_functions.golden | 13 + .../multiple_semicolons_everywhere.golden | 14 + ...d_access_struct_fields_in_functions.golden | 13 + test/parse/passthrough.golden | 8 + test/parse/precedence_test.golden | 7 + test/parse/redeclared_variable.golden | 5 + test/parse/simple_struct_access.golden | 8 + .../parse/struct_access_primitive_type.golden | 5 + test/parse/struct_field_access_test.golden | 31 + test/parse/struct_within_struct.golden | 12 + test/parse/type_as_function_name.golden | 3 + test/parse/type_as_variable_name.golden | 4 + test/parse/undeclared_function.golden | 4 + test/parse/undeclared_symbol.golden | 4 + test/parse/unknown_overload.golden | 14 + test/parse/use_builtin_functions.golden | 4 + test/parse/wrong_argument_count.golden | 17 + test/parse/wrong_multiply.golden | 7 + test/parse/wrong_type_for_function.golden | 14 + test/parse_all.suite | 32 + ..._and_access_struct_fields_in_functions.shd | 13 + test/passthrough.shd | 7 + test/precedence_test.shd | 7 + test/property_rename.shd | 11 + test/redeclared_variable.shd | 4 + .../assign_arithmetic_expression.golden | 6 + .../basic_property_and_return_value.golden | 12 + test/semant/complicated_computation.golden | 8 + test/semant/empty_struct.golden | 4 + test/semant/empty_vertex_main.golden | 4 + ...vertex_main_with_position_parameter.golden | 6 + test/semant/field_assignment.golden | 7 + .../field_without_type_specifier.golden | 4 + test/semant/float_suffix.golden | 4 + test/semant/function_call.golden | 6 + ...ction_call_out_of_order_declaration.golden | 6 + test/semant/function_call_return.golden | 6 + test/semant/function_with_int_return.golden | 6 + test/semant/functions_with_same_name.golden | 8 + test/semant/meta_block.golden | 13 + test/semant/multiple_functions.golden | 11 + .../multiple_semicolons_everywhere.golden | 13 + ...d_access_struct_fields_in_functions.golden | 15 + test/semant/passthrough.golden | 8 + test/semant/precedence_test.golden | 9 + test/semant/redeclared_variable.golden | 8 + test/semant/simple_struct_access.golden | 11 + .../struct_access_primitive_type.golden | 6 + test/semant/struct_within_struct.golden | 15 + test/semant/type_as_function_name.golden | 4 + test/semant/type_as_variable_name.golden | 4 + test/semant/undeclared_function.golden | 7 + test/semant/undeclared_symbol.golden | 4 + test/semant/unknown_overload.golden | 33 + test/semant/use_builtin_functions.golden | 6 + test/semant/wrong_argument_count.golden | 16 + test/semant/wrong_multiply.golden | 11 + test/semant/wrong_type_for_function.golden | 22 + test/semant_all.suite | 31 + test/simple_struct_access.shd | 8 + test/struct_access_primitive_type.shd | 4 + test/struct_with_multiple_members.shd | 5 + test/struct_within_struct.shd | 13 + test/type_as_function_name.shd | 1 + test/type_as_variable_name.shd | 3 + test/undeclared_function.shd | 3 + test/undeclared_symbol.shd | 3 + test/unknown_overload.shd | 7 + test/use_builtin_functions.shd | 3 + test/wrong_argument_count.shd | 11 + test/wrong_multiply.shd | 6 + test/wrong_type_for_function.shd | 13 + 177 files changed, 8799 insertions(+) create mode 100644 .gitignore create mode 100644 AST.jai create mode 100644 Codegen.jai create mode 100644 Error.jai create mode 100644 Lexing.jai create mode 100644 Parsing.jai create mode 100644 Semantic_Analysis.jai create mode 100644 Test.jai create mode 100644 build.bat create mode 100644 example.shd create mode 100644 hlsl_builtin.jai create mode 100644 module.jai create mode 100644 test/all.suite create mode 100644 test/assign_arithmetic_expression.shd create mode 100644 test/basic_property_and_return_value.shd create mode 100644 test/codegen/assign_arithmetic_expression.golden create mode 100644 test/codegen/basic_property_and_return_value.golden create mode 100644 test/codegen/complicated_computation.golden create mode 100644 test/codegen/empty_struct.golden create mode 100644 test/codegen/empty_vertex_main.golden create mode 100644 test/codegen/empty_vertex_main_with_position_parameter.golden create mode 100644 test/codegen/field_assignment.golden create mode 100644 test/codegen/function_call.golden create mode 100644 test/codegen/function_call_out_of_order_declaration.golden create mode 100644 test/codegen/function_call_return.golden create mode 100644 test/codegen/meta_block.golden create mode 100644 test/codegen/multiple_functions.golden create mode 100644 test/codegen/multiple_semicolons_everywhere.golden create mode 100644 test/codegen/pass_and_access_struct_fields_in_functions.golden create mode 100644 test/codegen/passthrough.golden create mode 100644 test/codegen/precedence_test.golden create mode 100644 test/codegen/simple_struct_access.golden create mode 100644 test/codegen/struct_within_struct.golden create mode 100644 test/codegen/use_builtin_functions.golden create mode 100644 test/codegen_all.suite create mode 100644 test/compile_all.suite create mode 100644 test/complicated_computation.shd create mode 100644 test/empty_struct.shd create mode 100644 test/empty_vertex_main.shd create mode 100644 test/empty_vertex_main_with_position_parameter.shd create mode 100644 test/field_assignment.shd create mode 100644 test/field_without_type_specifier.shd create mode 100644 test/float_suffix.shd create mode 100644 test/function_call.shd create mode 100644 test/function_call_out_of_order_declaration.shd create mode 100644 test/function_call_return.shd create mode 100644 test/function_with_int_return.shd create mode 100644 test/functions_with_same_name.shd create mode 100644 test/lex/assign_arithmetic_expression.golden create mode 100644 test/lex/basic_property_and_return_value.golden create mode 100644 test/lex/complicated_computation.golden create mode 100644 test/lex/empty_struct.golden create mode 100644 test/lex/empty_vertex_main.golden create mode 100644 test/lex/empty_vertex_main_with_position_parameter.golden create mode 100644 test/lex/field_assignment.golden create mode 100644 test/lex/field_without_type_specifier.golden create mode 100644 test/lex/float_suffix.golden create mode 100644 test/lex/foreign_function.golden create mode 100644 test/lex/foreign_overload.golden create mode 100644 test/lex/function_call.golden create mode 100644 test/lex/function_call_out_of_order_declaration.golden create mode 100644 test/lex/function_call_return.golden create mode 100644 test/lex/function_with_int_return.golden create mode 100644 test/lex/functions_with_same_name.golden create mode 100644 test/lex/meta_block.golden create mode 100644 test/lex/multiple_functions.golden create mode 100644 test/lex/multiple_semicolons_everywhere.golden create mode 100644 test/lex/pass_and_access_struct_fields_in_functions.golden create mode 100644 test/lex/passthrough.golden create mode 100644 test/lex/precedence_test.golden create mode 100644 test/lex/property_rename.golden create mode 100644 test/lex/redeclared_variable.golden create mode 100644 test/lex/simple_struct_access.golden create mode 100644 test/lex/struct_access_primitive_type.golden create mode 100644 test/lex/struct_field_access_test.golden create mode 100644 test/lex/struct_within_struct.golden create mode 100644 test/lex/type_as_function_name.golden create mode 100644 test/lex/type_as_variable_name.golden create mode 100644 test/lex/undeclared_function.golden create mode 100644 test/lex/undeclared_symbol.golden create mode 100644 test/lex/unknown_overload.golden create mode 100644 test/lex/use_builtin_functions.golden create mode 100644 test/lex/wrong_argument_count.golden create mode 100644 test/lex/wrong_multiply.golden create mode 100644 test/lex/wrong_type_for_function.golden create mode 100644 test/lex_all.suite create mode 100644 test/meta_block.shd create mode 100644 test/multiple_functions.shd create mode 100644 test/multiple_semicolons_everywhere.shd create mode 100644 test/parse/assign_arithmetic_expression.golden create mode 100644 test/parse/basic_property_and_return_value.golden create mode 100644 test/parse/complicated_computation.golden create mode 100644 test/parse/empty_struct.golden create mode 100644 test/parse/empty_vertex_main.golden create mode 100644 test/parse/empty_vertex_main_with_position_parameter.golden create mode 100644 test/parse/field_assignment.golden create mode 100644 test/parse/field_without_type_specifier.golden create mode 100644 test/parse/foreign_function.golden create mode 100644 test/parse/foreign_overload.golden create mode 100644 test/parse/function_call.golden create mode 100644 test/parse/function_call_out_of_order_declaration.golden create mode 100644 test/parse/function_call_return.golden create mode 100644 test/parse/function_with_int_return.golden create mode 100644 test/parse/functions_with_same_name.golden create mode 100644 test/parse/meta_block.golden create mode 100644 test/parse/multiple_functions.golden create mode 100644 test/parse/multiple_semicolons_everywhere.golden create mode 100644 test/parse/pass_and_access_struct_fields_in_functions.golden create mode 100644 test/parse/passthrough.golden create mode 100644 test/parse/precedence_test.golden create mode 100644 test/parse/redeclared_variable.golden create mode 100644 test/parse/simple_struct_access.golden create mode 100644 test/parse/struct_access_primitive_type.golden create mode 100644 test/parse/struct_field_access_test.golden create mode 100644 test/parse/struct_within_struct.golden create mode 100644 test/parse/type_as_function_name.golden create mode 100644 test/parse/type_as_variable_name.golden create mode 100644 test/parse/undeclared_function.golden create mode 100644 test/parse/undeclared_symbol.golden create mode 100644 test/parse/unknown_overload.golden create mode 100644 test/parse/use_builtin_functions.golden create mode 100644 test/parse/wrong_argument_count.golden create mode 100644 test/parse/wrong_multiply.golden create mode 100644 test/parse/wrong_type_for_function.golden create mode 100644 test/parse_all.suite create mode 100644 test/pass_and_access_struct_fields_in_functions.shd create mode 100644 test/passthrough.shd create mode 100644 test/precedence_test.shd create mode 100644 test/property_rename.shd create mode 100644 test/redeclared_variable.shd create mode 100644 test/semant/assign_arithmetic_expression.golden create mode 100644 test/semant/basic_property_and_return_value.golden create mode 100644 test/semant/complicated_computation.golden create mode 100644 test/semant/empty_struct.golden create mode 100644 test/semant/empty_vertex_main.golden create mode 100644 test/semant/empty_vertex_main_with_position_parameter.golden create mode 100644 test/semant/field_assignment.golden create mode 100644 test/semant/field_without_type_specifier.golden create mode 100644 test/semant/float_suffix.golden create mode 100644 test/semant/function_call.golden create mode 100644 test/semant/function_call_out_of_order_declaration.golden create mode 100644 test/semant/function_call_return.golden create mode 100644 test/semant/function_with_int_return.golden create mode 100644 test/semant/functions_with_same_name.golden create mode 100644 test/semant/meta_block.golden create mode 100644 test/semant/multiple_functions.golden create mode 100644 test/semant/multiple_semicolons_everywhere.golden create mode 100644 test/semant/pass_and_access_struct_fields_in_functions.golden create mode 100644 test/semant/passthrough.golden create mode 100644 test/semant/precedence_test.golden create mode 100644 test/semant/redeclared_variable.golden create mode 100644 test/semant/simple_struct_access.golden create mode 100644 test/semant/struct_access_primitive_type.golden create mode 100644 test/semant/struct_within_struct.golden create mode 100644 test/semant/type_as_function_name.golden create mode 100644 test/semant/type_as_variable_name.golden create mode 100644 test/semant/undeclared_function.golden create mode 100644 test/semant/undeclared_symbol.golden create mode 100644 test/semant/unknown_overload.golden create mode 100644 test/semant/use_builtin_functions.golden create mode 100644 test/semant/wrong_argument_count.golden create mode 100644 test/semant/wrong_multiply.golden create mode 100644 test/semant/wrong_type_for_function.golden create mode 100644 test/semant_all.suite create mode 100644 test/simple_struct_access.shd create mode 100644 test/struct_access_primitive_type.shd create mode 100644 test/struct_with_multiple_members.shd create mode 100644 test/struct_within_struct.shd create mode 100644 test/type_as_function_name.shd create mode 100644 test/type_as_variable_name.shd create mode 100644 test/undeclared_function.shd create mode 100644 test/undeclared_symbol.shd create mode 100644 test/unknown_overload.shd create mode 100644 test/use_builtin_functions.shd create mode 100644 test/wrong_argument_count.shd create mode 100644 test/wrong_multiply.shd create mode 100644 test/wrong_type_for_function.shd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f2dc28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.build +*.exe +*.rdbg +*.pdb +*.rdi \ No newline at end of file diff --git a/AST.jai b/AST.jai new file mode 100644 index 0000000..a103e66 --- /dev/null +++ b/AST.jai @@ -0,0 +1,369 @@ +///////////////////////////////////// +//~ nbr: Node data structure +// +// [ ] Add a way to infer or get file path from a node + +AST_Kind :: enum { + Program; + Function; + Return; + + // @Incomplete(nb): Should these three really be their own block types? + // Maybe they at least shouldn't need to have their own tokens... + Properties; + Meta; + Instance; + //== + + // Hint; + // Type; + // Operator; + Call; + Struct; + FieldList; + ArgList; + Variable; + Binary; + Unary; + Integer; + Float; + Expression_Statement; + Field; + Unnamed_Field; + Block; + Error; +} + +AST_Node :: struct { + kind : AST_Kind; + + // @Note(niels): Children nodes can be interpreted as anything useful. + // for an if-statement we would have at most 2 children + // a property block has a child node for each field declaration etc. + children : [..]*AST_Node; + parent : *AST_Node; + + // @Note(niels): Every node can have a name, but most nodes don't. A function or field declaration has one, + // but an if-statement does not + name : string; + + integer_value : int; + float_value : float; + + token : Token; + + assignment : bool; + + source_location : Source_Range; + + type_variable : Type_Variable_Handle; + + foreign_declaration : bool; + + // @Incomplete(nb): Change this to just be children and a single token_data field, + // then we can add new node types (hint, typespec, operator) and have them + // as children instead. + hint_tokens : [..]Token; + + vertex_entry_point : bool; + pixel_entry_point : bool; +} + + +// =========================================================== +// Pretty printing +pretty_print_call :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + append(builder, "("); + append(builder, node.name); + if node.children.count > 0 { + append(builder, " "); + pretty_print_children(node.children[0], indentation, builder, flags = 0); + } + append(builder, ")"); +} + +pretty_print_arglist :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + append(builder, "["); + + pretty_print_children(node, indentation + 1, builder, flags = .NewLine); + + append(builder, "]"); +} + +pretty_print_fieldlist :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + + append(builder, "["); + pretty_print_children(node, indentation + 1, builder, flags = .NewLine); + + append(builder, "]"); +} + +pretty_print_field :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + print_to_builder(builder, tprint("(:= %", node.name)); + + if node.kind != .Unnamed_Field && node.token.ident_value.count > 0 { + print_to_builder(builder, tprint(" %", node.token.ident_value)); + } + + for hint : node.hint_tokens { + if hint.string_value.count > 0 { + print_to_builder(builder, " (@%)", hint.string_value); + } + } + + if node.children.count > 0 { + append(builder, " "); + pretty_print_children(node, indentation, builder); + } + + append(builder, ")"); +} + +Children_Print_Flags :: enum_flags { + NewLine :: 1 << 0; + Separator :: 1 << 1; + Space :: 1 << 2; +} + +pretty_print_children :: (parent : *AST_Node, indentation : int, builder : *String_Builder, flags : Children_Print_Flags = .Separator) { + if !parent { + return; + } + + children := parent.children; + for child : children { + if it_index > 0 { + indent(builder, indentation); + } + + if !child continue; + pretty_print_node(child, 0, builder); + + if it_index != children.count - 1 { + if flags & .Separator { + append(builder, ","); + } + + append(builder, " "); + + if flags & .NewLine { + append(builder, "\n"); + } + } + } +} + +op_to_string :: (oper : Token) -> string { + if oper.kind == { + case .TOKEN_PLUS; + return "+"; + case .TOKEN_MINUS; + return "-"; + case .TOKEN_STAR; + return "*"; + case .TOKEN_SLASH; + return "/"; + case .TOKEN_ISEQUAL; + return "=="; + case .TOKEN_ASSIGN; + return "="; + case .TOKEN_ISNOTEQUAL; + return "!="; + case .TOKEN_LOGICALOR; + return "||"; + case .TOKEN_LOGICALAND; + return "&&"; + case .TOKEN_LESS; + return "<"; + case .TOKEN_LESSEQUALS; + return "<="; + case .TOKEN_GREATER; + return ">"; + case .TOKEN_GREATEREQUALS; + return ">="; + } + return ""; +} + +pretty_print_binary :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + append(builder, "("); + op := node.token; + + print_to_builder(builder, op_to_string(op)); + append(builder, " "); + + pretty_print_children(node, 0, builder, flags = 0); + append(builder, ")"); +} + +pretty_print_unary :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + +} + +print_return_node :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + append(builder, "(return "); + + pretty_print_children(node, 0, builder); + + append(builder, ")"); +} + +print_expression_statement :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + + if node.children[0] { + pretty_print_node(node.children[0], indentation, builder); + } +} + +pretty_print_node :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + if node.kind == { + case .Return; { + print_return_node(node, indentation, builder); + } + case .Struct; + case .ArgList; { + pretty_print_arglist(node, indentation + 2, builder); + } + case .FieldList; { + pretty_print_fieldlist(node, indentation + 2, builder); + } + case .Field; { + pretty_print_field(node, indentation, builder); + } + case .Unnamed_Field; { + pretty_print_field(node, indentation, builder); + } + case .Block; { + pretty_print_children(node, indentation + 2, builder, flags = .NewLine); + } + case .Binary; { + pretty_print_binary(node, indentation, builder); + } + case .Unary; { + pretty_print_unary(node, indentation, builder); + } + case .Variable; { + pretty_print_variable(node, indentation, builder); + } + case .Expression_Statement; { + print_expression_statement(node, indentation, builder); + } + case .Integer; { + print_to_builder(builder, "%", node.integer_value); + } + case .Float; { + print_to_builder(builder, "%", node.float_value); + } + case .Call; { + pretty_print_call(node, indentation, builder); + } + case .Error; { + print_to_builder(builder, "(error \"%\")", node.name); + } + } +} + +pretty_print_variable :: (node : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + print_to_builder(builder, "%", node.name); + for child : node.children { + if child.kind == .Variable { + append(builder, "."); + pretty_print_variable(child, indentation, builder); + } + } +} + +pretty_print_declaration :: (declaration : *AST_Node, indentation : int, builder : *String_Builder) { + indent(builder, indentation); + append(builder, "("); + + if declaration.foreign_declaration { + append(builder, "foreign "); + } + + if declaration.kind == .Function { + append(builder, "fun "); + } + + if declaration.vertex_entry_point { + append(builder, "vertex "); + } + + if declaration.pixel_entry_point { + append(builder, "pixel "); + } + + if declaration.kind == .Properties { + append(builder, "properties"); + if declaration.name.count > 0 { + print_to_builder(builder, " %", declaration.name); + } + } else if declaration.kind == .Instance { + append(builder, "instance"); + } else if declaration.kind == .Meta { + append(builder, "meta"); + } + else { + if declaration.kind == .Struct { + append(builder, "struct "); + } + print_to_builder(builder, "%", declaration.name); + } + + if declaration.kind == .Function && declaration.token.kind == .TOKEN_IDENTIFIER{ + print_to_builder(builder, " -> %", declaration.token.ident_value); + for hint : declaration.hint_tokens { + if hint.string_value.count > 0 { + print_to_builder(builder, " (@%)", hint.string_value); + } + } + + } + + if declaration.children.count > 0 { + print_to_builder(builder, "\n"); + pretty_print_children(declaration, indentation + 1, builder, flags = .NewLine); + } + + append(builder, ")"); + +} + +pretty_print_ast :: (root : *AST_Node, allocator : Allocator) -> string { + builder : String_Builder; + init_string_builder(*builder,, allocator); + + indentation := 0; + + append(*builder, "("); + append(*builder, "program\t\n"); + + indentation += 1; + + declarations := root.children; + + for declaration : declarations { + pretty_print_declaration(declaration, indentation, *builder); + + if it_index < declarations.count - 1 { + append(*builder, "\n\n"); + } + } + + append(*builder, ")"); + + return builder_to_string(*builder,, allocator); +} + +#scope_file +indent :: (builder : *String_Builder, indentation : int) { + for 0..indentation - 1 { + append(builder, " "); + } +} diff --git a/Codegen.jai b/Codegen.jai new file mode 100644 index 0000000..1956ecb --- /dev/null +++ b/Codegen.jai @@ -0,0 +1,403 @@ +Output_Language :: enum { + HLSL; + GLSL; +} + +Codegen_State :: struct { + path : string; + + scope_stack : Scope_Stack; + current_scope : Scope_Handle; + + type_variables : []Type_Variable; + root : *AST_Node; + + output_language : Output_Language; + + builder : String_Builder; + + result : Codegen_Result; +} + +Codegen_Result :: struct { + messages : [..]Compiler_Message; + + had_error : bool; + + result_text : string; // @Incomplete(nb): Result for now, should likely be far more sophisticated. +} + +init_codegen_state :: (state : *Codegen_State, root : *AST_Node, checker_result : Semantic_Check_Result, output_language : Output_Language) { + state.root = root; + state.scope_stack = checker_result.scope_stack; + state.type_variables = checker_result.type_variables; + state.current_scope = cast(Scope_Handle)1; + init_string_builder(*state.builder); +} + +indent :: (state : *Codegen_State, indentation : int) { + for 1..indentation append(*state.builder, " "); +} + +emit_field :: (state : *Codegen_State, node : *AST_Node, indentation : int) { + find_result := find_symbol(state.scope_stack, node.name, state.current_scope); + + field := h2tv(state.type_variables, find_result.type_variable); + + indent(state, indentation); + print_to_builder(*state.builder, "% ", type_to_string(field)); + print_to_builder(*state.builder, "%", node.name); + + for i :0..node.children.count - 1 { + + child := node.children[i]; + + print_to_builder(*state.builder, " = "); + emit_node(state, child, 0); + } + + for i :0..field.child_count - 1 { + child := h2tv(state.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 + append(*state.builder, " : POSITION"); + } + } +} + +emit_block :: (state : *Codegen_State, node : *AST_Node, indentation : int) { + for statement : node.children { + emit_node(state, statement, indentation); + + if it_index < node.children.count { + append(*state.builder, ";\n"); + } + } +} + +emit_call :: (state : *Codegen_State, node : *AST_Node, indentation : int) { + indent(state, indentation); + print_to_builder(*state.builder, "%(", node.name); + + if node.children.count > 0 { + args := node.children[0]; + + for child : args.children { + emit_node(state, child, 0); + + if it_index != args.children.count - 1 { + append(*state.builder, ", "); + } + } + } + + append(*state.builder, ")"); +} + +emit_properties :: (state : *Codegen_State, node : *AST_Node, indentation : int) { + find_result := find_symbol(state.scope_stack, ifx node.name.count > 0 then node.name else "properties", state.current_scope); + + if !find_result { + message : Compiler_Message; + message.message_kind = .Internal_Error; + message.path = state.path; + message.message = "Attempting to generate undeclared properties buffer. This should never happen at this stage."; + array_add(*state.result.messages, message); + } + assert(find_result != null, "Attempting to generate undeclared properties buffer. This should never happen at this stage."); + + variable := h2tv(state.type_variables, find_result.type_variable); + + print_to_builder(*state.builder, "cbuffer __PROPERTIES : register(b%) \n{\n", variable.buffer_index); + + previous_scope := state.current_scope; + state.current_scope = variable.scope; + + for child : node.children { + if child.kind == .FieldList { + for field : child.children { + emit_node(state, field, 1); + + append(*state.builder, ";\n"); + } + + } + + } + + state.current_scope = previous_scope; + + append(*state.builder, "}\n\n"); +} + +emit_function :: (state : *Codegen_State, node : *AST_Node, indentation : int, emit_body := true) { + name := get_actual_function_name(node); + find_result := find_symbol(state.scope_stack, name, state.current_scope); + + assert(find_result != null, "Attempting to generate undeclared function. This should never happen at this stage."); + if !find_result { + message : Compiler_Message; + message.message_kind = .Internal_Error; + message.path = state.path; + message.message = "Attempting to generate undeclared function. This should never happen at this stage."; + array_add(*state.result.messages, message); + } + + for func : find_result.functions { + function_variable := h2tv(state.type_variables, func.type_variable); + + indent(state, indentation); + + if function_variable.return_var { + return_variable := h2tv(state.type_variables, function_variable.return_var); + print_to_builder(*state.builder, "% ", type_to_string(return_variable)); + } else { + append(*state.builder, "void "); + } + + print_to_builder(*state.builder, "%", node.name); + + previous_scope := state.current_scope; + state.current_scope = function_variable.scope; + + append(*state.builder, "("); + + if node.children.count > 0 && node.children[0].kind == .FieldList { + params := node.children[0]; + + for child : params.children { + emit_node(state, child, 0); + + if it_index != params.children.count - 1 { + append(*state.builder, ", "); + } + } + } + + append(*state.builder, ")"); + + for hint : node.hint_tokens { + if hint.ident_value == "position" { + // @Incomplete(nb): Should be a lookup table somewhere + append(*state.builder, " : SV_POSITION"); + } + + if starts_with(hint.ident_value, "target") { + // @Incomplete(nb): Should be a lookup table somewhere + append(*state.builder, " : SV_TARGET"); + } + } + + if emit_body { + append(*state.builder, "\n{\n"); + + + if node.children.count > 1 { + emit_block(state, node.children[1], indentation + 1); + } + + append(*state.builder, "}\n"); + } else { + append(*state.builder, ";"); + } + + append(*state.builder, "\n"); + + + state.current_scope = previous_scope; + } + +} + +emit_operator :: (state : *Codegen_State, op_kind : Token_Kind) { + if op_kind == { + case .TOKEN_PLUS; { + append(*state.builder, "+"); + } + case .TOKEN_MINUS; { + append(*state.builder, "-"); + } + case .TOKEN_STAR; { + append(*state.builder, "*"); + } + case .TOKEN_SLASH; { + append(*state.builder, "/"); + } + case .TOKEN_ISEQUAL; { + append(*state.builder, "=="); + } + case .TOKEN_ASSIGN; { + append(*state.builder, "="); + } + case .TOKEN_ISNOTEQUAL; { + append(*state.builder, "!="); + } + case .TOKEN_LOGICALOR; { + append(*state.builder, "||"); + } + case .TOKEN_LOGICALAND; { + append(*state.builder, "&&"); + } + case .TOKEN_LESS; { + append(*state.builder, "<"); + } + case .TOKEN_LESSEQUALS; { + append(*state.builder, "<="); + } + case .TOKEN_GREATER; { + append(*state.builder, ">"); + } + case .TOKEN_GREATEREQUALS; { + append(*state.builder, ">="); + } + } +} + +emit_node :: (state : *Codegen_State, node : *AST_Node, indentation : int) { + if node.kind == { + case .Integer; { + print_to_builder(*state.builder, "%", node.integer_value); + } + case .Float; { + print_to_builder(*state.builder, "%f", formatFloat(node.float_value, zero_removal=.ONE_ZERO_AFTER_DECIMAL)); + } + case .Properties; { + + } + case .Field; { + emit_field(state, node, indentation); + } + case .Block; { + assert(false, "Not implemented yet: block"); + } + case .Variable; { + indent(*state.builder, indentation); + + is_properties := node.name == "properties"; + + if !is_properties { + print_to_builder(*state.builder, "%", node.name); + } + + if node.children.count > 0 { + if !is_properties { + append(*state.builder, "."); + } + emit_node(state, node.children[0], 0); + } + } + case .Binary; { + indent(*state.builder, indentation); + lhs := node.children[0]; + rhs := node.children[1]; + emit_node(state, lhs, 0); + + append(*state.builder, " "); + emit_operator(state, node.token.kind); + append(*state.builder, " "); + emit_node(state, rhs, 0); + } + case .Unary; { + assert(false, "Not implemented yet: unary"); + } + case .Expression_Statement; { + emit_node(state, node.children[0], indentation); + } + case .Call; { + emit_call(state, node, indentation); + } + case .Return; { + indent(*state.builder, indentation); + append(*state.builder, "return "); + emit_node(state, node.children[0], 0); + } + } +} + +emit_declaration :: (state : *Codegen_State, node : *AST_Node) { + if node.kind == { + case .Function; { + emit_function(state, node, 0); + } + case .Properties; { + emit_properties(state, node, 0); + } + case .Struct; { + print_to_builder(*state.builder, "struct %", node.name); + + current_scope := state.current_scope; + state.current_scope = h2tv(state.type_variables, node.type_variable).scope; + + field_list := node.children[0]; + + if field_list.children.count > 0 { + append(*state.builder, "\n{\n"); + } else { + append(*state.builder, " {"); + } + + + for child : field_list.children { + emit_node(state, child, 1); + + if it_index < field_list.children.count { + append(*state.builder, ";\n"); + } + } + + append(*state.builder, "}\n\n"); + state.current_scope = current_scope; + } + } +} + +codegen :: (state : *Codegen_State) -> Codegen_Result { + found_function : bool = false; + found_struct : bool = false; + + for variable : state.type_variables { + if variable.type == .Struct && variable.kind == .Declaration && !variable.builtin { + if variable.source_node.kind == .Properties continue; + if variable.source_node.kind == .Meta continue; + print_to_builder(*state.builder, "struct %;\n", variable.source_node.name); + found_struct = true; + } + } + + if found_struct { + append(*state.builder, "\n"); + } + + for variable : state.type_variables { + if variable.type == .Function && !variable.builtin + && !variable.source_node.vertex_entry_point && !variable.source_node.pixel_entry_point { + emit_function(state, variable.source_node, 0, false); + found_function = true; + } + } + if found_function { + append(*state.builder, "\n"); + } + + for declaration : state.root.children { + if declaration.foreign_declaration { + continue; + } + emit_declaration(state, declaration); + } + + state.result.result_text = builder_to_string(*state.builder); + + print("%\n", state.result.result_text); + return state.result; +} + +codegen :: (ast_root : *AST_Node, checker_result : Semantic_Check_Result, output_language : Output_Language) -> Codegen_Result { + codegen_state : Codegen_State; + init_codegen_state(*codegen_state, ast_root, checker_result, output_language); + return codegen(*codegen_state); +} diff --git a/Error.jai b/Error.jai new file mode 100644 index 0000000..435b71d --- /dev/null +++ b/Error.jai @@ -0,0 +1,150 @@ +Message_Kind :: enum { + Log; + Warning; + Error; + Internal_Error; +} + +Compiler_Message :: struct { + message_kind : Message_Kind; + + message : string; + path : string; + source_locations : [..]Source_Range; + + report_source_location : bool = true; +} + +indent :: (builder : *String_Builder, indentation : int) { + for 1..indentation append(builder, " "); +} + +newline :: (builder : *String_Builder) { + append(builder, "\n"); +} + +green :: (builder : *String_Builder) { + append(builder, green()); +} + +green :: () -> string { + return "\x1b[92m"; +} + +red :: (builder : *String_Builder) { + append(builder, red()); +} + +red :: () -> string { + return "\x1b[91m"; +} + +yellow :: (builder : *String_Builder) { + append(builder, yellow()); +} + +yellow :: () -> string { + return "\x1b[93m"; +} + +cyan :: (builder : *String_Builder) { + append(builder, cyan()); +} + +cyan :: () -> string { + return "\x1b[96m"; +} + +white :: (builder : *String_Builder) { + append(builder, white()); +} + +white :: () -> string { + return "\x1b[97m"; +} + +reset_color :: () -> string { + return "\x1b[0m"; +} + +reset_color :: (builder : *String_Builder) { + append(builder, reset_color()); +} + +add_message :: (messages : *[..]Compiler_Message, text : string, path : string, kind : Message_Kind) { + message : Compiler_Message; + message.message = text; + message.path = path; + message.report_source_location = false; + message.message_kind = kind; + array_add(messages, message); +} + +log_message :: (messages : *[..]Compiler_Message, text : string, path : string) { + add_message(messages, text, path, .Log); +} + +warning_message :: (messages : *[..]Compiler_Message, text : string, path : string) { + add_message(messages, text, path, .Warning); +} + +error_message :: (messages : *[..]Compiler_Message, text : string, path : string) { + add_message(messages, text, path, .Error); +} + +internal_error_message :: (messages : *[..]Compiler_Message, text : string, path : string) { + add_message(messages, text, path, .Internal_Error); +} + +copy_messages :: (source : []Compiler_Message, dest : *[..]Compiler_Message) { + for message : source { + array_add(dest, message); + } +} + +report_messages :: (messages : []Compiler_Message) -> string { + builder : String_Builder; + init_string_builder(*builder); + for message : messages { + report_message(*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 :: (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); + } else { + append(builder, "internal:"); + } + print_to_builder(builder, "%,%: ", source_locations[0].main_token.line, source_locations[0].main_token.column); + + if kind == .Log { + append(builder, "\x1b[31mlog: "); + } else if kind == .Error { + append(builder, "\x1b[31merror: "); + } + + append(builder, "\x1b[37m"); + print_to_builder(builder, "%\n", message); + append(builder, "\x1b[36m"); + + if report_source_location { + for location : source_locations { + append(builder, "\t"); + print_from_source_location(builder, location); + append(builder, "\n\t"); + begin := location.begin; + + print_token_pointer(builder, location.main_token); + append(builder, "\n"); + } + } + append(builder, "\x1b[37m"); +} + diff --git a/Lexing.jai b/Lexing.jai new file mode 100644 index 0000000..96e5c64 --- /dev/null +++ b/Lexing.jai @@ -0,0 +1,695 @@ +Lexer :: struct { + input : string; + cursor : int; + start : int; + current_line : int; + current_column : int; + + result : Lexing_Result; + + path : string; +} + +Lexing_Result :: struct { + tokens : [..]Token; + had_error : bool; + messages : [..]Compiler_Message; +} + +Token_Kind :: enum { + TOKEN_FLOATLITERAL; + TOKEN_INTLITERAL; + + TOKEN_LOGICALOR; + TOKEN_LOGICALAND; + TOKEN_ISEQUAL; + TOKEN_ISNOTEQUAL; + TOKEN_PLUSEQUALS; + TOKEN_MINUSEQUALS; + TOKEN_TIMESEQUALS; + TOKEN_DIVEQUALS; + TOKEN_MODEQUALS; + TOKEN_LESSEQUALS; + TOKEN_LESS; + TOKEN_GREATEREQUALS; + TOKEN_GREATER; + TOKEN_COLON; + TOKEN_DOUBLECOLON; + TOKEN_ASSIGN; + TOKEN_ARROW; + TOKEN_AT; + + TOKEN_PLUS; + TOKEN_STAR; + TOKEN_SLASH; + TOKEN_MOD; + TOKEN_MINUS; + + TOKEN_LEFTBRACE; + TOKEN_RIGHTBRACE; + TOKEN_LEFTBRACKET; + TOKEN_RIGHTBRACKET; + TOKEN_LEFTPAREN; + TOKEN_RIGHTPAREN; + TOKEN_SEMICOLON; + TOKEN_COMMA; + TOKEN_DOT; + + TOKEN_IDENTIFIER; + + // Keywords + TOKEN_BOOL; + + TOKEN_CASE; + TOKEN_CBUFFER; + TOKEN_COLUMNMAJOR; + TOKEN_CONST; + TOKEN_CONTINUE; + + TOKEN_DEFAULT; + TOKEN_DIRECTIVE; + TOKEN_DISCARD; + TOKEN_DO; + TOKEN_DOUBLE; + + TOKEN_ELSE; + TOKEN_EXPORT; + TOKEN_EXTERN; + + TOKEN_FALSE; + TOKEN_FOR; + + TOKEN_HALF; + TOKEN_HINT; + + TOKEN_IF; + TOKEN_IN; + TOKEN_INOUT; + TOKEN_INSTANCE; + + TOKEN_MATRIX; + TOKEN_META; + + TOKEN_OPTIONAL; + TOKEN_OUT; + + TOKEN_PIXEL; + TOKEN_PROPERTIES; + + TOKEN_RETURN; + TOKEN_REGISTER; + + TOKEN_STRUCT; + TOKEN_SWITCH; + + TOKEN_TRUE; + + TOKEN_UNORM; + TOKEN_UNSIGNED; + TOKEN_UINT; + + TOKEN_VECTOR; + TOKEN_VERTEX; + TOKEN_VOID; + + TOKEN_WHILE; + + TOKEN_EOF; + TOKEN_ERROR; +} + +Token :: struct { + kind : Token_Kind; + union { + ident_value : string; + integer_value : int; + float_value : float; + string_value : string; + } + + source : *u8; + + line : int; + length : int; + column : int; + index : int; + + error : string; +} + +Source_Range :: struct { + begin : Token; + end : Token; + main_token : Token; +} + +is_at_end :: (using lexer : *Lexer) -> bool { + return input.data[cursor] == #char "\0" || cursor == input.count; +} + +peek_char :: (using lexer : *Lexer) -> u8 { + return input.data[cursor]; +} + +peek_next_char :: (using lexer : *Lexer) -> u8 { + if is_at_end(lexer) return #char "\0"; + return input.data[cursor + 1]; +} + +match_character :: (lexer : *Lexer, expected : u8) -> bool { + if is_at_end(lexer) return false; + if lexer.input.data[lexer.cursor] != expected return false; + + lexer.cursor += 1; + return true; +} + +identifier :: (lexer : *Lexer) -> *Token { + while is_alpha(peek_char(lexer)) || is_digit(peek_char(lexer)) || peek_char(lexer) == #char "_" { + advance(lexer); + } + + return make_identifier(lexer, identifier_kind(lexer)); +} + +directive :: (lexer : *Lexer) -> *Token { + advance(lexer); + while is_alpha(peek_char(lexer)) || is_digit(peek_char(lexer)) || peek_char(lexer) == #char "_" { + advance(lexer); + } + + return make_directive(lexer); +} + +number :: (lexer : *Lexer) -> *Token { + while is_digit(peek_char(lexer)) advance(lexer); + + is_float := false; + + if peek_char(lexer) == #char "." && is_digit(peek_next_char(lexer)) { + is_float = true; + advance(lexer); + f_suffix := false; + while is_digit(peek_char(lexer)) { + advance(lexer); + } + if peek_char(lexer) == #char "f" { + advance(lexer); + record_error(lexer, "We don't use 'f' suffixes for floating point values."); + return null; + } + } + + if is_float { + return make_float(lexer); + } + return make_int(lexer); +} + +identifier_kind :: (using lexer : *Lexer) -> Token_Kind { + length := cursor - lexer.start; + + index := start; + identifier : string; + identifier.data = *input.data[start]; + identifier.count = length; + + if identifier == "bool" return .TOKEN_BOOL; + if identifier == "case" return .TOKEN_CASE; + if identifier == "columnmajor" return .TOKEN_COLUMNMAJOR; + if identifier == "const" return .TOKEN_CONST; + if identifier == "continue" return .TOKEN_CONTINUE; + if identifier == "default" return .TOKEN_DEFAULT; + if identifier == "directive" return .TOKEN_DIRECTIVE; + if identifier == "discard" return .TOKEN_DIRECTIVE; + if identifier == "discard" return .TOKEN_DISCARD; + if identifier == "do" return .TOKEN_DO; + if identifier == "double" return .TOKEN_DOUBLE; + if identifier == "else" return .TOKEN_ELSE; + if identifier == "export" return .TOKEN_EXPORT; + if identifier == "extern" return .TOKEN_EXTERN; + if identifier == "false" return .TOKEN_FALSE; + if identifier == "for" return .TOKEN_FOR; + if identifier == "half" return .TOKEN_HALF; + if identifier == "hint" return .TOKEN_HINT; + if identifier == "if" return .TOKEN_IF; + if identifier == "in" return .TOKEN_IN; + if identifier == "inout" return .TOKEN_INOUT; + if identifier == "instance" return .TOKEN_INSTANCE; + if identifier == "matrix" return .TOKEN_MATRIX; + if identifier == "meta" return .TOKEN_META; + if identifier == "optional" return .TOKEN_OPTIONAL; + if identifier == "out" return .TOKEN_OUT; + if identifier == "pixel" return .TOKEN_PIXEL; + if identifier == "properties" return .TOKEN_PROPERTIES; + if identifier == "return" return .TOKEN_RETURN; + if identifier == "register" return .TOKEN_REGISTER; + if identifier == "struct" return .TOKEN_STRUCT; + if identifier == "switch" return .TOKEN_SWITCH; + if identifier == "true" return .TOKEN_TRUE; + if identifier == "unorm" return .TOKEN_UNORM; + if identifier == "unsigned" return .TOKEN_UNSIGNED; + if identifier == "uint" return .TOKEN_UINT; + if identifier == "vector" return .TOKEN_VECTOR; + if identifier == "vertex" return .TOKEN_VERTEX; + if identifier == "void" return .TOKEN_VOID; + if identifier == "while" return .TOKEN_WHILE; + + return .TOKEN_IDENTIFIER; +} + +error_token :: (lexer : *Lexer, message : string) -> *Token { + token : *Token = new_token(lexer, .TOKEN_ERROR); + + lexer.result.had_error = true; + token.error = copy_string(message); + + return token; +} + +record_error :: (lexer : *Lexer, message : string) { + error : Compiler_Message; + error.message_kind = .Error; + error.message = message; + error.path = lexer.path; + + token := error_token(lexer, message); + source_location : Source_Range; + source_location.main_token = token; + + token.length += token.column; + token.source -= token.column; + token.column = 0; + + source_location.begin = token; + length := source_location.begin.column; + + source_location.end = token; + + array_add(*error.source_locations, source_location); + + lexer.result.had_error = true; + array_add(*lexer.result.messages, error); +} + +make_int :: (lexer : *Lexer) -> *Token { + token : *Token = new_token(lexer, .TOKEN_INTLITERAL); + + str : string = .{ count = token.length, + data = *lexer.input.data[lexer.start] }; + value, ok := string_to_int(str); + + if ok { + token.integer_value = value; + } + return token; +} + + +make_float :: (lexer : *Lexer) -> *Token { + token : *Token = new_token(lexer, .TOKEN_FLOATLITERAL); + + str : string = .{ count = token.length, + data = *lexer.input.data[lexer.start] }; + value, ok := string_to_float(str); + if ok { + token.float_value = value; + } + + return token; +} + +make_string :: () { + +} + +new_token :: (lexer : *Lexer, kind : Token_Kind) -> *Token { + length := lexer.cursor - lexer.start; + token : Token; + token.kind = kind; + token.line = lexer.current_line; + token.length = length; + token.column = lexer.current_column; + token.index = lexer.cursor - token.length; + + if token.length > 0 { + token.source = *lexer.input[token.index]; + } else { + token.source = *lexer.input[token.index - 1]; + } + lexer.current_column += length; + + array_add(*lexer.result.tokens, token); + return *lexer.result.tokens[lexer.result.tokens.count - 1]; +} + +make_directive :: (lexer : *Lexer) -> *Token { + lexer.start += 1; + return make_identifier(lexer, .TOKEN_DIRECTIVE); +} + +make_identifier :: (lexer : *Lexer, kind : Token_Kind) -> *Token { + token : *Token = new_token(lexer, kind); + + name : string = .{ count = token.length, + data = *lexer.input.data[lexer.start] }; + token.ident_value = name; + + return token; +} + +make_token :: (lexer : *Lexer, token_kind : Token_Kind) -> *Token { + return new_token(lexer, token_kind); +} + +skip_whitespace :: (lexer : *Lexer) { + while true { + c := peek_char(lexer); + + if c == { + case #char " "; { + lexer.current_column += 1; + advance(lexer); + continue; + } + case #char "\r"; #through; + case #char "\t"; { + advance(lexer); + continue; + } + case #char "\n"; { + advance(lexer); + lexer.current_line += 1; + lexer.current_column = 0; + continue; + } + case #char "/"; { + next := peek_next_char(lexer); + if next == #char "/" { + while peek_char(lexer) != #char "\n" && !is_at_end(lexer) { + advance(lexer); + } + continue; + } else { + return; + } + } + } + return; + } +} + +advance :: (using lexer : *Lexer) -> u8 { + c := input.data[cursor]; + cursor += 1; + return c; +} + +scan_next_token :: (lexer : *Lexer) -> *Token { + skip_whitespace(lexer); + lexer.start = lexer.cursor; + + if is_at_end(lexer) return make_token(lexer, .TOKEN_EOF); + + c := advance(lexer); + + if c == #char "#" return directive(lexer); + if is_alpha(c) return identifier(lexer); + if is_digit(c) return number(lexer); + + if c == { + case #char "+"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_PLUSEQUALS); + return make_token(lexer, .TOKEN_PLUS); + } + case #char "-"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_MINUSEQUALS); + if match_character(lexer, #char ">") return make_token(lexer, .TOKEN_ARROW); + return make_token(lexer, .TOKEN_MINUS); + } + case #char "*"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_TIMESEQUALS); + return make_token(lexer, .TOKEN_STAR); + } + case #char "/"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_DIVEQUALS); + return make_token(lexer, .TOKEN_SLASH); + } + case #char "%"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_MODEQUALS); + return make_token(lexer, .TOKEN_MOD); + } + case #char ":"; { + if match_character(lexer, #char ":") return make_token(lexer, .TOKEN_DOUBLECOLON); + return make_token(lexer, .TOKEN_COLON); + } + case #char "@"; { + return make_token(lexer, .TOKEN_AT); + } + case #char "|"; { + if match_character(lexer, #char "|") return make_token(lexer, .TOKEN_LOGICALOR); + } + case #char "&"; { + if match_character(lexer, #char "&") return make_token(lexer, .TOKEN_LOGICALAND); + } + case #char "!"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_ISNOTEQUAL); + } + case #char "="; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_ISEQUAL); + return make_token(lexer, .TOKEN_ASSIGN); + } + case #char ">"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_GREATEREQUALS); + return make_token(lexer, .TOKEN_GREATER); + } + case #char "<"; { + if match_character(lexer, #char "=") return make_token(lexer, .TOKEN_LESSEQUALS); + return make_token(lexer, .TOKEN_LESS); + } + case #char "{"; { + return make_token(lexer, .TOKEN_LEFTBRACE); + } + case #char "}"; { + return make_token(lexer, .TOKEN_RIGHTBRACE); + } + case #char "("; { + return make_token(lexer, .TOKEN_LEFTPAREN); + } + case #char ")"; { + return make_token(lexer, .TOKEN_RIGHTPAREN); + } + case #char "["; { + return make_token(lexer, .TOKEN_LEFTBRACKET); + } + case #char "]"; { + return make_token(lexer, .TOKEN_RIGHTBRACKET); + } + case #char ";"; return make_token(lexer, .TOKEN_SEMICOLON); + case #char ","; return make_token(lexer, .TOKEN_COMMA); + case #char "."; return make_token(lexer, .TOKEN_DOT); + } + + s : string = .{ count = 1, data = *c }; + record_error(lexer, tprint("Invalid token: %", s)); + return null; + // return error_token(lexer, tprint("Invalid token: %", s)); +} + +pretty_print_token :: (token : *Token, builder : *String_Builder) { + MAX :: 18; + kind_name := enum_names(Token_Kind)[cast(int)token.kind]; + diff := MAX - kind_name.count; + + print_to_builder(builder, "{kind = %; ", token.kind); + for i : 0..diff - 1 { + append(builder, " "); + } + + append_to_length :: (builder : *String_Builder, number : int) { + if number < 10 { + append(builder, " "); + } else if number < 100 { + append(builder, " "); + } else if number < 1000 { + append(builder, " "); + } else if number < 10000 { + append(builder, " "); + } + } + + print_to_builder(builder, "; index = %", token.index); + append_to_length(builder, token.index); + + print_to_builder(builder, "; length = %", token.length); + append_to_length(builder, token.length); + + print_to_builder(builder, "line = %", token.line); + append_to_length(builder, token.line); + + print_to_builder(builder, "; column = %", token.column); + append_to_length(builder, token.column); + + append(builder, "; value ='"); + value_length : int; + if token.kind == .TOKEN_IDENTIFIER { + print_to_builder(builder, "%", token.ident_value); + } else if token.kind == .TOKEN_INTLITERAL { + print_to_builder(builder, "%", token.integer_value); + } else if token.kind == .TOKEN_FLOATLITERAL { + print_to_builder(builder, "%", token.float_value); + } else if token.kind == .TOKEN_ERROR { + print_to_builder(builder, "%", token.error); + } else { + source : string = .{ count = token.length, + data = token.source }; + print_to_builder(builder, "%", source); + } + append(builder, "'; }\n"); +} + +pretty_print_tokens :: (lexer : *Lexer, allocator : Allocator) -> string { + builder : String_Builder; + + init_string_builder(*builder,, allocator); + + token : *Token = scan_next_token(lexer); + while token && token.kind != .TOKEN_EOF { + pretty_print_token(token, *builder); + token = scan_next_token(lexer); + } + + return builder_to_string(*builder,, allocator); +} + +pretty_print_tokens :: (tokens : []Token, allocator : Allocator) -> string { + builder : String_Builder; + + init_string_builder(*builder,, allocator); + + for token : tokens { + pretty_print_token(*token, *builder); + } + return builder_to_string(*builder,, allocator); +} + +output_as_code_string :: (lexer : *Lexer, allocator : *Allocator) -> string { + builder : String_Builder; + + new_context := context; + new_context.allocator = allocator; + push_context new_context { + init_string_builder(*builder); // @Incomplete: Consider passing builder as argument + + token : *Token = scan_next_token(lexer); + while token && token.kind != .TOKEN_EOF { + token = scan_next_token(lexer); + } + + return builder_to_string(*builder); + } +} + +print_token_pointer :: (builder : *String_Builder, token : Token) { + for i : 0..token.column - 1 { + append(builder, " "); + } + + for i : 0..token.length - 1 { + append(builder, "^"); + } +} + +print_from_source_location :: (builder : *String_Builder, source_location : Source_Range, indentation : int = 0) { + current := source_location.begin; + begin := source_location.begin; + end := source_location.end; + begin_pos := 0; + token_string : string; + count := end.index - begin.index + end.length; + + if indentation > 0 { + indent(builder, indentation); + for 0..count - 1 { + c := begin.source[it]; + if c == #char "\n" { + append(builder, "\n"); + indent(builder, indentation); + } else { + s : string; + s.count = 1; + s.data = *c; + print_to_builder(builder, "%", s); + } + + } + } else { + token_string = .{ count = count, data = begin.source }; + indent(builder, indentation); + print_to_builder(builder, "%", token_string); + } +} + +print_from_source_location :: (source_location : Source_Range, allocator := context.allocator, indentation : int = 0) -> string { + builder : String_Builder; + init_string_builder(*builder,, allocator); + print_from_source_location(*builder, source_location); + return builder_to_string(*builder,, allocator); +} + +lex :: (lexer : *Lexer, allocator : Allocator = context.allocator) -> Lexing_Result { + lexer.result.tokens.allocator = allocator; + token : *Token = scan_next_token(lexer); + while token && token.kind != .TOKEN_EOF { + token = scan_next_token(lexer); + } + + return lexer.result; +} + +init_lexer_from_string :: (lexer : *Lexer, input : string) { + ok := read_input_from_string(lexer, input); + if !ok { + record_error(lexer, "Unable to initialize from string\n"); + lexer.result.had_error = true; + } +} + +init_lexer_from_file :: (lexer : *Lexer, file_path : string) { + ok := read_input_from_file(lexer, file_path); + if !ok { + record_error(lexer, tprint("Unable to read file: %\n", file_path)); + lexer.result.had_error = true; + } +} + +read_input_from_string :: (lexer : *Lexer, input : string) -> bool { + lexer.input = input; + lexer.cursor = 0; + lexer.start = 0; + lexer.current_line = 1; + lexer.current_column = 0; + + return true; +} + +read_input_from_file :: (lexer : *Lexer, file_path : string) -> bool { + assert(file_path != ""); + + value, success := read_entire_file(file_path, true, true); + if !success { + free(value); + return false; + } + + lexer.path = copy_string(file_path); + lexer.input = value; + lexer.cursor = 0; + lexer.start = 0; + lexer.current_line = 1; + lexer.current_column = 0; + + return true; +} + +#import "Basic"; diff --git a/Parsing.jai b/Parsing.jai new file mode 100644 index 0000000..2335f8b --- /dev/null +++ b/Parsing.jai @@ -0,0 +1,1001 @@ +#import "Flat_Pool"; + +/** +* TODO: +* if parsing +* for/while loop parsing +**/ + +//////////////////////////// +//@nb - Parse_state state +Parse_State :: struct { + current : *Token; + previous : *Token; + tokens : [..]Token; + + current_token_index : int; + allocator : Allocator; + + had_error : bool; + + path : string; + + result : Parse_Result; +} + +//////////////////////////// +//@nb - Result and error handling +Parse_Result :: struct { + root : *AST_Node; + nodes : [..]AST_Node; + + had_error : bool; + + messages : [..]Compiler_Message; +} + +Parse_Error_Kind :: enum { + Parse_Error_Type_Missing; + Parse_Error_Expected_Expression; + Parse_Error_Empty_Block; + Parse_Error_Unexpected_Token; +} + +//////////////////////////// +//@nb - Parsing helper types +Separator_Type :: enum { + Comma; + Semicolon; +} + +Entry_Point_Type :: enum { + None; + Vertex; + Pixel; +} + +//////////////////////////// +//@nb - Expression parsing +Precedence :: enum { + PREC_NONE; + PREC_ASSIGNMENT; // = + PREC_OR; // || + PREC_AND; // && + PREC_BITWISE; // | & ^ + PREC_EQUALITY; // == != + PREC_COMPARISON; // < > <= >= + PREC_TERM; // + - + PREC_FACTOR; // * / + PREC_UNARY; // ! - + PREC_CALL; // . () + PREC_PRIMARY; +} + +Parse_Fn :: #type (parse_state: *Parse_State, left : *AST_Node) -> *AST_Node; +Parse_Rule :: struct { + prefix : Parse_Fn; + infix : Parse_Fn; + precedence : Precedence; +} + +parse_rules :: #run -> [(cast(int)Token_Kind.TOKEN_ERROR) + 1]Parse_Rule { + rules : [(cast(int)Token_Kind.TOKEN_ERROR) + 1]Parse_Rule; + rules[Token_Kind.TOKEN_LEFTPAREN] = .{grouping, call, .PREC_CALL}; + rules[Token_Kind.TOKEN_RIGHTPAREN] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_LEFTBRACE] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_RIGHTBRACE] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_COMMA] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_DOT] = .{null, dot, .PREC_CALL}; + rules[Token_Kind.TOKEN_PROPERTIES] = .{named_variable, null, .PREC_CALL}; + rules[Token_Kind.TOKEN_MINUS] = .{unary, binary, .PREC_TERM}; + rules[Token_Kind.TOKEN_PLUS] = .{null, binary, .PREC_TERM}; + rules[Token_Kind.TOKEN_SEMICOLON] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_SLASH] = .{null, binary, .PREC_FACTOR}; + rules[Token_Kind.TOKEN_STAR] = .{null, binary, .PREC_FACTOR}; + rules[Token_Kind.TOKEN_ISNOTEQUAL] = .{null, binary, .PREC_COMPARISON}; + rules[Token_Kind.TOKEN_ASSIGN] = .{null, binary, .PREC_COMPARISON}; + rules[Token_Kind.TOKEN_ISEQUAL] = .{null, binary, .PREC_EQUALITY}; + rules[Token_Kind.TOKEN_GREATER] = .{null, binary, .PREC_COMPARISON}; + rules[Token_Kind.TOKEN_GREATEREQUALS] = .{null, binary, .PREC_COMPARISON}; + rules[Token_Kind.TOKEN_LESS] = .{null, binary, .PREC_COMPARISON}; + rules[Token_Kind.TOKEN_LESSEQUALS] = .{null, binary, .PREC_COMPARISON}; + rules[Token_Kind.TOKEN_IDENTIFIER] = .{named_variable, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_INTLITERAL] = .{integer, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_FLOATLITERAL] = .{floating, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_ELSE] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_FALSE] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_FOR] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_IF] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_LOGICALOR] = .{null, binary, .PREC_OR}; + rules[Token_Kind.TOKEN_LOGICALAND] = .{null, binary, .PREC_AND}; + rules[Token_Kind.TOKEN_RETURN] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_TRUE] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_WHILE] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_ERROR] = .{null, null, .PREC_NONE}; + rules[Token_Kind.TOKEN_EOF] = .{null, null, .PREC_NONE}; + + return rules; +} + +init_parse_state :: (parse_state : *Parse_State, tokens : [..]Token, path : string, allocator : Allocator) { + parse_state.tokens = tokens; + parse_state.path = path; + parse_state.allocator = allocator; + parse_state.result.nodes.allocator = parse_state.allocator; + array_reserve(*parse_state.result.nodes, 4096); + parse_state.current_token_index = 0; +} + +//////////////////////////// +//@nb - Error handling functions + +//nb - Record an error and report it immediately to the user. +record_error :: (parse_state : *Parse_State, token : Token, message : string, report_source_location : bool = true) { + error : Compiler_Message; + error.message_kind = .Error; + error.message = message; + error.path = parse_state.path; + + source_location : Source_Range; + source_location.begin = token; + source_location.begin.column = 0; + source_location.begin.source = source_location.begin.source - source_location.begin.column; + source_location.main_token = token; + + advance_to_sync_point(parse_state); + error.report_source_location = report_source_location; + + source_location.end = parse_state.current; + array_add(*error.source_locations, source_location); + + parse_state.result.had_error = true; + array_add(*parse_state.result.messages, error); +} + +generate_source_location_from_token :: (state : *Parse_State, token : Token) -> Source_Range { + location : Source_Range; + begin : Token = token; + begin.index -= begin.column; + begin.length += begin.column; + begin.source -= begin.column; + begin.column = 0; + + location.begin = begin; + location.main_token = token; + + snapshot := snapshot_state(state); + advance_to_sync_point(state); + + location.end = state.current; + + rewind_to_snapshot(state, snapshot); + + return location; +} + +unexpected_token :: (state : *Parse_State, token : Token, message : string) { + record_error(state, token, message); +} + +expected_expression :: (state : *Parse_State, token : Token, message : string) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "%\n", message); + + location : Source_Range = generate_source_location_from_token(state, token); + + indent(*builder, 1); + cyan(*builder); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + + indent(*builder, 1); + print_token_pointer(*builder, token); + + final_message := builder_to_string(*builder); + record_error(state, token, final_message, false); +} + +missing_type_specifier :: (state : *Parse_State, token : Token, message : string) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "%\n", message); + + location := generate_source_location_from_token(state, token); + + indent(*builder, 1); + cyan(*builder); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + indent(*builder, 1); + + loc := location.begin; + increment := location.begin.length + 2; + loc.source += increment; + loc.index += increment; + loc.column += increment; + print_token_pointer(*builder, loc); + + final_message := builder_to_string(*builder); + record_error(state, token, final_message, false); +} + +empty_block :: (state : *Parse_State, token : Token, message : string) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "%\n", message); + + location := generate_source_location_from_token(state, token); + + indent(*builder, 1); + cyan(*builder); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + indent(*builder, 1); + + loc := location.begin; + // increment := location.begin.length + 2; + // loc.source += increment; + // loc.index += increment; + // loc.column += increment; + print_token_pointer(*builder, loc); + + final_message := builder_to_string(*builder); + record_error(state, token, final_message, false); +} + +error_node :: (parse_state : *Parse_State, message : string) -> *AST_Node { + node := make_node(parse_state, .Error); + node.name = copy_string(message); + + return node; +} + +//nb - Advance to the next sync point. +// A sync point is the next token that ends a statement or starts/ends a block. +advance_to_sync_point :: (parse_state : *Parse_State) { + while true { + if parse_state.current.kind == .TOKEN_SEMICOLON || parse_state.current.kind == .TOKEN_RIGHTBRACE || + parse_state.current.kind == .TOKEN_LEFTBRACE{ + break; + } + advance(parse_state); + } +} +//////////////////////////// + + +//////////////////////////// +//@nb - Base parsing functions + +make_node :: (parse_state : *Parse_State, kind : AST_Kind) -> *AST_Node { + node : AST_Node; + + node.kind = kind; + array_add(*parse_state.result.nodes, node); + + return *parse_state.result.nodes[parse_state.result.nodes.count - 1]; +} + +add_child :: (node : *AST_Node, child : *AST_Node) { + child.parent = node; + array_add(*node.children, child); +} + +Sync_Snapshot :: struct { + current : *Token; + previous : *Token; + current_token_index : int; +} + +snapshot_state :: (parse_state : *Parse_State) -> Sync_Snapshot { + snapshot : Sync_Snapshot; + snapshot.current = parse_state.current; + snapshot.previous = parse_state.previous; + snapshot.current_token_index = parse_state.current_token_index; + + return snapshot; +} + +rewind_to_snapshot :: (parse_state : *Parse_State, snapshot : Sync_Snapshot) { + parse_state.current = snapshot.current; + parse_state.previous = snapshot.previous; + parse_state.current_token_index = snapshot.current_token_index; +} + +advance :: (parse_state : *Parse_State) { + parse_state.previous = parse_state.current; + + while true { + parse_state.current = *parse_state.tokens[parse_state.current_token_index]; + parse_state.current_token_index += 1; + if parse_state.current.kind != .TOKEN_ERROR break; + + err := tprint("unknown token \x1b[1;37m'%'\x1b[0m", parse_state.current.string_value); + unexpected_token(parse_state, parse_state.current, err); + } +} + +//nb - Checks if the current token is of a certain kind and advances if it is +match :: (parse_state : *Parse_State, kind : Token_Kind) -> bool { + if !check(parse_state, kind) return false; + advance(parse_state); + return true; +} + +//nb - Checks if the current token is of a certain kind +check :: (parse_state : *Parse_State, kind : Token_Kind) -> bool { + return parse_state.current.kind == kind; +} + +//nb - Checks if the next token is of a certain kind +check_next :: (parse_state : *Parse_State, kind : Token_Kind) -> bool { + return parse_state.tokens[parse_state.current_token_index].kind == kind; +} + +//nb - Consume a token if +consume :: (parse_state : *Parse_State, kind : Token_Kind, message : string) { + if parse_state.current.kind == kind { + advance(parse_state); + return; + } + + unexpected_token(parse_state, parse_state.current, message); +} + +//////////////////////////// +//@nb - Expression parsing +get_rule :: (kind : Token_Kind) -> *Parse_Rule { + return *parse_rules[kind]; +} + +precedence :: (parse_state : *Parse_State, precedence : Precedence) -> *AST_Node { + advance(parse_state); + + prefix_rule := get_rule(parse_state.previous.kind).prefix; + if prefix_rule == null { + expected_expression(parse_state, parse_state.current, "Expected expression."); + // @Incomplete: Add error node here? + return error_node(parse_state, "Expected expression."); + } + + left := prefix_rule(parse_state, null); + + while precedence <= get_rule(parse_state.current.kind).precedence { + advance(parse_state); + if parse_state.current.kind == .TOKEN_EOF { + expected_expression(parse_state, parse_state.current, "Reached end of file. Expected expression."); + // @Incomplete: Add error node here? + return null; + } + infix_rule := get_rule(parse_state.previous.kind).infix; + left = infix_rule(parse_state, left); + } + + return left; +} + +named_variable :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + if check(parse_state, .TOKEN_LEFTPAREN) { + return call(parse_state, left); + } + + variable := make_node(parse_state, .Variable); + variable.source_location = generate_source_location_from_token(parse_state, parse_state.previous); + + variable.name = parse_state.previous.ident_value; + + return variable; +} + +binary :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + op := parse_state.previous.*; + rule := get_rule(op.kind); + + source_location := generate_source_location_from_token(parse_state, op); + // source_location : Source_Range; + // source_location.begin = left.source_location.begin; + + binary_expression := make_node(parse_state, .Binary); + + add_child(binary_expression, left); + add_child(binary_expression, precedence(parse_state, rule.precedence + 1)); + + if op.kind == { + case .TOKEN_PLUS; #through; + case .TOKEN_MINUS; #through; + case .TOKEN_STAR; #through; + case .TOKEN_SLASH; #through; + case .TOKEN_ISEQUAL; #through; + case .TOKEN_ASSIGN; #through; + case .TOKEN_ISNOTEQUAL; #through; + case .TOKEN_LOGICALOR; #through; + case .TOKEN_LOGICALAND; #through; + case .TOKEN_LESS; #through; + case .TOKEN_LESSEQUALS; #through; + case .TOKEN_GREATER; #through; + case .TOKEN_GREATEREQUALS; + { + binary_expression.token = op; + } + } + + // source_location.end = parse_state.previous; + binary_expression.source_location = source_location; + + return binary_expression; +} + +unary :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + op := parse_state.previous.*; + rule := get_rule(op.kind); + + unary_expression := make_node(parse_state, .Unary); + + add_child(unary_expression, precedence(parse_state, rule.precedence + 1)); + + if op.kind == { + case .TOKEN_MINUS; { + unary_expression.token = op; + } + } + + return unary_expression; +} + +grouping :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + grouping := expression(parse_state); + consume(parse_state, .TOKEN_RIGHTPAREN, "Expect ')' after group expression."); + return grouping; +} + +directive :: (state : *Parse_State) -> *AST_Node { + if state.current.ident_value == "foreign" { + advance(state); + identifier_token := state.current; + advance(state); + consume(state, .TOKEN_DOUBLECOLON, "Expect '::' after function name."); + func := function_declaration(state, identifier_token, .None, false, false); + func.foreign_declaration = true; + return func; + } + + return null; +} + +call :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + call := make_node(parse_state, .Call); + source_location := generate_source_location_from_token(parse_state, parse_state.previous); + // source_location : Source_Range; + // source_location.begin = parse_state.previous; + // source_location.main_token = parse_state.previous; + + prev := parse_state.previous; + call.name = prev.ident_value; + advance(parse_state); + arg_list := argument_list(parse_state); + if arg_list { + add_child(call, arg_list); + } + + snapshot := snapshot_state(parse_state); + + advance_to_sync_point(parse_state); + source_location.end = parse_state.current; + + rewind_to_snapshot(parse_state, snapshot); + call.source_location = source_location; + + return call; +} + +dot :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + consume(parse_state, .TOKEN_IDENTIFIER, "Expect property name after '.'."); + identifier := parse_state.previous; + + source_location : Source_Range; + source_location.begin = left.source_location.begin; + + if check(parse_state, .TOKEN_ASSIGN) { + advance(parse_state); + variable := make_node(parse_state, .Variable); + variable.source_location = generate_source_location_from_token(parse_state, identifier); + variable.name = identifier.ident_value; + + add_child(left, variable); + + node := make_node(parse_state, .Binary); + node.token = parse_state.previous; + add_child(node, left); + add_child(node, expression(parse_state)); + return node; + } else if check(parse_state, .TOKEN_DOT) { + // @Incomplete(nb): Another level of access + } + variable := make_node(parse_state, .Variable); + variable.name = identifier.ident_value; + + add_child(left, variable); + + source_location.end = parse_state.previous; + variable.source_location = source_location; + return left; +} + +integer :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + value := parse_state.previous.integer_value; + node := make_node(parse_state, .Integer); + node.source_location.begin = parse_state.previous; + node.source_location.end = parse_state.previous; + node.source_location.main_token = parse_state.previous; + node.integer_value = value; + return node; +} + +floating :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node { + value := parse_state.previous.float_value; + node := make_node(parse_state, .Float); + node.source_location.begin = parse_state.previous; + node.source_location.end = parse_state.previous; + node.source_location.main_token = parse_state.previous; + node.float_value = value; + return node; +} + +expression :: (parse_state : *Parse_State) -> *AST_Node { + expression := precedence(parse_state, .PREC_ASSIGNMENT); + return expression; +} + +//////////////////////////// +//@nb - Statement parsing functions + +field_assignment :: (parse_state : *Parse_State, identifier_token : *Token) -> *AST_Node { + node : *AST_Node = make_node(parse_state, .Field); + + identifier := identifier_token.*; + source_location : Source_Range; + source_location.begin = identifier; + + source_location.main_token = identifier; + node.name = identifier.string_value; + + add_child(node, expression(parse_state)); + + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +//nb - Non-const field declarations +field_declaration :: (parse_state : *Parse_State, identifier_token : *Token) -> *AST_Node { + node : *AST_Node = make_node(parse_state, .Field); + + identifier := identifier_token.*; + source_location : Source_Range; + source_location.begin = identifier; + + source_location.main_token = identifier; + node.name = identifier.string_value; + + consume(parse_state, .TOKEN_COLON, "Expected ':' after field name for declarations."); + + if check(parse_state, .TOKEN_IDENTIFIER) { + type_identifier := parse_state.current; + node.token = type_identifier; + advance(parse_state); + } else { + missing_type_specifier(parse_state, identifier_token, "Expected type specifier after field name."); + return node; + } + + if check(parse_state, .TOKEN_AT) { + while check(parse_state, .TOKEN_AT) { + advance(parse_state); + // @Incomplete(niels): this is a mapping + if check(parse_state, .TOKEN_IDENTIFIER) { + array_add(*node.hint_tokens, parse_state.current); + advance(parse_state); + } else if check(parse_state, .TOKEN_HINT) { + array_add(*node.hint_tokens, parse_state.current); + advance(parse_state); + } else if check(parse_state, .TOKEN_OPTIONAL) { + array_add(*node.hint_tokens, parse_state.current); + advance(parse_state); + } + } + + } else if match(parse_state, .TOKEN_ASSIGN) { + add_child(node, expression(parse_state)); + } + + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +argument_list :: (parse_state : *Parse_State) -> *AST_Node { + node : *AST_Node; + + source_location : Source_Range; + source_location.begin = parse_state.previous; + source_location.begin.index -= source_location.begin.column; + source_location.begin.source -= source_location.begin.column; + source_location.begin.length += source_location.begin.column; + source_location.begin.column = 0; + + source_location.main_token = parse_state.current; + + while !check(parse_state, .TOKEN_RIGHTPAREN) { + arg := expression(parse_state); + if !node { + node = make_node(parse_state, .ArgList); + } + + add_child(node, arg); + + if check(parse_state, .TOKEN_RIGHTPAREN) break; + consume(parse_state, .TOKEN_COMMA, "Expect ',' after function argument."); + } + + consume(parse_state, .TOKEN_RIGHTPAREN, "Expect ')' after function call."); + + if node { + snapshot := snapshot_state(parse_state); + + advance_to_sync_point(parse_state); + source_location.end = parse_state.current; + + rewind_to_snapshot(parse_state, snapshot); + node.source_location = source_location; + } + + return node; +} + +expression_statement :: (parse_state : *Parse_State) -> *AST_Node { + node := make_node(parse_state, .Expression_Statement); + + source_location : Source_Range; + source_location.begin = parse_state.current; + + expr := expression(parse_state); + add_child(node, expr); + consume(parse_state, .TOKEN_SEMICOLON, "Expect ';' after expression."); + while parse_state.current.kind == .TOKEN_SEMICOLON { + advance(parse_state); + } + source_location.end = parse_state.previous; + + node.source_location = source_location; + return node; +} + +statement :: (parse_state : *Parse_State) -> *AST_Node { + if match(parse_state, .TOKEN_RETURN) { + node := make_node(parse_state, .Return); + + source_location : Source_Range; + source_location.begin = parse_state.previous; + + return_expression := expression(parse_state); + consume(parse_state, .TOKEN_SEMICOLON, "Expect ';' after return statement."); + while parse_state.current.kind == .TOKEN_SEMICOLON { + advance(parse_state); + } + + if return_expression { + add_child(node, return_expression); + } + source_location.end = parse_state.previous; + node.source_location = source_location; + return node; + } else { + return expression_statement(parse_state); + } + + return error_node(parse_state, "Couldn't parse statement."); +} + +block :: (parse_state : *Parse_State) -> *AST_Node { + node : *AST_Node = make_node(parse_state, .Block); + + source_location : Source_Range; + + consume(parse_state, .TOKEN_LEFTBRACE, "Expect '{' at start of block."); + source_location.begin = parse_state.previous; + + while !check(parse_state, .TOKEN_RIGHTBRACE) && !check(parse_state, .TOKEN_EOF) { + decl := declaration(parse_state); + if decl { + add_child(node, decl); + } + } + consume(parse_state, .TOKEN_RIGHTBRACE, "Expect '}' after block."); + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +field_list :: (parse_state : *Parse_State, separator : Separator_Type, require_field_names := true) -> *AST_Node { + node : *AST_Node = make_node(parse_state, .FieldList); + array_reserve(*node.children, 16); + source_location : Source_Range; + source_location.begin = parse_state.previous; + source_location.main_token = parse_state.current; + + while check(parse_state, .TOKEN_IDENTIFIER) { + field : *AST_Node; + identifier := parse_state.current; + advance(parse_state); + if require_field_names { + field = field_declaration(parse_state, identifier); + } else { + field = make_node(parse_state, .Unnamed_Field); + + source_location : Source_Range; + source_location.begin = identifier; + + source_location.main_token = identifier; + field.name = identifier.ident_value; + field.token = identifier; + } + add_child(node, field); + + + if check(parse_state, .TOKEN_RIGHTPAREN) { + source_location.end = parse_state.current; + node.source_location = source_location; + return node; + } + + if separator == { + case .Comma; { + consume(parse_state, .TOKEN_COMMA, "Expect ',' after field declaration."); + } + case .Semicolon; { + consume(parse_state, .TOKEN_SEMICOLON, "Expect ';' after field declaration."); + } + } + } + + return node; +} + +function_declaration :: (parse_state : *Parse_State, identifier_token : *Token, entry_point_kind : Entry_Point_Type, expect_body : bool = true, require_field_names : bool = true) -> *AST_Node { + node : *AST_Node; + source_location : Source_Range; + + source_location = generate_source_location_from_token(parse_state, identifier_token); + + function_name_token := identifier_token; + + consume(parse_state, .TOKEN_LEFTPAREN, "Expect argument list after '::' in function declaration."); + + function_args := field_list(parse_state, .Comma, require_field_names); + + consume(parse_state, .TOKEN_RIGHTPAREN, "Expect right ')' after function argument list."); + return_type_token : Token; + hint_token : Token; + + if match(parse_state, .TOKEN_ARROW) { + return_type_token = parse_state.current; + advance(parse_state); + if check(parse_state, .TOKEN_AT) { + advance(parse_state); + hint_token = parse_state.current; + advance(parse_state); + } + } + + node = make_node(parse_state, .Function); + add_child(node, function_args); + name := function_name_token.ident_value; + + if entry_point_kind == { + case .Vertex; { + node.vertex_entry_point = true; + name = sprint("vs_%", function_name_token.ident_value); + } + case .Pixel; { + node.pixel_entry_point = true; + name = sprint("ps_%", function_name_token.ident_value); + } + } + + node.name = name; + node.token = return_type_token; + array_add(*node.hint_tokens, hint_token); + + if expect_body { + function_body := block(parse_state); + if function_body.children.count > 0 { + add_child(node, function_body); + } + } else { + consume(parse_state, .TOKEN_SEMICOLON, "Expect ';' after a function with no body."); + } + + node.source_location = source_location; + + return node; +} + +instance_block :: (parse_state : *Parse_State) -> *AST_Node { + node : *AST_Node; + + source_location : Source_Range; + source_location.begin = parse_state.current; + + consume(parse_state, .TOKEN_LEFTBRACE, "Expect '{' after 'instance' keyword"); + properties := field_list(parse_state, .Semicolon); + + node = make_node(parse_state, .Instance); + add_child(node, properties); + + consume(parse_state, .TOKEN_RIGHTBRACE, "Expect '}' after instance block"); + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +meta_block :: (parse_state : *Parse_State) -> *AST_Node { + node : *AST_Node; + + source_location : Source_Range; + source_location.begin = parse_state.current; + + consume(parse_state, .TOKEN_LEFTBRACE, "Expect '{' after 'meta' keyword"); + properties := field_list(parse_state, .Semicolon); + + node = make_node(parse_state, .Meta); + add_child(node, properties); + + consume(parse_state, .TOKEN_RIGHTBRACE, "Expect '}' after meta block"); + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +property_block :: (parse_state : *Parse_State, identifier_token : *Token = null) -> *AST_Node { + node : *AST_Node; + source_location : Source_Range; + source_location.begin = parse_state.current; + + consume(parse_state, .TOKEN_LEFTBRACE, "Expect '{' after 'property' keyword"); + properties := field_list(parse_state, .Semicolon); + + node = make_node(parse_state, .Properties); + if identifier_token { + node.name = identifier_token.ident_value; + } + add_child(node, properties); + + consume(parse_state, .TOKEN_RIGHTBRACE, "Expect '}' after 'property' keyword"); + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +struct_declaration :: (parse_state : *Parse_State, identifier_token : *Token) -> *AST_Node { + source_location := generate_source_location_from_token(parse_state, identifier_token); + + consume(parse_state, .TOKEN_LEFTBRACE, "Expect '{' before struct declaration."); + + fields := field_list(parse_state, .Semicolon); + + node := make_node(parse_state, .Struct); + node.name = identifier_token.ident_value; + add_child(node, fields); + + consume(parse_state, .TOKEN_RIGHTBRACE, "Expect '}' after struct declaration."); + source_location.end = parse_state.previous; + node.source_location = source_location; + + return node; +} + +access :: (parse_state : *Parse_State, identifier_token : *Token) -> *AST_Node { + err_node := error_node(parse_state, tprint("Accessors not yet implemented. Token: %.", identifier_token.ident_value)); + advance(parse_state); + return err_node; +} + +const_declaration :: (parse_state : *Parse_State, identifier_token : *Token) -> *AST_Node { + if match(parse_state, .TOKEN_STRUCT) { + return struct_declaration(parse_state, identifier_token); + } else if check(parse_state, .TOKEN_LEFTPAREN) { + return function_declaration(parse_state, identifier_token, .None); + } else if match(parse_state, .TOKEN_PROPERTIES) { + return property_block(parse_state, identifier_token); + } + return error_node(parse_state, tprint("Couldn't parse constant declaration at token %\n", parse_state.current.*)); +} + +declaration :: (parse_state : *Parse_State) -> *AST_Node { + decl_node : *AST_Node; + if match(parse_state, .TOKEN_PROPERTIES) { + decl_node = property_block(parse_state); + } else if match(parse_state, .TOKEN_INSTANCE) { + decl_node = instance_block(parse_state); + } else if match(parse_state, .TOKEN_META) { + decl_node = meta_block(parse_state); + } else if match(parse_state, .TOKEN_VERTEX) { + vertex_token := parse_state.previous; + identifier := parse_state.current; + + advance(parse_state); + consume(parse_state, .TOKEN_DOUBLECOLON, "Expect '::' after vertex entry point declaration."); + + decl_node = function_declaration(parse_state, identifier, .Vertex); + } else if match(parse_state, .TOKEN_PIXEL) { + pixel_token := parse_state.previous; + identifier := parse_state.current; + + advance(parse_state); + consume(parse_state, .TOKEN_DOUBLECOLON, "Expect '::' after pixel entry point declaration."); + + decl_node = function_declaration(parse_state, identifier, .Pixel); + } else if check(parse_state, .TOKEN_LEFTPAREN) { + decl_node = call(parse_state, null); + } else if check(parse_state, .TOKEN_DIRECTIVE) { + decl_node = directive(parse_state); + } else if check(parse_state, .TOKEN_IDENTIFIER) { + identifier := parse_state.current; + + if check_next(parse_state, .TOKEN_DOUBLECOLON) { + advance(parse_state); + advance(parse_state); + decl_node = const_declaration(parse_state, identifier); + } else if check_next(parse_state, .TOKEN_LEFTPAREN) { + decl_node = statement(parse_state); + } else if check_next(parse_state, .TOKEN_COLON) { + advance(parse_state); + decl_node = field_declaration(parse_state, identifier); + consume(parse_state, .TOKEN_SEMICOLON, "Expect ';' after a field declaration."); + } else if check_next(parse_state, .TOKEN_ASSIGN) { + decl_node = expression_statement(parse_state); + } + } else if check(parse_state, .TOKEN_OUT) || check(parse_state, .TOKEN_IN) { + error := error_node(parse_state, tprint("Expected a declaration or function call. '%' not allowed as a declaration name.", parse_state.current.kind)); + advance(parse_state); + decl_node = error; + } + + if !decl_node { + decl_node = statement(parse_state); + } + + while parse_state.current.kind == .TOKEN_SEMICOLON { + advance(parse_state); + } + + return decl_node; +} + +parse :: (parse_state : *Parse_State) -> Parse_Result { + advance(parse_state); + + if !match(parse_state, .TOKEN_EOF) { + parse_state.result.root = make_node(parse_state, .Program); + array_reserve(*parse_state.result.root.children, 1024); + program := parse_state.result.root; + + while !check(parse_state, .TOKEN_EOF) { + decl := declaration(parse_state); + if decl { + add_child(program, decl); + } + } + } + + return parse_state.result; +} + +#load "AST.jai"; diff --git a/Semantic_Analysis.jai b/Semantic_Analysis.jai new file mode 100644 index 0000000..2a5e31c --- /dev/null +++ b/Semantic_Analysis.jai @@ -0,0 +1,2118 @@ +///////////////////////////////////// +//~ nbr: +// + +///////////////////////////////////// +//~ nbr: Error reporting TODOs +// +// [x] Improve error reporting on mismatched overloads when types don't match, but arity does +// [ ] Improve error reporting for type mismatches in general. It seems like the expect node is no always correct. + +#import "Hash_Table"; + +VERTEX_MAIN_FUNCTION_PREFIX :: "vertex"; +PIXEL_MAIN_FUNCTION_PREFIX :: "pixel"; +PROPERTIES_PREFIX :: "properties"; + +Semantic_Type :: enum { + Invalid :: 128; + + Int :: 0; + Half :: 1; + Float :: 2; + Double :: 3; + Texture2D :: 8; + Sampler :: 9; + + Max_Builtin :: Sampler + 1; + + Unit; + Function; + Call; + + Unresolved_Variable; + Unresolved_Expression; + + Struct; + Array; +} + +Type_Variable_Kind :: enum { + Expression; + Declaration; // struct, properties, function, etc. +} + +Typenames :: string.[ + "int" , + "half" , + "float" , + "double" , + "float2" , + "float3" , + "float4" , + "float4x4" , + "sampler" , + "texture2D", +]; + +Type_Variable :: struct { + type : Semantic_Type; + kind : Type_Variable_Kind; + builtin : bool; + + name : string; + + //@Note(niels) For functions + return_var : Type_Variable_Handle; + + //@Note(niels) The scope this variable creates (function, struct, global) + scope : Scope_Handle; + + //@Note(niels): For struct members + field_parent : *AST_Node; + + typename : string; + + MAX_TYPE_VARIABLE_CHILDREN :: 16; + children : [MAX_TYPE_VARIABLE_CHILDREN]Type_Variable_Handle; + child_count : int; + + //@Note(niels): For constant buffers + buffer_index : u32; + + uf_parent : Type_Variable_Handle; + + source_node : *AST_Node; +} + +Type_Variable_Handle :: #type, distinct u32; +Type_Constraint_Handle :: #type, distinct u32; + +Type_Constraint_Kind :: enum { + Int_Literal; // [[I]] = int + Float_Literal; // [[F]] = float + Equivalence; // [[X]] = int/float + Equality; // E1 == E2: [[E1]] = [[E2]] && [[E1 == E2]] = bool + Boolean_Condition; // while/if (E): [[E]] == bool + Function_Decl; // X(X1, ..., Xn) { return E; }: [[X]] = ([[X1]], ..., [[Xn]]) -> [[E]] + Function_Call; // E(E1, ..., En): [[E]] = ([[E1]], ..., [[En]]) -> [[E(E1, ..., En)]] +} + +Type_Constraint :: struct { + kind : Type_Constraint_Kind; + + union { + literal : struct { + type_variable : Type_Variable_Handle; + union { + i : int; + f : float; + } + } + + equivalence : struct { + lhs : Type_Variable_Handle; + rhs : Type_Variable_Handle; + } + + function : struct { + symbol_variable : Type_Variable_Handle; + return_variable : Type_Variable_Handle; + arguments : [16]Type_Variable_Handle; + argument_count : int; + } + } + + usage_site : *AST_Node; + + binary_operator : Token; +} + +Scope_Stack :: struct { + allocator : Allocator; + + stack : [..]Scope; +} + +Defined_Symbol :: struct { + name : string; + + type_variable : Type_Variable_Handle; + source_node : *AST_Node; + + functions :[..]Defined_Symbol; + + builtin : bool; +} + +Scope_Kind :: enum { + Global; + Function; + Struct; + Properties; +} + +Scope :: struct { + table : Table(string, Defined_Symbol); + + //@Note(nb): Only for pretty printing + longest_key_length : int; + + name : string; + children : [..]Scope_Handle; + parent : Scope_Handle; + + builtin : bool; + + kind : Scope_Kind; +} + +Scope_Handle :: #type, distinct u32; + +Semantic_Check_Result :: struct { + messages : [..]Compiler_Message; + had_error : bool; + + scope_stack : Scope_Stack; + type_variables : [..]Type_Variable; +} + +Checker_State :: enum { + Type_Checking; + Adding_Builtins; +} + +Semantic_Checker :: struct { + program_root : *AST_Node; + path : string; + + state : Checker_State; + + current_scope : Scope_Handle; + + vertex_entry_point : *AST_Node; + pixel_entry_point : *AST_Node; + + // type_variables : [..]Type_Variable; + constraints : [..]Type_Constraint; + + result : Semantic_Check_Result; +} + +record_error :: (checker : *Semantic_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) { + record_error(checker, tprint("Invalid % name '%'", type, node.name), node.source_location); +} + +symbol_redeclaration :: (checker : *Semantic_Checker, redeclared_node : *AST_Node, symbol : *Defined_Symbol) { + /* + + Redeclaration of '%': + + foo : int; + ^^^ + + Here is the first redeclaration of 'foo': + + foo : int; + ^^^ + +*/ + + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "Redeclaration of '%'\n", symbol.name); + + cyan(*builder); + indent(*builder, 1); + print_to_builder(*builder, "%\n", print_from_source_location(redeclared_node.source_location)); + + indent(*builder, 1); + print_token_pointer(*builder, redeclared_node.source_location.main_token); + append(*builder, "\n\n"); + + white(*builder); + path := checker.path; + if path.count > 0 { + print_to_builder(*builder, "%:", checker.path); + } else { + append(*builder, "internal:"); + } + + if symbol.source_node { + location := symbol.source_node.source_location; + print_to_builder(*builder, "%,%: info: ", location.begin.line, location.begin.column); + print_to_builder(*builder, "Here is the first declaration of '%'\n", symbol.name); + + cyan(*builder); + indent(*builder, 1); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + indent(*builder, 1); + print_token_pointer(*builder, symbol.source_node.source_location.main_token); + } + + + message := builder_to_string(*builder); + + record_error(checker, message, redeclared_node.source_location, false); +} + +symbol_undeclared :: (checker : *Semantic_Checker, node : *AST_Node) { + /* +Use of undeclard symbol '%'. + b = f; + ^ +*/ + + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "Use of undeclared symbol '%'\n", node.name); + + cyan(*builder); + indent(*builder, 1); + + print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); + indent(*builder, 1); + print_token_pointer(*builder, node.source_location.main_token); + + message := builder_to_string(*builder); + + record_error(checker, message, node.source_location, false); +} + +foo :: (i : int, p : int) {} +foo :: (i : int, p : int, t : int) {} + +no_matching_overload_found :: (checker : *Semantic_Checker, call : *AST_Node, overloads : *Defined_Symbol, arg_node : *AST_Node = null) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "Procedure call did not match any of the possible overloads for '%'\n", overloads.name); + + cyan(*builder); + indent(*builder, 1); + append(*builder, "found:\n"); + indent(*builder, 2); + print_to_builder(*builder, "%\n", print_from_source_location(call.source_location)); + indent(*builder, 2); + print_token_pointer(*builder, call.source_location.main_token); + newline(*builder); + + if arg_node { + newline(*builder); + + white(*builder); + + location := arg_node.source_location; + indent(*builder, 1); + + field_list := arg_node.parent; + index : s64 = -1; + for child : field_list.children { + if child == arg_node { + index = it_index + 1; + break; + } + } + print_to_builder(*builder, "While matching argument % in function call.\n", index); + + cyan(*builder); + indent(*builder, 2); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + indent(*builder, 2); + print_token_pointer(*builder, arg_node.source_location.main_token); + newline(*builder); + } + + white(*builder); + indent(*builder, 1); + append(*builder, "Possible overloads:\n"); + + for func : overloads.functions { + func_var := h2tv(checker, func.type_variable); + + cyan(*builder); + // foo :: (f : float) {} (file_path:line_num) + func_location := func_var.source_node.source_location; + indent(*builder, 2); + print_to_builder(*builder, "% (%:%)\n", print_from_source_location(func_location), checker.path, + func_location.main_token.line); + + if !arg_node { + white(*builder); + + arg_list := call.children[0]; + indent(*builder, 2); + + func_var := h2tv(checker, func.type_variable); + + if arg_list.children.count != func_var.child_count { + print_to_builder(*builder, "Not enough arguments: Wanted %, got %.\n\n", func_var.child_count, arg_list.children.count); + } + + } + } + + locations : [1]Source_Range; + locations[0] = call.source_location; + message := builder_to_string(*builder); + record_error(checker, message, locations, false); +} + +not_all_control_paths_return_value :: (checker : *Semantic_Checker, node : *AST_Node) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "Not all control paths return a value.\n\n"); + + cyan(*builder); + + indent(*builder, 1); + + print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); + indent(*builder, 1); + print_token_pointer(*builder, node.token); + + white(*builder); + + message := builder_to_string(*builder); + + 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) { + builder : String_Builder; + init_string_builder(*builder,, temp); + + if args_call > args_def { + print_to_builder(*builder, "Too many arguments: Wanted %, got %\n", args_def, args_call); + } else { + print_to_builder(*builder, "Too few arguments: Wanted %, got %\n", args_def, args_call); + } + + /* +Too many arguments: Expected %, got %. + + found + foo(2, 3) + ^^^ + + expected + foo :: (x : int, y : int, z : int) + +*/ + cyan(*builder); + indent(*builder, 1); + append(*builder, "found:\n"); + indent(*builder, 2); + print_to_builder(*builder, "%\n", print_from_source_location(call.source_location)); + indent(*builder, 2); + print_token_pointer(*builder, call.source_location.main_token); + append(*builder, "\n\n"); + indent(*builder, 1); + append(*builder, "expected:\n"); + + indent(*builder, 2); + print_to_builder(*builder, "%\n", print_from_source_location(symbol.source_node.source_location)); + + locations : [1]Source_Range; + locations[0] = call.source_location; + + message := builder_to_string(*builder); + record_error(checker, message, locations, false); +} + +function_undeclared :: (checker : *Semantic_Checker, node : *AST_Node) { + /* +Error: Undeclared identifier 'name'. + + name(); + ^^^^ + +*/ + builder : String_Builder; + init_string_builder(*builder,, temp); + + 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)); + indent(*builder, 1); + print_token_pointer(*builder, node.source_location.main_token); + newline(*builder); + newline(*builder); + message := builder_to_string(*builder); + record_error(checker, message, node.source_location, false); +} + +field_not_defined_on_struct :: (checker : *Semantic_Checker, node : *AST_Node, struct_symbol : *Defined_Symbol) { + /* +Field '%' is not defined in struct '%'. + b.t = f; + ^ + + declaration: + Bar :: struct { + f : Foo; + } +*/ + + builder : String_Builder; + init_string_builder(*builder,, temp); + + print_to_builder(*builder, "Field '%' is not defined in struct '%'.\n", node.name, struct_symbol.name); + + cyan(*builder); + indent(*builder, 1); + print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); + indent(*builder, 1); + print_token_pointer(*builder, node.source_location.main_token); + newline(*builder); + newline(*builder); + + indent(*builder, 1); + append(*builder, "declaration:\n"); + print_from_source_location(*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) { + /* +Attempting to access a field on a primitive type '%'. + x.d = 5; + ^^ + + declaration: + x : int = 5; +*/ + + builder : String_Builder; + init_string_builder(*builder,, temp); + + variable := h2tv(checker, handle); + print_to_builder(*builder, "Attempting to access a field on a primitive type '%'.\n", proper_type_to_string(checker, variable)); + + indent(*builder, 1); + cyan(*builder); + print_to_builder(*builder, "%\n", print_from_source_location(node.source_location)); + indent(*builder, 1); + + node_variable := h2tv(checker, node.type_variable); + + for 0..node.name.count - 1 { + append(*builder, " "); + } + print_token_pointer(*builder, node.source_location.begin); + + append(*builder, "\n"); + + indent(*builder, 1); + append(*builder, "declaration:\n"); + + indent(*builder, 2); + print_to_builder(*builder, "%", print_from_source_location(variable.source_node.source_location)); + + message := builder_to_string(*builder,, temp); + record_error(checker, message, node.source_location, false); +} + +type_mismatch :: (checker : *Semantic_Checker, usage_site : *AST_Node, expect_node : *AST_Node, expect : Type_Variable_Handle, got : Type_Variable_Handle) { + expect_var := h2tv(checker, expect); + got_var := h2tv(checker, got); + + builder : String_Builder; + init_string_builder(*builder,, temp); + + if got_var.builtin { + print_to_builder(*builder, "% :: (", got_var.name); + + for i: 0..got_var.child_count - 1{ + child_handle := got_var.children[i]; + child := h2tv(checker, child_handle); + + print_to_builder(*builder, "% : %", child.name, type_to_string(child)); + } + } + + print_to_builder(*builder, "Type mismatch. Expected % got %\n", type_to_string(expect_var), type_to_string(got_var)); + + cyan(*builder); + location := usage_site.source_location; + indent(*builder, 1); + append(*builder, "found:\n"); + indent(*builder, 2); + print_to_builder(*builder, "%\n", print_from_source_location(location)); + indent(*builder, 2); + + print_token_pointer(*builder, location.main_token); + append(*builder, "\n"); + + indent(*builder, 1); + print_to_builder(*builder, "expected:\n"); + indent(*builder, 2); + proper_type_to_string(*builder, checker, expect_var); + append(*builder, "\n"); + + // indent(*builder, 2); + + { + // expect_location := expect_var.source_node.source_location; + // // token.length = expect_location.end.index + token.length - token.index + expect_location.end.length - 1; + + // print_token_pointer(*builder, expect_location.main_token); + append(*builder, "\n"); + } + + indent(*builder, 1); + print_to_builder(*builder, "got:\n"); + + indent(*builder, 2); + print_to_builder(*builder, "%\n", print_from_source_location(got_var.source_node.parent.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) { + error : Compiler_Message; + error.message_kind = .Error; + error.report_source_location = report_source_location; + + for location : locations { + array_add(*error.source_locations, location); + } + + error.path = checker.path; + error.message = error_string; + + checker.result.had_error = true; + array_add(*checker.result.messages, error); +} + +is_proper :: (var : Type_Variable) -> bool { + if var.type == { + case .Function; #through; + case .Int; #through; + case .Struct; #through; + case .Float; { + return true; + } + } + return false; +} + +use_scope :: (checker : *Semantic_Checker, handle : Scope_Handle) -> Scope_Handle { + assert(handle > 0, "Invalid scope handle: %", handle); + previous_scope := checker.current_scope; + checker.current_scope = handle; + + return previous_scope; +} + +push_scope :: (checker : *Semantic_Checker, name := "", kind : Scope_Kind = .Global) -> *Scope, Scope_Handle { + new_scope : Scope; + array_add(*checker.result.scope_stack.stack, new_scope); + + count := checker.result.scope_stack.stack.count; + scope := *checker.result.scope_stack.stack[count - 1]; + scope.parent = checker.current_scope; + scope.name = name; + scope.kind = kind; + if checker.state == .Adding_Builtins { + scope.builtin = true; + } + + if checker.current_scope { + scope := get_current_scope(checker); + array_add(*scope.children, xx count); + } + + checker.current_scope = xx count; + return scope, xx count; +} + +pop_scope :: (checker : *Semantic_Checker) -> Scope_Handle { + scope := get_scope(checker, checker.current_scope); + if !scope.parent { + return 0; + } + + checker.current_scope = scope.parent; + + return checker.current_scope; +} + +peek_scope :: (checker : *Semantic_Checker) -> *Scope, Scope_Handle { + if checker.result.scope_stack.stack.count == 0 { + return null, 0; + } + + count := checker.result.scope_stack.stack.count; + scope := *checker.result.scope_stack.stack[count - 1]; + return scope, xx count; +} + +get_current_scope :: (checker : *Semantic_Checker) -> *Scope { + return get_scope(checker, checker.current_scope); +} + +get_scope :: (scope_stack : Scope_Stack, handle : Scope_Handle) -> *Scope { + if handle == 0 { + return null; + } + + return *scope_stack.stack[handle - 1]; +} + +get_scope :: (checker : *Semantic_Checker, handle : Scope_Handle) -> *Scope { + return get_scope(*checker.result.scope_stack, handle); +} + +add_symbol_to_scope :: (checker : *Semantic_Checker, scope_handle : Scope_Handle, name : string, symbol : Defined_Symbol) -> *Defined_Symbol { + scope := get_scope(checker, scope_handle); + scope.longest_key_length = max(scope.longest_key_length, name.count); + + symbol_to_add : Defined_Symbol; + symbol_to_add.name = symbol.name; + symbol_to_add.type_variable = symbol.type_variable; + symbol_to_add.source_node = symbol.source_node; + symbol_to_add.functions = symbol.functions; + + if checker.state == .Adding_Builtins { + symbol_to_add.builtin = true; + } + + return table_set(*scope.table, name, symbol_to_add); +} + +new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Variable_Handle { + variable : Type_Variable; + handle := cast(Type_Variable_Handle)checker.result.type_variables.count + 1; + variable.uf_parent = handle; + array_add(*checker.result.type_variables, variable); + + return h2tv(checker, handle), handle; +} + + +add_child :: (variable : *Type_Variable, child : Type_Variable_Handle) { + assert(variable.child_count < Type_Variable.MAX_TYPE_VARIABLE_CHILDREN); + variable.children[variable.child_count] = child; + variable.child_count += 1; +} + +add_child :: (checker : *Semantic_Checker, handle : Type_Variable_Handle, child : Type_Variable_Handle) { + variable := h2tv(checker, handle); + assert(variable.child_count < Type_Variable.MAX_TYPE_VARIABLE_CHILDREN); + variable.children[variable.child_count] = child; + variable.child_count += 1; +} + +init_semantic_checker :: (checker : *Semantic_Checker, root : *AST_Node, path : string) { + checker.program_root = root; + checker.path = path; + array_reserve(*checker.result.type_variables, 2048); + array_reserve(*checker.result.scope_stack.stack, 256); + + global_scope, global_handle := push_scope(checker, kind = .Global); + array_reserve(*global_scope.children, 2048); +} + +find_symbol :: (scope_stack : Scope_Stack, name : string, current_scope : Scope_Handle, containing_scope : *Scope_Handle = null) -> *Defined_Symbol { + handle := current_scope; + current := get_scope(scope_stack, current_scope); + + while current { + table := current.table; + info := table_find_pointer(*table, name); + if info { + if containing_scope { + containing_scope.* = handle; + } + return info; + } + handle = current.parent; + current = get_scope(scope_stack, current.parent); + } + return null; +} + +find_symbol :: (checker : *Semantic_Checker, name : string, current_scope : Scope_Handle, containing_scope : *Scope_Handle = null) -> *Defined_Symbol { + return find_symbol(checker.result.scope_stack, name, current_scope, containing_scope); +} + +find_symbol :: (name : string, checker : *Semantic_Checker, containing_scope : *Scope_Handle = null) -> *Defined_Symbol { + return find_symbol(checker, name, checker.current_scope, containing_scope); +} + +h2tv :: (variables : []Type_Variable, handle : Type_Variable_Handle) -> *Type_Variable { + assert(handle > 0 && xx handle <= variables.count, tprint("Invalid handle: %. Range is: 1-%", handle, variables.count - 1)); + return *variables[handle - 1]; +} + +h2tv :: (checker : *Semantic_Checker, handle : Type_Variable_Handle) -> *Type_Variable { + return h2tv(checker.result.type_variables, handle); +} + +proper_type_to_string :: (builder : *String_Builder, checker : *Semantic_Checker, var : Type_Variable) { + if var.type == { + case .Int; #through; + case .Half; #through; + case .Float; #through; + case .Double; { + print_to_builder(builder, "%", Typenames[var.type]); + } + case .Struct; { + print_to_builder(builder, "%", var.typename); + } + case .Function; { + + append(builder, "("); + + for child : var.source_node.children { + if child.kind == .FieldList { + for field : child.children { + var := field.type_variable; + print_type_variable(builder, checker, var); + + if it_index != child.children.count - 1 { + append(builder, ", "); + } + } + } + } + + append(builder, ")"); + + if var.return_var > 0 { + append(builder, " -> ", ); + return_var := h2tv(checker, var.return_var); + if is_proper(return_var) { + proper_type_to_string(builder, checker, return_var); + } else { + append(builder, "[["); + print_type_variable(builder, checker, var.return_var); + append(builder, "]]", ); + } + } else { + append(builder, " -> unit"); + } + } + case; { + append(builder, "______not proper type______"); + } + } +} + +proper_type_to_string :: (checker : *Semantic_Checker, var : Type_Variable, allocator := context.allocator) -> string { + if var.type == { + case .Int; #through; + case .Half; #through; + case .Float; #through; + case .Double; { + return Typenames[var.type]; + } + case .Function; { + builder : String_Builder; + init_string_builder(*builder,, allocator); + + proper_type_to_string(*builder, checker, var); + return builder_to_string(*builder,, allocator); + } + } + + return "______not proper type______"; +} + + +get_type_from_identifier :: (checker : *Semantic_Checker, scope : Scope_Handle, node : *AST_Node, typename : *string = null) -> Semantic_Type { + type_string := node.token.ident_value; + + if type_string == Typenames[Semantic_Type.Int] return .Int; + if type_string == Typenames[Semantic_Type.Half] return .Half; + if type_string == Typenames[Semantic_Type.Float] return .Float; + if type_string == Typenames[Semantic_Type.Double] return .Double; + + symbol := find_symbol(checker, type_string, scope); + if symbol { + symbol_var := h2tv(checker, symbol.type_variable); + if symbol_var.type == .Struct { + if typename { + typename.* = symbol_var.typename; + } + return symbol_var.type; + } + } else { + return .Unresolved_Variable; + } + + return .Invalid; +} + +check_expression :: (node : *AST_Node, checker : *Semantic_Checker) -> Type_Variable_Handle { + return 0; +} + +check_block :: (checker : *Semantic_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 { + variable, handle := new_type_variable(checker); + variable.type = .Struct; + variable.kind = .Declaration; + variable.name = name; + variable.source_node = node; + variable.typename = name; + node.type_variable = handle; + + find_result := find_symbol(checker, name, checker.current_scope); + + if !find_result { + symbol : Defined_Symbol; + symbol.name = name; + symbol.source_node = node; + symbol.type_variable = handle; + add_symbol_to_scope(checker, checker.current_scope, name, symbol); + } else { + symbol_redeclaration(checker, node, find_result); + return 0; + } + + scope, scope_handle := push_scope(checker, name, .Struct); + variable.scope = scope_handle; + + for child : node.children { + if child.kind == .FieldList { + for field : child.children { + type_var := check_node(checker, field); + h2tv(checker, type_var).scope = scope_handle; + + if type_var > 0 { + add_child(checker, handle, type_var); + } + } + } + } + + pop_scope(checker); + + return handle; +} + +declare_struct :: (checker : *Semantic_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 { + name := ifx node.name.count == 0 then "properties" else node.name; + type_var := declare_struct(checker, node, name); + var := h2tv(checker, type_var); + var.typename = name; + var.buffer_index = 0; + return type_var; +} + +declare_meta :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { + name := ifx node.name.count == 0 then "meta" else node.name; + type_var := declare_struct(checker, node, name); + var := h2tv(checker, type_var); + var.typename = name; + var.buffer_index = 0; + return type_var; +} + +get_actual_function_name :: (node : *AST_Node) -> string { + name_to_check := node.name; + if node.vertex_entry_point { + + name_to_check = sprint("%__%", VERTEX_MAIN_FUNCTION_PREFIX, node.name); + } else if node.pixel_entry_point { + name_to_check = sprint("%__%", PIXEL_MAIN_FUNCTION_PREFIX, node.name); + } + return name_to_check; +} + +declare_foreign_function :: (checker : *Semantic_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 { + if !node.foreign_declaration && !can_declare(checker, node.name) { + invalid_symbol_name(checker, node, "function"); + return 0; + } + + variable, handle := new_type_variable(checker); + variable.type = .Function; + variable.kind = .Declaration; + variable.name = node.name; + variable.source_node = node; + variable.builtin = builtin; + node.type_variable = handle; + + name_to_check := get_actual_function_name(node); + + if node.vertex_entry_point { + checker.vertex_entry_point = node; + } + + if node.pixel_entry_point { + checker.pixel_entry_point = node; + } + find_result := find_symbol(checker, name_to_check, checker.current_scope); + + if !find_result { + function : Defined_Symbol; + function.name = name_to_check; + function.source_node = node; + function.type_variable = handle; + + symbol : Defined_Symbol; + symbol.name = name_to_check; + symbol.source_node = node; + symbol.type_variable = 0; + array_reserve(*symbol.functions, 16); + array_add(*symbol.functions, function); + + add_symbol_to_scope(checker, checker.current_scope, name_to_check, symbol); + } else { + //@Note(niels): This is some ugly code, but it's probably fine for now. + for child : node.children { + if child.kind != .FieldList { + continue; + } + + for function : find_result.functions { + func_var := h2tv(checker, function.type_variable); + if func_var.child_count != child.children.count { + continue; + } + + all_same : bool = true; + for i : 0..func_var.child_count - 1 { + arg := func_var.children[i]; + node_child := child.children[it_index]; + arg_type := get_type_from_identifier(checker, checker.current_scope, node_child); + + other_arg := h2tv(checker, arg); + + if arg_type != other_arg.type { + all_same = false; + break; + } else { + if arg_type == .Struct && other_arg.type == .Struct { + if node_child.token.ident_value != other_arg.typename { + all_same = false; + break; + } + } + } + } + + if all_same { + symbol_redeclaration(checker, node, find_result); + return 0; + } else { + function : Defined_Symbol; + function.name = name_to_check; + function.source_node = node; + function.type_variable = handle; + + array_add(*find_result.functions, function); + break; + } + } + + function : Defined_Symbol; + function.name = name_to_check; + function.source_node = node; + function.type_variable = handle; + + array_add(*find_result.functions, function); + } + } + + if !builtin { + scope, scope_handle := push_scope(checker, name_to_check, .Function); + variable.scope = scope_handle; + } + + for child : node.children { + if child.kind == .FieldList { + for field : child.children { + type_var := check_node(checker, field); + if type_var > 0 { + if builtin { + var := h2tv(checker, type_var); + var.builtin = true; + } + add_child(checker, handle, type_var); + } + } + } + } + + if builtin && node.token.ident_value.count > 0 { + return_var, return_handle := new_type_variable(checker); + return_var.type = get_type_from_identifier(checker, checker.current_scope, node, *return_var.typename); + h2tv(checker, handle).return_var = return_handle; + } + + if !builtin { + pop_scope(checker); + } + + return handle; +} + +create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) { + name_to_check := get_actual_function_name(node); + find_result := find_symbol(checker, name_to_check, checker.current_scope); + + if !find_result { + assert(false, "Compiler error. Functions should all be declared at this point in time."); + } + + //@Note(niels): Constraint should be: + // X(X1, ..., Xn) { return E; }: [[X]] = ([[X1]], ..., [[Xn]]) -> [[E]] + // We return the type variable handle for X (the function name) + + // @Incomplete(niels): In this case we will have a list of function overloads + // The list is most often of size 1, but in the case it is > 1 + // we have overloads that we have to match against. + // This means our constraint gets slightly more complicated. + // At this point we could consider cheating and already matching the types + // at this point and finding the correct function variable. + // We can do this because technically we have already declared all functions at this point. + // So we don't have any unresolved types as of this point. + handle := find_result.type_variable; + if node.foreign_declaration { + return; + } + + for function : find_result.functions { + variable := h2tv(checker, function.type_variable); + + assert(variable.scope > 0, "Declared function is missing scope."); + + previous_scope := use_scope(checker, variable.scope); + + constraint : Type_Constraint; + constraint.kind = .Function_Decl; + constraint.function.symbol_variable = function.type_variable; + + for i : 0..variable.child_count - 1 { + arg_var := variable.children[i]; + + if arg_var > 0 { + constraint.function.arguments[constraint.function.argument_count] = arg_var; + constraint.function.argument_count += 1; + } + } + + for child : node.children { + if child.kind == .Block { + for statement : child.children { + if statement.kind == .Return { + result_var := check_node(checker, statement); + if result_var > 0 { + variable.return_var = result_var; + constraint.function.return_variable = variable.return_var; + } + } else { + result_var := check_node(checker, statement); + if result_var > 0 { + stm := h2tv(checker, result_var); + add_child(variable, result_var); + } + } + } + } + } + + if node.token.ident_value.count > 0 && !variable.return_var { + not_all_control_paths_return_value(checker, node); + } + + array_add(*checker.constraints, constraint); + + use_scope(checker, previous_scope); + } +} + +create_literal_constraint :: (checker : *Semantic_Checker, value : int, type_variable : Type_Variable_Handle) { + constraint : Type_Constraint; + constraint.kind = .Int_Literal; + constraint.literal.i = value; + constraint.literal.type_variable = type_variable; + + array_add(*checker.constraints, constraint); +} + +create_literal_constraint :: (checker : *Semantic_Checker, value : float, type_variable : Type_Variable_Handle) -> Type_Constraint_Handle { + constraint : Type_Constraint; + constraint.kind = .Float_Literal; + constraint.literal.f = value; + constraint.literal.type_variable = type_variable; + + array_add(*checker.constraints, constraint); + + return cast(Type_Constraint_Handle)checker.constraints.count; +} + +create_equivalence_constraint :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rhs : Type_Variable_Handle, usage_site : *AST_Node = null) -> Type_Constraint_Handle { + constraint : Type_Constraint; + constraint.kind = .Equivalence; + constraint.equivalence.lhs = lhs; + constraint.equivalence.rhs = rhs; + constraint.usage_site = usage_site; + + array_add(*checker.constraints, constraint); + + return cast(Type_Constraint_Handle)checker.constraints.count; +} + +create_variable :: (checker : *Semantic_Checker, node : *AST_Node, field_parent : *AST_Node = null) -> Type_Variable_Handle { + find_result := find_symbol(checker, node.name, checker.current_scope); + // x : int; + // x.d = 5; + + if find_result { + node.type_variable = find_result.type_variable; + variable := h2tv(checker, find_result.type_variable); + variable.field_parent = field_parent; + + if get_scope(checker, checker.current_scope).kind == .Struct { + variable.scope = checker.current_scope; + } + + if node.children.count > 0 { + if variable.type != .Struct { + field_access_on_primitive_type(checker, node, find_result.type_variable); + return 0; + } else { + struct_symbol := find_symbol(checker, variable.typename, checker.current_scope); + type_variable := h2tv(checker, struct_symbol.type_variable); + + previous_scope := use_scope(checker, type_variable.scope); + child := node.children[0]; + var := find_symbol(checker, child.name, type_variable.scope); + if var == null { + field_not_defined_on_struct(checker, child, struct_symbol); + return 0; + } + access := create_variable(checker, child, node); + use_scope(checker, previous_scope); + return access; + } + } + return find_result.type_variable; + } + + symbol_undeclared(checker, node); + return 0; +} + +can_declare :: (checker : *Semantic_Checker, name : string) -> bool { + max_value := Semantic_Type.Max_Builtin; + + for i : 0..max_value - 1 { + kind := cast(Semantic_Type)i; + if name == Typenames[kind] { + return false; + } + } + return true; +} + +//@Incomplete(niels): Handle meta stuff here +create_field :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { + variable, handle := new_type_variable(checker); + variable.name = node.name; + typename : string; + variable.type = get_type_from_identifier(checker, checker.current_scope, node, *typename); + variable.typename = typename; + variable.source_node = node; + variable.scope = checker.current_scope; + node.type_variable = handle; + + if node.kind != .Unnamed_Field { + if !can_declare(checker, node.name) { + invalid_symbol_name(checker, node, "variable"); + return 0; + } + + find_result := find_symbol(checker, node.name, checker.current_scope); + + if !find_result { + symbol : Defined_Symbol; + symbol.name = node.name; + symbol.source_node = node; + symbol.type_variable = handle; + add_symbol_to_scope(checker, checker.current_scope, node.name, symbol); + } else { + symbol_redeclaration(checker, node, find_result); + return 0; + } + } + + if node.token.ident_value.count > 0 { + variable.type = get_type_from_identifier(checker, checker.current_scope, node); + } + + if node.children.count > 0 { + rhs : Type_Variable_Handle; + assert(node.children.count == 1); + for child : node.children { + rhs = check_node(checker, child); + } + create_equivalence_constraint(checker, handle, rhs, node); + } + + return handle; +} + +create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Variable_Handle) { + find_result := find_symbol(checker, node.name, checker.current_scope); + + if !find_result { + function_undeclared(checker, node); + return; + } + + // @Incomplete(niels): Fix overload resolution. + // Currently we don't have proper resolution. We don't even pick a proper function. + // We need to run through all functions in this find result, and match the arguments. + // If no overload is found, we have to print out all overloads and post mismatched arguments. + // If an overload is found we proceed as usual. + + overload_found := false; + arg_node : *AST_Node = null; + + for *func : find_result.functions { + if overload_found { + break; + } + + function := h2tv(checker, func.type_variable); + + if function.return_var > 0 { + return_var := h2tv(checker, function.return_var); + constrained_var := h2tv(checker, type_var); + constrained_var.type = return_var.type; + constrained_var.typename = return_var.typename; + } + + if node.children.count == 0 && function.child_count == 0 { + overload_found = true; + break; + } + + all_args_match : bool = true; + + for child : node.children { + if child.kind == { + case .ArgList; { + if child.children.count != function.child_count { + // mismatched_arguments(checker, node, func, child.children.count, function.child_count); + break; + } + + for arg_child : child.children { + arg_var := check_node(checker, arg_child); + function_param := function.children[it_index]; + + // @Incomplete(nb): Improve the error handling of this constraint. + // The usage site might be the call, but really the usage site + // is the variable, with the call around it. + // We could probably expand source locations to always include the whole line + // That is unlikely to be annoying now that I think about it. + // So maybe we just always do that? Then we always have the complete information + // and the actual token we want to focus on is just the one we have? + // @Update(nb): We actually do this now for a bunch of places, but not all. + // Error reporting in this case is still not great, since it doesn't properly mark the + // faulty variable. + create_equivalence_constraint(checker, arg_var, function_param, arg_child); + if !types_compatible(checker, arg_var, function_param) { + if all_args_match { + arg_node = arg_child; + } + all_args_match = false; + } else { + overload_found = all_args_match; + } + } + } + } + } + } + + if !overload_found { + no_matching_overload_found(checker, node, find_result, arg_node); + } +} + +check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { + if node.kind == { + case .Function; { + create_function_constraint(checker, node); + return 0; + } + case. Field; { + field_var := create_field(checker, node); + return field_var; + } + case .Unnamed_Field; { + field_var := create_field(checker, node); + return field_var; + } + case .Binary; { + lhs_var := check_node(checker, node.children[0]); + if lhs_var == 0 { + return 0; + } + rhs_var := check_node(checker, node.children[1]); + if rhs_var == 0 { + return 0; + } + + variable, handle := new_type_variable(checker); + lhs_type := h2tv(checker, lhs_var); + variable.type = lhs_type.type; + variable.scope = lhs_type.scope; + variable.source_node = node; + node.type_variable = handle; + add_child(variable, lhs_var); + add_child(variable, rhs_var); + + if node.token.kind == { + case .TOKEN_PLUS; #through; + case .TOKEN_MINUS; #through; + case .TOKEN_STAR; #through; + case .TOKEN_SLASH; { + create_equivalence_constraint(checker, rhs_var, lhs_var, node); + + proper_variable, rhs_handle := new_type_variable(checker); + proper_variable.type = h2tv(checker, lhs_var).type; + proper_variable.source_node = h2tv(checker, lhs_var).source_node; + proper_variable.field_parent = h2tv(checker, lhs_var).field_parent; + + create_equivalence_constraint(checker, handle, rhs_handle, node); + } + case .TOKEN_ASSIGN; { + create_equivalence_constraint(checker, lhs_var, rhs_var, node); + } + } + return handle; + } + case .Return; { + return check_node(checker, node.children[0]); + } + case .Variable; { + return create_variable(checker, node); + } + case .Integer; { + type_variable, handle := new_type_variable(checker); + type_variable.type = .Int; + type_variable.source_node = node; + node.type_variable = handle; + type_constraint := create_literal_constraint(checker, node.integer_value, handle); + + return handle; + } + case .Float; { + type_variable, handle := new_type_variable(checker); + type_variable.type = .Float; + type_variable.source_node = node; + node.type_variable = handle; + type_constraint := create_literal_constraint(checker, node.float_value, handle); + + return handle; + } + case .Expression_Statement; { + return check_node(checker, node.children[0]); + } + case .Call; { + type_variable, handle := new_type_variable(checker); + type_variable.type = .Unresolved_Expression; + type_variable.source_node = node; + node.type_variable = handle; + + create_call_constraint(checker, node, handle); + + return handle; + } + } + return 0; +} + +traverse :: (checker : *Semantic_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 == .Meta { + declare_meta(checker, declaration); + } + } + + if checker.result.had_error { + return; + } + + for declaration : declarations { + check_node(checker, declaration); + } +} + +traverse :: (checker : *Semantic_Checker) { + traverse(checker, checker.program_root); +} + +find :: (checker : *Semantic_Checker, root_handle : Type_Variable_Handle) -> Type_Variable_Handle { + assert(root_handle > 0); + root := h2tv(checker, root_handle); + + if root.uf_parent != root_handle { + root.uf_parent = find(checker, root.uf_parent); + } + + return root.uf_parent; +} + +Unification_Result :: enum { + Unification_Success; + Unification_Failure; +} + +types_compatible :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rhs : Type_Variable_Handle) -> bool { + lhs_var := h2tv(checker, lhs); + rhs_var := h2tv(checker, rhs); + + if lhs_var.type == { + case .Int; #through; + case .Half; #through; + case .Float; #through; + case .Double; { + return rhs_var.type == .Int || rhs_var.type == .Half || + rhs_var.type == .Float || rhs_var.type == .Double; + } + case .Struct; { + if rhs_var.type != .Struct { + return false; + } + + lhs_node := lhs_var.source_node; + rhs_node := rhs_var.source_node; + + lhs_struct := find_symbol(checker, lhs_var.typename, xx 1); + rhs_struct := find_symbol(checker, rhs_var.typename, xx 1); + + if !lhs_struct || !rhs_struct { + return false; + } + + if !lhs_struct.type_variable || !rhs_struct.type_variable { + return false; + } + + lhs_struct_var := h2tv(checker, lhs_struct.type_variable); + rhs_struct_var := h2tv(checker, rhs_struct.type_variable); + + if lhs_struct_var.child_count != rhs_struct_var.child_count { + return false; + } + + for i : 0..lhs_struct_var.child_count - 1 { + lhs_child := lhs_struct_var.children[i]; + rhs_child := rhs_struct_var.children[i]; + if !types_compatible(checker, lhs_child, rhs_child) return false; + } + + return true; + } + case .Unresolved_Expression; #through; + case .Unresolved_Variable; { + return true; + } + } + + return false; +} + +union_terms :: (checker : *Semantic_Checker, lhs_handle : Type_Variable_Handle, rhs_handle : Type_Variable_Handle, usage_site : *AST_Node) { + + if !types_compatible(checker, lhs_handle, rhs_handle) { + lhs_var := h2tv(checker, lhs_handle); + rhs_var := h2tv(checker, rhs_handle); + + if usage_site { + type_mismatch(checker, usage_site, rhs_var.source_node.parent, rhs_handle, lhs_handle); + } else { + type_mismatch(checker, lhs_var.source_node.parent, rhs_var.source_node.parent, rhs_handle, lhs_handle); + } + + return; + } + + if lhs_handle != rhs_handle { + lhs := h2tv(checker, lhs_handle); + lhs.uf_parent = rhs_handle; + } +} + +unify :: (checker : *Semantic_Checker, lhs_handle : Type_Variable_Handle, rhs_handle : Type_Variable_Handle, usage_site : *AST_Node = null) -> Unification_Result { + rep_lhs := find(checker, lhs_handle); + rep_rhs := find(checker, rhs_handle); + + if rep_lhs != rep_rhs { + lhs := h2tv(checker, rep_lhs); + rhs := h2tv(checker, rep_rhs); + if !is_proper(lhs) && !is_proper(rhs) { + union_terms(checker, rep_lhs, rep_rhs, usage_site); + } else if !is_proper(lhs) && is_proper(rhs) { + union_terms(checker, rep_lhs, rep_rhs, usage_site); + } else if is_proper(lhs) && !is_proper(rhs) { + union_terms(checker, rep_rhs, rep_lhs, usage_site); + } else if is_proper(lhs) && is_proper(rhs) { + union_terms(checker, rep_lhs, rep_rhs, usage_site); + + //@Incomplete(niels): Evaluate sub-terms for functions. + } else { + return .Unification_Failure; + } + } + return .Unification_Success; +} + +union_find :: (checker : *Semantic_Checker) -> bool { + for constraint : checker.constraints { + if constraint.kind == { + case .Int_Literal; { + + } + case .Float_Literal; { + + } + case .Equivalence; { + if !constraint.equivalence.lhs || !constraint.equivalence.rhs { + return false; + } + + handle_lhs := find(checker, constraint.equivalence.lhs); + handle_rhs := find(checker, constraint.equivalence.rhs); + + unification_result := unify(checker, handle_lhs, handle_rhs, constraint.usage_site); + if unification_result == .Unification_Failure { + return false; + } + } + case .Function_Decl; { + + } + } + } + + return true; +} + +add_hlsl_builtins :: (checker : *Semantic_Checker) { + #load "hlsl_builtin.jai"; + + checker.state = .Adding_Builtins; + + lexer : Lexer; + + init_lexer_from_string(*lexer, HLSL_BULTIN); + if lexer.result.had_error { + print("%\n", report_messages(lexer.result.messages)); + return; + } + + lex_result := lex(*lexer,, *temp); + if lex_result.had_error { + print("%\n", report_messages(lex_result.messages)); + return; + } + + parse_state : Parse_State; + init_parse_state(*parse_state, lex_result.tokens, lexer.path, context.allocator); + + parse_result := parse(*parse_state); + if parse_result.had_error { + print("%\n", report_messages(parse_result.messages)); + return; + } + + type_check(checker, parse_result.root); + check_result := checker.result; + if check_result.had_error { + print("%\n", report_messages(check_result.messages)); + return; + } + + for *type_var : check_result.type_variables { + type_var.builtin = true; + } + + checker.state = .Type_Checking; +} + +type_check :: (checker : *Semantic_Checker, root : *AST_Node) { + traverse(checker, root); + + // if checker.result.had_error { + // //@Incomplete(niels): handle error... + // return checker.result; + // } + uf_result := union_find(checker); + + if !uf_result { + //@Incomplete(niels): handle error... + // return result; + } + + for *type_variable : checker.result.type_variables { + if type_variable.type == .Unresolved_Variable { + rep := h2tv(checker, type_variable.uf_parent); + type_variable.type = rep.type; + } + } +} + +check :: (checker : *Semantic_Checker, root : *AST_Node) -> Semantic_Check_Result { + array_reserve(*checker.result.messages, 16); + array_reserve(*checker.constraints, 1024); + add_hlsl_builtins(checker); + + type_check(checker, root); + + return checker.result; +} + +check :: (checker : *Semantic_Checker) -> Semantic_Check_Result { + return check(checker, checker.program_root); +} + +// =========================================================== +// Pretty printing + +pretty_print_children :: (checker : *Semantic_Checker, builder : *String_Builder, type : Type_Variable, indentation : int) { + indent(builder, indentation); + for 0..type.child_count - 1 { + child_handle := type.children[it]; + child := h2tv(checker, child_handle); + // if child.kind != .Function { + // print_to_builder(builder, "% : %", child.name, type_to_string(child)); + // } else { + // pretty_print_function(checker, builder, "", child, 0); + // } + } +} + +type_to_string :: (type_variable : Type_Variable) -> string { + if type_variable.type == { + case .Invalid; + return "{{invalid}}"; + case .Unit; + return "()"; + case .Int; #through; + case .Half; #through; + case .Float; #through; + case .Double; { + return Typenames[type_variable.type]; + } + case .Function; #through; + case .Struct; + return type_variable.typename; + case .Array; + return "array"; + } + return ""; +} + +print_key :: (checker : *Semantic_Checker, builder : *String_Builder, name : string) { + scope := get_current_scope(checker); + target_length := scope.longest_key_length + 1; + missing_padding := target_length - name.count; + str := tprint("[%]", name); + append(builder, str); + for 0..missing_padding - 1 { + append(builder, " "); + } + + append(builder, ": "); +} + +pretty_print_function :: (checker : *Semantic_Checker, builder : *String_Builder, name : string, function : Type_Variable, indentation : int) { + indent(builder, indentation); + print_key(checker, builder, name); + append(builder, "("); + + for child : function.source_node.children { + if child.kind == .FieldList { + for field : child.children { + tv := h2tv(checker, field.type_variable); + if tv.type != .Function { + if tv.builtin { + print_to_builder(builder, "%", tv.name); + } else { + print_to_builder(builder, "% : %", tv.name, type_to_string(tv)); + } + } else { + pretty_print_function(checker, builder, "", tv, 0); + } + + if it_index < child.children.count - 1 { + append(builder, ", "); + } + } + } + } + + if function.return_var > 0 { + print_to_builder(builder, ") -> %\n", type_to_string(h2tv(checker, function.return_var))); + } else { + append(builder, ")\n"); + } +} + +pretty_print_struct :: (checker : *Semantic_Checker, builder : *String_Builder, name : string, struct_type : Type_Variable, indentation : int) { + indent(builder, indentation); + print_key(checker, builder, name); + append(builder, "{"); + + for 0..struct_type.child_count - 1 { + child_handle := struct_type.children[it]; + child := h2tv(checker, child_handle); + print_to_builder(builder, child.name); + append(builder, " : "); + print_to_builder(builder, type_to_string(child)); + + if it < struct_type.child_count - 1 { + append(builder, ", "); + } + } + + pretty_print_children(checker, builder, struct_type, 0); + append(builder, "}\n"); +} + +pretty_print_scope :: (checker : *Semantic_Checker, scope : *Scope, builder : *String_Builder, indentation : int = 0) { + if scope.builtin { + return; + } + + table := scope.table; + + indent(builder, indentation); + append(builder, "scope ("); + if scope.name.count > 0 { + print_to_builder(builder, "%", scope.name); + } else { + append(builder, "global"); + } + append(builder, ") ["); + if scope.table.count > 0 { + append(builder, "\n"); + } + + for table { + key, value := it_index, it; + if value.builtin continue; + + if value.functions.count > 0 { + for func : value.functions { + type_variable := h2tv(checker, func.type_variable); + if type_variable.type == { + case .Function; { + pretty_print_function(checker, builder, key, type_variable, 1); + } + case .Struct; { + if type_variable.typename.count > 0 && type_variable.kind != .Declaration { + indent(builder, indentation + 1); + print_key(checker, builder, key); + print_type_variable(builder, type_variable, checker); + append(builder, "\n"); + // print_to_builder(builder, "%\n", type_variable.typename); + } else { + pretty_print_struct(checker, builder, key, type_variable, 1); + } + } + case; { + indent(builder, indentation + 1); + print_key(checker, builder, key); + print_to_builder(builder, "%\n", type_to_string(type_variable)); + } + } + } + } else { + type_variable := h2tv(checker, value.type_variable); + if type_variable.type == { + case .Function; { + pretty_print_function(checker, builder, key, type_variable, 1); + } + case .Struct; { + if type_variable.typename.count > 0 && type_variable.kind != .Declaration { + indent(builder, indentation + 1); + print_key(checker, builder, key); + print_to_builder(builder, "%\n", type_variable.typename); + } else { + pretty_print_struct(checker, builder, key, type_variable, 1); + } + } + case; { + indent(builder, indentation + 1); + print_key(checker, builder, key); + print_to_builder(builder, "%\n", type_to_string(type_variable)); + } + } + } + + } + + for child : scope.children { + child_scope := *checker.result.scope_stack.stack[child - 1]; + pretty_print_scope(checker, child_scope, builder, indentation + 1); + } + + if scope.table.count > 0 { + indent(builder, indentation); + } + append(builder, "]\n"); +} + +pretty_print_constraint :: (checker : *Semantic_Checker, constraint : Type_Constraint, builder : *String_Builder) { + if constraint.kind == { + case .Int_Literal; { + print_to_builder(builder, "[[%]] = int\n", constraint.literal.i); + } + case .Float_Literal; { + print_to_builder(builder, "[[%]] = float\n", constraint.literal.f); + } + case .Equivalence; { + lhs_var := h2tv(checker, constraint.equivalence.lhs); + rhs_var := h2tv(checker, constraint.equivalence.rhs); + + append(builder, "[["); + print_type_variable(builder, lhs_var, checker); + append(builder, "]] = "); + if rhs_var.source_node { + append(builder, "[["); + } + + print_type_variable(builder, rhs_var, checker); + if rhs_var.source_node { + append(builder, "]]"); + } + append(builder, "\n"); + } + case .Function_Decl; { + sym := h2tv(checker, constraint.function.symbol_variable); + print_to_builder(builder, "[[%]] =", sym.name); + append(builder, " ("); + if constraint.function.argument_count > 0 { + for i : 0..constraint.function.argument_count - 1 { + arg := h2tv(checker, constraint.function.arguments[i]); + print_to_builder(builder, "[[%]]", arg.name); + + if i < constraint.function.argument_count - 1 { + append(builder, ", "); + } + } + } + append(builder, ")"); + + if constraint.function.return_variable > 0 { + return_var := h2tv(checker, constraint.function.return_variable); + + append(builder, " -> "); + append(builder, "[["); + + print_type_variable(builder, return_var, checker); + + append(builder, "]]", ); + append(builder, "\n"); + } else { + append(builder, " -> unit\n"); + } + } + } +} + +print_type_variable :: (builder : *String_Builder, variable : Type_Variable, checker : *Semantic_Checker) { + if variable.builtin { + if variable.type != .Function || variable.type != .Struct { + print_to_builder(builder, "%", type_to_string(variable)); + } else { + print_to_builder(builder, "%", variable.name); + } + } else { + node := variable.source_node; + if node { + if node.kind == { + case .Properties; { + if node.name.count > 0 { + print_to_builder(builder, "% : ", node.name); + } + + append(builder, "properties"); + } + case .Meta; { + append(builder, "meta"); + } + case .Function; #through; + case .Struct; #through; + case .Field; { + if variable.field_parent { + print_to_builder(builder, "%.", variable.field_parent.name); + } + + print_to_builder(builder, "%", node.name); + } + case .Binary; { + left_most := node.children[0]; + + while left_most.kind == .Binary { + left_most = left_most.children[0]; + } + + right_most := node.children[1]; + while right_most.kind == .Binary { + right_most = right_most.children[1]; + } + + source_location : Source_Range; + source_location.begin = left_most.source_location.main_token; + source_location.end = right_most.source_location.main_token; + source_location.main_token = node.source_location.main_token; + + print_from_source_location(builder, source_location); + } + case .Call; { + if variable.return_var { + assert(false); + print_to_builder(builder, "%", variable.typename); + print_type_variable(builder, checker, variable.return_var); + } + + print_to_builder(builder, "%(", node.name); + + + for child : node.children { + if child.kind == .ArgList { + for arg : child.children { + print_type_variable(builder, checker, arg.type_variable); + + if it_index < child.children.count - 1 { + append(builder, ", "); + } + } + } + } + + append(builder, ")"); + } + case; { + print_from_source_location(builder, node.source_location); + } + } + } + } +} + +print_type_variable :: (builder : *String_Builder, checker : *Semantic_Checker, handle : Type_Variable_Handle) { + variable := h2tv(checker, handle); + print_type_variable(builder, variable, checker); +} + +pretty_print_symbol_table :: (checker : *Semantic_Checker, allocator : Allocator) -> string { + builder : String_Builder; + init_string_builder(*builder,, allocator); + + pretty_print_scope(checker, *checker.result.scope_stack.stack[0], *builder); + + return builder_to_string(*builder,, allocator); +} + +pretty_print_type_variable :: (checker : *Semantic_Checker, type_variable : *Type_Variable, builder : *String_Builder) { + rep := type_variable.uf_parent; + if type_variable.name.count > 0 { + append(builder, "[["); + print_type_variable(builder, type_variable, checker); + append(builder, "]] = "); + rep_var := h2tv(checker, rep); + if is_proper(type_variable) { + print_to_builder(builder, proper_type_to_string(checker, type_variable, temp)); + } else if type_variable.type == .Struct { + if type_variable.kind == .Declaration { + append(builder, "{"); + + for 0..type_variable.child_count - 1 { + child_handle := type_variable.children[it]; + child := h2tv(checker, child_handle); + print_to_builder(builder, child.name); + append(builder, " : "); + print_to_builder(builder, type_to_string(child)); + + if it < type_variable.child_count - 1 { + append(builder, ", "); + } + } + + append(builder, "}"); + } else if type_variable.typename.count > 0 { + print_to_builder(builder, "%", type_variable.typename); + } + } else { + print_from_source_location(builder, rep_var.source_node.source_location); + } + append(builder, "\n"); + } +} + +pretty_print_type_variables :: (checker : *Semantic_Checker, allocator : Allocator) -> string { + builder : String_Builder; + + init_string_builder(*builder,, allocator); + + for *type_variable : checker.result.type_variables { + if type_variable.builtin continue; + + pretty_print_type_variable(checker, type_variable, *builder); + } + + return builder_to_string(*builder,, allocator); +} + +pretty_print_type_constraints :: (checker : *Semantic_Checker, allocator : Allocator) -> string { + builder : String_Builder; + init_string_builder(*builder,, allocator); + + for *constraint : checker.constraints { + pretty_print_constraint(checker, constraint, *builder); + } + + return builder_to_string(*builder,, allocator); +} diff --git a/Test.jai b/Test.jai new file mode 100644 index 0000000..0adc572 --- /dev/null +++ b/Test.jai @@ -0,0 +1,762 @@ +///////////////////////////////////// +//~ nbr: General improvements +// +// [x] Print out all failed tests in a list at the end +// [ ] Use unix (posix? bash? ascii?) color codes for errors +// [ ] Print golden file as green and new output as red + +#import "Basic"; +#import "File"; +#import "String"; +#import "File_Utilities"; +#import "Print_Color"; + +#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"; + +SHADER_EXTENSION :: "shd"; +SUITE_EXTENSION :: "suite"; + +Stage_Flags :: enum_flags u16 { + Lexer :: 0x1; + Parser :: 0x2; + Semantic_Analysis :: 0x4; + Codegen :: 0x8; + Compile :: 0x10; +} + +Output_Type :: enum_flags u16 { + Golden :: 0x1; + StdOut :: 0x2; +} + +Result_Type :: enum { + File_Read_Failed; + Golden_File_Not_Found; + StdOut; + Golden_Output; + Passed; + Failed; +} + +Result :: struct { + type : Result_Type; + path : string; + stage : Stage_Flags; + + golden_path : string; + info_text : string; +} + +Test_Case :: struct { + path : string; + stage_flags : Stage_Flags; +} + +Test_Suite :: struct { + name : string; + test_cases : [..]Test_Case; + + results : [..]Result; +} + +get_golden_path :: (file_path : string, stage : Stage_Flags, allocator := context.allocator) -> string { + path := parse_path(file_path); + file_without_extension := split(path.words[path.words.count - 1], "."); + + builder : String_Builder; + builder.allocator = temp; + + final_path_length := file_path.count - SHADER_EXTENSION.count + GOLDEN_EXTENSION.count + 1; // +1 for dot + + path.words.count -= 1; + + if stage == { + case .Lexer; { + dir := tprint("%/%", TESTS_FOLDER, LEXER_FOLDER); + make_directory_if_it_does_not_exist(dir); + array_add(*path.words, LEXER_FOLDER); + } + case .Parser; { + dir := tprint("%/%", TESTS_FOLDER, PARSER_FOLDER); + make_directory_if_it_does_not_exist(dir); + array_add(*path.words, PARSER_FOLDER); + } + case .Semantic_Analysis; { + dir := tprint("%/%", TESTS_FOLDER, SEMANTIC_ANALYSIS_FOLDER); + make_directory_if_it_does_not_exist(dir); + array_add(*path.words, SEMANTIC_ANALYSIS_FOLDER); + } + case .Codegen; { + dir := tprint("%/%", TESTS_FOLDER, CODEGEN_FOLDER); + make_directory_if_it_does_not_exist(dir); + array_add(*path.words, CODEGEN_FOLDER); + } + case .Compile; { + dir := tprint("%/%", TESTS_FOLDER, COMPILED_FOLDER); + make_directory_if_it_does_not_exist(dir); + array_add(*path.words, COMPILED_FOLDER); + } + } + + init_string_builder(*builder, file_without_extension.count + GOLDEN_EXTENSION.count + 1); + append(*builder, file_without_extension[0]); + append(*builder, "."); + append(*builder, GOLDEN_EXTENSION); + golden_path := builder_to_string(*builder); + array_add(*path.words, golden_path); + + final_path := path_to_string(path); + + return final_path; +} + +run_lexer_test :: (file_path : string, lexer : *Lexer, output_type : Output_Type = 0) -> Result { + ok := read_input_from_file(lexer, file_path); + + result_data : Result; + result_data.path = file_path; + result_data.stage = .Lexer; + + if !ok { + result_data.type = .File_Read_Failed; + result_data.info_text = tprint("Unable to read file: %\n", file_path); + + return result_data; + } else { + result_text : string; + result := lex(lexer, *temp); + + if result.had_error { + result_data.type = .Failed; + result_text = report_messages(result.messages); + } else { + result_text = pretty_print_tokens(result.tokens, *temp); + } + + if output_type & .StdOut { + result_data.info_text = result_text; + result_data.type = .StdOut; + return result_data; + } + + golden_path := get_golden_path(file_path, .Lexer); + do_golden_comparison(golden_path, result_text, *result_data, output_type); + return result_data; + } +} + +run_parser_test :: (file_path : string, output_type : Output_Type = 0) -> Result, *AST_Node { + lexer : Lexer; + result_data : Result; + result_data.path = file_path; + + ok := read_input_from_file(*lexer, file_path); + if !ok { + log_error("Unable to read file: %\n", file_path); + result_data.type = .File_Read_Failed; + result_data.stage = .Lexer; + return result_data, null; + } + + result := lex(*lexer, *temp); + if result.had_error { + result_data.type = .Passed; + return result_data, null; + } + + result_data =, root := run_parser_test(*lexer, output_type); + + return result_data, root; +} + +do_golden_comparison :: (golden_path : string, comparison_text : string, result_data : *Result, output_type : Output_Type) { + if output_type & .Golden { + // Output the comparison file + write_entire_file(golden_path, comparison_text); + result_data.golden_path = copy_string(golden_path); + result_data.type = .Golden_Output; + return; + } else { + // Do the comparison + if !file_exists(golden_path) { + result_data.info_text = tprint("Golden file % does not exist. Please run with -output-as-golden at least once.\n", golden_path); + result_data.type = .Golden_File_Not_Found; + return; + } + + golden_text, ok := read_entire_file(golden_path); + if !ok { + result_data.info_text = tprint("Unable to open golden file %\n", golden_path); + result_data.type = .Golden_File_Not_Found; + return; + } + + comp := replace(comparison_text, "\r\n", "\n"); + gold := replace(golden_text, "\r\n", "\n"); + result := compare(comp, gold) == 0; + if !result { + result_data.type = .Failed; + result_data.info_text = tprint("Golden file:\n%\n===============\n%", gold, comp); + } else { + result_data.type = .Passed; + } + } +} + +run_parser_test :: (lexer : *Lexer, output_type : Output_Type = 0) -> Result, *AST_Node { + parse_state : Parse_State; + result_data : Result; + result_data.path = lexer.path; + result_data.stage = .Parser; + init_parse_state(*parse_state, lexer.result.tokens, lexer.path, context.allocator); + + result := parse(*parse_state); + result_node : *AST_Node; + result_text : string; + + if result.had_error { + result_data.type = .Failed; + result_text = report_messages(result.messages,, temp); + } else { + result_text = pretty_print_ast(parse_state.result.root, *temp); + result_node = parse_state.result.root; + } + + if output_type & .StdOut { + result_data.info_text = result_text; + result_data.type = .StdOut; + return result_data, result_node; + } + + golden_path := get_golden_path(parse_state.path, .Parser); + do_golden_comparison(golden_path, result_text, *result_data, output_type); + return result_data, result_node; +} + +run_semantic_analysis_test :: (file_path : string, output_type : Output_Type = 0) -> Result, Semantic_Check_Result { + lexer : Lexer; + result_data : Result; + result_data.path = file_path; + + ok := read_input_from_file(*lexer, file_path); + if !ok { + log_error("Unable to read file: %\n", file_path); + result_data.type = .File_Read_Failed; + result_data.stage = .Lexer; + + return result_data, .{}; + } + + lex_result := lex(*lexer, *temp); + if lex_result.had_error { + result_data.type = .Failed; + result_data.stage = .Lexer; + result_data.info_text = report_messages(lex_result.messages); + + if output_type & .StdOut { + result_data.type = .StdOut; + return result_data, .{}; + } + golden_path := get_golden_path(file_path, .Semantic_Analysis); + do_golden_comparison(golden_path, result_data.info_text, *result_data, output_type); + return result_data, .{}; + } + + parse_state : Parse_State; + result_data.stage = .Parser; + init_parse_state(*parse_state, lex_result.tokens, lexer.path, context.allocator); + + parse_result := parse(*parse_state); + if parse_result.had_error { + result_data.type = .Failed; + result_data.info_text = report_messages(parse_result.messages); + + if output_type & .StdOut { + result_data.type = .StdOut; + return result_data, .{}; + } + + golden_path := get_golden_path(file_path, .Semantic_Analysis); + do_golden_comparison(golden_path, result_data.info_text, *result_data, output_type); + return result_data, .{}; + } + + result, check_result := run_semantic_analysis_test(file_path, parse_state.result.root, output_type); + return result, check_result; +} + +run_semantic_analysis_test :: (file_path : string, root : *AST_Node, output_type : Output_Type = 0) -> Result, Semantic_Check_Result { + result_data : Result; + + result_data.path = file_path; + result_data.stage = .Semantic_Analysis; + checker : Semantic_Checker; + init_semantic_checker(*checker, root, file_path); + result_text : string; + + result := check(*checker); + if result.had_error { + result_data.type = .Failed; + result_text = report_messages(checker.result.messages); + } else { + result_text = pretty_print_symbol_table(*checker, temp); + constraints := pretty_print_type_constraints(*checker, temp); + type_vars := pretty_print_type_variables(*checker, temp); + print("Constraints\n%\n", constraints); + print("Solution\n%\n", type_vars); + } + + if output_type & .StdOut { + result_data.info_text = result_text; + result_data.type = .StdOut; + return result_data, .{}; + } + + golden_path := get_golden_path(checker.path, .Semantic_Analysis); + do_golden_comparison(golden_path, result_text, *result_data, output_type); + return result_data, result; +} + +run_codegen_test :: (path : string, root : *AST_Node, check_result : Semantic_Check_Result, output_type : Output_Type = 0) -> Result, Codegen_Result { + + result_data : Result; + result_data.path = path; + result_data.stage = .Codegen; + + state : Codegen_State; + init_codegen_state(*state, root, check_result, .HLSL); + + result_text : string; + + result := codegen(*state); + + if result.had_error { + result_data.type = .Failed; + result_data.info_text = report_messages(result.messages); + return result_data, .{}; + } + + result_text = result.result_text; + + if output_type & .StdOut { + result_data.info_text = result_text; + result_data.type = .StdOut; + return result_data, result; + } + + golden_path := get_golden_path(path, .Codegen); + do_golden_comparison(golden_path, result_text, *result_data, output_type); + return result_data, result; +} + +run_codegen_test :: (path : string, root : *AST_Node, output_type : Output_Type = 0) -> Result, Codegen_Result { + checker : Semantic_Checker; + init_semantic_checker(*checker, root, path); + + result_data : Result; + result_data.path = path; + result_data.stage = .Semantic_Analysis; + + check_result := check(*checker); + if check_result.had_error { + result_data.type = .Failed; + result_data.info_text = report_messages(check_result.messages); + return result_data, .{}; + } + + result, codegen_result := run_codegen_test(path, root, check_result, output_type); + return result, codegen_result; +} + +run_codegen_test :: (path : string, output_type : Output_Type = 0) -> Result, Codegen_Result { + lexer : Lexer; + result_data : Result; + result_data.path = path; + + ok := read_input_from_file(*lexer, path); + if !ok { + log_error("Unable to read file: %\n", path); + result_data.type = .File_Read_Failed; + result_data.stage = .Lexer; + return result_data, .{}; + } + + lex_result := lex(*lexer, *temp); + if lex_result.had_error { + result_data.type = .Failed; + result_data.stage = .Lexer; + return result_data, .{}; + } + + parse_state : Parse_State; + result_data.stage = .Parser; + init_parse_state(*parse_state, lex_result.tokens, lexer.path, context.allocator); + + parse_result := parse(*parse_state); + if parse_result.had_error { + result_data.type = .Failed; + result_data.info_text = pretty_print_ast(parse_result.root, *temp); + return result_data, .{}; + } + + result, codegen_result := run_codegen_test(path, parse_result.root, output_type); + return result, codegen_result; +} + +run_compile_test :: (path : string, output_type : Output_Type = 0) -> Result, Compilation_Result { + compiler : Shader_Compiler; + result : Result; + compilation_result := compile_file(*compiler, path); + if compilation_result.had_error { + result.type = .Failed; + result.info_text = tprint("Failed compiling: %\n", path); + } + + return result, compilation_result; +} + +make_test_case :: (path : string, stage_flags : Stage_Flags, allocator := context.allocator) -> Test_Case { + test_case : Test_Case; + test_case.path = copy_string(path,, allocator); + replace_chars(test_case.path, "\\", #char "/"); + test_case.stage_flags = stage_flags; + + return test_case; +} + +run_test :: (file_path : string, stage_flags : Stage_Flags, results : *[..]Result, output_type : Output_Type = 0) { + lexer : Lexer; + result : Result; + if stage_flags & .Lexer { + result = run_lexer_test(file_path, *lexer, output_type); + record_result(results, result); + } + + root_node : *AST_Node; + if stage_flags & .Parser { + if stage_flags & .Lexer && result.type == .Passed || result.type == .Golden_Output { + result, root_node = run_parser_test(*lexer, output_type); + } else { + result, root_node = run_parser_test(file_path, output_type); + } + record_result(results, result); + } + + check_result : Semantic_Check_Result; + if stage_flags & .Semantic_Analysis { + if stage_flags & .Parser && (result.type == .Passed || result.type == .Golden_Output) { + result, check_result = run_semantic_analysis_test(file_path, root_node, output_type); + } else { + result, check_result = run_semantic_analysis_test(file_path, output_type); + } + record_result(results, result); + } + + if stage_flags & .Codegen { + if stage_flags & .Semantic_Analysis && (result.type == .Passed || result.type == .Golden_Output) { + result = run_codegen_test(file_path, root_node, check_result, output_type); + } else if root_node { + result = run_codegen_test(file_path, root_node, output_type); + } else { + result = run_codegen_test(file_path, output_type); + } + record_result(results, result); + } + + if stage_flags & .Compile { + result = run_compile_test(file_path, output_type); + } +} + +run_test :: (test_case : Test_Case, results : *[..]Result, output_type : Output_Type = 0) { + print("%Running test: %\n", cyan(), test_case.path); + run_test(test_case.path, test_case.stage_flags, results, output_type); +} + +record_result :: (results : *[..]Result, result : Result) { + array_add(results, result); +} + +run_test_suite :: (using suite : *Test_Suite, output_type : Output_Type = 0) { + if suite.name.count > 0 { + print("%Running suite: %\n", green(), suite.name); + print("%", reset_color()); + } + + Fail_Data :: struct { + path : string; + stage : string; + } + + failed_test_paths : [..]Fail_Data; + failed_test_paths.allocator = temp; + + builder : String_Builder; + init_string_builder(*builder,, temp); + + for test_case : test_cases { + run_test(test_case, *suite.results, output_type); + + for < suite.results { + result := suite.results[it_index]; + if compare(result.path, test_case.path) == 0 { + if result.type == { + case .Failed; { + array_add(*failed_test_paths, .{ result.path, stage_to_string(result.stage) }); + } + case .File_Read_Failed; { + array_add(*failed_test_paths, .{ result.path, "file not found" }); + } + case .Golden_File_Not_Found; { + array_add(*failed_test_paths, .{ result.path, tprint("golden file not found for %", stage_to_string(result.stage)) }); + } + } + evaluate_result(result); + } else { + break; + } + } + + print("\n"); + } + print("\n"); + + if output_type == 0 { + if failed_test_paths.count == 0 { + green(*builder); + print_to_builder(*builder, "All % tests passed!\n", test_cases.count); + reset_color(*builder); + } else { + print_to_builder(*builder, "%/% tests passed\n", test_cases.count - failed_test_paths.count, test_cases.count); + red(*builder); + + print_to_builder(*builder, "% failed\n", failed_test_paths.count); + for failed_test : failed_test_paths { + print_to_builder(*builder, "% failed with error: %\n", failed_test.path, failed_test.stage); + } + reset_color(*builder); + } + } + + print("%\n", builder_to_string(*builder)); +} + +read_suite :: (file_path : string, suite : *Test_Suite) -> bool { + bytes, ok := read_entire_file(file_path); + if !ok { + log_error("Unable to read suite file %\n", file_path); + return false; + } + + path := parse_path(file_path); + file_without_extension := split(path.words[path.words.count - 1], "."); + suite.name = copy_string(file_without_extension[0]); + split_lines := split(bytes, "\n"); + + for split_line : split_lines { + line := split(split_line, " "); + if line[0].count == 0 { + continue; + } + + if line[0].data[0] == #char "#" { + continue; + } + + if line.count == 1 { + log_error("Invalid line - % - %\n", it_index + 1, line); + continue; + } + test_case_path := line[0]; + stage_flags : Stage_Flags; + + for i: 0..line.count - 1 { + trimmed := trim(line[i]); + if equal(trimmed, "lex") { + stage_flags |= .Lexer; + } else if equal(trimmed, "parse") { + stage_flags |= .Parser; + } else if equal(trimmed, "semant") { + stage_flags |= .Semantic_Analysis; + } else if equal(trimmed, "codegen") { + stage_flags |= .Codegen; + } else if equal(trimmed, "compile") { + stage_flags |= .Compile; + } + } + + test_case := make_test_case(test_case_path, stage_flags); + array_add(*suite.test_cases, test_case); + } + + return true; +} + +read_test :: () { + +} + +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 .Codegen; return "codegen"; + case .Compile; return "compiled"; + case; return ""; + } +} + +evaluate_result :: (result : Result) { + stage : string = stage_to_string(result.stage); + + if #complete result.type == { + case .File_Read_Failed; { + print("%", red()); + print("% failed with File_Read_Failed\n", result.path); + } + case .Golden_File_Not_Found; { + print("%", red()); + print("% failed with Golden File Not Found for stage %\n", result.path, stage); + } + case .StdOut; { + } + case .Golden_Output; { + print("%", yellow()); + print("% output new golden file at %\n", result.path, result.golden_path); + } + case .Passed; { + print("%", green()); + print("% passed %\n", result.path, stage); + } + case .Failed; { + print("%", red()); + print("% failed %\n", result.path, stage); + } + } + + if result.info_text.count > 0 { + print("%", cyan()); + print("--- Info text ---\n"); + print("%", yellow()); + print("%\n", result.info_text); + } + + print("%", reset_color()); +} + +main :: () { + lexer : Lexer; + + args := get_command_line_arguments(); + + suites : [..]Test_Suite; + output_type : Output_Type = 0; + + Argument_Parse_State :: enum { + None; + Run_Suite; + Run_Test; + } + + arg_parse_state : Argument_Parse_State; + current_suite : *Test_Suite; + + path : string; + + for i: 1..args.count - 1 { + arg := args[i]; + if arg == "-output-as-golden" { + output_type |= .Golden; + continue; + } else if arg == "-output" { + output_type |= .StdOut; + continue; + } + + if arg_parse_state == { + case .Run_Suite; { + if arg == "-output-as-golden" { + output_type |= .Golden; + } else if arg == "-output" { + output_type |= .StdOut; + } else { + print("%Unknown argument %\n", red(), arg); + } + } + case .Run_Test; { + cases := current_suite.test_cases.count; + if arg == "-lex" { + 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 == "-codegen" { + current_suite.test_cases[cases - 1].stage_flags |= .Codegen; + } else if arg == "-compile" { + current_suite.test_cases[cases - 1].stage_flags |= .Compile; + } else if contains(arg, ".") { + split_path := split(arg, "."); + extension := split_path[1]; + if extension == SHADER_EXTENSION { + path := copy_string(arg); + test_case := make_test_case(path, 0); + array_add(*current_suite.test_cases, test_case); + } + } else { + print("%Unknown argument %\n", red, arg); + } + } + case .None; { + if contains(arg, ".") { + split_path := split(arg, "."); + extension := split_path[1]; + + if extension == SHADER_EXTENSION { + if arg_parse_state == .Run_Suite { + log_error("Unable to run a test while already running suite."); + continue; + } + + if !current_suite { + suite : Test_Suite; + array_add(*suites, suite); + current_suite = *suites[0]; + } + + arg_parse_state = .Run_Test; + path := copy_string(arg); + test_case := make_test_case(path, 0); + array_add(*current_suite.test_cases, test_case); + } else if extension == SUITE_EXTENSION { + if arg_parse_state == .Run_Test { + log_error("Unable to run a suite while already running test."); + continue; + } + + arg_parse_state = .Run_Suite; + path := copy_string(arg); + + suite : Test_Suite; + read_suite(path, *suite); + array_add(*suites, suite); + current_suite = *suites[0]; + } + } + } + } + } + + for suite : suites { + run_test_suite(*suite, output_type); + } +} diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..9ab76cf --- /dev/null +++ b/build.bat @@ -0,0 +1,3 @@ +@echo off + +jai Test.jai diff --git a/example.shd b/example.shd new file mode 100644 index 0000000..d753ce2 --- /dev/null +++ b/example.shd @@ -0,0 +1,29 @@ +property { + mix_amount : float; + projection : float4x4; @camera_projection + view : float4x4; @camera_view +} + +PSInput :: struct { + position : @position + normal : @normal + light_view_position : @extra // TEXCOORD3? + frag_pos : @extra // TEXCOORD4? +} + +PSOutput :: struct { + color : float4; @target0; + emission : float4; @target1; +} + +vertex main :: (position : float3 @position, uv : float2 @uv, normal : float3 @normal) -> PSInput { + ps_input : PSInput; + + return ps_input; +} + +pixel main :: (input : PSInput) -> float4 { + ps_out : PSOutput; + + return ps_out; +} \ No newline at end of file diff --git a/hlsl_builtin.jai b/hlsl_builtin.jai new file mode 100644 index 0000000..603ca9a --- /dev/null +++ b/hlsl_builtin.jai @@ -0,0 +1,252 @@ +HLSL_BULTIN :: #string DONE + +float2 :: struct { + x : float; + y : float; +} + +float3 :: struct { + x : float; + y : float; + z : float; +} + +float4 :: struct { + x : float; + y : float; + z : float; + w : float; +} + +float4x4 :: struct { + m11 : float; + m12 : float; + m13 : float; + m14 : float; + m21 : float; + m22 : float; + m23 : float; + m24 : float; + m31 : float; + m32 : float; + m33 : float; + m34 : float; + m41 : float; + m42 : float; + m43 : float; + m44 : float; +} + +int2 :: struct { + x : int; + y : int; +} + +int3 :: struct { + x : int; + y : int; + z : int; +} + +int4 :: struct { + x : int; + y : int; + z : int; + w : int; +} + +int4x4 :: struct { + m11 : int; + m12 : int; + m13 : int; + m14 : int; + m21 : int; + m22 : int; + m23 : int; + m24 : int; + m31 : int; + m32 : int; + m33 : int; + m34 : int; + m41 : int; + m42 : int; + m43 : int; + m44 : int; +} + +//~ nbr: Constructors + #foreign float2 :: (float, float) -> float2; + #foreign float3 :: (float, float, float) -> float3; + #foreign float4 :: (float, float, float, float) -> float4; + +//~ nbr: Vectors + #foreign cross :: (float3, float3) -> float3; + #foreign distance :: (float2, float2) -> float; + #foreign distance :: (float3, float3) -> float; + #foreign distance :: (float4, float4) -> float; + + #foreign dot :: (float2, float2) -> float; + #foreign dot :: (float3, float3) -> float; + #foreign dot :: (float4, float4) -> float; + + #foreign normalize :: (float2) -> float2; + #foreign normalize :: (float3) -> float3; + #foreign normalize :: (float4) -> float4; + + #foreign transpose :: (float4x4) -> float4x4; + +//~ nbr: Multiplies + #foreign mul :: (float2, float2) -> float2; + #foreign mul :: (float3, float3) -> float3; + #foreign mul :: (float4, float4) -> float4; + #foreign mul :: (float4x4, float4x4) -> float4x4; + +//~ nbr: General + #foreign abs :: (float) -> float; + #foreign abs :: (float2) -> float2; + #foreign abs :: (float3) -> float3; + #foreign abs :: (float4) -> float4; + #foreign abs :: (float4x4) -> float4x4; + + #foreign min :: (float) -> float; + #foreign min :: (float2) -> float2; + #foreign min :: (float3) -> float3; + #foreign min :: (float4) -> float4; + #foreign min :: (float4x4) -> float4x4; + + #foreign max :: (float) -> float; + #foreign max :: (float2) -> float2; + #foreign max :: (float3) -> float3; + #foreign max :: (float4) -> float4; + #foreign max :: (float4x4) -> float4x4; + + #foreign ceil :: (float) -> float; + #foreign ceil :: (float2) -> float2; + #foreign ceil :: (float3) -> float3; + #foreign ceil :: (float4) -> float4; + #foreign ceil :: (float4x4) -> float4x4; + + #foreign floor :: (float) -> float; + #foreign floor :: (float2) -> float2; + #foreign floor :: (float3) -> float3; + #foreign floor :: (float4) -> float4; + #foreign floor :: (float4x4) -> float4x4; + + #foreign round :: (float) -> float; + #foreign round :: (float2) -> float2; + #foreign round :: (float3) -> float3; + #foreign round :: (float4) -> float4; + #foreign round :: (float4x4) -> float4x4; + + #foreign clamp :: (float, float, float) -> float; + #foreign clamp :: (float2, float2, float2) -> float2; + #foreign clamp :: (float3, float3, float3) -> float3; + #foreign clamp :: (float4, float4, float4) -> float4; + #foreign clamp :: (float4x4, float4x4, float4x4) -> float4x4; + + #foreign log :: (float) -> float; + #foreign log :: (float2) -> float2; + #foreign log :: (float3) -> float3; + #foreign log :: (float4) -> float4; + #foreign log :: (float4x4) -> float4x4; + + #foreign log2 :: (float) -> float; + #foreign log2 :: (float2) -> float2; + #foreign log2 :: (float3) -> float3; + #foreign log2 :: (float4) -> float4; + #foreign log2 :: (float4x4) -> float4x4; + + #foreign log10 :: (float) -> float; + #foreign log10 :: (float2) -> float2; + #foreign log10 :: (float3) -> float3; + #foreign log10 :: (float4) -> float4; + #foreign log10 :: (float4x4) -> float4x4; + + #foreign pow :: (float, float, float) -> float; + #foreign pow :: (float2, float2, float2) -> float2; + #foreign pow :: (float3, float3, float3) -> float3; + #foreign pow :: (float4, float4, float4) -> float4; + #foreign pow :: (float4x4, float4x4, float4x4) -> float4x4; + + #foreign smoothstep :: (float, float, float) -> float; + #foreign smoothstep :: (float2, float2, float2) -> float2; + #foreign smoothstep :: (float3, float3, float3) -> float3; + #foreign smoothstep :: (float4, float4, float4) -> float4; + #foreign smoothstep :: (float4x4, float4x4, float4x4) -> float4x4; + + #foreign step :: (float, float) -> float; + #foreign step :: (float2, float2) -> float2; + #foreign step :: (float3, float3) -> float3; + #foreign step :: (float4, float4) -> float4; + #foreign step :: (float4x4, float4x4) -> float4x4; + + #foreign sqrt :: (float) -> float; + #foreign sqrt :: (float2) -> float2; + #foreign sqrt :: (float3) -> float3; + #foreign sqrt :: (float4) -> float4; + #foreign sqrt :: (float4x4) -> float4x4; + + + +//~ nbr: Trigonometry + #foreign cos :: (float) -> float; + #foreign cos :: (float2) -> float2; + #foreign cos :: (float3) -> float3; + #foreign cos :: (float4) -> float4; + #foreign cos :: (float4x4) -> float4x4; + + #foreign cosh :: (float) -> float; + #foreign cosh :: (float2) -> float2; + #foreign cosh :: (float3) -> float3; + #foreign cosh :: (float4) -> float4; + #foreign cosh :: (float4x4) -> float4x4; + + #foreign acos :: (float) -> float; + #foreign acos :: (float2) -> float2; + #foreign acos :: (float3) -> float3; + #foreign acos :: (float4) -> float4; + #foreign acos :: (float4x4) -> float4x4; + + #foreign sin :: (float) -> float; + #foreign sin :: (float2) -> float2; + #foreign sin :: (float3) -> float3; + #foreign sin :: (float4) -> float4; + #foreign sin :: (float4x4) -> float4x4; + + #foreign sinh :: (float) -> float; + #foreign sinh :: (float2) -> float2; + #foreign sinh :: (float3) -> float3; + #foreign sinh :: (float4) -> float4; + #foreign sinh :: (float4x4) -> float4x4; + + #foreign asin :: (float) -> float; + #foreign asin :: (float2) -> float2; + #foreign asin :: (float3) -> float3; + #foreign asin :: (float4) -> float4; + #foreign asin :: (float4x4) -> float4x4; + + #foreign tan :: (float) -> float; + #foreign tan :: (float2) -> float2; + #foreign tan :: (float3) -> float3; + #foreign tan :: (float4) -> float4; + #foreign tan :: (float4x4) -> float4x4; + + #foreign tanh :: (float) -> float; + #foreign tanh :: (float2) -> float2; + #foreign tanh :: (float3) -> float3; + #foreign tanh :: (float4) -> float4; + #foreign tanh :: (float4x4) -> float4x4; + + #foreign atan :: (float) -> float; + #foreign atan :: (float2) -> float2; + #foreign atan :: (float3) -> float3; + #foreign atan :: (float4) -> float4; + #foreign atan :: (float4x4) -> float4x4; + + #foreign atan2 :: (float, float) -> float; + #foreign atan2 :: (float2, float2) -> float2; + #foreign atan2 :: (float3, float3) -> float3; + #foreign atan2 :: (float4, float4) -> float4; +#foreign atan2 :: (float4x4, float4x4) -> float4x4; + +DONE diff --git a/module.jai b/module.jai new file mode 100644 index 0000000..ed632e2 --- /dev/null +++ b/module.jai @@ -0,0 +1,408 @@ +#load "Lexing.jai"; +#load "Error.jai"; +#load "Parsing.jai"; +#load "Semantic_Analysis.jai"; +#load "Codegen.jai"; + + +add_define :: (env : *Environment, key : string) { + for define : env.defines { + if define == key { + return; + } + } + + array_add(*env.defines, key); +} + +remove_define :: (env : *Environment, key : string) { + for define : env.defines { + if define == key { + env.defines[it_index] = env.defines[env.defines.count - 1]; + } + } +} + +Environment :: struct { + defines : [..]string; +} + +Shader_Compiler :: struct { + environment : Environment; +} + +Field_Kind :: enum { + Int :: 0; + Half :: 1; + Float :: 2; + Double :: 3; + Texture2D :: 8; + Sampler :: 9; + + Function; + Struct; + Array; +} + +Field_Type :: struct { + kind : Field_Kind; + + name : string; //@Note(niels): for structs + + children : [..]Field; +} + +Hint_Kind :: enum { + None; + + Position; + Target; + + Custom; +} + +Field_Hint :: struct { + kind : Hint_Kind; + + target_index : int; + custom_hint_name : string; +} + +Field :: struct { + name : string; + + type : Field_Type; + hints : [..]Field_Hint; +} + +Entry_Point :: struct { + name : string; + + function_input : [..]Field; + return_value : Field; +} + +Shader_Variant :: struct { + text : string; + + vertex_entry_point : struct { + name : string; + + input : [..]Field; + } + + pixel_entry_point : struct { + name : string; + + return_value : Field; + } +} + +Property_Field :: struct { + base_field : Field; + + // @Incomplete(nb): Editor information, min max, etc. + // This should also be compiled out for ship +} + +Properties :: struct { + fields : [..]Property_Field; + + buffer_index : u32; +} + +Shader_Variant_Collection :: struct { + properties : Properties; + + variants : [..]Shader_Variant; +} + +Compilation_Result :: struct { + messages : [..]Compiler_Message; + + had_error : bool; + + collection : Shader_Variant_Collection; +} + +pretty_print_field :: (field : *Field) -> string { + builder : String_Builder; + init_string_builder(*builder,, temp); + + pretty_print_field(*builder, field); + + return builder_to_string(*builder); +} + +Min_Field_Name :: 10; + +pretty_print_field :: (builder : *String_Builder, field : *Field) { + if field.name.count > 0 { + print_to_builder(builder, "% ", field.name); + append(builder, "- "); + } else { + append(builder, "return - "); + } + + type := field.type; + + if type.kind == { + case .Int; { + append(builder, "int"); + } + case .Half; { + append(builder, "half"); + } + case .Float; { + append(builder, "float"); + } + case .Double; { + append(builder, "double"); + } + case .Texture2D; { + append(builder, "texture2D"); + } + case .Sampler; { + append(builder, "sampler"); + } + case .Struct; { + print_to_builder(builder, "struct : % {", type.name); + + for *child : type.children { + pretty_print_field(builder, child); + if it_index < type.children.count - 1 { + append(builder, " "); + } + } + + append(builder, "} "); + } + case .Array; { + + } + } + + for hint : field.hints { + if hint.kind == { + case .Position; { + append(builder, "(@position)"); + } + case .Target; { + print_to_builder(builder, "(@target%)", hint.target_index); + } + case .Custom; { + print_to_builder(builder, "(@%)", hint.custom_hint_name); + } + } + + if it_index != field.hints.count - 1 { + append(builder, ", "); + } + } +} + +type_variable_to_field :: (checker : *Semantic_Checker, variable : Type_Variable_Handle) -> Field { + return type_variable_to_field(checker, h2tv(checker, variable)); +} + +type_variable_to_field :: (checker : *Semantic_Checker, variable : *Type_Variable) -> Field { + field : Field; + + field.name = variable.name; + + type : Field_Type; + + if variable.type == { + case .Int; { + type.kind = Field_Kind.Int; + } + case .Half; { + type.kind = Field_Kind.Half; + } + case .Float; { + type.kind = Field_Kind.Float; + } + case .Double; { + type.kind = Field_Kind.Double; + } + case .Texture2D; { + type.kind = Field_Kind.Texture2D; + } + case .Sampler; { + type.kind = Field_Kind.Sampler; + } + case .Struct; { + type.kind = Field_Kind.Struct; + + find_result := find_symbol(checker, variable.typename, xx 1); + assert(find_result != null, "Internal compiler error\n"); + + type_var := h2tv(checker, find_result.type_variable); + + for i : 0..type_var.child_count - 1 { + child := type_var.children[i]; + child_field := type_variable_to_field(checker, h2tv(checker, child)); + array_add(*type.children, child_field); + } + + type.name = variable.typename; + } + } + + for hint : 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; + } + field_hint.kind = .Target; + } else { + // @Incomplete(nb): custo hints + } + array_add(*field.hints, field_hint); + } + + field.type = type; + + return field; +} + +compile_file :: (compiler : *Shader_Compiler, path : string) -> Compilation_Result { + result : Compilation_Result; + + lexer : Lexer; + + init_lexer_from_file(*lexer, path); + if lexer.result.had_error { + copy_messages(lexer.result.messages, *result.messages); + result.had_error = true; + return result; + } + + lex_result := lex(*lexer,, *temp); + if lex_result.had_error { + copy_messages(lex_result.messages, *result.messages); + result.had_error = true; + return result; + } + + parse_state : Parse_State; + init_parse_state(*parse_state, lex_result.tokens, lexer.path, context.allocator); + + parse_result := parse(*parse_state); + if parse_result.had_error { + copy_messages(parse_result.messages, *result.messages); + result.had_error = true; + return result; + } + + checker : Semantic_Checker; + init_semantic_checker(*checker, parse_result.root, path); + + check_result := check(*checker); + if check_result.had_error { + copy_messages(check_result.messages, *result.messages); + result.had_error = true; + return result; + } + + state : Codegen_State; + init_codegen_state(*state, parse_result.root, check_result, .HLSL); + + result_text : string; + + codegen_result := codegen(*state); + if codegen_result.had_error { + copy_messages(codegen_result.messages, *result.messages); + result.had_error = true; + + return result; + } + + // @Incomplete(nb): Assumes only a single variant for now + + variant : Shader_Variant; + variant.text = codegen_result.result_text; + + if checker.vertex_entry_point { + variant.vertex_entry_point.name = checker.vertex_entry_point.name; + + type_variable := h2tv(*checker, checker.vertex_entry_point.type_variable); + assert(type_variable.type == .Function); + + node := type_variable.source_node; + if node.children.count > 0 { + if node.children[0].kind == .FieldList { + field_list := node.children[0]; + for child : field_list.children { + tv := h2tv(*checker, child.type_variable); + field := type_variable_to_field(*checker, tv); + print("%\n", pretty_print_field(*field)); + array_add(*variant.vertex_entry_point.input, field); + } + } + } + } + + find_result := find_symbol(*check_result.scope_stack, "properties", xx 1); + if find_result { + property_variable := h2tv(check_result.type_variables, find_result.type_variable); + + for i : 0..property_variable.child_count - 1 { + child := property_variable.children[i]; + field := type_variable_to_field(*checker, h2tv(*checker, child)); + prop_field : Property_Field; + prop_field.base_field = field; + array_add(*result.collection.properties.fields, prop_field); + } + result.collection.properties.buffer_index = property_variable.buffer_index; + } + + if checker.pixel_entry_point { + variant.pixel_entry_point.name = checker.pixel_entry_point.name; + + type_variable := h2tv(*checker, checker.pixel_entry_point.type_variable); + assert(type_variable.type == .Function); + + field := type_variable_to_field(*checker, type_variable.return_var); + 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; + } + field_hint.kind = .Target; + } else { + // @Incomplete(nb): custo hints + } + array_add(*field.hints, field_hint); + } + + variant.pixel_entry_point.return_value = field; + print("%\n", pretty_print_field(*field)); + } + + array_add(*result.collection.variants, variant); + + return result; +} diff --git a/test/all.suite b/test/all.suite new file mode 100644 index 0000000..5c9e248 --- /dev/null +++ b/test/all.suite @@ -0,0 +1,12 @@ +test/assign_arithmetic_expression.shd lex parse +test/empty_vertex_main.shd lex parse +test/empty_vertex_main_with_position_parameter.shd lex parse +test/meta_block.shd lex parse +test/basic_property_and_return_value.shd lex parse +test/function_call_return.shd lex parse +test/struct_field_access_test.shd lex parse +test/pass_and_access_struct_fields_in_functions.shd lex parse +test/field_without_type_specifier.shd lex parse +test/functions_with_same_name.shd lex parse +test/function_with_int_return.shd lex parse +test/type_as_variable_name.shd lex parse \ No newline at end of file diff --git a/test/assign_arithmetic_expression.shd b/test/assign_arithmetic_expression.shd new file mode 100644 index 0000000..2f58d35 --- /dev/null +++ b/test/assign_arithmetic_expression.shd @@ -0,0 +1,3 @@ +vertex main :: () { + x : float = 2.0 + 5.0; +} diff --git a/test/basic_property_and_return_value.shd b/test/basic_property_and_return_value.shd new file mode 100644 index 0000000..3b9be73 --- /dev/null +++ b/test/basic_property_and_return_value.shd @@ -0,0 +1,11 @@ +properties { + color : float4; +} + +vertex main :: (pos : float3 @position) -> float3 @position { + return pos; +} + +pixel main :: () -> float4 @target0 { + return properties.color; +} diff --git a/test/codegen/assign_arithmetic_expression.golden b/test/codegen/assign_arithmetic_expression.golden new file mode 100644 index 0000000..81b0e2f --- /dev/null +++ b/test/codegen/assign_arithmetic_expression.golden @@ -0,0 +1,5 @@ +void vs_main() +{ + float x = 2.0f + 5.0f; +} + diff --git a/test/codegen/basic_property_and_return_value.golden b/test/codegen/basic_property_and_return_value.golden new file mode 100644 index 0000000..7dce171 --- /dev/null +++ b/test/codegen/basic_property_and_return_value.golden @@ -0,0 +1,15 @@ +cbuffer __PROPERTIES : register(b0) +{ + float4 color; +} + +float3 vs_main(float3 pos : POSITION) : SV_POSITION +{ + return pos; +} + +float4 ps_main() : SV_TARGET +{ + return color; +} + diff --git a/test/codegen/complicated_computation.golden b/test/codegen/complicated_computation.golden new file mode 100644 index 0000000..964ff54 --- /dev/null +++ b/test/codegen/complicated_computation.golden @@ -0,0 +1,7 @@ +void vs_main() +{ + float x = 5.0f; + float y = 3000.0f; + float z = y * y + x; +} + diff --git a/test/codegen/empty_struct.golden b/test/codegen/empty_struct.golden new file mode 100644 index 0000000..24d298a --- /dev/null +++ b/test/codegen/empty_struct.golden @@ -0,0 +1,4 @@ +struct Foo; + +struct Foo {} + diff --git a/test/codegen/empty_vertex_main.golden b/test/codegen/empty_vertex_main.golden new file mode 100644 index 0000000..3385d47 --- /dev/null +++ b/test/codegen/empty_vertex_main.golden @@ -0,0 +1,4 @@ +void vs_main() +{ +} + diff --git a/test/codegen/empty_vertex_main_with_position_parameter.golden b/test/codegen/empty_vertex_main_with_position_parameter.golden new file mode 100644 index 0000000..9a84e84 --- /dev/null +++ b/test/codegen/empty_vertex_main_with_position_parameter.golden @@ -0,0 +1,5 @@ +float3 vs_main(float3 pos : POSITION) +{ + return pos; +} + diff --git a/test/codegen/field_assignment.golden b/test/codegen/field_assignment.golden new file mode 100644 index 0000000..4cad7a0 --- /dev/null +++ b/test/codegen/field_assignment.golden @@ -0,0 +1,7 @@ +float4 vs_main(float4 pos : POSITION) : SV_POSITION +{ + float x = 5.0f; + x = 7.0f; + return pos; +} + diff --git a/test/codegen/function_call.golden b/test/codegen/function_call.golden new file mode 100644 index 0000000..d4c18a6 --- /dev/null +++ b/test/codegen/function_call.golden @@ -0,0 +1,12 @@ +int foo(); + +int foo() +{ + return 4; +} + +void vs_main() +{ + foo(); +} + diff --git a/test/codegen/function_call_out_of_order_declaration.golden b/test/codegen/function_call_out_of_order_declaration.golden new file mode 100644 index 0000000..5e4725d --- /dev/null +++ b/test/codegen/function_call_out_of_order_declaration.golden @@ -0,0 +1,11 @@ +void foo(); + +void vs_main() +{ + foo(); +} + +void foo() +{ +} + diff --git a/test/codegen/function_call_return.golden b/test/codegen/function_call_return.golden new file mode 100644 index 0000000..7799da6 --- /dev/null +++ b/test/codegen/function_call_return.golden @@ -0,0 +1,9 @@ +void vs_main() +{ +} + +float4 ps_main() : SV_TARGET +{ + return float4(1, 1, 1, 1); +} + diff --git a/test/codegen/meta_block.golden b/test/codegen/meta_block.golden new file mode 100644 index 0000000..e8380b3 --- /dev/null +++ b/test/codegen/meta_block.golden @@ -0,0 +1,15 @@ +cbuffer __PROPERTIES : register(b0) +{ + float4 color; +} + +float3 vs_main(float3 pos : POSITION, float2 uv) : SV_POSITION +{ + return pos; +} + +float4 ps_main() : SV_TARGET +{ + return color; +} + diff --git a/test/codegen/multiple_functions.golden b/test/codegen/multiple_functions.golden new file mode 100644 index 0000000..a2a8be4 --- /dev/null +++ b/test/codegen/multiple_functions.golden @@ -0,0 +1,19 @@ +int foo(); +float bar(); + +int foo() +{ + return 5; +} + +float bar() +{ + return 1235.0f * 500; +} + +void vs_main() +{ + int x = foo(); + float y = bar(); +} + diff --git a/test/codegen/multiple_semicolons_everywhere.golden b/test/codegen/multiple_semicolons_everywhere.golden new file mode 100644 index 0000000..3991c4f --- /dev/null +++ b/test/codegen/multiple_semicolons_everywhere.golden @@ -0,0 +1,19 @@ +float4 foo(); + +float3 vs_main(float3 pos : POSITION) : SV_POSITION +{ + return pos; +} + +float4 foo() +{ + return float4(1.0f, 1.0f, 1.0f, 1.0f); +} + +float4 ps_main() : SV_TARGET +{ + float4 y = foo(); + float4 color = y; + return color; +} + diff --git a/test/codegen/pass_and_access_struct_fields_in_functions.golden b/test/codegen/pass_and_access_struct_fields_in_functions.golden new file mode 100644 index 0000000..4bab942 --- /dev/null +++ b/test/codegen/pass_and_access_struct_fields_in_functions.golden @@ -0,0 +1,21 @@ +struct Foo; + +float foo(Foo f); + +struct Foo +{ + float some_data; +} + +float foo(Foo f) +{ + return f.some_data * 2.0f; +} + +void vs_main() +{ + Foo f; + f.some_data = 4.0f; + float d = foo(f); +} + diff --git a/test/codegen/passthrough.golden b/test/codegen/passthrough.golden new file mode 100644 index 0000000..5a7589b --- /dev/null +++ b/test/codegen/passthrough.golden @@ -0,0 +1,10 @@ +float3 vs_main(float3 pos : POSITION) : SV_POSITION +{ + return pos; +} + +float4 ps_main() : SV_TARGET +{ + return float4(1.0f, 1.0f, 1.0f, 1.0f); +} + diff --git a/test/codegen/precedence_test.golden b/test/codegen/precedence_test.golden new file mode 100644 index 0000000..d127b05 --- /dev/null +++ b/test/codegen/precedence_test.golden @@ -0,0 +1,8 @@ +void vs_main() +{ + float x = 2; + float y = 5; + float z = 10; + float w = x * y + y * z - x / y * x; +} + diff --git a/test/codegen/simple_struct_access.golden b/test/codegen/simple_struct_access.golden new file mode 100644 index 0000000..98d6e5f --- /dev/null +++ b/test/codegen/simple_struct_access.golden @@ -0,0 +1,13 @@ +struct Data; + +struct Data +{ + float4 color; +} + +void vs_main() +{ + Data d; + float4 x = d.color; +} + diff --git a/test/codegen/struct_within_struct.golden b/test/codegen/struct_within_struct.golden new file mode 100644 index 0000000..8685c7f --- /dev/null +++ b/test/codegen/struct_within_struct.golden @@ -0,0 +1,20 @@ +struct Foo; +struct Bar; + +struct Foo +{ + float4 color; +} + +struct Bar +{ + Foo t; +} + +void vs_main() +{ + Foo f; + Bar b; + b.t = f; +} + diff --git a/test/codegen/use_builtin_functions.golden b/test/codegen/use_builtin_functions.golden new file mode 100644 index 0000000..fead5e5 --- /dev/null +++ b/test/codegen/use_builtin_functions.golden @@ -0,0 +1,5 @@ +void vs_main() +{ + float4 f = float4(1, 1, 1, 1); +} + diff --git a/test/codegen_all.suite b/test/codegen_all.suite new file mode 100644 index 0000000..b117314 --- /dev/null +++ b/test/codegen_all.suite @@ -0,0 +1,19 @@ +test/assign_arithmetic_expression.shd codegen +test/basic_property_and_return_value.shd codegen +test/complicated_computation.shd codegen +test/empty_struct.shd codegen +test/empty_vertex_main.shd codegen +test/empty_vertex_main_with_position_parameter.shd codegen +test/field_assignment.shd codegen +test/function_call.shd codegen +test/function_call_out_of_order_declaration.shd codegen +test/function_call_return.shd codegen +test/meta_block.shd codegen +test/multiple_functions.shd codegen +test/multiple_semicolons_everywhere.shd codegen +test/pass_and_access_struct_fields_in_functions.shd codegen +test/passthrough.shd codegen +test/property_rename.shd codegen +test/simple_struct_access.shd codegen +test/struct_within_struct.shd codegen +test/use_builtin_functions.shd codegen diff --git a/test/compile_all.suite b/test/compile_all.suite new file mode 100644 index 0000000..e86a0f0 --- /dev/null +++ b/test/compile_all.suite @@ -0,0 +1,20 @@ +test/assign_arithmetic_expression.shd compile +test/basic_property_and_return_value.shd compile +test/complicated_computation.shd compile +test/empty_struct.shd compile +test/empty_vertex_main.shd compile +test/empty_vertex_main_with_position_parameter.shd compile +test/field_assignment.shd compile +test/float_suffix.shd compile +test/function_call.shd compile +test/function_call_out_of_order_declaration.shd compile +test/function_call_return.shd compile +test/functions_with_same_name.shd compile +test/meta_block.shd compile +test/multiple_functions.shd compile +test/multiple_semicolons_everywhere.shd compile +test/pass_and_access_struct_fields_in_functions.shd compile +test/passthrough.shd compile +test/simple_struct_access.shd compile +test/struct_within_struct.shd compile +test/use_builtin_functions.shd compile \ No newline at end of file diff --git a/test/complicated_computation.shd b/test/complicated_computation.shd new file mode 100644 index 0000000..6869d0c --- /dev/null +++ b/test/complicated_computation.shd @@ -0,0 +1,6 @@ +vertex main :: () { + x : float = 5.0; + y : float = 3000.0; + + z : float = y * y + x; +} diff --git a/test/empty_struct.shd b/test/empty_struct.shd new file mode 100644 index 0000000..6f8cdf9 --- /dev/null +++ b/test/empty_struct.shd @@ -0,0 +1,3 @@ +Foo :: struct {} + + diff --git a/test/empty_vertex_main.shd b/test/empty_vertex_main.shd new file mode 100644 index 0000000..21695c3 --- /dev/null +++ b/test/empty_vertex_main.shd @@ -0,0 +1,3 @@ +vertex main :: () { + +} \ No newline at end of file diff --git a/test/empty_vertex_main_with_position_parameter.shd b/test/empty_vertex_main_with_position_parameter.shd new file mode 100644 index 0000000..863b215 --- /dev/null +++ b/test/empty_vertex_main_with_position_parameter.shd @@ -0,0 +1,3 @@ +vertex main :: (pos : float3 @position) -> float3 { + return pos; +} diff --git a/test/field_assignment.shd b/test/field_assignment.shd new file mode 100644 index 0000000..2e493ee --- /dev/null +++ b/test/field_assignment.shd @@ -0,0 +1,6 @@ +vertex main :: (pos : float4 @position) -> float4 @position { + x : float = 5.0; + x = 7.0; + + return pos; +} diff --git a/test/field_without_type_specifier.shd b/test/field_without_type_specifier.shd new file mode 100644 index 0000000..a025c7b --- /dev/null +++ b/test/field_without_type_specifier.shd @@ -0,0 +1,3 @@ +vertex main :: () { + x := 5.0; +} diff --git a/test/float_suffix.shd b/test/float_suffix.shd new file mode 100644 index 0000000..f7fee39 --- /dev/null +++ b/test/float_suffix.shd @@ -0,0 +1,3 @@ +vertex main :: () { + x : float = 2.0f; +} diff --git a/test/function_call.shd b/test/function_call.shd new file mode 100644 index 0000000..bed9e80 --- /dev/null +++ b/test/function_call.shd @@ -0,0 +1,7 @@ +foo :: () -> int { + return 4; +} + +vertex main :: () { + foo(); +} diff --git a/test/function_call_out_of_order_declaration.shd b/test/function_call_out_of_order_declaration.shd new file mode 100644 index 0000000..81237d2 --- /dev/null +++ b/test/function_call_out_of_order_declaration.shd @@ -0,0 +1,7 @@ +vertex main :: () { + foo(); +} + +foo :: () { + +} diff --git a/test/function_call_return.shd b/test/function_call_return.shd new file mode 100644 index 0000000..98ca8cb --- /dev/null +++ b/test/function_call_return.shd @@ -0,0 +1,7 @@ +vertex main :: () { + +} + +pixel main :: () -> float4 @target0 { + return float4(1, 1, 1, 1); +} diff --git a/test/function_with_int_return.shd b/test/function_with_int_return.shd new file mode 100644 index 0000000..45b8d20 --- /dev/null +++ b/test/function_with_int_return.shd @@ -0,0 +1,3 @@ +vertex main :: (pos : float3) -> int { + +} diff --git a/test/functions_with_same_name.shd b/test/functions_with_same_name.shd new file mode 100644 index 0000000..716465b --- /dev/null +++ b/test/functions_with_same_name.shd @@ -0,0 +1,7 @@ +foo :: () {} +foo :: () {} +bar :: () {} + +vertex main :: () { + +} diff --git a/test/lex/assign_arithmetic_expression.golden b/test/lex/assign_arithmetic_expression.golden new file mode 100644 index 0000000..5f52ea0 --- /dev/null +++ b/test/lex/assign_arithmetic_expression.golden @@ -0,0 +1,16 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 5 line = 2 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 32 ; length = 1 line = 2 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 34 ; length = 3 line = 2 ; column = 12 ; value ='2'; } +{kind = TOKEN_PLUS; ; index = 38 ; length = 1 line = 2 ; column = 16 ; value ='+'; } +{kind = TOKEN_FLOATLITERAL; ; index = 40 ; length = 3 line = 2 ; column = 18 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 43 ; length = 1 line = 2 ; column = 21 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 46 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 49 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/basic_property_and_return_value.golden b/test/lex/basic_property_and_return_value.golden new file mode 100644 index 0000000..2e5bc66 --- /dev/null +++ b/test/lex/basic_property_and_return_value.golden @@ -0,0 +1,43 @@ +{kind = TOKEN_PROPERTIES; ; index = 0 ; length = 10 line = 1 ; column = 0 ; value ='properties'; } +{kind = TOKEN_LEFTBRACE; ; index = 11 ; length = 1 line = 1 ; column = 11 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 15 ; length = 5 line = 2 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 21 ; length = 1 line = 2 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 23 ; length = 6 line = 2 ; column = 8 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 29 ; length = 1 line = 2 ; column = 14 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 32 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 37 ; length = 6 line = 5 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 44 ; length = 4 line = 5 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 49 ; length = 2 line = 5 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 52 ; length = 1 line = 5 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 53 ; length = 3 line = 5 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 57 ; length = 1 line = 5 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 59 ; length = 6 line = 5 ; column = 22 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 66 ; length = 1 line = 5 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 67 ; length = 8 line = 5 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 75 ; length = 1 line = 5 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 77 ; length = 2 line = 5 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 80 ; length = 6 line = 5 ; column = 43 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 87 ; length = 1 line = 5 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 88 ; length = 8 line = 5 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 97 ; length = 1 line = 5 ; column = 60 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 103 ; length = 6 line = 6 ; column = 2 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 110 ; length = 3 line = 6 ; column = 9 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 113 ; length = 1 line = 6 ; column = 12 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 116 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 121 ; length = 5 line = 9 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 127 ; length = 4 line = 9 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 132 ; length = 2 line = 9 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 135 ; length = 1 line = 9 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 136 ; length = 1 line = 9 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 138 ; length = 2 line = 9 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 141 ; length = 6 line = 9 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 148 ; length = 1 line = 9 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 149 ; length = 7 line = 9 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 157 ; length = 1 line = 9 ; column = 36 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 163 ; length = 6 line = 10 ; column = 2 ; value ='return'; } +{kind = TOKEN_PROPERTIES; ; index = 170 ; length = 10 line = 10 ; column = 9 ; value ='properties'; } +{kind = TOKEN_DOT; ; index = 180 ; length = 1 line = 10 ; column = 19 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 181 ; length = 5 line = 10 ; column = 20 ; value ='color'; } +{kind = TOKEN_SEMICOLON; ; index = 186 ; length = 1 line = 10 ; column = 25 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 189 ; length = 1 line = 11 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 192 ; length = 0 line = 12 ; column = 0 ; value =''; } diff --git a/test/lex/complicated_computation.golden b/test/lex/complicated_computation.golden new file mode 100644 index 0000000..dcc929a --- /dev/null +++ b/test/lex/complicated_computation.golden @@ -0,0 +1,30 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 5 line = 2 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 32 ; length = 1 line = 2 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 34 ; length = 3 line = 2 ; column = 12 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 37 ; length = 1 line = 2 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 41 ; length = 1 line = 3 ; column = 0 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 43 ; length = 1 line = 3 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 45 ; length = 5 line = 3 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 51 ; length = 1 line = 3 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 53 ; length = 6 line = 3 ; column = 12 ; value ='3000'; } +{kind = TOKEN_SEMICOLON; ; index = 59 ; length = 1 line = 3 ; column = 18 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 65 ; length = 1 line = 5 ; column = 0 ; value ='z'; } +{kind = TOKEN_COLON; ; index = 67 ; length = 1 line = 5 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 69 ; length = 5 line = 5 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 75 ; length = 1 line = 5 ; column = 10 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 77 ; length = 1 line = 5 ; column = 12 ; value ='y'; } +{kind = TOKEN_STAR; ; index = 79 ; length = 1 line = 5 ; column = 14 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 81 ; length = 1 line = 5 ; column = 16 ; value ='y'; } +{kind = TOKEN_PLUS; ; index = 83 ; length = 1 line = 5 ; column = 18 ; value ='+'; } +{kind = TOKEN_IDENTIFIER; ; index = 85 ; length = 1 line = 5 ; column = 20 ; value ='x'; } +{kind = TOKEN_SEMICOLON; ; index = 86 ; length = 1 line = 5 ; column = 21 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 89 ; length = 1 line = 6 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 92 ; length = 0 line = 7 ; column = 0 ; value =''; } diff --git a/test/lex/empty_struct.golden b/test/lex/empty_struct.golden new file mode 100644 index 0000000..009e35d --- /dev/null +++ b/test/lex/empty_struct.golden @@ -0,0 +1,6 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='Foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 7 ; length = 6 line = 1 ; column = 7 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 14 ; length = 1 line = 1 ; column = 14 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 22 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/empty_vertex_main.golden b/test/lex/empty_vertex_main.golden new file mode 100644 index 0000000..399ab87 --- /dev/null +++ b/test/lex/empty_vertex_main.golden @@ -0,0 +1,8 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 23 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 24 ; length = 0 line = 3 ; column = 1 ; value =''; } diff --git a/test/lex/empty_vertex_main_with_position_parameter.golden b/test/lex/empty_vertex_main_with_position_parameter.golden new file mode 100644 index 0000000..48fe23d --- /dev/null +++ b/test/lex/empty_vertex_main_with_position_parameter.golden @@ -0,0 +1,18 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 29 ; length = 1 line = 1 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 8 line = 1 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 38 ; length = 1 line = 1 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 40 ; length = 2 line = 1 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 6 line = 1 ; column = 43 ; value ='float3'; } +{kind = TOKEN_LEFTBRACE; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 54 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 61 ; length = 3 line = 2 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 64 ; length = 1 line = 2 ; column = 10 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 67 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 70 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/field_assignment.golden b/test/lex/field_assignment.golden new file mode 100644 index 0000000..f9fd785 --- /dev/null +++ b/test/lex/field_assignment.golden @@ -0,0 +1,30 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 29 ; length = 1 line = 1 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 8 line = 1 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 38 ; length = 1 line = 1 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 40 ; length = 2 line = 1 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 6 line = 1 ; column = 43 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 8 line = 1 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 60 ; length = 1 line = 1 ; column = 60 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 64 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 66 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 68 ; length = 5 line = 2 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 74 ; length = 1 line = 2 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 76 ; length = 3 line = 2 ; column = 12 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 79 ; length = 1 line = 2 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 83 ; length = 1 line = 3 ; column = 0 ; value ='x'; } +{kind = TOKEN_ASSIGN; ; index = 85 ; length = 1 line = 3 ; column = 2 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 87 ; length = 3 line = 3 ; column = 4 ; value ='7'; } +{kind = TOKEN_SEMICOLON; ; index = 90 ; length = 1 line = 3 ; column = 7 ; value =';'; } +{kind = TOKEN_RETURN; ; index = 96 ; length = 6 line = 5 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 103 ; length = 3 line = 5 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 106 ; length = 1 line = 5 ; column = 10 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 109 ; length = 1 line = 6 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 112 ; length = 0 line = 7 ; column = 0 ; value =''; } diff --git a/test/lex/field_without_type_specifier.golden b/test/lex/field_without_type_specifier.golden new file mode 100644 index 0000000..5584e28 --- /dev/null +++ b/test/lex/field_without_type_specifier.golden @@ -0,0 +1,13 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_ASSIGN; ; index = 25 ; length = 1 line = 2 ; column = 3 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 27 ; length = 3 line = 2 ; column = 5 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 30 ; length = 1 line = 2 ; column = 8 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 33 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 36 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/float_suffix.golden b/test/lex/float_suffix.golden new file mode 100644 index 0000000..b5bf71b --- /dev/null +++ b/test/lex/float_suffix.golden @@ -0,0 +1,4 @@ +test/float_suffix.shd:2,12: error: We don't use 'f' suffixes for floating point values. + x : float = 2.0f + ^^^^ + \ No newline at end of file diff --git a/test/lex/foreign_function.golden b/test/lex/foreign_function.golden new file mode 100644 index 0000000..24bca42 --- /dev/null +++ b/test/lex/foreign_function.golden @@ -0,0 +1,40 @@ +{kind = TOKEN_DIRECTIVE; ; index = 1 ; length = 7 line = 1 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 9 ; length = 6 line = 1 ; column = 8 ; value ='float2'; } +{kind = TOKEN_DOUBLECOLON; ; index = 16 ; length = 2 line = 1 ; column = 15 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 19 ; length = 1 line = 1 ; column = 18 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 20 ; length = 5 line = 1 ; column = 19 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 25 ; length = 1 line = 1 ; column = 24 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 27 ; length = 5 line = 1 ; column = 26 ; value ='float'; } +{kind = TOKEN_RIGHTPAREN; ; index = 32 ; length = 1 line = 1 ; column = 31 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 34 ; length = 2 line = 1 ; column = 33 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 37 ; length = 6 line = 1 ; column = 36 ; value ='float2'; } +{kind = TOKEN_SEMICOLON; ; index = 43 ; length = 1 line = 1 ; column = 42 ; value =';'; } +{kind = TOKEN_DIRECTIVE; ; index = 47 ; length = 7 line = 2 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 55 ; length = 6 line = 2 ; column = 8 ; value ='float3'; } +{kind = TOKEN_DOUBLECOLON; ; index = 62 ; length = 2 line = 2 ; column = 15 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 65 ; length = 1 line = 2 ; column = 18 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 66 ; length = 5 line = 2 ; column = 19 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 71 ; length = 1 line = 2 ; column = 24 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 73 ; length = 5 line = 2 ; column = 26 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 78 ; length = 1 line = 2 ; column = 31 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 80 ; length = 5 line = 2 ; column = 33 ; value ='float'; } +{kind = TOKEN_RIGHTPAREN; ; index = 85 ; length = 1 line = 2 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 87 ; length = 2 line = 2 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 90 ; length = 6 line = 2 ; column = 43 ; value ='float3'; } +{kind = TOKEN_SEMICOLON; ; index = 96 ; length = 1 line = 2 ; column = 49 ; value =';'; } +{kind = TOKEN_DIRECTIVE; ; index = 100 ; length = 7 line = 3 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 108 ; length = 6 line = 3 ; column = 8 ; value ='float4'; } +{kind = TOKEN_DOUBLECOLON; ; index = 115 ; length = 2 line = 3 ; column = 15 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 118 ; length = 1 line = 3 ; column = 18 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 119 ; length = 5 line = 3 ; column = 19 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 124 ; length = 1 line = 3 ; column = 24 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 126 ; length = 5 line = 3 ; column = 26 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 131 ; length = 1 line = 3 ; column = 31 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 133 ; length = 5 line = 3 ; column = 33 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 138 ; length = 1 line = 3 ; column = 38 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 140 ; length = 5 line = 3 ; column = 40 ; value ='float'; } +{kind = TOKEN_RIGHTPAREN; ; index = 145 ; length = 1 line = 3 ; column = 45 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 147 ; length = 2 line = 3 ; column = 47 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 150 ; length = 6 line = 3 ; column = 50 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 156 ; length = 1 line = 3 ; column = 56 ; value =';'; } +{kind = TOKEN_EOF; ; index = 159 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/foreign_overload.golden b/test/lex/foreign_overload.golden new file mode 100644 index 0000000..b07661e --- /dev/null +++ b/test/lex/foreign_overload.golden @@ -0,0 +1,96 @@ +{kind = TOKEN_DIRECTIVE; ; index = 1 ; length = 7 line = 1 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 9 ; length = 3 line = 1 ; column = 8 ; value ='mul'; } +{kind = TOKEN_DOUBLECOLON; ; index = 13 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 17 ; length = 6 line = 1 ; column = 16 ; value ='float2'; } +{kind = TOKEN_COMMA; ; index = 23 ; length = 1 line = 1 ; column = 22 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 25 ; length = 6 line = 1 ; column = 24 ; value ='float2'; } +{kind = TOKEN_RIGHTPAREN; ; index = 31 ; length = 1 line = 1 ; column = 30 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 33 ; length = 2 line = 1 ; column = 32 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 36 ; length = 6 line = 1 ; column = 35 ; value ='float2'; } +{kind = TOKEN_SEMICOLON; ; index = 42 ; length = 1 line = 1 ; column = 41 ; value =';'; } +{kind = TOKEN_DIRECTIVE; ; index = 46 ; length = 7 line = 2 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 54 ; length = 3 line = 2 ; column = 8 ; value ='mul'; } +{kind = TOKEN_DOUBLECOLON; ; index = 58 ; length = 2 line = 2 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 61 ; length = 1 line = 2 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 62 ; length = 6 line = 2 ; column = 16 ; value ='float3'; } +{kind = TOKEN_COMMA; ; index = 68 ; length = 1 line = 2 ; column = 22 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 70 ; length = 6 line = 2 ; column = 24 ; value ='float3'; } +{kind = TOKEN_RIGHTPAREN; ; index = 76 ; length = 1 line = 2 ; column = 30 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 78 ; length = 2 line = 2 ; column = 32 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 81 ; length = 6 line = 2 ; column = 35 ; value ='float3'; } +{kind = TOKEN_SEMICOLON; ; index = 87 ; length = 1 line = 2 ; column = 41 ; value =';'; } +{kind = TOKEN_DIRECTIVE; ; index = 91 ; length = 7 line = 3 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 99 ; length = 3 line = 3 ; column = 8 ; value ='mul'; } +{kind = TOKEN_DOUBLECOLON; ; index = 103 ; length = 2 line = 3 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 106 ; length = 1 line = 3 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 107 ; length = 6 line = 3 ; column = 16 ; value ='float4'; } +{kind = TOKEN_COMMA; ; index = 113 ; length = 1 line = 3 ; column = 22 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 115 ; length = 6 line = 3 ; column = 24 ; value ='float4'; } +{kind = TOKEN_RIGHTPAREN; ; index = 121 ; length = 1 line = 3 ; column = 30 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 123 ; length = 2 line = 3 ; column = 32 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 126 ; length = 6 line = 3 ; column = 35 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 132 ; length = 1 line = 3 ; column = 41 ; value =';'; } +{kind = TOKEN_DIRECTIVE; ; index = 136 ; length = 7 line = 4 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 144 ; length = 3 line = 4 ; column = 8 ; value ='mul'; } +{kind = TOKEN_DOUBLECOLON; ; index = 148 ; length = 2 line = 4 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 151 ; length = 1 line = 4 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 152 ; length = 8 line = 4 ; column = 16 ; value ='float4x4'; } +{kind = TOKEN_COMMA; ; index = 160 ; length = 1 line = 4 ; column = 24 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 162 ; length = 8 line = 4 ; column = 26 ; value ='float4x4'; } +{kind = TOKEN_RIGHTPAREN; ; index = 170 ; length = 1 line = 4 ; column = 34 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 172 ; length = 2 line = 4 ; column = 36 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 175 ; length = 8 line = 4 ; column = 39 ; value ='float4x4'; } +{kind = TOKEN_SEMICOLON; ; index = 183 ; length = 1 line = 4 ; column = 47 ; value =';'; } +{kind = TOKEN_DIRECTIVE; ; index = 189 ; length = 7 line = 6 ; column = 0 ; value ='foreign'; } +{kind = TOKEN_IDENTIFIER; ; index = 197 ; length = 6 line = 6 ; column = 8 ; value ='float2'; } +{kind = TOKEN_DOUBLECOLON; ; index = 204 ; length = 2 line = 6 ; column = 15 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 207 ; length = 1 line = 6 ; column = 18 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 208 ; length = 5 line = 6 ; column = 19 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 213 ; length = 1 line = 6 ; column = 24 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 215 ; length = 5 line = 6 ; column = 26 ; value ='float'; } +{kind = TOKEN_RIGHTPAREN; ; index = 220 ; length = 1 line = 6 ; column = 31 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 222 ; length = 2 line = 6 ; column = 33 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 225 ; length = 6 line = 6 ; column = 36 ; value ='float2'; } +{kind = TOKEN_SEMICOLON; ; index = 231 ; length = 1 line = 6 ; column = 42 ; value =';'; } +{kind = TOKEN_VERTEX; ; index = 236 ; length = 6 line = 8 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 243 ; length = 4 line = 8 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 248 ; length = 2 line = 8 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 251 ; length = 1 line = 8 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 252 ; length = 1 line = 8 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 254 ; length = 1 line = 8 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 258 ; length = 2 line = 9 ; column = 0 ; value ='v1'; } +{kind = TOKEN_COLON; ; index = 261 ; length = 1 line = 9 ; column = 3 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 263 ; length = 6 line = 9 ; column = 5 ; value ='float2'; } +{kind = TOKEN_ASSIGN; ; index = 270 ; length = 1 line = 9 ; column = 12 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 272 ; length = 6 line = 9 ; column = 14 ; value ='float2'; } +{kind = TOKEN_LEFTPAREN; ; index = 278 ; length = 1 line = 9 ; column = 20 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 279 ; length = 3 line = 9 ; column = 21 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 282 ; length = 1 line = 9 ; column = 24 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 284 ; length = 3 line = 9 ; column = 26 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 287 ; length = 1 line = 9 ; column = 29 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 288 ; length = 1 line = 9 ; column = 30 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 292 ; length = 2 line = 10 ; column = 0 ; value ='v2'; } +{kind = TOKEN_COLON; ; index = 295 ; length = 1 line = 10 ; column = 3 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 297 ; length = 6 line = 10 ; column = 5 ; value ='float2'; } +{kind = TOKEN_ASSIGN; ; index = 304 ; length = 1 line = 10 ; column = 12 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 306 ; length = 6 line = 10 ; column = 14 ; value ='float2'; } +{kind = TOKEN_LEFTPAREN; ; index = 312 ; length = 1 line = 10 ; column = 20 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 313 ; length = 3 line = 10 ; column = 21 ; value ='3'; } +{kind = TOKEN_COMMA; ; index = 316 ; length = 1 line = 10 ; column = 24 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 318 ; length = 3 line = 10 ; column = 26 ; value ='3'; } +{kind = TOKEN_RIGHTPAREN; ; index = 321 ; length = 1 line = 10 ; column = 29 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 322 ; length = 1 line = 10 ; column = 30 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 328 ; length = 2 line = 12 ; column = 0 ; value ='v3'; } +{kind = TOKEN_COLON; ; index = 331 ; length = 1 line = 12 ; column = 3 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 333 ; length = 6 line = 12 ; column = 5 ; value ='float2'; } +{kind = TOKEN_ASSIGN; ; index = 340 ; length = 1 line = 12 ; column = 12 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 342 ; length = 3 line = 12 ; column = 14 ; value ='mul'; } +{kind = TOKEN_LEFTPAREN; ; index = 345 ; length = 1 line = 12 ; column = 17 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 346 ; length = 2 line = 12 ; column = 18 ; value ='v1'; } +{kind = TOKEN_COMMA; ; index = 348 ; length = 1 line = 12 ; column = 20 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 350 ; length = 2 line = 12 ; column = 22 ; value ='v2'; } +{kind = TOKEN_RIGHTPAREN; ; index = 352 ; length = 1 line = 12 ; column = 24 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 353 ; length = 1 line = 12 ; column = 25 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 356 ; length = 1 line = 13 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 359 ; length = 0 line = 14 ; column = 0 ; value =''; } diff --git a/test/lex/function_call.golden b/test/lex/function_call.golden new file mode 100644 index 0000000..7035218 --- /dev/null +++ b/test/lex/function_call.golden @@ -0,0 +1,23 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 7 ; length = 1 line = 1 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 8 ; length = 1 line = 1 ; column = 8 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 10 ; length = 2 line = 1 ; column = 10 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 13 ; length = 3 line = 1 ; column = 13 ; value ='int'; } +{kind = TOKEN_LEFTBRACE; ; index = 17 ; length = 1 line = 1 ; column = 17 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 21 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_INTLITERAL; ; index = 28 ; length = 1 line = 2 ; column = 7 ; value ='4'; } +{kind = TOKEN_SEMICOLON; ; index = 29 ; length = 1 line = 2 ; column = 8 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 32 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 37 ; length = 6 line = 5 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 44 ; length = 4 line = 5 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 49 ; length = 2 line = 5 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 52 ; length = 1 line = 5 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 53 ; length = 1 line = 5 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 55 ; length = 1 line = 5 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 59 ; length = 3 line = 6 ; column = 0 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 62 ; length = 1 line = 6 ; column = 3 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 63 ; length = 1 line = 6 ; column = 4 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 64 ; length = 1 line = 6 ; column = 5 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 67 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 70 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/function_call_out_of_order_declaration.golden b/test/lex/function_call_out_of_order_declaration.golden new file mode 100644 index 0000000..0be035c --- /dev/null +++ b/test/lex/function_call_out_of_order_declaration.golden @@ -0,0 +1,18 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 3 line = 2 ; column = 0 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 25 ; length = 1 line = 2 ; column = 3 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 26 ; length = 1 line = 2 ; column = 4 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 27 ; length = 1 line = 2 ; column = 5 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 30 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 35 ; length = 3 line = 5 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 39 ; length = 2 line = 5 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 42 ; length = 1 line = 5 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 43 ; length = 1 line = 5 ; column = 8 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 45 ; length = 1 line = 5 ; column = 10 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 50 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 53 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/function_call_return.golden b/test/lex/function_call_return.golden new file mode 100644 index 0000000..4276da3 --- /dev/null +++ b/test/lex/function_call_return.golden @@ -0,0 +1,31 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 23 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 28 ; length = 5 line = 5 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 34 ; length = 4 line = 5 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 39 ; length = 2 line = 5 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 42 ; length = 1 line = 5 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 43 ; length = 1 line = 5 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 45 ; length = 2 line = 5 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 48 ; length = 6 line = 5 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 55 ; length = 1 line = 5 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 56 ; length = 7 line = 5 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 64 ; length = 1 line = 5 ; column = 36 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 68 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 75 ; length = 6 line = 6 ; column = 7 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 81 ; length = 1 line = 6 ; column = 13 ; value ='('; } +{kind = TOKEN_INTLITERAL; ; index = 82 ; length = 1 line = 6 ; column = 14 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 83 ; length = 1 line = 6 ; column = 15 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 85 ; length = 1 line = 6 ; column = 17 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 86 ; length = 1 line = 6 ; column = 18 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 88 ; length = 1 line = 6 ; column = 20 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 89 ; length = 1 line = 6 ; column = 21 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 91 ; length = 1 line = 6 ; column = 23 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 92 ; length = 1 line = 6 ; column = 24 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 93 ; length = 1 line = 6 ; column = 25 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 96 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 99 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/function_with_int_return.golden b/test/lex/function_with_int_return.golden new file mode 100644 index 0000000..0af12e5 --- /dev/null +++ b/test/lex/function_with_int_return.golden @@ -0,0 +1,13 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float3'; } +{kind = TOKEN_RIGHTPAREN; ; index = 28 ; length = 1 line = 1 ; column = 28 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 30 ; length = 2 line = 1 ; column = 30 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 33 ; length = 3 line = 1 ; column = 33 ; value ='int'; } +{kind = TOKEN_LEFTBRACE; ; index = 37 ; length = 1 line = 1 ; column = 37 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 43 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 46 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/functions_with_same_name.golden b/test/lex/functions_with_same_name.golden new file mode 100644 index 0000000..2d43d18 --- /dev/null +++ b/test/lex/functions_with_same_name.golden @@ -0,0 +1,26 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 7 ; length = 1 line = 1 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 8 ; length = 1 line = 1 ; column = 8 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 10 ; length = 1 line = 1 ; column = 10 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 11 ; length = 1 line = 1 ; column = 11 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 14 ; length = 3 line = 2 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 18 ; length = 2 line = 2 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 21 ; length = 1 line = 2 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 22 ; length = 1 line = 2 ; column = 8 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 24 ; length = 1 line = 2 ; column = 10 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 25 ; length = 1 line = 2 ; column = 11 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 28 ; length = 3 line = 3 ; column = 0 ; value ='bar'; } +{kind = TOKEN_DOUBLECOLON; ; index = 32 ; length = 2 line = 3 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 35 ; length = 1 line = 3 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 36 ; length = 1 line = 3 ; column = 8 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 38 ; length = 1 line = 3 ; column = 10 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 39 ; length = 1 line = 3 ; column = 11 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 44 ; length = 6 line = 5 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 4 line = 5 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 56 ; length = 2 line = 5 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 59 ; length = 1 line = 5 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 60 ; length = 1 line = 5 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 62 ; length = 1 line = 5 ; column = 18 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 67 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 70 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/meta_block.golden b/test/lex/meta_block.golden new file mode 100644 index 0000000..5225800 --- /dev/null +++ b/test/lex/meta_block.golden @@ -0,0 +1,60 @@ +{kind = TOKEN_META; ; index = 0 ; length = 4 line = 1 ; column = 0 ; value ='meta'; } +{kind = TOKEN_LEFTBRACE; ; index = 5 ; length = 1 line = 1 ; column = 5 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 9 ; length = 4 line = 2 ; column = 0 ; value ='name'; } +{kind = TOKEN_COLON; ; index = 18 ; length = 1 line = 2 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 20 ; length = 8 line = 2 ; column = 11 ; value ='LitBasic'; } +{kind = TOKEN_SEMICOLON; ; index = 28 ; length = 1 line = 2 ; column = 19 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 32 ; length = 8 line = 3 ; column = 0 ; value ='category'; } +{kind = TOKEN_COLON; ; index = 41 ; length = 1 line = 3 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 5 line = 3 ; column = 11 ; value ='Scene'; } +{kind = TOKEN_SEMICOLON; ; index = 48 ; length = 1 line = 3 ; column = 16 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 51 ; length = 1 line = 4 ; column = 0 ; value ='}'; } +{kind = TOKEN_PROPERTIES; ; index = 56 ; length = 10 line = 6 ; column = 0 ; value ='properties'; } +{kind = TOKEN_LEFTBRACE; ; index = 67 ; length = 1 line = 6 ; column = 11 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 71 ; length = 5 line = 7 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 77 ; length = 1 line = 7 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 79 ; length = 6 line = 7 ; column = 8 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 85 ; length = 1 line = 7 ; column = 14 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 88 ; length = 1 line = 8 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 93 ; length = 6 line = 10 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 100 ; length = 4 line = 10 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 105 ; length = 2 line = 10 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 108 ; length = 1 line = 10 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 109 ; length = 3 line = 10 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 113 ; length = 1 line = 10 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 115 ; length = 6 line = 10 ; column = 22 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 122 ; length = 1 line = 10 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 123 ; length = 8 line = 10 ; column = 30 ; value ='position'; } +{kind = TOKEN_COMMA; ; index = 131 ; length = 1 line = 10 ; column = 38 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 133 ; length = 2 line = 10 ; column = 40 ; value ='uv'; } +{kind = TOKEN_COLON; ; index = 136 ; length = 1 line = 10 ; column = 43 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 138 ; length = 6 line = 10 ; column = 45 ; value ='float2'; } +{kind = TOKEN_AT; ; index = 145 ; length = 1 line = 10 ; column = 52 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 146 ; length = 2 line = 10 ; column = 53 ; value ='uv'; } +{kind = TOKEN_RIGHTPAREN; ; index = 148 ; length = 1 line = 10 ; column = 55 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 150 ; length = 2 line = 10 ; column = 57 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 153 ; length = 6 line = 10 ; column = 60 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 160 ; length = 1 line = 10 ; column = 67 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 161 ; length = 8 line = 10 ; column = 68 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 170 ; length = 1 line = 10 ; column = 77 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 174 ; length = 6 line = 11 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 181 ; length = 3 line = 11 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 184 ; length = 1 line = 11 ; column = 10 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 187 ; length = 1 line = 12 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 192 ; length = 5 line = 14 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 198 ; length = 4 line = 14 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 203 ; length = 2 line = 14 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 206 ; length = 1 line = 14 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 207 ; length = 1 line = 14 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 209 ; length = 2 line = 14 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 212 ; length = 6 line = 14 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 219 ; length = 1 line = 14 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 220 ; length = 7 line = 14 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 228 ; length = 1 line = 14 ; column = 36 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 232 ; length = 6 line = 15 ; column = 0 ; value ='return'; } +{kind = TOKEN_PROPERTIES; ; index = 239 ; length = 10 line = 15 ; column = 7 ; value ='properties'; } +{kind = TOKEN_DOT; ; index = 249 ; length = 1 line = 15 ; column = 17 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 250 ; length = 5 line = 15 ; column = 18 ; value ='color'; } +{kind = TOKEN_SEMICOLON; ; index = 255 ; length = 1 line = 15 ; column = 23 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 258 ; length = 1 line = 16 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 261 ; length = 0 line = 17 ; column = 0 ; value =''; } diff --git a/test/lex/multiple_functions.golden b/test/lex/multiple_functions.golden new file mode 100644 index 0000000..2d2c8a5 --- /dev/null +++ b/test/lex/multiple_functions.golden @@ -0,0 +1,48 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 7 ; length = 1 line = 1 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 8 ; length = 1 line = 1 ; column = 8 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 10 ; length = 2 line = 1 ; column = 10 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 13 ; length = 3 line = 1 ; column = 13 ; value ='int'; } +{kind = TOKEN_LEFTBRACE; ; index = 17 ; length = 1 line = 1 ; column = 17 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 21 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_INTLITERAL; ; index = 28 ; length = 1 line = 2 ; column = 7 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 29 ; length = 1 line = 2 ; column = 8 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 32 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 37 ; length = 3 line = 5 ; column = 0 ; value ='bar'; } +{kind = TOKEN_DOUBLECOLON; ; index = 41 ; length = 2 line = 5 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 44 ; length = 1 line = 5 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 45 ; length = 1 line = 5 ; column = 8 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 47 ; length = 2 line = 5 ; column = 10 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 50 ; length = 5 line = 5 ; column = 13 ; value ='float'; } +{kind = TOKEN_LEFTBRACE; ; index = 56 ; length = 1 line = 5 ; column = 19 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 60 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_FLOATLITERAL; ; index = 67 ; length = 6 line = 6 ; column = 7 ; value ='1235'; } +{kind = TOKEN_STAR; ; index = 74 ; length = 1 line = 6 ; column = 14 ; value ='*'; } +{kind = TOKEN_INTLITERAL; ; index = 76 ; length = 3 line = 6 ; column = 16 ; value ='500'; } +{kind = TOKEN_SEMICOLON; ; index = 79 ; length = 1 line = 6 ; column = 19 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 82 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 87 ; length = 6 line = 9 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 94 ; length = 4 line = 9 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 99 ; length = 2 line = 9 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 102 ; length = 1 line = 9 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 103 ; length = 1 line = 9 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 105 ; length = 1 line = 9 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 109 ; length = 1 line = 10 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 111 ; length = 1 line = 10 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 113 ; length = 3 line = 10 ; column = 4 ; value ='int'; } +{kind = TOKEN_ASSIGN; ; index = 117 ; length = 1 line = 10 ; column = 8 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 119 ; length = 3 line = 10 ; column = 10 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 122 ; length = 1 line = 10 ; column = 13 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 123 ; length = 1 line = 10 ; column = 14 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 124 ; length = 1 line = 10 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 128 ; length = 1 line = 11 ; column = 0 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 130 ; length = 1 line = 11 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 132 ; length = 5 line = 11 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 138 ; length = 1 line = 11 ; column = 10 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 140 ; length = 3 line = 11 ; column = 12 ; value ='bar'; } +{kind = TOKEN_LEFTPAREN; ; index = 143 ; length = 1 line = 11 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 144 ; length = 1 line = 11 ; column = 16 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 145 ; length = 1 line = 11 ; column = 17 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 148 ; length = 1 line = 12 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 151 ; length = 0 line = 13 ; column = 0 ; value =''; } diff --git a/test/lex/multiple_semicolons_everywhere.golden b/test/lex/multiple_semicolons_everywhere.golden new file mode 100644 index 0000000..0f57e21 --- /dev/null +++ b/test/lex/multiple_semicolons_everywhere.golden @@ -0,0 +1,77 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 29 ; length = 1 line = 1 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 8 line = 1 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 38 ; length = 1 line = 1 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 40 ; length = 2 line = 1 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 6 line = 1 ; column = 43 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 8 line = 1 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 60 ; length = 1 line = 1 ; column = 60 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 64 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 71 ; length = 3 line = 2 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 74 ; length = 1 line = 2 ; column = 10 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 75 ; length = 1 line = 2 ; column = 11 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 76 ; length = 1 line = 2 ; column = 12 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 79 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 84 ; length = 3 line = 5 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 88 ; length = 2 line = 5 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 91 ; length = 1 line = 5 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 92 ; length = 1 line = 5 ; column = 8 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 94 ; length = 2 line = 5 ; column = 10 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 97 ; length = 6 line = 5 ; column = 13 ; value ='float4'; } +{kind = TOKEN_LEFTBRACE; ; index = 104 ; length = 1 line = 5 ; column = 20 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 108 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 115 ; length = 6 line = 6 ; column = 7 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 121 ; length = 1 line = 6 ; column = 13 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 122 ; length = 3 line = 6 ; column = 14 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 125 ; length = 1 line = 6 ; column = 17 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 127 ; length = 3 line = 6 ; column = 19 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 130 ; length = 1 line = 6 ; column = 22 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 132 ; length = 3 line = 6 ; column = 24 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 135 ; length = 1 line = 6 ; column = 27 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 137 ; length = 3 line = 6 ; column = 29 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 140 ; length = 1 line = 6 ; column = 32 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 141 ; length = 1 line = 6 ; column = 33 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 142 ; length = 1 line = 6 ; column = 34 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 143 ; length = 1 line = 6 ; column = 35 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 146 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 151 ; length = 5 line = 9 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 157 ; length = 4 line = 9 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 162 ; length = 2 line = 9 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 165 ; length = 1 line = 9 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 166 ; length = 1 line = 9 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 168 ; length = 2 line = 9 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 171 ; length = 6 line = 9 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 178 ; length = 1 line = 9 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 179 ; length = 7 line = 9 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 187 ; length = 1 line = 9 ; column = 36 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 191 ; length = 1 line = 10 ; column = 0 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 193 ; length = 1 line = 10 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 195 ; length = 6 line = 10 ; column = 4 ; value ='float4'; } +{kind = TOKEN_ASSIGN; ; index = 202 ; length = 1 line = 10 ; column = 11 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 204 ; length = 3 line = 10 ; column = 13 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 207 ; length = 1 line = 10 ; column = 16 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 208 ; length = 1 line = 10 ; column = 17 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 209 ; length = 1 line = 10 ; column = 18 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 210 ; length = 1 line = 10 ; column = 19 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 211 ; length = 1 line = 10 ; column = 20 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 212 ; length = 1 line = 10 ; column = 21 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 216 ; length = 1 line = 11 ; column = 0 ; value =';'; } +{kind = TOKEN_SEMICOLON; ; index = 217 ; length = 1 line = 11 ; column = 1 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 221 ; length = 5 line = 12 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 227 ; length = 1 line = 12 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 229 ; length = 6 line = 12 ; column = 8 ; value ='float4'; } +{kind = TOKEN_ASSIGN; ; index = 236 ; length = 1 line = 12 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 238 ; length = 1 line = 12 ; column = 17 ; value ='y'; } +{kind = TOKEN_SEMICOLON; ; index = 239 ; length = 1 line = 12 ; column = 18 ; value =';'; } +{kind = TOKEN_RETURN; ; index = 243 ; length = 6 line = 13 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 250 ; length = 5 line = 13 ; column = 7 ; value ='color'; } +{kind = TOKEN_SEMICOLON; ; index = 255 ; length = 1 line = 13 ; column = 12 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 258 ; length = 1 line = 14 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 261 ; length = 0 line = 15 ; column = 0 ; value =''; } diff --git a/test/lex/pass_and_access_struct_fields_in_functions.golden b/test/lex/pass_and_access_struct_fields_in_functions.golden new file mode 100644 index 0000000..181080d --- /dev/null +++ b/test/lex/pass_and_access_struct_fields_in_functions.golden @@ -0,0 +1,54 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='Foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 7 ; length = 6 line = 1 ; column = 7 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 14 ; length = 1 line = 1 ; column = 14 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 18 ; length = 9 line = 2 ; column = 0 ; value ='some_data'; } +{kind = TOKEN_COLON; ; index = 28 ; length = 1 line = 2 ; column = 10 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 5 line = 2 ; column = 12 ; value ='float'; } +{kind = TOKEN_SEMICOLON; ; index = 35 ; length = 1 line = 2 ; column = 17 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 38 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 3 line = 5 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 47 ; length = 2 line = 5 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 50 ; length = 1 line = 5 ; column = 7 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 1 line = 5 ; column = 8 ; value ='f'; } +{kind = TOKEN_COLON; ; index = 53 ; length = 1 line = 5 ; column = 10 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 55 ; length = 3 line = 5 ; column = 12 ; value ='Foo'; } +{kind = TOKEN_RIGHTPAREN; ; index = 58 ; length = 1 line = 5 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 60 ; length = 2 line = 5 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 63 ; length = 5 line = 5 ; column = 20 ; value ='float'; } +{kind = TOKEN_LEFTBRACE; ; index = 69 ; length = 1 line = 5 ; column = 26 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 73 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 80 ; length = 1 line = 6 ; column = 7 ; value ='f'; } +{kind = TOKEN_DOT; ; index = 81 ; length = 1 line = 6 ; column = 8 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 82 ; length = 9 line = 6 ; column = 9 ; value ='some_data'; } +{kind = TOKEN_STAR; ; index = 92 ; length = 1 line = 6 ; column = 19 ; value ='*'; } +{kind = TOKEN_FLOATLITERAL; ; index = 94 ; length = 3 line = 6 ; column = 21 ; value ='2'; } +{kind = TOKEN_SEMICOLON; ; index = 97 ; length = 1 line = 6 ; column = 24 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 100 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 105 ; length = 6 line = 9 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 112 ; length = 4 line = 9 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 117 ; length = 2 line = 9 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 120 ; length = 1 line = 9 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 121 ; length = 1 line = 9 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 123 ; length = 1 line = 9 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 127 ; length = 1 line = 10 ; column = 0 ; value ='f'; } +{kind = TOKEN_COLON; ; index = 129 ; length = 1 line = 10 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 131 ; length = 3 line = 10 ; column = 4 ; value ='Foo'; } +{kind = TOKEN_SEMICOLON; ; index = 134 ; length = 1 line = 10 ; column = 7 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 138 ; length = 1 line = 11 ; column = 0 ; value ='f'; } +{kind = TOKEN_DOT; ; index = 139 ; length = 1 line = 11 ; column = 1 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 140 ; length = 9 line = 11 ; column = 2 ; value ='some_data'; } +{kind = TOKEN_ASSIGN; ; index = 150 ; length = 1 line = 11 ; column = 12 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 152 ; length = 3 line = 11 ; column = 14 ; value ='4'; } +{kind = TOKEN_SEMICOLON; ; index = 155 ; length = 1 line = 11 ; column = 17 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 159 ; length = 1 line = 12 ; column = 0 ; value ='d'; } +{kind = TOKEN_COLON; ; index = 161 ; length = 1 line = 12 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 163 ; length = 5 line = 12 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 169 ; length = 1 line = 12 ; column = 10 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 171 ; length = 3 line = 12 ; column = 12 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 174 ; length = 1 line = 12 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 175 ; length = 1 line = 12 ; column = 16 ; value ='f'; } +{kind = TOKEN_RIGHTPAREN; ; index = 176 ; length = 1 line = 12 ; column = 17 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 177 ; length = 1 line = 12 ; column = 18 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 180 ; length = 1 line = 13 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 183 ; length = 0 line = 14 ; column = 0 ; value =''; } diff --git a/test/lex/passthrough.golden b/test/lex/passthrough.golden new file mode 100644 index 0000000..9064cc9 --- /dev/null +++ b/test/lex/passthrough.golden @@ -0,0 +1,43 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 29 ; length = 1 line = 1 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 8 line = 1 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 38 ; length = 1 line = 1 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 40 ; length = 2 line = 1 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 6 line = 1 ; column = 43 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 8 line = 1 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 60 ; length = 1 line = 1 ; column = 60 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 64 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 71 ; length = 3 line = 2 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 74 ; length = 1 line = 2 ; column = 10 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 77 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 82 ; length = 5 line = 5 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 88 ; length = 4 line = 5 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 93 ; length = 2 line = 5 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 96 ; length = 1 line = 5 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 97 ; length = 1 line = 5 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 99 ; length = 2 line = 5 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 102 ; length = 6 line = 5 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 109 ; length = 1 line = 5 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 110 ; length = 7 line = 5 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 118 ; length = 1 line = 5 ; column = 36 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 122 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 129 ; length = 6 line = 6 ; column = 7 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 135 ; length = 1 line = 6 ; column = 13 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 136 ; length = 3 line = 6 ; column = 14 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 139 ; length = 1 line = 6 ; column = 17 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 141 ; length = 3 line = 6 ; column = 19 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 144 ; length = 1 line = 6 ; column = 22 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 146 ; length = 3 line = 6 ; column = 24 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 149 ; length = 1 line = 6 ; column = 27 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 151 ; length = 3 line = 6 ; column = 29 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 154 ; length = 1 line = 6 ; column = 32 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 155 ; length = 1 line = 6 ; column = 33 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 158 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 161 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/precedence_test.golden b/test/lex/precedence_test.golden new file mode 100644 index 0000000..7a8a783 --- /dev/null +++ b/test/lex/precedence_test.golden @@ -0,0 +1,50 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 5 line = 2 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 32 ; length = 1 line = 2 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 34 ; length = 3 line = 2 ; column = 12 ; value ='2'; } +{kind = TOKEN_SEMICOLON; ; index = 37 ; length = 1 line = 2 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 41 ; length = 1 line = 3 ; column = 0 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 43 ; length = 1 line = 3 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 45 ; length = 5 line = 3 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 51 ; length = 1 line = 3 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 53 ; length = 3 line = 3 ; column = 12 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 56 ; length = 1 line = 3 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 60 ; length = 1 line = 4 ; column = 0 ; value ='z'; } +{kind = TOKEN_COLON; ; index = 62 ; length = 1 line = 4 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 64 ; length = 5 line = 4 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 70 ; length = 1 line = 4 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 72 ; length = 4 line = 4 ; column = 12 ; value ='10'; } +{kind = TOKEN_SEMICOLON; ; index = 76 ; length = 1 line = 4 ; column = 16 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 82 ; length = 1 line = 6 ; column = 0 ; value ='w'; } +{kind = TOKEN_COLON; ; index = 84 ; length = 1 line = 6 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 86 ; length = 5 line = 6 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 92 ; length = 1 line = 6 ; column = 10 ; value ='='; } +{kind = TOKEN_LEFTPAREN; ; index = 94 ; length = 1 line = 6 ; column = 12 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 95 ; length = 1 line = 6 ; column = 13 ; value ='x'; } +{kind = TOKEN_STAR; ; index = 97 ; length = 1 line = 6 ; column = 15 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 99 ; length = 1 line = 6 ; column = 17 ; value ='y'; } +{kind = TOKEN_RIGHTPAREN; ; index = 100 ; length = 1 line = 6 ; column = 18 ; value =')'; } +{kind = TOKEN_PLUS; ; index = 102 ; length = 1 line = 6 ; column = 20 ; value ='+'; } +{kind = TOKEN_IDENTIFIER; ; index = 104 ; length = 1 line = 6 ; column = 22 ; value ='y'; } +{kind = TOKEN_STAR; ; index = 106 ; length = 1 line = 6 ; column = 24 ; value ='*'; } +{kind = TOKEN_LEFTPAREN; ; index = 108 ; length = 1 line = 6 ; column = 26 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 109 ; length = 1 line = 6 ; column = 27 ; value ='z'; } +{kind = TOKEN_MINUS; ; index = 111 ; length = 1 line = 6 ; column = 29 ; value ='-'; } +{kind = TOKEN_IDENTIFIER; ; index = 113 ; length = 1 line = 6 ; column = 31 ; value ='x'; } +{kind = TOKEN_SLASH; ; index = 115 ; length = 1 line = 6 ; column = 33 ; value ='/'; } +{kind = TOKEN_LEFTPAREN; ; index = 117 ; length = 1 line = 6 ; column = 35 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 118 ; length = 1 line = 6 ; column = 36 ; value ='y'; } +{kind = TOKEN_STAR; ; index = 120 ; length = 1 line = 6 ; column = 38 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 122 ; length = 1 line = 6 ; column = 40 ; value ='x'; } +{kind = TOKEN_RIGHTPAREN; ; index = 123 ; length = 1 line = 6 ; column = 41 ; value =')'; } +{kind = TOKEN_RIGHTPAREN; ; index = 124 ; length = 1 line = 6 ; column = 42 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 125 ; length = 1 line = 6 ; column = 43 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 128 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 131 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/property_rename.golden b/test/lex/property_rename.golden new file mode 100644 index 0000000..d7ecb8f --- /dev/null +++ b/test/lex/property_rename.golden @@ -0,0 +1,45 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 5 line = 1 ; column = 0 ; value ='props'; } +{kind = TOKEN_COLON; ; index = 6 ; length = 1 line = 1 ; column = 6 ; value =':'; } +{kind = TOKEN_PROPERTIES; ; index = 8 ; length = 10 line = 1 ; column = 8 ; value ='properties'; } +{kind = TOKEN_LEFTBRACE; ; index = 19 ; length = 1 line = 1 ; column = 19 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 23 ; length = 5 line = 2 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 29 ; length = 1 line = 2 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 31 ; length = 6 line = 2 ; column = 8 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 37 ; length = 1 line = 2 ; column = 14 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 40 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 45 ; length = 6 line = 5 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 52 ; length = 4 line = 5 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 57 ; length = 2 line = 5 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 60 ; length = 1 line = 5 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 61 ; length = 3 line = 5 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 65 ; length = 1 line = 5 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 67 ; length = 6 line = 5 ; column = 22 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 74 ; length = 1 line = 5 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 75 ; length = 8 line = 5 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 83 ; length = 1 line = 5 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 85 ; length = 2 line = 5 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 88 ; length = 6 line = 5 ; column = 43 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 95 ; length = 1 line = 5 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 96 ; length = 8 line = 5 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 105 ; length = 1 line = 5 ; column = 60 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 109 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 116 ; length = 3 line = 6 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 119 ; length = 1 line = 6 ; column = 10 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 122 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 127 ; length = 5 line = 9 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 133 ; length = 4 line = 9 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 138 ; length = 2 line = 9 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 141 ; length = 1 line = 9 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 142 ; length = 1 line = 9 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 144 ; length = 2 line = 9 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 147 ; length = 6 line = 9 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 154 ; length = 1 line = 9 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 155 ; length = 7 line = 9 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 163 ; length = 1 line = 9 ; column = 36 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 169 ; length = 6 line = 10 ; column = 2 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 176 ; length = 5 line = 10 ; column = 9 ; value ='props'; } +{kind = TOKEN_DOT; ; index = 181 ; length = 1 line = 10 ; column = 14 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 182 ; length = 5 line = 10 ; column = 15 ; value ='color'; } +{kind = TOKEN_SEMICOLON; ; index = 187 ; length = 1 line = 10 ; column = 20 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 190 ; length = 1 line = 11 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 193 ; length = 0 line = 12 ; column = 0 ; value =''; } diff --git a/test/lex/redeclared_variable.golden b/test/lex/redeclared_variable.golden new file mode 100644 index 0000000..94affdc --- /dev/null +++ b/test/lex/redeclared_variable.golden @@ -0,0 +1,20 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 5 line = 2 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 32 ; length = 1 line = 2 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 34 ; length = 3 line = 2 ; column = 12 ; value ='1'; } +{kind = TOKEN_SEMICOLON; ; index = 37 ; length = 1 line = 2 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 41 ; length = 1 line = 3 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 43 ; length = 1 line = 3 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 45 ; length = 5 line = 3 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 51 ; length = 1 line = 3 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 53 ; length = 3 line = 3 ; column = 12 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 56 ; length = 1 line = 3 ; column = 15 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 59 ; length = 1 line = 4 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 62 ; length = 0 line = 5 ; column = 0 ; value =''; } diff --git a/test/lex/simple_struct_access.golden b/test/lex/simple_struct_access.golden new file mode 100644 index 0000000..8b294de --- /dev/null +++ b/test/lex/simple_struct_access.golden @@ -0,0 +1,29 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 4 line = 1 ; column = 0 ; value ='Data'; } +{kind = TOKEN_DOUBLECOLON; ; index = 5 ; length = 2 line = 1 ; column = 5 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 8 ; length = 6 line = 1 ; column = 8 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 19 ; length = 5 line = 2 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 25 ; length = 1 line = 2 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 27 ; length = 6 line = 2 ; column = 8 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 33 ; length = 1 line = 2 ; column = 14 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 36 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 41 ; length = 6 line = 5 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 48 ; length = 4 line = 5 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 53 ; length = 2 line = 5 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 56 ; length = 1 line = 5 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 57 ; length = 1 line = 5 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 59 ; length = 1 line = 5 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 63 ; length = 1 line = 6 ; column = 0 ; value ='d'; } +{kind = TOKEN_COLON; ; index = 65 ; length = 1 line = 6 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 67 ; length = 4 line = 6 ; column = 4 ; value ='Data'; } +{kind = TOKEN_SEMICOLON; ; index = 71 ; length = 1 line = 6 ; column = 8 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 75 ; length = 1 line = 7 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 77 ; length = 1 line = 7 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 79 ; length = 6 line = 7 ; column = 4 ; value ='float4'; } +{kind = TOKEN_ASSIGN; ; index = 86 ; length = 1 line = 7 ; column = 11 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 88 ; length = 1 line = 7 ; column = 13 ; value ='d'; } +{kind = TOKEN_DOT; ; index = 89 ; length = 1 line = 7 ; column = 14 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 90 ; length = 5 line = 7 ; column = 15 ; value ='color'; } +{kind = TOKEN_SEMICOLON; ; index = 95 ; length = 1 line = 7 ; column = 20 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 98 ; length = 1 line = 8 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 101 ; length = 0 line = 9 ; column = 0 ; value =''; } diff --git a/test/lex/struct_access_primitive_type.golden b/test/lex/struct_access_primitive_type.golden new file mode 100644 index 0000000..8bea16e --- /dev/null +++ b/test/lex/struct_access_primitive_type.golden @@ -0,0 +1,20 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 3 line = 2 ; column = 4 ; value ='int'; } +{kind = TOKEN_ASSIGN; ; index = 30 ; length = 1 line = 2 ; column = 8 ; value ='='; } +{kind = TOKEN_INTLITERAL; ; index = 32 ; length = 1 line = 2 ; column = 10 ; value ='5'; } +{kind = TOKEN_SEMICOLON; ; index = 33 ; length = 1 line = 2 ; column = 11 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 37 ; length = 1 line = 3 ; column = 0 ; value ='x'; } +{kind = TOKEN_DOT; ; index = 38 ; length = 1 line = 3 ; column = 1 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 39 ; length = 1 line = 3 ; column = 2 ; value ='d'; } +{kind = TOKEN_ASSIGN; ; index = 41 ; length = 1 line = 3 ; column = 4 ; value ='='; } +{kind = TOKEN_INTLITERAL; ; index = 43 ; length = 1 line = 3 ; column = 6 ; value ='4'; } +{kind = TOKEN_SEMICOLON; ; index = 44 ; length = 1 line = 3 ; column = 7 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 47 ; length = 1 line = 4 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 50 ; length = 0 line = 5 ; column = 0 ; value =''; } diff --git a/test/lex/struct_field_access_test.golden b/test/lex/struct_field_access_test.golden new file mode 100644 index 0000000..245f788 --- /dev/null +++ b/test/lex/struct_field_access_test.golden @@ -0,0 +1,167 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 10 line = 1 ; column = 0 ; value ='Vertex_Out'; } +{kind = TOKEN_DOUBLECOLON; ; index = 11 ; length = 2 line = 1 ; column = 11 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 14 ; length = 6 line = 1 ; column = 14 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 21 ; length = 1 line = 1 ; column = 21 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 25 ; length = 8 line = 2 ; column = 0 ; value ='position'; } +{kind = TOKEN_COLON; ; index = 34 ; length = 1 line = 2 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 36 ; length = 6 line = 2 ; column = 11 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 43 ; length = 1 line = 2 ; column = 18 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 44 ; length = 8 line = 2 ; column = 19 ; value ='position'; } +{kind = TOKEN_SEMICOLON; ; index = 52 ; length = 1 line = 2 ; column = 27 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 56 ; length = 6 line = 3 ; column = 0 ; value ='normal'; } +{kind = TOKEN_COLON; ; index = 65 ; length = 1 line = 3 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 67 ; length = 6 line = 3 ; column = 11 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 74 ; length = 1 line = 3 ; column = 18 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 75 ; length = 6 line = 3 ; column = 19 ; value ='normal'; } +{kind = TOKEN_SEMICOLON; ; index = 81 ; length = 1 line = 3 ; column = 25 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 85 ; length = 2 line = 4 ; column = 0 ; value ='uv'; } +{kind = TOKEN_COLON; ; index = 94 ; length = 1 line = 4 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 96 ; length = 6 line = 4 ; column = 11 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 103 ; length = 1 line = 4 ; column = 18 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 104 ; length = 2 line = 4 ; column = 19 ; value ='uv'; } +{kind = TOKEN_SEMICOLON; ; index = 106 ; length = 1 line = 4 ; column = 21 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 110 ; length = 8 line = 5 ; column = 0 ; value ='frag_pos'; } +{kind = TOKEN_COLON; ; index = 119 ; length = 1 line = 5 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 121 ; length = 6 line = 5 ; column = 11 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 128 ; length = 1 line = 5 ; column = 18 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 129 ; length = 6 line = 5 ; column = 19 ; value ='interp'; } +{kind = TOKEN_SEMICOLON; ; index = 135 ; length = 1 line = 5 ; column = 25 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 138 ; length = 1 line = 6 ; column = 0 ; value ='}'; } +{kind = TOKEN_INSTANCE; ; index = 143 ; length = 8 line = 8 ; column = 0 ; value ='instance'; } +{kind = TOKEN_LEFTBRACE; ; index = 152 ; length = 1 line = 8 ; column = 9 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 156 ; length = 5 line = 9 ; column = 0 ; value ='model'; } +{kind = TOKEN_COLON; ; index = 162 ; length = 1 line = 9 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 164 ; length = 8 line = 9 ; column = 8 ; value ='float4x4'; } +{kind = TOKEN_AT; ; index = 173 ; length = 1 line = 9 ; column = 17 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 174 ; length = 5 line = 9 ; column = 18 ; value ='model'; } +{kind = TOKEN_SEMICOLON; ; index = 179 ; length = 1 line = 9 ; column = 23 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 182 ; length = 1 line = 10 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 187 ; length = 6 line = 12 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 194 ; length = 4 line = 12 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 199 ; length = 2 line = 12 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 202 ; length = 1 line = 12 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 203 ; length = 8 line = 12 ; column = 16 ; value ='position'; } +{kind = TOKEN_COLON; ; index = 212 ; length = 1 line = 12 ; column = 25 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 214 ; length = 6 line = 12 ; column = 27 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 221 ; length = 1 line = 12 ; column = 34 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 222 ; length = 8 line = 12 ; column = 35 ; value ='position'; } +{kind = TOKEN_COMMA; ; index = 230 ; length = 1 line = 12 ; column = 43 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 232 ; length = 2 line = 12 ; column = 45 ; value ='uv'; } +{kind = TOKEN_COLON; ; index = 235 ; length = 1 line = 12 ; column = 48 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 237 ; length = 6 line = 12 ; column = 50 ; value ='float2'; } +{kind = TOKEN_AT; ; index = 244 ; length = 1 line = 12 ; column = 57 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 245 ; length = 2 line = 12 ; column = 58 ; value ='uv'; } +{kind = TOKEN_COMMA; ; index = 247 ; length = 1 line = 12 ; column = 60 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 249 ; length = 6 line = 12 ; column = 62 ; value ='normal'; } +{kind = TOKEN_COLON; ; index = 256 ; length = 1 line = 12 ; column = 69 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 258 ; length = 6 line = 12 ; column = 71 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 265 ; length = 1 line = 12 ; column = 78 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 266 ; length = 6 line = 12 ; column = 79 ; value ='normal'; } +{kind = TOKEN_RIGHTPAREN; ; index = 272 ; length = 1 line = 12 ; column = 85 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 274 ; length = 2 line = 12 ; column = 87 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 277 ; length = 10 line = 12 ; column = 90 ; value ='Vertex_Out'; } +{kind = TOKEN_LEFTBRACE; ; index = 288 ; length = 1 line = 12 ; column = 101 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 292 ; length = 5 line = 13 ; column = 0 ; value ='v_out'; } +{kind = TOKEN_COLON; ; index = 298 ; length = 1 line = 13 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 300 ; length = 10 line = 13 ; column = 8 ; value ='Vertex_Out'; } +{kind = TOKEN_SEMICOLON; ; index = 310 ; length = 1 line = 13 ; column = 18 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 316 ; length = 5 line = 15 ; column = 0 ; value ='v_out'; } +{kind = TOKEN_DOT; ; index = 321 ; length = 1 line = 15 ; column = 5 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 322 ; length = 8 line = 15 ; column = 6 ; value ='position'; } +{kind = TOKEN_ASSIGN; ; index = 331 ; length = 1 line = 15 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 333 ; length = 3 line = 15 ; column = 17 ; value ='mul'; } +{kind = TOKEN_LEFTPAREN; ; index = 336 ; length = 1 line = 15 ; column = 20 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 337 ; length = 8 line = 15 ; column = 21 ; value ='position'; } +{kind = TOKEN_COMMA; ; index = 345 ; length = 1 line = 15 ; column = 29 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 347 ; length = 5 line = 15 ; column = 31 ; value ='model'; } +{kind = TOKEN_RIGHTPAREN; ; index = 352 ; length = 1 line = 15 ; column = 36 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 353 ; length = 1 line = 15 ; column = 37 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 357 ; length = 5 line = 16 ; column = 0 ; value ='v_out'; } +{kind = TOKEN_DOT; ; index = 362 ; length = 1 line = 16 ; column = 5 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 363 ; length = 6 line = 16 ; column = 6 ; value ='normal'; } +{kind = TOKEN_ASSIGN; ; index = 372 ; length = 1 line = 16 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 374 ; length = 6 line = 16 ; column = 17 ; value ='normal'; } +{kind = TOKEN_SEMICOLON; ; index = 380 ; length = 1 line = 16 ; column = 23 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 384 ; length = 5 line = 17 ; column = 0 ; value ='v_out'; } +{kind = TOKEN_DOT; ; index = 389 ; length = 1 line = 17 ; column = 5 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 390 ; length = 2 line = 17 ; column = 6 ; value ='uv'; } +{kind = TOKEN_ASSIGN; ; index = 399 ; length = 1 line = 17 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 401 ; length = 2 line = 17 ; column = 17 ; value ='uv'; } +{kind = TOKEN_SEMICOLON; ; index = 403 ; length = 1 line = 17 ; column = 19 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 407 ; length = 5 line = 18 ; column = 0 ; value ='v_out'; } +{kind = TOKEN_DOT; ; index = 412 ; length = 1 line = 18 ; column = 5 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 413 ; length = 8 line = 18 ; column = 6 ; value ='frag_pos'; } +{kind = TOKEN_ASSIGN; ; index = 422 ; length = 1 line = 18 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 424 ; length = 8 line = 18 ; column = 17 ; value ='position'; } +{kind = TOKEN_SEMICOLON; ; index = 432 ; length = 1 line = 18 ; column = 25 ; value =';'; } +{kind = TOKEN_RETURN; ; index = 438 ; length = 6 line = 20 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 445 ; length = 5 line = 20 ; column = 7 ; value ='v_out'; } +{kind = TOKEN_SEMICOLON; ; index = 450 ; length = 1 line = 20 ; column = 12 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 453 ; length = 1 line = 21 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 458 ; length = 9 line = 23 ; column = 0 ; value ='Pixel_Out'; } +{kind = TOKEN_DOUBLECOLON; ; index = 468 ; length = 2 line = 23 ; column = 10 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 471 ; length = 6 line = 23 ; column = 13 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 478 ; length = 1 line = 23 ; column = 20 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 482 ; length = 5 line = 24 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 491 ; length = 1 line = 24 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 493 ; length = 6 line = 24 ; column = 11 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 500 ; length = 1 line = 24 ; column = 18 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 501 ; length = 7 line = 24 ; column = 19 ; value ='target0'; } +{kind = TOKEN_SEMICOLON; ; index = 508 ; length = 1 line = 24 ; column = 26 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 512 ; length = 8 line = 25 ; column = 0 ; value ='emission'; } +{kind = TOKEN_COLON; ; index = 521 ; length = 1 line = 25 ; column = 9 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 523 ; length = 6 line = 25 ; column = 11 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 530 ; length = 1 line = 25 ; column = 18 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 531 ; length = 7 line = 25 ; column = 19 ; value ='target1'; } +{kind = TOKEN_SEMICOLON; ; index = 538 ; length = 1 line = 25 ; column = 26 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 541 ; length = 1 line = 26 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 546 ; length = 5 line = 28 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 552 ; length = 4 line = 28 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 557 ; length = 2 line = 28 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 560 ; length = 1 line = 28 ; column = 14 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 561 ; length = 4 line = 28 ; column = 15 ; value ='v_in'; } +{kind = TOKEN_COLON; ; index = 566 ; length = 1 line = 28 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 568 ; length = 10 line = 28 ; column = 22 ; value ='Vertex_Out'; } +{kind = TOKEN_RIGHTPAREN; ; index = 578 ; length = 1 line = 28 ; column = 32 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 580 ; length = 2 line = 28 ; column = 34 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 583 ; length = 9 line = 28 ; column = 37 ; value ='Pixel_Out'; } +{kind = TOKEN_LEFTBRACE; ; index = 593 ; length = 1 line = 28 ; column = 47 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 597 ; length = 5 line = 29 ; column = 0 ; value ='p_out'; } +{kind = TOKEN_COLON; ; index = 603 ; length = 1 line = 29 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 605 ; length = 9 line = 29 ; column = 8 ; value ='Pixel_Out'; } +{kind = TOKEN_SEMICOLON; ; index = 614 ; length = 1 line = 29 ; column = 17 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 620 ; length = 5 line = 31 ; column = 0 ; value ='p_out'; } +{kind = TOKEN_DOT; ; index = 625 ; length = 1 line = 31 ; column = 5 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 626 ; length = 5 line = 31 ; column = 6 ; value ='color'; } +{kind = TOKEN_ASSIGN; ; index = 635 ; length = 1 line = 31 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 637 ; length = 6 line = 31 ; column = 17 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 643 ; length = 1 line = 31 ; column = 23 ; value ='('; } +{kind = TOKEN_INTLITERAL; ; index = 644 ; length = 1 line = 31 ; column = 24 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 645 ; length = 1 line = 31 ; column = 25 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 647 ; length = 3 line = 31 ; column = 27 ; value ='0.5'; } +{kind = TOKEN_COMMA; ; index = 650 ; length = 1 line = 31 ; column = 30 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 652 ; length = 1 line = 31 ; column = 32 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 653 ; length = 1 line = 31 ; column = 33 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 655 ; length = 1 line = 31 ; column = 35 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 656 ; length = 1 line = 31 ; column = 36 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 657 ; length = 1 line = 31 ; column = 37 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 661 ; length = 5 line = 32 ; column = 0 ; value ='p_out'; } +{kind = TOKEN_DOT; ; index = 666 ; length = 1 line = 32 ; column = 5 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 667 ; length = 8 line = 32 ; column = 6 ; value ='emission'; } +{kind = TOKEN_ASSIGN; ; index = 676 ; length = 1 line = 32 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 678 ; length = 6 line = 32 ; column = 17 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 684 ; length = 1 line = 32 ; column = 23 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 685 ; length = 3 line = 32 ; column = 24 ; value ='2'; } +{kind = TOKEN_COMMA; ; index = 688 ; length = 1 line = 32 ; column = 27 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 690 ; length = 3 line = 32 ; column = 29 ; value ='2'; } +{kind = TOKEN_COMMA; ; index = 693 ; length = 1 line = 32 ; column = 32 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 695 ; length = 3 line = 32 ; column = 34 ; value ='2'; } +{kind = TOKEN_COMMA; ; index = 698 ; length = 1 line = 32 ; column = 37 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 700 ; length = 3 line = 32 ; column = 39 ; value ='2'; } +{kind = TOKEN_RIGHTPAREN; ; index = 703 ; length = 1 line = 32 ; column = 42 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 704 ; length = 1 line = 32 ; column = 43 ; value =';'; } +{kind = TOKEN_RETURN; ; index = 710 ; length = 6 line = 34 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 717 ; length = 5 line = 34 ; column = 7 ; value ='p_out'; } +{kind = TOKEN_SEMICOLON; ; index = 722 ; length = 1 line = 34 ; column = 12 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 725 ; length = 1 line = 35 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 728 ; length = 0 line = 36 ; column = 0 ; value =''; } diff --git a/test/lex/struct_within_struct.golden b/test/lex/struct_within_struct.golden new file mode 100644 index 0000000..85df68a --- /dev/null +++ b/test/lex/struct_within_struct.golden @@ -0,0 +1,40 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='Foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 7 ; length = 6 line = 1 ; column = 7 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 14 ; length = 1 line = 1 ; column = 14 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 18 ; length = 5 line = 2 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 6 line = 2 ; column = 8 ; value ='float4'; } +{kind = TOKEN_SEMICOLON; ; index = 32 ; length = 1 line = 2 ; column = 14 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 35 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 40 ; length = 3 line = 5 ; column = 0 ; value ='Bar'; } +{kind = TOKEN_DOUBLECOLON; ; index = 44 ; length = 2 line = 5 ; column = 4 ; value ='::'; } +{kind = TOKEN_STRUCT; ; index = 47 ; length = 6 line = 5 ; column = 7 ; value ='struct'; } +{kind = TOKEN_LEFTBRACE; ; index = 54 ; length = 1 line = 5 ; column = 14 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 61 ; length = 1 line = 6 ; column = 4 ; value ='t'; } +{kind = TOKEN_COLON; ; index = 63 ; length = 1 line = 6 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 65 ; length = 3 line = 6 ; column = 8 ; value ='Foo'; } +{kind = TOKEN_SEMICOLON; ; index = 68 ; length = 1 line = 6 ; column = 11 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 71 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 76 ; length = 6 line = 9 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 83 ; length = 4 line = 9 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 88 ; length = 2 line = 9 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 91 ; length = 1 line = 9 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 92 ; length = 1 line = 9 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 94 ; length = 1 line = 9 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 98 ; length = 1 line = 10 ; column = 0 ; value ='f'; } +{kind = TOKEN_COLON; ; index = 100 ; length = 1 line = 10 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 102 ; length = 3 line = 10 ; column = 4 ; value ='Foo'; } +{kind = TOKEN_SEMICOLON; ; index = 105 ; length = 1 line = 10 ; column = 7 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 109 ; length = 1 line = 11 ; column = 0 ; value ='b'; } +{kind = TOKEN_COLON; ; index = 111 ; length = 1 line = 11 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 113 ; length = 3 line = 11 ; column = 4 ; value ='Bar'; } +{kind = TOKEN_SEMICOLON; ; index = 116 ; length = 1 line = 11 ; column = 7 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 120 ; length = 1 line = 12 ; column = 0 ; value ='b'; } +{kind = TOKEN_DOT; ; index = 121 ; length = 1 line = 12 ; column = 1 ; value ='.'; } +{kind = TOKEN_IDENTIFIER; ; index = 122 ; length = 1 line = 12 ; column = 2 ; value ='t'; } +{kind = TOKEN_ASSIGN; ; index = 124 ; length = 1 line = 12 ; column = 4 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 126 ; length = 1 line = 12 ; column = 6 ; value ='f'; } +{kind = TOKEN_SEMICOLON; ; index = 127 ; length = 1 line = 12 ; column = 7 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 130 ; length = 1 line = 13 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 133 ; length = 0 line = 14 ; column = 0 ; value =''; } diff --git a/test/lex/type_as_function_name.golden b/test/lex/type_as_function_name.golden new file mode 100644 index 0000000..eb61f48 --- /dev/null +++ b/test/lex/type_as_function_name.golden @@ -0,0 +1,7 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='int'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 7 ; length = 1 line = 1 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 8 ; length = 1 line = 1 ; column = 8 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 10 ; length = 1 line = 1 ; column = 10 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 11 ; length = 1 line = 1 ; column = 11 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 14 ; length = 0 line = 2 ; column = 0 ; value =''; } diff --git a/test/lex/type_as_variable_name.golden b/test/lex/type_as_variable_name.golden new file mode 100644 index 0000000..6912c23 --- /dev/null +++ b/test/lex/type_as_variable_name.golden @@ -0,0 +1,14 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 3 line = 2 ; column = 0 ; value ='int'; } +{kind = TOKEN_COLON; ; index = 26 ; length = 1 line = 2 ; column = 4 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 28 ; length = 5 line = 2 ; column = 6 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 34 ; length = 1 line = 2 ; column = 12 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 36 ; length = 3 line = 2 ; column = 14 ; value ='4'; } +{kind = TOKEN_SEMICOLON; ; index = 39 ; length = 1 line = 2 ; column = 17 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 42 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 45 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/undeclared_function.golden b/test/lex/undeclared_function.golden new file mode 100644 index 0000000..df39f4b --- /dev/null +++ b/test/lex/undeclared_function.golden @@ -0,0 +1,12 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 3 line = 2 ; column = 0 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 25 ; length = 1 line = 2 ; column = 3 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 26 ; length = 1 line = 2 ; column = 4 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 27 ; length = 1 line = 2 ; column = 5 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 30 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 33 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/undeclared_symbol.golden b/test/lex/undeclared_symbol.golden new file mode 100644 index 0000000..68966c4 --- /dev/null +++ b/test/lex/undeclared_symbol.golden @@ -0,0 +1,14 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='b'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 3 line = 2 ; column = 4 ; value ='int'; } +{kind = TOKEN_ASSIGN; ; index = 30 ; length = 1 line = 2 ; column = 8 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 32 ; length = 1 line = 2 ; column = 10 ; value ='f'; } +{kind = TOKEN_SEMICOLON; ; index = 33 ; length = 1 line = 2 ; column = 11 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 36 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 39 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/unknown_overload.golden b/test/lex/unknown_overload.golden new file mode 100644 index 0000000..074657c --- /dev/null +++ b/test/lex/unknown_overload.golden @@ -0,0 +1,51 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 7 ; length = 1 line = 1 ; column = 7 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 8 ; length = 2 line = 1 ; column = 8 ; value ='v1'; } +{kind = TOKEN_COLON; ; index = 11 ; length = 1 line = 1 ; column = 11 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 13 ; length = 6 line = 1 ; column = 13 ; value ='float3'; } +{kind = TOKEN_COMMA; ; index = 19 ; length = 1 line = 1 ; column = 19 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 21 ; length = 2 line = 1 ; column = 21 ; value ='v2'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 1 ; column = 24 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 6 line = 1 ; column = 26 ; value ='float3'; } +{kind = TOKEN_RIGHTPAREN; ; index = 32 ; length = 1 line = 1 ; column = 32 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 34 ; length = 1 line = 1 ; column = 34 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 35 ; length = 1 line = 1 ; column = 35 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 38 ; length = 3 line = 2 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 42 ; length = 2 line = 2 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 45 ; length = 1 line = 2 ; column = 7 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 46 ; length = 2 line = 2 ; column = 8 ; value ='v1'; } +{kind = TOKEN_COLON; ; index = 49 ; length = 1 line = 2 ; column = 11 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 6 line = 2 ; column = 13 ; value ='float2'; } +{kind = TOKEN_COMMA; ; index = 57 ; length = 1 line = 2 ; column = 19 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 59 ; length = 2 line = 2 ; column = 21 ; value ='v2'; } +{kind = TOKEN_COLON; ; index = 62 ; length = 1 line = 2 ; column = 24 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 64 ; length = 6 line = 2 ; column = 26 ; value ='float2'; } +{kind = TOKEN_COMMA; ; index = 70 ; length = 1 line = 2 ; column = 32 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 72 ; length = 2 line = 2 ; column = 34 ; value ='v3'; } +{kind = TOKEN_COLON; ; index = 75 ; length = 1 line = 2 ; column = 37 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 77 ; length = 6 line = 2 ; column = 39 ; value ='float2'; } +{kind = TOKEN_RIGHTPAREN; ; index = 83 ; length = 1 line = 2 ; column = 45 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 85 ; length = 1 line = 2 ; column = 47 ; value ='{'; } +{kind = TOKEN_RIGHTBRACE; ; index = 86 ; length = 1 line = 2 ; column = 48 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 91 ; length = 6 line = 4 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 98 ; length = 4 line = 4 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 103 ; length = 2 line = 4 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 106 ; length = 1 line = 4 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 107 ; length = 1 line = 4 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 109 ; length = 1 line = 4 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 113 ; length = 1 line = 5 ; column = 0 ; value ='v'; } +{kind = TOKEN_COLON; ; index = 115 ; length = 1 line = 5 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 117 ; length = 5 line = 5 ; column = 4 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 123 ; length = 1 line = 5 ; column = 10 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 125 ; length = 3 line = 5 ; column = 12 ; value ='2'; } +{kind = TOKEN_SEMICOLON; ; index = 128 ; length = 1 line = 5 ; column = 15 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 132 ; length = 3 line = 6 ; column = 0 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 135 ; length = 1 line = 6 ; column = 3 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 136 ; length = 1 line = 6 ; column = 4 ; value ='v'; } +{kind = TOKEN_COMMA; ; index = 137 ; length = 1 line = 6 ; column = 5 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 139 ; length = 1 line = 6 ; column = 7 ; value ='v'; } +{kind = TOKEN_RIGHTPAREN; ; index = 140 ; length = 1 line = 6 ; column = 8 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 141 ; length = 1 line = 6 ; column = 9 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 144 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 147 ; length = 0 line = 8 ; column = 0 ; value =''; } diff --git a/test/lex/use_builtin_functions.golden b/test/lex/use_builtin_functions.golden new file mode 100644 index 0000000..aa2a6e9 --- /dev/null +++ b/test/lex/use_builtin_functions.golden @@ -0,0 +1,23 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 16 ; length = 1 line = 1 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 18 ; length = 1 line = 1 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 1 line = 2 ; column = 0 ; value ='f'; } +{kind = TOKEN_COLON; ; index = 24 ; length = 1 line = 2 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 26 ; length = 6 line = 2 ; column = 4 ; value ='float4'; } +{kind = TOKEN_ASSIGN; ; index = 33 ; length = 1 line = 2 ; column = 11 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 35 ; length = 6 line = 2 ; column = 13 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 41 ; length = 1 line = 2 ; column = 19 ; value ='('; } +{kind = TOKEN_INTLITERAL; ; index = 42 ; length = 1 line = 2 ; column = 20 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 43 ; length = 1 line = 2 ; column = 21 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 45 ; length = 1 line = 2 ; column = 23 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 46 ; length = 1 line = 2 ; column = 24 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 48 ; length = 1 line = 2 ; column = 26 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 49 ; length = 1 line = 2 ; column = 27 ; value =','; } +{kind = TOKEN_INTLITERAL; ; index = 51 ; length = 1 line = 2 ; column = 29 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 52 ; length = 1 line = 2 ; column = 30 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 53 ; length = 1 line = 2 ; column = 31 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 56 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 59 ; length = 0 line = 4 ; column = 0 ; value =''; } diff --git a/test/lex/wrong_argument_count.golden b/test/lex/wrong_argument_count.golden new file mode 100644 index 0000000..5da749f --- /dev/null +++ b/test/lex/wrong_argument_count.golden @@ -0,0 +1,73 @@ +{kind = TOKEN_IDENTIFIER; ; index = 0 ; length = 3 line = 1 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 4 ; length = 2 line = 1 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 7 ; length = 1 line = 1 ; column = 7 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 8 ; length = 1 line = 1 ; column = 8 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 10 ; length = 1 line = 1 ; column = 10 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 12 ; length = 5 line = 1 ; column = 12 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 17 ; length = 1 line = 1 ; column = 17 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 19 ; length = 1 line = 1 ; column = 19 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 21 ; length = 1 line = 1 ; column = 21 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 23 ; length = 5 line = 1 ; column = 23 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 28 ; length = 1 line = 1 ; column = 28 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 1 line = 1 ; column = 30 ; value ='z'; } +{kind = TOKEN_COLON; ; index = 32 ; length = 1 line = 1 ; column = 32 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 34 ; length = 5 line = 1 ; column = 34 ; value ='float'; } +{kind = TOKEN_RIGHTPAREN; ; index = 39 ; length = 1 line = 1 ; column = 39 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 41 ; length = 2 line = 1 ; column = 41 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 44 ; length = 5 line = 1 ; column = 44 ; value ='float'; } +{kind = TOKEN_LEFTBRACE; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 54 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 61 ; length = 1 line = 2 ; column = 7 ; value ='x'; } +{kind = TOKEN_STAR; ; index = 63 ; length = 1 line = 2 ; column = 9 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 65 ; length = 1 line = 2 ; column = 11 ; value ='y'; } +{kind = TOKEN_STAR; ; index = 67 ; length = 1 line = 2 ; column = 13 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 69 ; length = 1 line = 2 ; column = 15 ; value ='z'; } +{kind = TOKEN_SEMICOLON; ; index = 70 ; length = 1 line = 2 ; column = 16 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 73 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 76 ; length = 3 line = 4 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 80 ; length = 2 line = 4 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 83 ; length = 1 line = 4 ; column = 7 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 84 ; length = 1 line = 4 ; column = 8 ; value ='x'; } +{kind = TOKEN_COLON; ; index = 86 ; length = 1 line = 4 ; column = 10 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 88 ; length = 5 line = 4 ; column = 12 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 93 ; length = 1 line = 4 ; column = 17 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 95 ; length = 1 line = 4 ; column = 19 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 97 ; length = 1 line = 4 ; column = 21 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 99 ; length = 5 line = 4 ; column = 23 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 104 ; length = 1 line = 4 ; column = 28 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 106 ; length = 1 line = 4 ; column = 30 ; value ='z'; } +{kind = TOKEN_COLON; ; index = 108 ; length = 1 line = 4 ; column = 32 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 110 ; length = 5 line = 4 ; column = 34 ; value ='float'; } +{kind = TOKEN_COMMA; ; index = 115 ; length = 1 line = 4 ; column = 39 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 117 ; length = 1 line = 4 ; column = 41 ; value ='w'; } +{kind = TOKEN_COLON; ; index = 119 ; length = 1 line = 4 ; column = 43 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 121 ; length = 5 line = 4 ; column = 45 ; value ='float'; } +{kind = TOKEN_RIGHTPAREN; ; index = 126 ; length = 1 line = 4 ; column = 50 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 128 ; length = 2 line = 4 ; column = 52 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 131 ; length = 5 line = 4 ; column = 55 ; value ='float'; } +{kind = TOKEN_LEFTBRACE; ; index = 137 ; length = 1 line = 4 ; column = 61 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 141 ; length = 6 line = 5 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 148 ; length = 1 line = 5 ; column = 7 ; value ='x'; } +{kind = TOKEN_STAR; ; index = 150 ; length = 1 line = 5 ; column = 9 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 152 ; length = 1 line = 5 ; column = 11 ; value ='y'; } +{kind = TOKEN_STAR; ; index = 154 ; length = 1 line = 5 ; column = 13 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 156 ; length = 1 line = 5 ; column = 15 ; value ='z'; } +{kind = TOKEN_STAR; ; index = 158 ; length = 1 line = 5 ; column = 17 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 160 ; length = 1 line = 5 ; column = 19 ; value ='w'; } +{kind = TOKEN_SEMICOLON; ; index = 161 ; length = 1 line = 5 ; column = 20 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 164 ; length = 1 line = 6 ; column = 0 ; value ='}'; } +{kind = TOKEN_VERTEX; ; index = 169 ; length = 6 line = 8 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 176 ; length = 4 line = 8 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 181 ; length = 2 line = 8 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 184 ; length = 1 line = 8 ; column = 15 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 185 ; length = 1 line = 8 ; column = 16 ; value =')'; } +{kind = TOKEN_LEFTBRACE; ; index = 187 ; length = 1 line = 8 ; column = 18 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 191 ; length = 3 line = 9 ; column = 0 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 194 ; length = 1 line = 9 ; column = 3 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 195 ; length = 3 line = 9 ; column = 4 ; value ='2'; } +{kind = TOKEN_COMMA; ; index = 198 ; length = 1 line = 9 ; column = 7 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 200 ; length = 3 line = 9 ; column = 9 ; value ='3'; } +{kind = TOKEN_RIGHTPAREN; ; index = 203 ; length = 1 line = 9 ; column = 12 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 204 ; length = 1 line = 9 ; column = 13 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 207 ; length = 1 line = 10 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 212 ; length = 0 line = 12 ; column = 0 ; value =''; } diff --git a/test/lex/wrong_multiply.golden b/test/lex/wrong_multiply.golden new file mode 100644 index 0000000..ca3c1e8 --- /dev/null +++ b/test/lex/wrong_multiply.golden @@ -0,0 +1,54 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 29 ; length = 1 line = 1 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 8 line = 1 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 38 ; length = 1 line = 1 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 40 ; length = 2 line = 1 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 6 line = 1 ; column = 43 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 8 line = 1 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 60 ; length = 1 line = 1 ; column = 60 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 64 ; length = 3 line = 2 ; column = 0 ; value ='res'; } +{kind = TOKEN_COLON; ; index = 68 ; length = 1 line = 2 ; column = 4 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 70 ; length = 6 line = 2 ; column = 6 ; value ='float2'; } +{kind = TOKEN_ASSIGN; ; index = 77 ; length = 1 line = 2 ; column = 13 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 79 ; length = 6 line = 2 ; column = 15 ; value ='float2'; } +{kind = TOKEN_LEFTPAREN; ; index = 85 ; length = 1 line = 2 ; column = 21 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 86 ; length = 3 line = 2 ; column = 22 ; value ='2'; } +{kind = TOKEN_COMMA; ; index = 89 ; length = 1 line = 2 ; column = 25 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 91 ; length = 3 line = 2 ; column = 27 ; value ='2'; } +{kind = TOKEN_RIGHTPAREN; ; index = 94 ; length = 1 line = 2 ; column = 30 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 95 ; length = 1 line = 2 ; column = 31 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 99 ; length = 3 line = 3 ; column = 0 ; value ='foo'; } +{kind = TOKEN_COLON; ; index = 103 ; length = 1 line = 3 ; column = 4 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 105 ; length = 5 line = 3 ; column = 6 ; value ='float'; } +{kind = TOKEN_ASSIGN; ; index = 111 ; length = 1 line = 3 ; column = 12 ; value ='='; } +{kind = TOKEN_FLOATLITERAL; ; index = 113 ; length = 3 line = 3 ; column = 14 ; value ='1'; } +{kind = TOKEN_SEMICOLON; ; index = 116 ; length = 1 line = 3 ; column = 17 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 120 ; length = 6 line = 4 ; column = 0 ; value ='result'; } +{kind = TOKEN_COLON; ; index = 127 ; length = 1 line = 4 ; column = 7 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 129 ; length = 6 line = 4 ; column = 9 ; value ='float4'; } +{kind = TOKEN_ASSIGN; ; index = 136 ; length = 1 line = 4 ; column = 16 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 138 ; length = 6 line = 4 ; column = 18 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 144 ; length = 1 line = 4 ; column = 24 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 145 ; length = 3 line = 4 ; column = 25 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 148 ; length = 1 line = 4 ; column = 28 ; value =','; } +{kind = TOKEN_IDENTIFIER; ; index = 150 ; length = 3 line = 4 ; column = 30 ; value ='foo'; } +{kind = TOKEN_STAR; ; index = 154 ; length = 1 line = 4 ; column = 34 ; value ='*'; } +{kind = TOKEN_IDENTIFIER; ; index = 156 ; length = 3 line = 4 ; column = 36 ; value ='res'; } +{kind = TOKEN_COMMA; ; index = 159 ; length = 1 line = 4 ; column = 39 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 161 ; length = 3 line = 4 ; column = 41 ; value ='0'; } +{kind = TOKEN_COMMA; ; index = 164 ; length = 1 line = 4 ; column = 44 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 166 ; length = 3 line = 4 ; column = 46 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 169 ; length = 1 line = 4 ; column = 49 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 170 ; length = 1 line = 4 ; column = 50 ; value =';'; } +{kind = TOKEN_RETURN; ; index = 174 ; length = 6 line = 5 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 181 ; length = 6 line = 5 ; column = 7 ; value ='result'; } +{kind = TOKEN_SEMICOLON; ; index = 187 ; length = 1 line = 5 ; column = 13 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 190 ; length = 1 line = 6 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 193 ; length = 0 line = 7 ; column = 0 ; value =''; } diff --git a/test/lex/wrong_type_for_function.golden b/test/lex/wrong_type_for_function.golden new file mode 100644 index 0000000..1d1614a --- /dev/null +++ b/test/lex/wrong_type_for_function.golden @@ -0,0 +1,73 @@ +{kind = TOKEN_VERTEX; ; index = 0 ; length = 6 line = 1 ; column = 0 ; value ='vertex'; } +{kind = TOKEN_IDENTIFIER; ; index = 7 ; length = 4 line = 1 ; column = 7 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 12 ; length = 2 line = 1 ; column = 12 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 15 ; length = 1 line = 1 ; column = 15 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 16 ; length = 3 line = 1 ; column = 16 ; value ='pos'; } +{kind = TOKEN_COLON; ; index = 20 ; length = 1 line = 1 ; column = 20 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 22 ; length = 6 line = 1 ; column = 22 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 29 ; length = 1 line = 1 ; column = 29 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 30 ; length = 8 line = 1 ; column = 30 ; value ='position'; } +{kind = TOKEN_RIGHTPAREN; ; index = 38 ; length = 1 line = 1 ; column = 38 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 40 ; length = 2 line = 1 ; column = 40 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 43 ; length = 6 line = 1 ; column = 43 ; value ='float3'; } +{kind = TOKEN_AT; ; index = 50 ; length = 1 line = 1 ; column = 50 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 51 ; length = 8 line = 1 ; column = 51 ; value ='position'; } +{kind = TOKEN_LEFTBRACE; ; index = 60 ; length = 1 line = 1 ; column = 60 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 64 ; length = 6 line = 2 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 71 ; length = 3 line = 2 ; column = 7 ; value ='pos'; } +{kind = TOKEN_SEMICOLON; ; index = 74 ; length = 1 line = 2 ; column = 10 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 77 ; length = 1 line = 3 ; column = 0 ; value ='}'; } +{kind = TOKEN_IDENTIFIER; ; index = 82 ; length = 3 line = 5 ; column = 0 ; value ='foo'; } +{kind = TOKEN_DOUBLECOLON; ; index = 86 ; length = 2 line = 5 ; column = 4 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 89 ; length = 1 line = 5 ; column = 7 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 90 ; length = 1 line = 5 ; column = 8 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 92 ; length = 2 line = 5 ; column = 10 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 95 ; length = 6 line = 5 ; column = 13 ; value ='float2'; } +{kind = TOKEN_LEFTBRACE; ; index = 102 ; length = 1 line = 5 ; column = 20 ; value ='{'; } +{kind = TOKEN_RETURN; ; index = 106 ; length = 6 line = 6 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 113 ; length = 6 line = 6 ; column = 7 ; value ='float2'; } +{kind = TOKEN_LEFTPAREN; ; index = 119 ; length = 1 line = 6 ; column = 13 ; value ='('; } +{kind = TOKEN_FLOATLITERAL; ; index = 120 ; length = 3 line = 6 ; column = 14 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 123 ; length = 1 line = 6 ; column = 17 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 125 ; length = 3 line = 6 ; column = 19 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 128 ; length = 1 line = 6 ; column = 22 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 129 ; length = 1 line = 6 ; column = 23 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 132 ; length = 1 line = 7 ; column = 0 ; value ='}'; } +{kind = TOKEN_PIXEL; ; index = 137 ; length = 5 line = 9 ; column = 0 ; value ='pixel'; } +{kind = TOKEN_IDENTIFIER; ; index = 143 ; length = 4 line = 9 ; column = 6 ; value ='main'; } +{kind = TOKEN_DOUBLECOLON; ; index = 148 ; length = 2 line = 9 ; column = 11 ; value ='::'; } +{kind = TOKEN_LEFTPAREN; ; index = 151 ; length = 1 line = 9 ; column = 14 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 152 ; length = 1 line = 9 ; column = 15 ; value =')'; } +{kind = TOKEN_ARROW; ; index = 154 ; length = 2 line = 9 ; column = 17 ; value ='->'; } +{kind = TOKEN_IDENTIFIER; ; index = 157 ; length = 6 line = 9 ; column = 20 ; value ='float4'; } +{kind = TOKEN_AT; ; index = 164 ; length = 1 line = 9 ; column = 27 ; value ='@'; } +{kind = TOKEN_IDENTIFIER; ; index = 165 ; length = 7 line = 9 ; column = 28 ; value ='target0'; } +{kind = TOKEN_LEFTBRACE; ; index = 173 ; length = 1 line = 9 ; column = 36 ; value ='{'; } +{kind = TOKEN_IDENTIFIER; ; index = 177 ; length = 1 line = 10 ; column = 0 ; value ='y'; } +{kind = TOKEN_COLON; ; index = 179 ; length = 1 line = 10 ; column = 2 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 181 ; length = 6 line = 10 ; column = 4 ; value ='float2'; } +{kind = TOKEN_ASSIGN; ; index = 188 ; length = 1 line = 10 ; column = 11 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 190 ; length = 3 line = 10 ; column = 13 ; value ='foo'; } +{kind = TOKEN_LEFTPAREN; ; index = 193 ; length = 1 line = 10 ; column = 16 ; value ='('; } +{kind = TOKEN_RIGHTPAREN; ; index = 194 ; length = 1 line = 10 ; column = 17 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 195 ; length = 1 line = 10 ; column = 18 ; value =';'; } +{kind = TOKEN_IDENTIFIER; ; index = 199 ; length = 5 line = 11 ; column = 0 ; value ='color'; } +{kind = TOKEN_COLON; ; index = 205 ; length = 1 line = 11 ; column = 6 ; value =':'; } +{kind = TOKEN_IDENTIFIER; ; index = 207 ; length = 6 line = 11 ; column = 8 ; value ='float4'; } +{kind = TOKEN_ASSIGN; ; index = 214 ; length = 1 line = 11 ; column = 15 ; value ='='; } +{kind = TOKEN_IDENTIFIER; ; index = 216 ; length = 6 line = 11 ; column = 17 ; value ='float4'; } +{kind = TOKEN_LEFTPAREN; ; index = 222 ; length = 1 line = 11 ; column = 23 ; value ='('; } +{kind = TOKEN_IDENTIFIER; ; index = 223 ; length = 1 line = 11 ; column = 24 ; value ='y'; } +{kind = TOKEN_COMMA; ; index = 224 ; length = 1 line = 11 ; column = 25 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 226 ; length = 3 line = 11 ; column = 27 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 229 ; length = 1 line = 11 ; column = 30 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 231 ; length = 3 line = 11 ; column = 32 ; value ='1'; } +{kind = TOKEN_COMMA; ; index = 234 ; length = 1 line = 11 ; column = 35 ; value =','; } +{kind = TOKEN_FLOATLITERAL; ; index = 236 ; length = 3 line = 11 ; column = 37 ; value ='1'; } +{kind = TOKEN_RIGHTPAREN; ; index = 239 ; length = 1 line = 11 ; column = 40 ; value =')'; } +{kind = TOKEN_SEMICOLON; ; index = 240 ; length = 1 line = 11 ; column = 41 ; value =';'; } +{kind = TOKEN_RETURN; ; index = 244 ; length = 6 line = 12 ; column = 0 ; value ='return'; } +{kind = TOKEN_IDENTIFIER; ; index = 251 ; length = 5 line = 12 ; column = 7 ; value ='color'; } +{kind = TOKEN_SEMICOLON; ; index = 256 ; length = 1 line = 12 ; column = 12 ; value =';'; } +{kind = TOKEN_RIGHTBRACE; ; index = 259 ; length = 1 line = 13 ; column = 0 ; value ='}'; } +{kind = TOKEN_EOF; ; index = 262 ; length = 0 line = 14 ; column = 0 ; value =''; } diff --git a/test/lex_all.suite b/test/lex_all.suite new file mode 100644 index 0000000..13038bc --- /dev/null +++ b/test/lex_all.suite @@ -0,0 +1,32 @@ +test/assign_arithmetic_expression.shd lex +test/basic_property_and_return_value.shd lex +test/complicated_computation.shd lex +test/empty_struct.shd lex +test/empty_vertex_main.shd lex +test/empty_vertex_main_with_position_parameter.shd lex +test/field_assignment.shd lex +test/field_without_type_specifier.shd lex +test/float_suffix.shd lex +test/function_call.shd lex +test/function_call_out_of_order_declaration.shd lex +test/function_call_return.shd lex +test/functions_with_same_name.shd lex +test/function_with_int_return.shd lex +test/meta_block.shd lex +test/multiple_functions.shd lex +test/multiple_semicolons_everywhere.shd lex +test/pass_and_access_struct_fields_in_functions.shd lex +test/passthrough.shd lex +test/property_rename.shd lex +test/redeclared_variable.shd lex +test/simple_struct_access.shd lex +test/struct_access_primitive_type.shd lex +test/struct_within_struct.shd lex +test/type_as_variable_name.shd lex +test/undeclared_function.shd lex +test/undeclared_symbol.shd lex +test/unknown_overload.shd lex +test/use_builtin_functions.shd lex +test/wrong_argument_count.shd lex +test/wrong_multiply.shd lex +test/wrong_type_for_function.shd lex diff --git a/test/meta_block.shd b/test/meta_block.shd new file mode 100644 index 0000000..1c2695b --- /dev/null +++ b/test/meta_block.shd @@ -0,0 +1,16 @@ +meta { + name : LitBasic; + category : Scene; +} + +properties { + color : float4; +} + +vertex main :: (pos : float3 @position, uv : float2 @uv) -> float3 @position { + return pos; +} + +pixel main :: () -> float4 @target0 { + return properties.color; +} diff --git a/test/multiple_functions.shd b/test/multiple_functions.shd new file mode 100644 index 0000000..6deaf30 --- /dev/null +++ b/test/multiple_functions.shd @@ -0,0 +1,12 @@ +foo :: () -> int { + return 5; +} + +bar :: () -> float { + return 1235.0 * 500; +} + +vertex main :: () { + x : int = foo(); + y : float = bar(); +} diff --git a/test/multiple_semicolons_everywhere.shd b/test/multiple_semicolons_everywhere.shd new file mode 100644 index 0000000..0db69de --- /dev/null +++ b/test/multiple_semicolons_everywhere.shd @@ -0,0 +1,14 @@ +vertex main :: (pos : float3 @position) -> float3 @position { + return pos;;; +} + +foo :: () -> float4 { + return float4(1.0, 1.0, 1.0, 1.0);;; +} + +pixel main :: () -> float4 @target0 { + y : float4 = foo();;;; + ;; + color : float4 = y; + return color; +} diff --git a/test/parse/assign_arithmetic_expression.golden b/test/parse/assign_arithmetic_expression.golden new file mode 100644 index 0000000..75418c8 --- /dev/null +++ b/test/parse/assign_arithmetic_expression.golden @@ -0,0 +1,4 @@ +(program + (fun vertex vs_main + [] + (:= x float (+ 2 5)))) \ No newline at end of file diff --git a/test/parse/basic_property_and_return_value.golden b/test/parse/basic_property_and_return_value.golden new file mode 100644 index 0000000..872ae3d --- /dev/null +++ b/test/parse/basic_property_and_return_value.golden @@ -0,0 +1,11 @@ +(program + (properties + [(:= color float4)]) + + (fun vertex vs_main -> float3 (@position) + [(:= pos float3 (@position))] + (return pos)) + + (fun pixel ps_main -> float4 (@target0) + [] + (return properties.color))) \ No newline at end of file diff --git a/test/parse/complicated_computation.golden b/test/parse/complicated_computation.golden new file mode 100644 index 0000000..0b3f2a7 --- /dev/null +++ b/test/parse/complicated_computation.golden @@ -0,0 +1,6 @@ +(program + (fun vertex vs_main + [] + (:= x float 5) + (:= y float 3000) + (:= z float (+ (* y y) x)))) \ No newline at end of file diff --git a/test/parse/empty_struct.golden b/test/parse/empty_struct.golden new file mode 100644 index 0000000..958643d --- /dev/null +++ b/test/parse/empty_struct.golden @@ -0,0 +1,3 @@ +(program + (struct Foo + [])) \ No newline at end of file diff --git a/test/parse/empty_vertex_main.golden b/test/parse/empty_vertex_main.golden new file mode 100644 index 0000000..05724ee --- /dev/null +++ b/test/parse/empty_vertex_main.golden @@ -0,0 +1,3 @@ +(program + (fun vertex vs_main + [])) \ No newline at end of file diff --git a/test/parse/empty_vertex_main_with_position_parameter.golden b/test/parse/empty_vertex_main_with_position_parameter.golden new file mode 100644 index 0000000..55ac1b1 --- /dev/null +++ b/test/parse/empty_vertex_main_with_position_parameter.golden @@ -0,0 +1,4 @@ +(program + (fun vertex vs_main -> float3 + [(:= pos float3 (@position))] + (return pos))) \ No newline at end of file diff --git a/test/parse/field_assignment.golden b/test/parse/field_assignment.golden new file mode 100644 index 0000000..98b9338 --- /dev/null +++ b/test/parse/field_assignment.golden @@ -0,0 +1,5 @@ +(program + (fun vertex vs_main -> float4 (@position) + [(:= pos float4 (@position))] + (:= x float 5) + (= x 7))) \ No newline at end of file diff --git a/test/parse/field_without_type_specifier.golden b/test/parse/field_without_type_specifier.golden new file mode 100644 index 0000000..d3f51d8 --- /dev/null +++ b/test/parse/field_without_type_specifier.golden @@ -0,0 +1,4 @@ +test/field_without_type_specifier.shd:2,0: error: Expected type specifier after field name. + x := 5.0; + ^ + \ No newline at end of file diff --git a/test/parse/foreign_function.golden b/test/parse/foreign_function.golden new file mode 100644 index 0000000..d7c7968 --- /dev/null +++ b/test/parse/foreign_function.golden @@ -0,0 +1,15 @@ +(program + (foreign fun float2 -> float2 + [(:= float) + (:= float)]) + + (foreign fun float3 -> float3 + [(:= float) + (:= float) + (:= float)]) + + (foreign fun float4 -> float4 + [(:= float) + (:= float) + (:= float) + (:= float)])) \ No newline at end of file diff --git a/test/parse/foreign_overload.golden b/test/parse/foreign_overload.golden new file mode 100644 index 0000000..8cfe34b --- /dev/null +++ b/test/parse/foreign_overload.golden @@ -0,0 +1,26 @@ +(program + (foreign fun mul -> float2 + [(:= float2) + (:= float2)]) + + (foreign fun mul -> float3 + [(:= float3) + (:= float3)]) + + (foreign fun mul -> float4 + [(:= float4) + (:= float4)]) + + (foreign fun mul -> float4x4 + [(:= float4x4) + (:= float4x4)]) + + (foreign fun float2 -> float2 + [(:= float) + (:= float)]) + + (fun vertex vs_main + [] + (:= v1 float2 (float2 1 1)) + (:= v2 float2 (float2 3 3)) + (:= v3 float2 (mul v1 v2)))) \ No newline at end of file diff --git a/test/parse/function_call.golden b/test/parse/function_call.golden new file mode 100644 index 0000000..08645cd --- /dev/null +++ b/test/parse/function_call.golden @@ -0,0 +1,8 @@ +(program + (fun foo -> int + [] + (return 4)) + + (fun vertex vs_main + [] + (foo))) \ No newline at end of file diff --git a/test/parse/function_call_out_of_order_declaration.golden b/test/parse/function_call_out_of_order_declaration.golden new file mode 100644 index 0000000..37a74df --- /dev/null +++ b/test/parse/function_call_out_of_order_declaration.golden @@ -0,0 +1,7 @@ +(program + (fun vertex vs_main + [] + (foo)) + + (fun foo + [])) \ No newline at end of file diff --git a/test/parse/function_call_return.golden b/test/parse/function_call_return.golden new file mode 100644 index 0000000..991be8a --- /dev/null +++ b/test/parse/function_call_return.golden @@ -0,0 +1,7 @@ +(program + (fun vertex vs_main + []) + + (fun pixel ps_main -> float4 (@target0) + [] + (return (float4 1 1 1 1)))) \ No newline at end of file diff --git a/test/parse/function_with_int_return.golden b/test/parse/function_with_int_return.golden new file mode 100644 index 0000000..a2b901d --- /dev/null +++ b/test/parse/function_with_int_return.golden @@ -0,0 +1,3 @@ +(program + (fun vertex vs_main -> int + [(:= pos float3)])) \ No newline at end of file diff --git a/test/parse/functions_with_same_name.golden b/test/parse/functions_with_same_name.golden new file mode 100644 index 0000000..99a19ed --- /dev/null +++ b/test/parse/functions_with_same_name.golden @@ -0,0 +1,12 @@ +(program + (fun foo + []) + + (fun foo + []) + + (fun bar + []) + + (fun vertex vs_main + [])) \ No newline at end of file diff --git a/test/parse/meta_block.golden b/test/parse/meta_block.golden new file mode 100644 index 0000000..588da3d --- /dev/null +++ b/test/parse/meta_block.golden @@ -0,0 +1,16 @@ +(program + (meta + [(:= name LitBasic) + (:= category Scene)]) + + (properties + [(:= color float4)]) + + (fun vertex vs_main -> float3 (@position) + [(:= pos float3 (@position)) + (:= uv float2 (@uv))] + (return pos)) + + (fun pixel ps_main -> float4 (@target0) + [] + (return properties.color))) \ No newline at end of file diff --git a/test/parse/multiple_functions.golden b/test/parse/multiple_functions.golden new file mode 100644 index 0000000..ef863b9 --- /dev/null +++ b/test/parse/multiple_functions.golden @@ -0,0 +1,13 @@ +(program + (fun foo -> int + [] + (return 5)) + + (fun bar -> float + [] + (return (* 1235 500))) + + (fun vertex vs_main + [] + (:= x int (foo)) + (:= y float (bar)))) \ No newline at end of file diff --git a/test/parse/multiple_semicolons_everywhere.golden b/test/parse/multiple_semicolons_everywhere.golden new file mode 100644 index 0000000..98c8308 --- /dev/null +++ b/test/parse/multiple_semicolons_everywhere.golden @@ -0,0 +1,14 @@ +(program + (fun vertex vs_main -> float3 (@position) + [(:= pos float3 (@position))] + (return pos)) + + (fun foo -> float4 + [] + (return (float4 1 1 1 1))) + + (fun pixel ps_main -> float4 (@target0) + [] + (:= y float4 (foo)) + (:= color float4 y) + (return color))) \ No newline at end of file diff --git a/test/parse/pass_and_access_struct_fields_in_functions.golden b/test/parse/pass_and_access_struct_fields_in_functions.golden new file mode 100644 index 0000000..e6f79e8 --- /dev/null +++ b/test/parse/pass_and_access_struct_fields_in_functions.golden @@ -0,0 +1,13 @@ +(program + (struct Foo + [(:= some_data float)]) + + (fun foo -> float + [(:= f Foo)] + (return (* f.some_data 2))) + + (fun vertex vs_main + [] + (:= f Foo) + (= f.some_data 4) + (:= d float (foo f)))) \ No newline at end of file diff --git a/test/parse/passthrough.golden b/test/parse/passthrough.golden new file mode 100644 index 0000000..03ae03e --- /dev/null +++ b/test/parse/passthrough.golden @@ -0,0 +1,8 @@ +(program + (fun vertex vs_main -> float3 (@position) + [(:= pos float3 (@position))] + (return pos)) + + (fun pixel ps_main -> float4 (@target0) + [] + (return (float4 1 1 1 1)))) \ No newline at end of file diff --git a/test/parse/precedence_test.golden b/test/parse/precedence_test.golden new file mode 100644 index 0000000..94c7827 --- /dev/null +++ b/test/parse/precedence_test.golden @@ -0,0 +1,7 @@ +(program + (fun vertex vs_main + [] + (:= x float 2) + (:= y float 5) + (:= z float 10) + (:= w float (+ (* x y) (* y (- z (/ x (* y x)))))))) \ No newline at end of file diff --git a/test/parse/redeclared_variable.golden b/test/parse/redeclared_variable.golden new file mode 100644 index 0000000..d147f29 --- /dev/null +++ b/test/parse/redeclared_variable.golden @@ -0,0 +1,5 @@ +(program + (fun vertex vs_main + [] + (:= x float 1) + (:= x float 5))) \ No newline at end of file diff --git a/test/parse/simple_struct_access.golden b/test/parse/simple_struct_access.golden new file mode 100644 index 0000000..885933f --- /dev/null +++ b/test/parse/simple_struct_access.golden @@ -0,0 +1,8 @@ +(program + (struct Data + [(:= color float4)]) + + (fun vertex vs_main + [] + (:= d Data) + (:= x float4 d.color))) \ No newline at end of file diff --git a/test/parse/struct_access_primitive_type.golden b/test/parse/struct_access_primitive_type.golden new file mode 100644 index 0000000..3cf9f4a --- /dev/null +++ b/test/parse/struct_access_primitive_type.golden @@ -0,0 +1,5 @@ +(program + (fun vertex vs_main + [] + (:= x int 5) + (= x.d 4))) \ No newline at end of file diff --git a/test/parse/struct_field_access_test.golden b/test/parse/struct_field_access_test.golden new file mode 100644 index 0000000..1eac9b0 --- /dev/null +++ b/test/parse/struct_field_access_test.golden @@ -0,0 +1,31 @@ +(program + (struct Vertex_Out + [(:= position float3 (@position)) + (:= normal float3 (@normal)) + (:= uv float3 (@uv)) + (:= frag_pos float3 (@interp))]) + + (instance + [(:= model float4x4 (@model))]) + + (fun vertex main + [(:= position float3 (@position)) + (:= uv float2 (@uv)) + (:= normal float3 (@normal))] + (:= v_out Vertex_Out) + (= v_out.position (mul position model)) + (= v_out.normal normal) + (= v_out.uv uv) + (= v_out.frag_pos position) + (return v_out)) + + (struct Pixel_Out + [(:= color float4 (@target0)) + (:= emission float4 (@target1))]) + + (fun pixel main + [(:= v_in Vertex_Out)] + (:= p_out Pixel_Out) + (= p_out.color (float4 1 0.5 1 1)) + (= p_out.emission (float4 2 2 2 2)) + (return p_out))) \ No newline at end of file diff --git a/test/parse/struct_within_struct.golden b/test/parse/struct_within_struct.golden new file mode 100644 index 0000000..4a446fc --- /dev/null +++ b/test/parse/struct_within_struct.golden @@ -0,0 +1,12 @@ +(program + (struct Foo + [(:= color float4)]) + + (struct Bar + [(:= t Foo)]) + + (fun vertex vs_main + [] + (:= f Foo) + (:= b Bar) + (= b.t f))) \ No newline at end of file diff --git a/test/parse/type_as_function_name.golden b/test/parse/type_as_function_name.golden new file mode 100644 index 0000000..a18c0e0 --- /dev/null +++ b/test/parse/type_as_function_name.golden @@ -0,0 +1,3 @@ +(program + (fun int + [])) \ No newline at end of file diff --git a/test/parse/type_as_variable_name.golden b/test/parse/type_as_variable_name.golden new file mode 100644 index 0000000..e9b253f --- /dev/null +++ b/test/parse/type_as_variable_name.golden @@ -0,0 +1,4 @@ +(program + (fun vertex vs_main + [] + (:= int float 4))) \ No newline at end of file diff --git a/test/parse/undeclared_function.golden b/test/parse/undeclared_function.golden new file mode 100644 index 0000000..3b8dc2c --- /dev/null +++ b/test/parse/undeclared_function.golden @@ -0,0 +1,4 @@ +(program + (fun vertex vs_main + [] + (foo))) \ No newline at end of file diff --git a/test/parse/undeclared_symbol.golden b/test/parse/undeclared_symbol.golden new file mode 100644 index 0000000..12f6b40 --- /dev/null +++ b/test/parse/undeclared_symbol.golden @@ -0,0 +1,4 @@ +(program + (fun vertex vs_main + [] + (:= b int f))) \ No newline at end of file diff --git a/test/parse/unknown_overload.golden b/test/parse/unknown_overload.golden new file mode 100644 index 0000000..0eacd96 --- /dev/null +++ b/test/parse/unknown_overload.golden @@ -0,0 +1,14 @@ +(program + (fun foo + [(:= v1 float3) + (:= v2 float3)]) + + (fun foo + [(:= v1 float2) + (:= v2 float2) + (:= v3 float2)]) + + (fun vertex vs_main + [] + (:= v float 2) + (foo v v))) \ No newline at end of file diff --git a/test/parse/use_builtin_functions.golden b/test/parse/use_builtin_functions.golden new file mode 100644 index 0000000..ce3f292 --- /dev/null +++ b/test/parse/use_builtin_functions.golden @@ -0,0 +1,4 @@ +(program + (fun vertex vs_main + [] + (:= f float4 (float4 1 1 1 1)))) \ No newline at end of file diff --git a/test/parse/wrong_argument_count.golden b/test/parse/wrong_argument_count.golden new file mode 100644 index 0000000..02bd703 --- /dev/null +++ b/test/parse/wrong_argument_count.golden @@ -0,0 +1,17 @@ +(program + (fun foo -> float + [(:= x float) + (:= y float) + (:= z float)] + (return (* (* x y) z))) + + (fun foo -> float + [(:= x float) + (:= y float) + (:= z float) + (:= w float)] + (return (* (* (* x y) z) w))) + + (fun vertex vs_main + [] + (foo 2 3))) \ No newline at end of file diff --git a/test/parse/wrong_multiply.golden b/test/parse/wrong_multiply.golden new file mode 100644 index 0000000..3dc2f46 --- /dev/null +++ b/test/parse/wrong_multiply.golden @@ -0,0 +1,7 @@ +(program + (fun vertex vs_main -> float4 (@position) + [(:= pos float4 (@position))] + (:= res float2 (float2 2 2)) + (:= foo float 1) + (:= result float4 (float4 1 (* foo res) 0 1)) + (return result))) \ No newline at end of file diff --git a/test/parse/wrong_type_for_function.golden b/test/parse/wrong_type_for_function.golden new file mode 100644 index 0000000..937494b --- /dev/null +++ b/test/parse/wrong_type_for_function.golden @@ -0,0 +1,14 @@ +(program + (fun vertex vs_main -> float3 (@position) + [(:= pos float3 (@position))] + (return pos)) + + (fun foo -> float2 + [] + (return (float2 1 1))) + + (fun pixel ps_main -> float4 (@target0) + [] + (:= y float2 (foo)) + (:= color float4 (float4 y 1 1 1)) + (return color))) \ No newline at end of file diff --git a/test/parse_all.suite b/test/parse_all.suite new file mode 100644 index 0000000..158b1ae --- /dev/null +++ b/test/parse_all.suite @@ -0,0 +1,32 @@ +test/assign_arithmetic_expression.shd parse +test/basic_property_and_return_value.shd parse +test/complicated_computation.shd parse +test/empty_struct.shd parse +test/empty_vertex_main.shd parse +test/empty_vertex_main_with_position_parameter.shd parse +test/field_assignment.shd parse +test/field_without_type_specifier.shd parse +test/float_suffix.shd parse +test/function_call.shd parse +test/function_call_out_of_order_declaration.shd parse +test/function_call_return.shd parse +test/functions_with_same_name.shd parse +test/function_with_int_return.shd parse +test/meta_block.shd parse +test/multiple_functions.shd parse +test/multiple_semicolons_everywhere.shd parse +test/pass_and_access_struct_fields_in_functions.shd parse +test/passthrough.shd parse +test/property_rename.shd parse +test/redeclared_variable.shd parse +test/simple_struct_access.shd parse +test/struct_access_primitive_type.shd parse +test/struct_within_struct.shd parse +test/type_as_variable_name.shd parse +test/undeclared_function.shd parse +test/undeclared_symbol.shd parse +test/unknown_overload.shd parse +test/use_builtin_functions.shd parse +test/wrong_argument_count.shd parse +test/wrong_multiply.shd parse +test/wrong_type_for_function.shd parse diff --git a/test/pass_and_access_struct_fields_in_functions.shd b/test/pass_and_access_struct_fields_in_functions.shd new file mode 100644 index 0000000..ab849c0 --- /dev/null +++ b/test/pass_and_access_struct_fields_in_functions.shd @@ -0,0 +1,13 @@ +Foo :: struct { + some_data : float; +} + +foo :: (f : Foo) -> float { + return f.some_data * 2.0; +} + +vertex main :: () { + f : Foo; + f.some_data = 4.0; + d : float = foo(f); +} diff --git a/test/passthrough.shd b/test/passthrough.shd new file mode 100644 index 0000000..98b8204 --- /dev/null +++ b/test/passthrough.shd @@ -0,0 +1,7 @@ +vertex main :: (pos : float3 @position) -> float3 @position { + return pos; +} + +pixel main :: () -> float4 @target0 { + return float4(1.0, 1.0, 1.0, 1.0); +} diff --git a/test/precedence_test.shd b/test/precedence_test.shd new file mode 100644 index 0000000..1cb0672 --- /dev/null +++ b/test/precedence_test.shd @@ -0,0 +1,7 @@ +vertex main :: () { + x : float = 2.0; + y : float = 5.0; + z : float = 10.0; + + w : float = (x * y) + y * (z - x / (y * x)); +} diff --git a/test/property_rename.shd b/test/property_rename.shd new file mode 100644 index 0000000..8367a5a --- /dev/null +++ b/test/property_rename.shd @@ -0,0 +1,11 @@ +props :: properties { + color : float4; +} + +vertex main :: (pos : float4 @position) -> float4 @position { + return pos; +} + +pixel main :: () -> float4 @target0 { + return props.color; +} diff --git a/test/redeclared_variable.shd b/test/redeclared_variable.shd new file mode 100644 index 0000000..72181a8 --- /dev/null +++ b/test/redeclared_variable.shd @@ -0,0 +1,4 @@ +vertex main :: () { + x : float = 1.0; + x : float = 5.0; +} diff --git a/test/semant/assign_arithmetic_expression.golden b/test/semant/assign_arithmetic_expression.golden new file mode 100644 index 0000000..d17a764 --- /dev/null +++ b/test/semant/assign_arithmetic_expression.golden @@ -0,0 +1,6 @@ +scope (global) [ + [vertex__vs_main] : () + scope (vertex__vs_main) [ + [x] : float + ] +] diff --git a/test/semant/basic_property_and_return_value.golden b/test/semant/basic_property_and_return_value.golden new file mode 100644 index 0000000..6f84e05 --- /dev/null +++ b/test/semant/basic_property_and_return_value.golden @@ -0,0 +1,12 @@ +scope (global) [ + [pixel__ps_main] : () -> float4 + [vertex__vs_main] : (pos : float3) -> float3 + [properties] : {color : float4} + scope (properties) [ + [color] : float4 + ] + scope (vertex__vs_main) [ + [pos] : float3 + ] + scope (pixel__ps_main) [] +] diff --git a/test/semant/complicated_computation.golden b/test/semant/complicated_computation.golden new file mode 100644 index 0000000..e0affca --- /dev/null +++ b/test/semant/complicated_computation.golden @@ -0,0 +1,8 @@ +scope (global) [ + [vertex__vs_main] : () + scope (vertex__vs_main) [ + [x] : float + [z] : float + [y] : float + ] +] diff --git a/test/semant/empty_struct.golden b/test/semant/empty_struct.golden new file mode 100644 index 0000000..883a0b6 --- /dev/null +++ b/test/semant/empty_struct.golden @@ -0,0 +1,4 @@ +scope (global) [ + [Foo] : {} + scope (Foo) [] +] diff --git a/test/semant/empty_vertex_main.golden b/test/semant/empty_vertex_main.golden new file mode 100644 index 0000000..38cee29 --- /dev/null +++ b/test/semant/empty_vertex_main.golden @@ -0,0 +1,4 @@ +scope (global) [ + [vertex__vs_main] : () + scope (vertex__vs_main) [] +] diff --git a/test/semant/empty_vertex_main_with_position_parameter.golden b/test/semant/empty_vertex_main_with_position_parameter.golden new file mode 100644 index 0000000..078d32e --- /dev/null +++ b/test/semant/empty_vertex_main_with_position_parameter.golden @@ -0,0 +1,6 @@ +scope (global) [ + [vertex__vs_main] : (pos : float3) -> float3 + scope (vertex__vs_main) [ + [pos] : float3 + ] +] diff --git a/test/semant/field_assignment.golden b/test/semant/field_assignment.golden new file mode 100644 index 0000000..2e01cf4 --- /dev/null +++ b/test/semant/field_assignment.golden @@ -0,0 +1,7 @@ +scope (global) [ + [vertex__vs_main] : (pos : float4) + scope (vertex__vs_main) [ + [x] : float + [pos] : float4 + ] +] diff --git a/test/semant/field_without_type_specifier.golden b/test/semant/field_without_type_specifier.golden new file mode 100644 index 0000000..d3f51d8 --- /dev/null +++ b/test/semant/field_without_type_specifier.golden @@ -0,0 +1,4 @@ +test/field_without_type_specifier.shd:2,0: error: Expected type specifier after field name. + x := 5.0; + ^ + \ No newline at end of file diff --git a/test/semant/float_suffix.golden b/test/semant/float_suffix.golden new file mode 100644 index 0000000..b5bf71b --- /dev/null +++ b/test/semant/float_suffix.golden @@ -0,0 +1,4 @@ +test/float_suffix.shd:2,12: error: We don't use 'f' suffixes for floating point values. + x : float = 2.0f + ^^^^ + \ No newline at end of file diff --git a/test/semant/function_call.golden b/test/semant/function_call.golden new file mode 100644 index 0000000..b6710d7 --- /dev/null +++ b/test/semant/function_call.golden @@ -0,0 +1,6 @@ +scope (global) [ + [foo] : () -> int + [vertex__vs_main] : () + scope (foo) [] + scope (vertex__vs_main) [] +] diff --git a/test/semant/function_call_out_of_order_declaration.golden b/test/semant/function_call_out_of_order_declaration.golden new file mode 100644 index 0000000..26a6aa9 --- /dev/null +++ b/test/semant/function_call_out_of_order_declaration.golden @@ -0,0 +1,6 @@ +scope (global) [ + [foo] : () + [vertex__vs_main] : () + scope (vertex__vs_main) [] + scope (foo) [] +] diff --git a/test/semant/function_call_return.golden b/test/semant/function_call_return.golden new file mode 100644 index 0000000..91b7254 --- /dev/null +++ b/test/semant/function_call_return.golden @@ -0,0 +1,6 @@ +scope (global) [ + [pixel__ps_main] : () -> float4 + [vertex__vs_main] : () + scope (vertex__vs_main) [] + scope (pixel__ps_main) [] +] diff --git a/test/semant/function_with_int_return.golden b/test/semant/function_with_int_return.golden new file mode 100644 index 0000000..261f982 --- /dev/null +++ b/test/semant/function_with_int_return.golden @@ -0,0 +1,6 @@ +scope (global) [ + [vertex__vs_main] : (pos : float3) + scope (vertex__vs_main) [ + [pos] : float3 + ] +] diff --git a/test/semant/functions_with_same_name.golden b/test/semant/functions_with_same_name.golden new file mode 100644 index 0000000..53fee92 --- /dev/null +++ b/test/semant/functions_with_same_name.golden @@ -0,0 +1,8 @@ +test/functions_with_same_name.shd:2,0: error: Redeclaration of 'foo' + foo :: () { + ^^^ + +test/functions_with_same_name.shd:1,0: info: Here is the first declaration of 'foo' + foo :: () { + ^^^ + \ No newline at end of file diff --git a/test/semant/meta_block.golden b/test/semant/meta_block.golden new file mode 100644 index 0000000..5d9be1e --- /dev/null +++ b/test/semant/meta_block.golden @@ -0,0 +1,13 @@ +scope (global) [ + [pixel__ps_main] : () -> float4 + [vertex__vs_main] : (pos : float3, uv : float2) -> float3 + [properties] : properties + scope (properties) [ + [color] : float4 + ] + scope (vertex__vs_main) [ + [pos] : float3 + [uv] : float2 + ] + scope (pixel__ps_main) [] +] diff --git a/test/semant/multiple_functions.golden b/test/semant/multiple_functions.golden new file mode 100644 index 0000000..4362a5b --- /dev/null +++ b/test/semant/multiple_functions.golden @@ -0,0 +1,11 @@ +scope (global) [ + [foo] : () -> int + [vertex__vs_main] : () + [bar] : () -> float + scope (foo) [] + scope (bar) [] + scope (vertex__vs_main) [ + [x] : int + [y] : float + ] +] diff --git a/test/semant/multiple_semicolons_everywhere.golden b/test/semant/multiple_semicolons_everywhere.golden new file mode 100644 index 0000000..9eadf9c --- /dev/null +++ b/test/semant/multiple_semicolons_everywhere.golden @@ -0,0 +1,13 @@ +scope (global) [ + [pixel__ps_main] : () -> float4 + [foo] : () -> float4 + [vertex__vs_main] : (pos : float3) -> float3 + scope (vertex__vs_main) [ + [pos] : float3 + ] + scope (foo) [] + scope (pixel__ps_main) [ + [y] : float4 + [color] : float4 + ] +] diff --git a/test/semant/pass_and_access_struct_fields_in_functions.golden b/test/semant/pass_and_access_struct_fields_in_functions.golden new file mode 100644 index 0000000..a048c59 --- /dev/null +++ b/test/semant/pass_and_access_struct_fields_in_functions.golden @@ -0,0 +1,15 @@ +scope (global) [ + [foo] : (f : Foo) -> float + [vertex__vs_main] : () + [Foo] : {some_data : float} + scope (Foo) [ + [some_data] : float + ] + scope (foo) [ + [f] : Foo + ] + scope (vertex__vs_main) [ + [d] : float + [f] : Foo + ] +] diff --git a/test/semant/passthrough.golden b/test/semant/passthrough.golden new file mode 100644 index 0000000..81f0bde --- /dev/null +++ b/test/semant/passthrough.golden @@ -0,0 +1,8 @@ +scope (global) [ + [pixel__ps_main] : () -> float4 + [vertex__vs_main] : (pos : float3) -> float3 + scope (vertex__vs_main) [ + [pos] : float3 + ] + scope (pixel__ps_main) [] +] diff --git a/test/semant/precedence_test.golden b/test/semant/precedence_test.golden new file mode 100644 index 0000000..d8e6aed --- /dev/null +++ b/test/semant/precedence_test.golden @@ -0,0 +1,9 @@ +scope (global) [ + [vertex__vs_main] : (x : float, y : float, z : float, w : float) + scope (vertex__vs_main) [ + [x] : float + [z] : float + [y] : float + [w] : float + ] +] diff --git a/test/semant/redeclared_variable.golden b/test/semant/redeclared_variable.golden new file mode 100644 index 0000000..5365fcb --- /dev/null +++ b/test/semant/redeclared_variable.golden @@ -0,0 +1,8 @@ +test/redeclared_variable.shd:3,0: error: Redeclaration of 'x' + x : float = 5.0 + ^ + +test/redeclared_variable.shd:2,0: info: Here is the first declaration of 'x' + x : float = 1.0 + ^ + \ No newline at end of file diff --git a/test/semant/simple_struct_access.golden b/test/semant/simple_struct_access.golden new file mode 100644 index 0000000..41a65bd --- /dev/null +++ b/test/semant/simple_struct_access.golden @@ -0,0 +1,11 @@ +scope (global) [ + [Data] : {color : float4} + [vertex__vs_main] : () + scope (Data) [ + [color] : float4 + ] + scope (vertex__vs_main) [ + [x] : float4 + [d] : Data + ] +] diff --git a/test/semant/struct_access_primitive_type.golden b/test/semant/struct_access_primitive_type.golden new file mode 100644 index 0000000..466f3b9 --- /dev/null +++ b/test/semant/struct_access_primitive_type.golden @@ -0,0 +1,6 @@ +test/struct_access_primitive_type.shd:3,0: error: Attempting to access a field on a primitive type 'int'. + x.d = 4; + ^ + declaration: + x : int = 5 + \ No newline at end of file diff --git a/test/semant/struct_within_struct.golden b/test/semant/struct_within_struct.golden new file mode 100644 index 0000000..c7339f0 --- /dev/null +++ b/test/semant/struct_within_struct.golden @@ -0,0 +1,15 @@ +scope (global) [ + [Bar] : {t : Foo} + [vertex__vs_main] : () + [Foo] : {color : float4} + scope (Foo) [ + [color] : float4 + ] + scope (Bar) [ + [t] : Foo + ] + scope (vertex__vs_main) [ + [b] : Bar + [f] : Foo + ] +] diff --git a/test/semant/type_as_function_name.golden b/test/semant/type_as_function_name.golden new file mode 100644 index 0000000..cc4d143 --- /dev/null +++ b/test/semant/type_as_function_name.golden @@ -0,0 +1,4 @@ +test/type_as_function_name.shd:1,0: error: Invalid function name 'int' + int :: () { + ^^^ + \ No newline at end of file diff --git a/test/semant/type_as_variable_name.golden b/test/semant/type_as_variable_name.golden new file mode 100644 index 0000000..20bc8d9 --- /dev/null +++ b/test/semant/type_as_variable_name.golden @@ -0,0 +1,4 @@ +test/type_as_variable_name.shd:2,0: error: Invalid variable name 'int' + int : float = 4.0 + ^^^ + \ No newline at end of file diff --git a/test/semant/undeclared_function.golden b/test/semant/undeclared_function.golden new file mode 100644 index 0000000..fb159b8 --- /dev/null +++ b/test/semant/undeclared_function.golden @@ -0,0 +1,7 @@ +test/undeclared_function.shd:2,0: error: Attempt to call undeclared function 'foo'. + + foo(); + ^^^ + + + \ No newline at end of file diff --git a/test/semant/undeclared_symbol.golden b/test/semant/undeclared_symbol.golden new file mode 100644 index 0000000..445c854 --- /dev/null +++ b/test/semant/undeclared_symbol.golden @@ -0,0 +1,4 @@ +test/undeclared_symbol.shd:2,10: error: Use of undeclared symbol 'f' + b : int = f; + ^ + \ No newline at end of file diff --git a/test/semant/unknown_overload.golden b/test/semant/unknown_overload.golden new file mode 100644 index 0000000..fb7f709 --- /dev/null +++ b/test/semant/unknown_overload.golden @@ -0,0 +1,33 @@ +test/unknown_overload.shd:6,0: error: Procedure call did not match any of the possible overloads for 'foo' + found: + foo(v, v); + ^^^ + + While matching argument 1 in function call. + foo(v, v); + ^ + Possible overloads: + foo :: (v1 : float3, v2 : float3) { (test/unknown_overload.shd:1) + foo :: (v1 : float2, v2 : float2, v3 : float2) { (test/unknown_overload.shd:2) + +test/unknown_overload.shd:6,4: error: Type mismatch. Expected float3 got float + found: + foo(v, v); + ^ + expected: + float3 + + got: + v : float = 2.0 + +test/unknown_overload.shd:6,7: error: Type mismatch. Expected float3 got float + found: + foo(v, v); + ^ + expected: + float3 + + got: + v : float = 2.0 + + \ No newline at end of file diff --git a/test/semant/use_builtin_functions.golden b/test/semant/use_builtin_functions.golden new file mode 100644 index 0000000..ef03716 --- /dev/null +++ b/test/semant/use_builtin_functions.golden @@ -0,0 +1,6 @@ +scope (global) [ + [vertex__vs_main] : () + scope (vertex__vs_main) [ + [f] : float4 + ] +] diff --git a/test/semant/wrong_argument_count.golden b/test/semant/wrong_argument_count.golden new file mode 100644 index 0000000..d127721 --- /dev/null +++ b/test/semant/wrong_argument_count.golden @@ -0,0 +1,16 @@ +test/wrong_argument_count.shd:5,19: error: Use of undeclared symbol 'w' + return x * y * z * w; + ^ +test/wrong_argument_count.shd:9,0: error: Procedure call did not match any of the possible overloads for 'foo' + found: + foo(2.0, 3.0); + ^^^ + Possible overloads: + foo :: (x : float, y : float, z : float) -> float { (test/wrong_argument_count.shd:1) + Not enough arguments: Wanted 3, got 2. + + foo :: (x : float, y : float, z : float, w : float) -> float { (test/wrong_argument_count.shd:4) + Not enough arguments: Wanted 4, got 2. + + + \ No newline at end of file diff --git a/test/semant/wrong_multiply.golden b/test/semant/wrong_multiply.golden new file mode 100644 index 0000000..a2e935f --- /dev/null +++ b/test/semant/wrong_multiply.golden @@ -0,0 +1,11 @@ +test/wrong_multiply.shd:4,34: error: Type mismatch. Expected float got float2 + found: + result : float4 = float4(1.0, foo * res, 0.0, 1.0); + ^ + expected: + float + + got: + res : float2 = float2(2.0, 2.0) + + \ No newline at end of file diff --git a/test/semant/wrong_type_for_function.golden b/test/semant/wrong_type_for_function.golden new file mode 100644 index 0000000..d14646f --- /dev/null +++ b/test/semant/wrong_type_for_function.golden @@ -0,0 +1,22 @@ +test/wrong_type_for_function.shd: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: + foreign float4 :: (float, float, float, float) -> float4; (test/wrong_type_for_function.shd:79) + +test/wrong_type_for_function.shd: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 new file mode 100644 index 0000000..2ac7b7a --- /dev/null +++ b/test/semant_all.suite @@ -0,0 +1,31 @@ +test/assign_arithmetic_expression.shd semant +test/basic_property_and_return_value.shd semant +test/complicated_computation.shd semant +test/empty_struct.shd semant +test/empty_vertex_main.shd semant +test/empty_vertex_main_with_position_parameter.shd semant +test/field_assignment.shd semant +test/field_without_type_specifier.shd semant +test/float_suffix.shd semant +test/function_call.shd semant +test/function_call_out_of_order_declaration.shd semant +test/function_call_return.shd semant +test/functions_with_same_name.shd semant +test/function_with_int_return.shd semant +test/multiple_functions.shd semant +test/multiple_semicolons_everywhere.shd semant +test/pass_and_access_struct_fields_in_functions.shd semant +test/passthrough.shd semant +test/property_rename.shd semant +test/redeclared_variable.shd semant +test/simple_struct_access.shd semant +test/struct_access_primitive_type.shd semant +test/struct_within_struct.shd semant +test/type_as_variable_name.shd semant +test/undeclared_function.shd semant +test/undeclared_symbol.shd semant +test/unknown_overload.shd semant +test/use_builtin_functions.shd semant +test/wrong_argument_count.shd semant +test/wrong_multiply.shd semant +test/wrong_type_for_function.shd semant diff --git a/test/simple_struct_access.shd b/test/simple_struct_access.shd new file mode 100644 index 0000000..72cac07 --- /dev/null +++ b/test/simple_struct_access.shd @@ -0,0 +1,8 @@ +Data :: struct { + color : float4; +} + +vertex main :: () { + d : Data; + x : float4 = d.color; +} diff --git a/test/struct_access_primitive_type.shd b/test/struct_access_primitive_type.shd new file mode 100644 index 0000000..9a720a5 --- /dev/null +++ b/test/struct_access_primitive_type.shd @@ -0,0 +1,4 @@ +vertex main :: () { + x : int = 5; + x.d = 4; +} diff --git a/test/struct_with_multiple_members.shd b/test/struct_with_multiple_members.shd new file mode 100644 index 0000000..6617f01 --- /dev/null +++ b/test/struct_with_multiple_members.shd @@ -0,0 +1,5 @@ +Foo :: struct { + color : float4; + pos : float2; + uv : float2; +} diff --git a/test/struct_within_struct.shd b/test/struct_within_struct.shd new file mode 100644 index 0000000..cee1754 --- /dev/null +++ b/test/struct_within_struct.shd @@ -0,0 +1,13 @@ +Foo :: struct { + color : float4; +} + +Bar :: struct { + t : Foo; +} + +vertex main :: () { + f : Foo; + b : Bar; + b.t = f; +} diff --git a/test/type_as_function_name.shd b/test/type_as_function_name.shd new file mode 100644 index 0000000..0b1ca5f --- /dev/null +++ b/test/type_as_function_name.shd @@ -0,0 +1 @@ +int :: () {} diff --git a/test/type_as_variable_name.shd b/test/type_as_variable_name.shd new file mode 100644 index 0000000..8ad8f6c --- /dev/null +++ b/test/type_as_variable_name.shd @@ -0,0 +1,3 @@ +vertex main :: () { + int : float = 4.0; +} diff --git a/test/undeclared_function.shd b/test/undeclared_function.shd new file mode 100644 index 0000000..6ae1ae3 --- /dev/null +++ b/test/undeclared_function.shd @@ -0,0 +1,3 @@ +vertex main :: () { + foo(); +} diff --git a/test/undeclared_symbol.shd b/test/undeclared_symbol.shd new file mode 100644 index 0000000..75aa132 --- /dev/null +++ b/test/undeclared_symbol.shd @@ -0,0 +1,3 @@ +vertex main :: () { + b : int = f; +} diff --git a/test/unknown_overload.shd b/test/unknown_overload.shd new file mode 100644 index 0000000..96fd0f9 --- /dev/null +++ b/test/unknown_overload.shd @@ -0,0 +1,7 @@ +foo :: (v1 : float3, v2 : float3) {} +foo :: (v1 : float2, v2 : float2, v3 : float2) {} + +vertex main :: () { + v : float = 2.0; + foo(v, v); +} diff --git a/test/use_builtin_functions.shd b/test/use_builtin_functions.shd new file mode 100644 index 0000000..b8bd212 --- /dev/null +++ b/test/use_builtin_functions.shd @@ -0,0 +1,3 @@ +vertex main :: () { + f : float4 = float4(1, 1, 1, 1); +} diff --git a/test/wrong_argument_count.shd b/test/wrong_argument_count.shd new file mode 100644 index 0000000..6f3e788 --- /dev/null +++ b/test/wrong_argument_count.shd @@ -0,0 +1,11 @@ +foo :: (x : float, y : float, z : float) -> float { + return x * y * z; +} +foo :: (x : float, y : float, z : float, w : float) -> float { + return x * y * z * w; +} + +vertex main :: () { + foo(2.0, 3.0); +} + diff --git a/test/wrong_multiply.shd b/test/wrong_multiply.shd new file mode 100644 index 0000000..87cd93f --- /dev/null +++ b/test/wrong_multiply.shd @@ -0,0 +1,6 @@ +vertex main :: (pos : float4 @position) -> float4 @position { + res : float2 = float2(2.0, 2.0); + foo : float = 1.0; + result : float4 = float4(1.0, foo * res, 0.0, 1.0); + return result; +} diff --git a/test/wrong_type_for_function.shd b/test/wrong_type_for_function.shd new file mode 100644 index 0000000..cf4fa72 --- /dev/null +++ b/test/wrong_type_for_function.shd @@ -0,0 +1,13 @@ +vertex main :: (pos : float3 @position) -> float3 @position { + return pos; +} + +foo :: () -> float2 { + return float2(1.0, 1.0); +} + +pixel main :: () -> float4 @target0 { + y : float2 = foo(); + color : float4 = float4(y, 1.0, 1.0, 1.0); + return color; +}