From de0254c4e657540bc7c68de0481d83bf3be9b51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szikszai=20Guszt=C3=A1v?= Date: Tue, 8 Aug 2023 16:32:46 +0200 Subject: [PATCH] Refactorings --- spec/compilers/block_with_early_return | 11 +- spec/compilers/block_with_early_return_await | 10 +- ...ructuring => case_with_type_destructuring} | 18 +- spec/compilers/component_instance_access | 20 +- spec/compilers/css_with_if_with_interpolation | 44 + spec/compilers/destructuring | 42 +- spec/compilers/directives/highlight | 15 + spec/compilers/encode | 4 +- spec/compilers/{record_field => field} | 0 spec/compilers/html_attribute_ref | 10 +- spec/compilers/html_fragment | 6 +- spec/compilers/if_let | 12 +- spec/compilers/if_let_await | 12 +- spec/compilers/operation_or | 10 +- spec/compilers/record_constructor | 36 - spec/compilers/record_constructor_partial | 44 - spec/compilers/{enum => type} | 22 +- .../{enum_record => type_with_variants} | 47 +- spec/compilers_spec.cr | 42 +- spec/errors/access_expected_field | 14 + spec/errors/access_field_not_found | 31 + spec/errors/access_not_record | 26 + spec/errors/argument_expected_colon | 16 + spec/errors/argument_expected_default_value | 17 + spec/errors/argument_expected_type | 16 + .../array_access_expected_closing_bracket | 15 + spec/errors/array_access_expected_index | 14 + spec/errors/array_access_index_not_number | 42 + spec/errors/array_access_invalid_tuple | 31 + spec/errors/array_access_not_an_array | 36 + ...ray_destructuring_expected_closing_bracket | 15 + spec/errors/array_expected_closing_bracket | 14 + spec/errors/array_expected_type_or_variable | 19 + spec/errors/array_not_matches | 41 + spec/errors/array_not_matches_defined_type | 41 + ...set_directive_expected_closing_parenthesis | 15 + spec/errors/asset_directive_expected_file | 23 + ...set_directive_expected_opening_parenthesis | 15 + spec/errors/asset_directive_expected_path | 15 + spec/errors/block_no_expressions | 26 + spec/errors/call_argument_size_mismatch | 40 + spec/errors/call_argument_type_mismatch | 42 + spec/errors/call_expected_closing_parenthesis | 18 + spec/errors/call_not_a_function | 34 + spec/errors/call_not_found_argument | 35 + spec/errors/call_with_mixed_arguments | 27 + spec/errors/case_branch_expected_expression | 20 + spec/errors/case_branch_not_matches | 37 + spec/errors/case_expected_branches | 14 + spec/errors/case_expected_closing_bracket | 16 + spec/errors/case_expected_closing_parenthesis | 14 + spec/errors/case_expected_condition | 14 + spec/errors/case_expected_opening_bracket | 14 + spec/errors/case_not_covered | 28 + spec/errors/case_type_not_covered | 38 + spec/errors/case_unnecessary_all | 31 + spec/errors/component_expected_body | 10 + .../errors/component_expected_closing_bracket | 13 + spec/errors/component_expected_name | 13 + .../errors/component_expected_opening_bracket | 11 + spec/errors/component_exposed_name_conflict | 44 + .../component_lifecycle_function_mismatch | 36 + spec/errors/component_main_properties | 36 + spec/errors/component_multiple_exposed | 35 + spec/errors/component_multiple_providers | 38 + spec/errors/component_multiple_stores | 38 + spec/errors/component_no_render_function | 17 + spec/errors/component_reference_name_conflict | 39 + .../errors/component_render_function_mismatch | 30 + spec/errors/component_style_name_conflict | 52 + spec/errors/connect_expected_closing_bracket | 12 + spec/errors/connect_expected_exposing | 13 + spec/errors/connect_expected_keys | 12 + spec/errors/connect_expected_opening_bracket | 12 + spec/errors/connect_expected_store | 13 + spec/errors/connect_not_found_member | 30 + spec/errors/connect_not_found_store | 21 + spec/errors/connect_variable_expected_as | 16 + spec/errors/constant_expected_equal_sign | 12 + spec/errors/constant_expected_expression | 12 + spec/errors/constant_expected_name | 12 + spec/errors/css_definition_expected_semicolon | 14 + spec/errors/css_definition_no_property | 24 + spec/errors/css_definition_type_mismatch | 35 + .../css_font_face_expected_closing_bracket | 17 + .../errors/css_font_face_expected_definitions | 15 + .../css_font_face_expected_opening_bracket | 16 + spec/errors/css_font_face_interpolation | 29 + .../css_keyframes_expected_closing_bracket | 20 + spec/errors/css_keyframes_expected_name | 14 + .../css_keyframes_expected_opening_bracket | 15 + spec/errors/css_keyframes_expected_selectors | 15 + spec/errors/css_nested_at_expected_body | 14 + .../css_nested_at_expected_closing_bracket | 17 + spec/errors/css_nested_at_expected_condition | 14 + .../css_nested_at_expected_opening_bracket | 15 + spec/errors/css_selector_expected_body | 14 + .../css_selector_expected_closing_bracket | 17 + spec/errors/decode_complex_type | 43 + spec/errors/decode_expected_as | 15 + spec/errors/decode_expected_object | 32 + spec/errors/decode_expected_subject | 15 + spec/errors/decode_expected_type | 14 + spec/errors/destructuring_multiple_spreads | 25 + spec/errors/destructuring_tuple_mismatch | 31 + spec/errors/destructuring_type_field_missing | 30 + spec/errors/destructuring_type_mismatch | 35 + spec/errors/destructuring_type_missing | 24 + .../errors/destructuring_type_variant_missing | 40 + .../documentation_directive_entity_not_found | 26 + ...ion_directive_expected_closing_parenthesis | 15 + .../documentation_directive_expected_entity | 15 + ...ion_directive_expected_opening_parenthesis | 15 + spec/errors/encode_complex_type | 39 + spec/errors/encode_expected_expression | 18 + spec/errors/entity_name_conflict | 35 + spec/errors/env_expected_name | 15 + spec/errors/env_not_found_variable | 22 + .../for_array_or_set_arguments_mismatch | 25 + spec/errors/for_condition_type_mismatch | 35 + spec/errors/for_expected_body | 14 + spec/errors/for_expected_closing_bracket | 17 + spec/errors/for_expected_closing_parenthesis | 15 + spec/errors/for_expected_of | 15 + spec/errors/for_expected_opening_bracket | 15 + spec/errors/for_expected_subject | 14 + spec/errors/for_map_arguments_mismatch | 31 + spec/errors/for_type_mismatch | 34 + spec/errors/format_directive_expected_body | 14 + .../format_directive_expected_closing_bracket | 15 + .../format_directive_expected_opening_bracket | 15 + spec/errors/function_argument_conflict | 39 + ...unction_argument_must_have_a_default_value | 28 + spec/errors/function_expected_closing_bracket | 12 + .../function_expected_closing_parenthesis | 13 + spec/errors/function_expected_expression | 12 + spec/errors/function_expected_name | 12 + spec/errors/function_expected_opening_bracket | 12 + .../errors/function_expected_type_or_variable | 12 + spec/errors/function_type_mismatch | 49 + spec/errors/get_expected_closing_bracket | 12 + spec/errors/get_expected_expression | 12 + spec/errors/get_expected_name | 12 + spec/errors/get_expected_opening_bracket | 12 + spec/errors/get_expected_type | 12 + spec/errors/get_type_mismatch | 48 + spec/errors/here_doc_expected_end | 14 + .../here_doc_interpolation_type_mismatch | 32 + spec/errors/here_document_expected_start | 14 + spec/errors/highlight_directive_expected_body | 14 + ...ghlight_directive_expected_closing_bracket | 15 + ...ghlight_directive_expected_opening_bracket | 15 + ...html_attribute_component_key_type_mismatch | 36 + ...attribute_component_property_type_mismatch | 39 + ..._attribute_element_attribute_type_mismatch | 29 + .../html_attribute_expected_closing_bracket | 15 + .../errors/html_attribute_expected_equal_sign | 15 + .../errors/html_attribute_expected_expression | 15 + .../html_attribute_expected_opening_bracket | 15 + ...tml_attribute_not_found_component_property | 36 + spec/errors/html_component_attribute_required | 40 + .../html_component_expected_closing_bracket | 15 + .../html_component_expected_closing_tag | 15 + spec/errors/html_component_expected_reference | 15 + spec/errors/html_component_global_component | 28 + .../errors/html_component_not_found_component | 22 + ...l_component_reference_outside_of_component | 32 + spec/errors/html_content_type_mismatch | 29 + .../html_element_expected_closing_bracket | 15 + spec/errors/html_element_expected_closing_tag | 18 + spec/errors/html_element_expected_reference | 14 + spec/errors/html_element_expected_style | 14 + spec/errors/html_element_ref_forbidden | 22 + ...tml_element_reference_outside_of_component | 26 + .../html_element_style_outside_of_component | 26 + .../html_expression_expected_closing_tag | 15 + .../errors/html_fragment_expected_closing_tag | 15 + spec/errors/html_style_argument_size_mismatch | 24 + spec/errors/html_style_argument_type_mismatch | 34 + .../html_style_expected_closing_parenthesis | 15 + spec/errors/html_style_not_found | 18 + spec/errors/if_condition_type_mismatch | 29 + spec/errors/if_else_type_mismatch | 37 + spec/errors/if_expected_closing_parenthesis | 15 + spec/errors/if_expected_condition | 14 + spec/errors/if_expected_else_closing_bracket | 15 + spec/errors/if_expected_else_expression | 14 + spec/errors/if_expected_else_opening_bracket | 15 + .../errors/if_expected_truthy_closing_bracket | 15 + spec/errors/if_expected_truthy_expression | 15 + .../errors/if_expected_truthy_opening_bracket | 15 + ...ine_directive_expected_closing_parenthesis | 15 + spec/errors/inline_directive_expected_file | 22 + ...ine_directive_expected_opening_parenthesis | 15 + spec/errors/inline_directive_expected_path | 15 + spec/errors/inline_function_expected_body | 15 + .../inline_function_expected_closing_bracket | 15 + ...line_function_expected_closing_parenthesis | 15 + .../inline_function_expected_opening_bracket | 15 + spec/errors/inline_function_expected_type | 14 + spec/errors/inline_function_type_mismatch | 52 + .../interpolation_expected_closing_bracket | 15 + spec/errors/interpolation_expected_expression | 15 + spec/errors/invalid_self_reference | 38 + spec/errors/locale_expected_closing_bracket | 10 + spec/errors/locale_expected_language | 10 + spec/errors/locale_expected_opening_bracket | 10 + spec/errors/member_access_expected_variable | 14 + spec/errors/module_expected_body | 10 + spec/errors/module_expected_closing_bracket | 12 + spec/errors/module_expected_name | 13 + spec/errors/module_expected_opening_bracket | 10 + .../negated_expression_expected_expression | 14 + spec/errors/negated_expression_not_bool | 33 + spec/errors/next_call_expected_fields | 14 + spec/errors/next_call_invalid_invocation | 30 + spec/errors/next_call_state_not_found | 30 + spec/errors/next_call_state_type_mismatch | 50 + spec/errors/number_literal_expected_decimal | 14 + spec/errors/operation_expected_expression | 15 + spec/errors/operation_numeric_type_mismatch | 34 + spec/errors/operation_or_not_maybe_or_result | 35 + spec/errors/operation_or_type_mismatch | 36 + spec/errors/operation_pipe_ambiguous | 27 + spec/errors/operation_plus_type_mismatch | 28 + spec/errors/property_expected_default_value | 12 + spec/errors/property_expected_name | 12 + spec/errors/property_expected_type | 12 + spec/errors/property_type_mismatch | 37 + spec/errors/property_type_or_default_needed | 27 + spec/errors/property_with_type_variables | 43 + spec/errors/provider_expeceted_colon | 10 + spec/errors/provider_expected_body | 10 + spec/errors/provider_expected_closing_bracket | 12 + spec/errors/provider_expected_name | 10 + spec/errors/provider_expected_opening_bracket | 10 + spec/errors/provider_expected_subscription | 11 + spec/errors/provider_not_found_subscription | 18 + ...ecord_not_found_matching_record_definition | 27 + .../record_update_expected_closing_bracket | 15 + spec/errors/record_update_expected_fields | 14 + spec/errors/record_update_not_found_key | 46 + spec/errors/record_update_not_updating_record | 61 ++ spec/errors/record_update_type_mismatch | 65 ++ spec/errors/record_with_holes | 15 + spec/errors/recursion | 40 + .../regexp_literal_expected_closing_slash | 15 + spec/errors/return_call_expected_expression | 14 + spec/errors/return_call_invalid | 22 + spec/errors/route_expected_body | 12 + spec/errors/route_expected_closing_bracket | 14 + .../errors/route_expected_closing_parenthesis | 13 + spec/errors/route_expected_opening_bracket | 12 + spec/errors/route_param_invalid | 24 + spec/errors/routes_expected_body | 10 + spec/errors/routes_expected_closing_bracket | 17 + spec/errors/routes_expected_opening_bracket | 11 + spec/errors/spread_expected_variable | 14 + spec/errors/state_expected_default_value | 12 + spec/errors/state_expected_equal_sign | 12 + spec/errors/state_expected_name | 12 + spec/errors/state_expected_type | 12 + spec/errors/state_type_mismatch | 30 + spec/errors/statement_last_target | 19 + spec/errors/statement_return_required | 22 + spec/errors/statement_return_type_mismatch | 51 + spec/errors/store_expected_body | 10 + spec/errors/store_expected_closing_bracket | 12 + spec/errors/store_expected_name | 10 + spec/errors/store_expected_opening_bracket | 10 + spec/errors/string_expected_closing_quote | 15 + spec/errors/string_expected_other_string | 15 + ...string_literal_interpolation_type_mismatch | 30 + spec/errors/style_expected_body | 12 + spec/errors/style_expected_closing_bracket | 14 + .../errors/style_expected_closing_parenthesis | 13 + spec/errors/style_expected_name | 12 + spec/errors/style_expected_opening_bracket | 12 + spec/errors/suite_expected_body | 10 + spec/errors/suite_expected_closing_bracket | 16 + spec/errors/suite_expected_name | 10 + spec/errors/suite_expected_opening_bracket | 10 + ...svg_directive_expected_closing_parenthesis | 15 + spec/errors/svg_directive_expected_dimensions | 29 + spec/errors/svg_directive_expected_file | 22 + ...svg_directive_expected_opening_parenthesis | 15 + spec/errors/svg_directive_expected_path | 15 + spec/errors/svg_directive_expected_svg | 27 + spec/errors/svg_directive_expected_svg_tag | 23 + spec/errors/test_expected_body | 12 + spec/errors/test_expected_closing_bracket | 14 + spec/errors/test_expected_name | 12 + spec/errors/test_expected_opening_bracket | 12 + spec/errors/test_type_mismatch | 29 + spec/errors/translation_mismatch | 66 ++ spec/errors/translation_missing | 18 + spec/errors/translation_not_translated | 30 + ...destructuring_expected_closing_parenthesis | 17 + ...tuple_literal_expected_closing_parenthesis | 6 + .../type_definition_expected_closing_bracket} | 9 +- ...pe_definition_expected_closing_parenthesis | 11 + spec/errors/type_definition_expected_name | 10 + .../type_definition_field_expected_colon | 13 + .../type_definition_field_expected_mapping | 12 + .../type_definition_field_expected_type | 12 + .../type_definition_not_defined_parameter | 15 + spec/errors/type_definition_unused_parameter | 17 + ...destructuring_expected_closing_parenthesis | 18 + .../type_destructuring_expected_variant | 16 + spec/errors/type_expected_closing_parenthesis | 12 + .../type_expected_type_or_type_variable | 12 + .../type_variant_expected_closing_parenthesis | 13 + spec/errors/unary_minus_not_number | 26 + spec/errors/use_condition_mismatch | 45 + spec/errors/use_expected_condition | 12 + .../use_expected_condition_closing_bracket | 13 + .../use_expected_condition_opening_bracket | 13 + spec/errors/use_expected_provider | 12 + spec/errors/use_expected_record | 12 + spec/errors/use_not_found_provider | 26 + spec/errors/use_subscription_mismatch | 61 ++ spec/errors/variable_missing | 30 + spec/errors/variable_reserved | 24 + spec/errors_spec.cr | 25 + spec/examples/access | 157 +++ spec/{type_checking => examples}/access_call | 0 spec/examples/argument | 41 + spec/{type_checking => examples}/array_access | 45 +- spec/examples/array_destructuring | 4 + .../{type_checking => examples}/array_literal | 21 +- spec/examples/bool_literal | 19 + spec/examples/call | 224 +++++ spec/examples/case | 104 ++ spec/{type_checking => examples}/case_array | 28 +- spec/{type_checking => examples}/case_tuple | 11 +- spec/examples/comment | 4 + spec/examples/component | 126 +++ spec/examples/connect | 70 ++ spec/examples/constant | 17 + .../css_definition | 59 +- spec/examples/css_font_face | 45 + spec/examples/css_keyframes | 37 + spec/examples/css_nested_at | 29 + spec/examples/css_selector | 41 + spec/examples/decode | 64 ++ spec/examples/destructuring | 143 +++ spec/examples/directives/asset | 18 + spec/examples/directives/documentation | 28 + spec/examples/directives/format | 23 + spec/examples/directives/highlight | 12 + spec/examples/directives/inline | 18 + spec/examples/directives/svg | 42 + spec/examples/encode | 14 + spec/examples/env | 16 + .../for => examples/for_expression} | 76 +- spec/examples/function | 125 +++ spec/examples/get | 39 + spec/examples/here_document | 45 + spec/examples/html_attribute | 190 ++++ spec/examples/html_component | 75 ++ spec/examples/html_element | 101 ++ .../html_expression} | 12 +- spec/examples/html_fragment | 4 + spec/examples/html_style | 61 ++ spec/examples/if | 145 +++ spec/examples/inline_function | 46 + spec/examples/interpolation | 14 + spec/{type_checking => examples}/js | 4 +- spec/examples/locale | 58 ++ spec/examples/member_access | 14 + spec/examples/module | 63 ++ spec/examples/negated_expression | 42 + spec/examples/next_call | 67 ++ spec/examples/number_literal | 14 + spec/examples/operation | 142 +++ spec/examples/parenthesized_expression | 6 + spec/{type_checking => examples}/pipe | 35 +- spec/{type_checking => examples}/property | 40 +- spec/examples/provider | 71 ++ spec/examples/record | 165 ++++ .../{type_checking => examples}/record_update | 36 +- .../recursive => examples/recursion} | 23 +- spec/examples/regexp_literal | 4 + .../return => examples/return_call} | 55 +- spec/examples/route | 31 + spec/examples/routes | 19 + .../self_reference} | 18 +- spec/examples/spread | 4 + spec/examples/state | 41 + spec/examples/statement | 35 + spec/examples/store | 43 + spec/examples/string_literal | 46 + spec/examples/style | 36 + spec/examples/suite | 30 + spec/examples/test | 25 + spec/examples/tuple | 30 + spec/examples/type | 46 + spec/examples/type_definition | 47 + spec/examples/type_definition_field | 9 + spec/examples/type_destructuring | 14 + spec/examples/type_variable | 6 + spec/examples/type_variant | 3 + spec/examples/unary_minus | 16 + spec/{type_checking => examples}/use | 58 +- spec/examples/variable | 83 ++ spec/{type_checking => examples}/void | 0 spec/examples_spec.cr | 67 ++ spec/formatters/access | 8 +- spec/formatters/constant_provider | 4 +- spec/formatters/decode | 4 +- spec/formatters/directives/format | 2 +- spec/formatters/enum_with_comments | 16 - spec/formatters/enum_with_options | 29 - spec/formatters/{record_field => field} | 4 +- ...record_field_multiline => field_multiline} | 4 +- ...ield_with_comments => field_with_comments} | 4 +- spec/formatters/html_fragment | 2 - spec/formatters/inline_function_multiline | 4 +- spec/formatters/member_access | 4 +- spec/formatters/provider | 4 +- spec/formatters/provider_with_comments | 4 +- spec/formatters/provider_with_items | 4 +- spec/formatters/record_constructor | 27 - .../record_constructor_with_new_line | 30 - spec/formatters/record_multiline | 4 +- spec/formatters/record_singleline | 4 +- spec/formatters/record_update_multiline | 4 +- spec/formatters/record_update_singleline | 4 +- spec/formatters/statement | 6 +- spec/formatters/tuple_destructuring | 4 +- spec/formatters/tuple_multiple | 4 +- spec/formatters/tuple_single | 2 +- spec/formatters/type | 4 +- .../{record_definition => type_definition} | 4 +- ...comments => type_definition_with_comments} | 5 +- ...n_with_from => type_definition_with_using} | 4 +- spec/formatters/{enum_record => type_record} | 8 +- ...record_multiline => type_record_multiline} | 4 +- spec/formatters/type_with_parameters | 2 +- spec/formatters/use | 4 +- spec/formatting_spec.cr | 70 +- spec/html_snippet_spec.cr | 12 +- spec/installer/repository_spec.cr | 24 +- .../definition/location/html_style | 2 +- .../{enum_id_name => type_definition} | 0 ...ructuring_name => type_destructuring_name} | 0 ...uring_option => type_destructuring_option} | 0 .../location/{type_enum => type_type} | 0 .../location/{enum_id_option => type_variant} | 0 ... => variable_casebranch_typedestructuring} | 0 .../location_link/connect_variable_get | 4 +- .../definition/location_link/html_style | 2 +- .../module_access_component_gets | 4 +- .../location_link/module_access_store_gets | 4 +- ...ructuring_name => type_destructuring_name} | 0 ...uring_option => type_destructuring_option} | 0 ... => variable_casebranch_typedestructuring} | 0 .../location_link/variable_component_get | 4 +- .../location_link/variable_store_get | 4 +- spec/language_server/hover/function_provider | 2 +- spec/language_server/hover/module_access | 2 +- .../hover/{enum => type_definition} | 0 ...{enum_destructuring => type_destructuring} | 0 spec/language_server/hover/type_record | 2 +- .../hover/{type_enum => type_type} | 4 +- .../hover/{enum_id => type_variant} | 0 .../hover/{enum_option => type_variant_2} | 0 spec/language_server/ls_spec.cr | 2 +- spec/messages_spec.cr | 15 - spec/parsers/access_spec.cr | 9 - spec/parsers/argument_spec.cr | 17 - spec/parsers/array_access_spec.cr | 12 - spec/parsers/array_destructuring.cr | 18 - spec/parsers/array_literal_spec.cr | 16 - spec/parsers/bool_literal_spec.cr | 12 - spec/parsers/call_spec.cr | 9 - spec/parsers/case_branch_spec.cr | 14 - spec/parsers/case_spec.cr | 24 - spec/parsers/comment_spec.cr | 16 - spec/parsers/component_spec.cr | 27 - spec/parsers/connect_spec.cr | 21 - spec/parsers/connect_variable_spec.cr | 12 - spec/parsers/constant_spec.cr | 19 - spec/parsers/css_definition_spec.cr | 22 - spec/parsers/css_interpolation_spec.cr | 18 - spec/parsers/css_keyframes.cr | 12 - spec/parsers/css_selector_spec.cr | 12 - spec/parsers/decode.cr | 19 - spec/parsers/directives/documentation.cr | 16 - spec/parsers/directives/format_spec.cr | 16 - spec/parsers/env_spec.cr | 16 - spec/parsers/for_spec.cr | 25 - spec/parsers/function_spec.cr | 26 - spec/parsers/get_spec.cr | 24 - spec/parsers/html_attribute_spec.cr | 20 - spec/parsers/html_component_spec.cr | 20 - spec/parsers/html_element_spec.cr | 25 - spec/parsers/html_expression_spec.cr | 17 - spec/parsers/html_fragment_spec.cr | 19 - spec/parsers/if_spec.cr | 32 - spec/parsers/inline_function_spec.cr | 20 - spec/parsers/js_spec.cr | 22 - spec/parsers/locale_key_spec.cr | 11 - spec/parsers/locale_spec.cr | 16 - spec/parsers/member_access_spec.cr | 11 - spec/parsers/module_access_spec.cr | 16 - spec/parsers/module_spec.cr | 23 - spec/parsers/negated_expression_spec.cr | 15 - spec/parsers/next_call_spec.cr | 13 - spec/parsers/number_literal_spec.cr | 15 - spec/parsers/operation_spec.cr | 41 - spec/parsers/parenthesized_expression_spec.cr | 15 - spec/parsers/pipe_spec.cr | 11 - spec/parsers/property_spec.cr | 19 - spec/parsers/provider_spec.cr | 18 - spec/parsers/record_definition_field_spec.cr | 19 - spec/parsers/record_definition_spec.cr | 20 - spec/parsers/record_field_spec.cr | 16 - spec/parsers/record_spec.cr | 18 - spec/parsers/record_update_spec.cr | 19 - spec/parsers/regexp_literal_spec.cr | 14 - spec/parsers/return_call_spec.cr | 13 - spec/parsers/route_spec.cr | 22 - spec/parsers/routes_spec.cr | 16 - spec/parsers/spread.cr | 13 - spec/parsers/state_spec.cr | 22 - spec/parsers/statement_spec.cr | 12 - spec/parsers/store_spec.cr | 21 - spec/parsers/string_literal_spec.cr | 17 - spec/parsers/style_spec.cr | 22 - spec/parsers/tuple_destructuring_spec.cr | 18 - spec/parsers/tuple_literal_spec.cr | 19 - spec/parsers/type_spec.cr | 29 - spec/parsers/type_variable_spec.cr | 14 - spec/parsers/unary_minus_spec.cr | 13 - spec/parsers/use_spec.cr | 23 - spec/parsers/variable_spec.cr | 76 -- spec/parsers/void_spec.cr | 11 - spec/recursion_spec.cr | 120 --- spec/spec_helper.cr | 11 - spec/type_checking/access | 50 - spec/type_checking/argument | 19 - .../type_checking/argument_with_default_value | 19 - ...rgument_with_default_value_inline_function | 21 - spec/type_checking/bool_literal_false | 23 - spec/type_checking/bool_literal_true | 23 - spec/type_checking/case | 57 -- spec/type_checking/case_branch | 67 -- spec/type_checking/case_type_unification | 39 - spec/type_checking/component | 43 - spec/type_checking/connect | 83 -- spec/type_checking/css_font_face | 31 - spec/type_checking/css_selector | 38 - spec/type_checking/css_string | 15 - spec/type_checking/css_with_arguments | 19 - spec/type_checking/decode | 47 - spec/type_checking/directives/documentation | 15 - spec/type_checking/directives/format | 10 - spec/type_checking/directives/svg | 29 - spec/type_checking/enum | 17 - spec/type_checking/enum_id | 46 - spec/type_checking/enum_record | 13 - spec/type_checking/env | 11 - spec/type_checking/function | 35 - spec/type_checking/function_call | 71 -- spec/type_checking/function_call_labelled | 39 - .../type_checking/function_returning_argument | 19 - .../function_returning_variable_argument | 9 - spec/type_checking/get | 23 - .../global_component_inside_call | 19 - spec/type_checking/html_attribute | 11 - spec/type_checking/html_attribute_array | 33 - spec/type_checking/html_attribute_disabled | 11 - spec/type_checking/html_attribute_event | 17 - spec/type_checking/html_attribute_key | 23 - spec/type_checking/html_attribute_not_found | 27 - spec/type_checking/html_attribute_readonly | 11 - spec/type_checking/html_attribute_ref | 11 - .../html_attribute_type_mismatch | 27 - spec/type_checking/html_component | 43 - .../html_element_not_in_component | 52 - spec/type_checking/html_element_style | 16 - spec/type_checking/html_expression | 11 - spec/type_checking/html_style | 39 - spec/type_checking/if | 29 - spec/type_checking/if_in_html | 21 - spec/type_checking/if_let | 59 -- spec/type_checking/inline_function | 38 - spec/type_checking/locale_key | 43 - spec/type_checking/member_access | 19 - spec/type_checking/module | 11 - spec/type_checking/module_access | 42 - spec/type_checking/module_access_get | 9 - spec/type_checking/module_access_provider | 19 - .../type_checking/module_access_subscriptions | 19 - spec/type_checking/module_call | 88 -- spec/type_checking/negated_bool | 5 - spec/type_checking/negated_expression | 31 - spec/type_checking/next_call | 50 - spec/type_checking/number_literal | 9 - spec/type_checking/open_module | 39 - spec/type_checking/operation_bool | 19 - spec/type_checking/operation_numeric | 39 - spec/type_checking/operation_or | 32 - spec/type_checking/operation_plus | 23 - spec/type_checking/operation_with_pipe | 15 - spec/type_checking/parenthesized_expression | 9 - spec/type_checking/provider_const | 24 - spec/type_checking/record | 50 - spec/type_checking/record_constructor | 67 -- .../type_checking/record_definition_not_found | 39 - spec/type_checking/record_field | 17 - spec/type_checking/record_same | 44 - spec/type_checking/route | 11 - spec/type_checking/routes | 9 - spec/type_checking/state | 28 - spec/type_checking/statement | 20 - spec/type_checking/store | 41 - spec/type_checking/store_call_with_next | 18 - spec/type_checking/string_literal | 21 - spec/type_checking/suite_const | 30 - spec/type_checking/tuple_with_pipe | 11 - spec/type_checking/type_normalize | 33 - spec/type_checking/unary_minus | 15 - spec/type_checking/uncapitalized_type | 11 - spec/type_checking/variable | 37 - spec/type_checking_spec.cr | 59 -- src/all.cr | 10 +- src/ast.cr | 64 +- src/ast/access.cr | 20 +- src/ast/argument.cr | 10 +- src/ast/array_access.cr | 12 +- src/ast/array_destructuring.cr | 34 +- src/ast/array_literal.cr | 19 +- src/ast/block.cr | 19 +- src/ast/bool_literal.cr | 16 +- src/ast/call.cr | 10 +- src/ast/call_expression.cr | 14 - src/ast/case.cr | 9 +- src/ast/case_branch.cr | 10 +- src/ast/comment.cr | 13 +- src/ast/component.cr | 14 +- src/ast/connect.cr | 8 +- src/ast/connect_variable.cr | 12 +- src/ast/constant.cr | 10 +- src/ast/css_definition.cr | 6 +- src/ast/css_font_face.cr | 6 +- src/ast/css_keyframes.cr | 6 +- src/ast/css_nested_at.cr | 8 +- src/ast/css_selector.cr | 6 +- src/ast/data.cr | 14 - src/ast/decode.cr | 8 +- src/ast/directives/asset.cr | 40 - src/ast/directives/documentation.cr | 8 +- src/ast/directives/file_based.cr | 54 + src/ast/directives/format.cr | 8 +- src/ast/directives/highlight.cr | 8 +- src/ast/directives/inline.cr | 25 - src/ast/directives/svg.cr | 25 - src/ast/encode.cr | 8 +- src/ast/enum.cr | 17 - src/ast/enum_destructuring.cr | 27 - src/ast/enum_id.cr | 15 - src/ast/enum_option.cr | 15 - src/ast/enum_record.cr | 8 - src/ast/enum_record_definition.cr | 13 - src/ast/env.cr | 8 +- src/ast/field.cr | 15 + src/ast/for.cr | 12 +- src/ast/for_condition.cr | 13 - src/ast/function.cr | 8 +- src/ast/get.cr | 8 +- src/ast/here_doc.cr | 29 - src/ast/here_document.cr | 15 + src/ast/html_attribute.cr | 16 +- src/ast/html_component.cr | 30 +- src/ast/html_element.cr | 23 +- src/ast/html_expression.cr | 14 +- src/ast/html_fragment.cr | 9 +- src/ast/html_style.cr | 10 +- src/ast/id.cr | 13 + src/ast/if.cr | 13 +- src/ast/inline_function.cr | 8 +- src/ast/interpolation.cr | 8 +- src/ast/js.cr | 6 +- src/ast/locale.cr | 8 +- src/ast/locale_key.cr | 8 +- src/ast/member_access.cr | 8 +- src/ast/module.cr | 8 +- src/ast/module_access.cr | 16 - src/ast/negated_expression.cr | 8 +- src/ast/next_call.cr | 10 +- src/ast/node.cr | 51 +- src/ast/number_literal.cr | 18 +- src/ast/operation.cr | 10 +- src/ast/option.cr | 13 - src/ast/parenthesized_expression.cr | 8 +- src/ast/pipe.cr | 23 +- src/ast/property.cr | 8 +- src/ast/provider.cr | 10 +- src/ast/record.cr | 12 +- src/ast/record_definition.cr | 16 - src/ast/record_field.cr | 15 - src/ast/record_update.cr | 10 +- src/ast/regexp_literal.cr | 20 +- src/ast/return_call.cr | 12 +- src/ast/route.cr | 6 +- src/ast/routes.cr | 6 +- src/ast/spread.cr | 6 +- src/ast/state.cr | 8 +- src/ast/statement.cr | 11 +- src/ast/store.cr | 12 +- src/ast/string_literal.cr | 22 +- src/ast/style.cr | 6 +- src/ast/suite.cr | 10 +- src/ast/test.cr | 6 +- src/ast/tuple_destructuring.cr | 14 +- src/ast/tuple_literal.cr | 19 +- src/ast/type.cr | 10 +- src/ast/type_definition.cr | 16 + ...tion_field.cr => type_definition_field.cr} | 10 +- src/ast/type_destructuring.cr | 15 + src/ast/type_id.cr | 13 - src/ast/type_variable.cr | 8 +- src/ast/type_variant.cr | 21 + src/ast/unary_minus.cr | 8 +- src/ast/use.cr | 10 +- src/ast/variable.cr | 8 +- src/ast/void.cr | 10 - src/builder.cr | 4 +- src/cli.cr | 13 +- src/commands/compile.cr | 4 +- src/compiler.cr | 3 +- src/compilers/access.cr | 51 +- src/compilers/array_access.cr | 18 +- src/compilers/block.cr | 16 +- src/compilers/call_expression.cr | 7 - src/compilers/case.cr | 2 +- src/compilers/case_branch.cr | 4 +- src/compilers/component.cr | 8 +- src/compilers/constant.cr | 2 +- src/compilers/decode.cr | 15 +- src/compilers/destructuring.cr | 17 +- src/compilers/directives/documentation.cr | 2 +- src/compilers/directives/highlight.cr | 2 +- src/compilers/enum.cr | 31 - src/compilers/enum_id.cr | 60 -- src/compilers/field.cr | 19 + src/compilers/for_expression.cr | 2 +- src/compilers/function.cr | 2 +- src/compilers/here_doc.cr | 2 +- src/compilers/html_attribute.cr | 4 +- src/compilers/html_component.cr | 6 +- src/compilers/html_element.cr | 6 +- src/compilers/html_fragment.cr | 11 +- src/compilers/if.cr | 19 +- src/compilers/inline_function.cr | 2 +- src/compilers/module_access.cr | 20 - src/compilers/next_call.cr | 8 +- src/compilers/number_literal.cr | 2 +- src/compilers/record.cr | 5 +- src/compilers/record_constructor.cr | 47 - src/compilers/record_definition.cr | 24 - src/compilers/record_field.cr | 13 - src/compilers/regexp_literal.cr | 2 +- src/compilers/route.cr | 2 +- src/compilers/statement.cr | 4 +- src/compilers/top_level.cr | 59 +- src/compilers/type_definition.cr | 62 ++ src/compilers/variable.cr | 108 +- src/compilers/void.cr | 7 - src/documentation_generator.cr | 8 +- src/documentation_generator/connect.cr | 2 +- src/documentation_generator/enum.cr | 20 - .../{type_id.cr => id.cr} | 4 +- ...ecord_definition.cr => type_definition.cr} | 2 +- ...tion_field.cr => type_definition_field.cr} | 4 +- .../{enum_option.cr => type_variant.cr} | 2 +- src/env.cr | 10 +- src/errorable.cr | 190 ++++ src/errors/error.cr | 29 - src/errors/install_error.cr | 4 - src/errors/json_error.cr | 4 - src/errors/syntax_error.cr | 4 - src/errors/top_level.cr | 16 - src/errors/type_error.cr | 4 - src/formatter.cr | 1 + src/formatters/access.cr | 6 +- src/formatters/array_access.cr | 13 +- src/formatters/block.cr | 2 +- src/formatters/call_expression.cr | 14 - src/formatters/case_branch.cr | 8 +- src/formatters/comment.cr | 2 +- src/formatters/connect_variable.cr | 14 +- src/formatters/constant.cr | 10 +- src/formatters/enum.cr | 22 - src/formatters/enum_destructuring.cr | 17 - src/formatters/enum_id.cr | 21 - src/formatters/enum_option.cr | 13 - src/formatters/enum_record_definition.cr | 14 - src/formatters/field.cr | 24 + src/formatters/for.cr | 11 +- src/formatters/here_doc.cr | 2 +- src/formatters/html_fragment.cr | 7 +- src/formatters/{type_id.cr => id.cr} | 2 +- src/formatters/module_access.cr | 17 - src/formatters/property.cr | 14 +- src/formatters/record.cr | 32 +- src/formatters/record_definition.cr | 19 - src/formatters/record_field.cr | 20 - src/formatters/regexp_literal.cr | 2 +- src/formatters/top_level.cr | 3 +- src/formatters/tuple_destructuring.cr | 2 +- src/formatters/tuple_literal.cr | 4 +- src/formatters/type_definition.cr | 24 + ...tion_field.cr => type_definition_field.cr} | 2 +- src/formatters/type_destructuring.cr | 17 + src/formatters/type_variant.cr | 20 + src/formatters/void.cr | 7 - src/helpers.cr | 148 +++ src/installer.cr | 39 +- src/installer/repository.cr | 108 +- src/ls/completion.cr | 6 +- src/ls/completion_item/constant.cr | 2 +- src/ls/completion_item/function.cr | 4 +- src/ls/completion_item/get.cr | 2 +- src/ls/completions/enum.cr | 42 - src/ls/completions/type_definition.cr | 47 + src/ls/definition.cr | 9 + src/ls/definition/access.cr | 30 +- src/ls/definition/connect_variable.cr | 12 +- src/ls/definition/enum_destructuring.cr | 23 - src/ls/definition/enum_id.cr | 42 - src/ls/definition/id.cr | 23 + src/ls/definition/module_access.cr | 20 - src/ls/definition/type.cr | 17 +- src/ls/definition/type_destructuring.cr | 8 + src/ls/definition/type_id.cr | 37 - src/ls/definition/variable.cr | 86 +- src/ls/folding_range.cr | 5 - src/ls/hover.cr | 13 +- src/ls/hover/access.cr | 14 + src/ls/hover/enum.cr | 26 - src/ls/hover/enum_id.cr | 12 - src/ls/hover/enum_option.cr | 12 - src/ls/hover/function.cr | 2 +- src/ls/hover/get.cr | 2 +- src/ls/hover/html_component.cr | 4 +- src/ls/hover/module_access.cr | 12 - src/ls/hover/property.cr | 2 +- src/ls/hover/state.cr | 2 +- src/ls/hover/type.cr | 17 +- src/ls/hover/type_definition.cr | 33 + ...destructuring.cr => type_destructuring.cr} | 4 +- src/ls/hover/type_variant.cr | 20 + src/ls/semantic_tokens.cr | 14 +- src/ls/server.cr | 2 +- src/lsp/protocol/folding_range.cr | 8 +- src/lsp/protocol/position.cr | 4 +- src/macros.cr | 83 -- src/message.cr | 235 ----- src/messages/access_expected_variable.cr | 11 - src/messages/access_field_not_found.cr | 13 - src/messages/access_not_record.cr | 11 - src/messages/argument_expected_colon.cr | 11 - .../argument_expected_default_value.cr | 13 - .../argument_expected_type_or_variable.cr | 11 - .../array_access_expected_closing_bracket.cr | 13 - src/messages/array_access_expected_index.cr | 11 - src/messages/array_access_index_not_number.cr | 11 - src/messages/array_access_invalid_tuple.cr | 15 - src/messages/array_access_not_an_array.cr | 11 - ..._destructuring_expected_closing_bracket.cr | 13 - .../array_expected_closing_bracket.cr | 13 - ...array_literal_expected_type_or_variable.cr | 15 - src/messages/array_not_matches.cr | 23 - .../array_not_matches_defined_type.cr | 13 - ..._directive_expected_closing_parentheses.cr | 15 - src/messages/asset_directive_expected_file.cr | 14 - ..._directive_expected_opening_parentheses.cr | 16 - src/messages/asset_directive_expected_path.cr | 11 - src/messages/browser_not_found.cr | 12 - src/messages/call_argument_size_mismatch.cr | 12 - src/messages/call_argument_type_mismatch.cr | 15 - .../call_expected_closing_parentheses.cr | 15 - src/messages/call_not_a_function.cr | 10 - src/messages/call_not_found_argument.cr | 13 - src/messages/call_type_mismatch.cr | 13 - src/messages/call_with_mixed_arguments.cr | 9 - .../case_branch_expected_expression.cr | 11 - src/messages/case_branch_not_matches.cr | 23 - src/messages/case_enum_not_covered.cr | 15 - src/messages/case_expected_branches.cr | 15 - src/messages/case_expected_closing_bracket.cr | 7 - .../case_expected_closing_parentheses.cr | 16 - src/messages/case_expected_condition.cr | 15 - src/messages/case_expected_opening_bracket.cr | 7 - src/messages/case_not_covered.cr | 15 - src/messages/case_unnecessary_all.cr | 9 - .../component_entity_name_conflict.cr | 14 - src/messages/component_expected_body.cr | 13 - .../component_expected_closing_bracket.cr | 7 - src/messages/component_expected_name.cr | 18 - .../component_expected_opening_bracket.cr | 7 - .../component_exposed_name_conflict.cr | 13 - .../component_function_type_mismatch.cr | 13 - src/messages/component_main_property.cr | 12 - src/messages/component_multiple_connects.cr | 12 - src/messages/component_multiple_exposed.cr | 12 - src/messages/component_multiple_uses.cr | 12 - src/messages/component_not_found_render.cr | 11 - .../component_reference_name_conflict.cr | 11 - .../component_render_type_mismatch.cr | 15 - src/messages/component_state_name_conflict.cr | 14 - src/messages/component_style_name_conflict.cr | 11 - .../connect_expected_closing_bracket.cr | 13 - src/messages/connect_expected_exposing.cr | 17 - src/messages/connect_expected_keys.cr | 19 - .../connect_expected_opening_bracket.cr | 13 - src/messages/connect_expected_type.cr | 23 - src/messages/connect_not_found_member.cr | 12 - src/messages/connect_not_found_store.cr | 11 - src/messages/connect_variable_expected_as.cr | 20 - src/messages/constant_expected_equal_sign.cr | 16 - src/messages/constant_expected_name.cr | 7 - src/messages/constant_expected_value.cr | 13 - .../css_definition_expected_semicolon.cr | 11 - src/messages/css_definition_type_mismatch.cr | 19 - .../css_font_face_expected_closing_bracket.cr | 7 - .../css_font_face_expected_opening_bracket.cr | 7 - src/messages/css_font_face_interpolation.cr | 9 - .../css_keyframes_expected_closing_bracket.cr | 7 - src/messages/css_keyframes_expected_name.cr | 11 - .../css_keyframes_expected_opening_bracket.cr | 7 - .../css_nested_at_expected_closing_bracket.cr | 7 - .../css_nested_at_expected_condition.cr | 11 - .../css_nested_at_expected_opening_bracket.cr | 7 - ..._nested_at_expected_space_after_keyword.cr | 14 - src/messages/css_no_property.cr | 10 - .../css_selector_expected_closing_bracket.cr | 7 - .../css_selector_expected_opening_bracket.cr | 7 - src/messages/decode_complex_type.cr | 27 - src/messages/decode_expected_as.cr | 17 - src/messages/decode_expected_expression.cr | 14 - src/messages/decode_expected_object.cr | 13 - src/messages/decode_expected_type.cr | 15 - .../destructuring_multiple_spreads.cr | 15 - src/messages/destructuring_no_parameter.cr | 19 - src/messages/destructuring_tuple_mismatch.cr | 21 - src/messages/destructuring_type_mismatch.cr | 21 - ...ocumentation_directive_entity_not_found.cr | 11 - ..._directive_expected_closing_parentheses.cr | 16 - ...documentation_directive_expected_entity.cr | 15 - ..._directive_expected_opening_parentheses.cr | 16 - src/messages/encode_complex_type.cr | 25 - src/messages/encode_expected_expression.cr | 14 - ...tructuring_expected_closing_parentheses.cr | 16 - ...num_destructuring_expected_double_colon.cr | 19 - .../enum_destructuring_expected_option.cr | 13 - src/messages/enum_expected_closing_bracket.cr | 7 - .../enum_expected_closing_parentheses.cr | 16 - src/messages/enum_expected_name.cr | 18 - src/messages/enum_expected_opening_bracket.cr | 7 - src/messages/enum_id_enum_missing.cr | 13 - .../enum_id_expected_closing_parentheses.cr | 16 - src/messages/enum_id_expected_double_colon.cr | 19 - src/messages/enum_id_expected_option.cr | 15 - src/messages/enum_id_type_mismatch.cr | 15 - src/messages/enum_id_type_missing.cr | 10 - src/messages/enum_not_defined_parameter.cr | 15 - ...num_option_expected_closing_parentheses.cr | 16 - src/messages/enum_unused_parameter.cr | 15 - src/messages/env_expected_name.cr | 19 - src/messages/env_file_not_found.cr | 9 - src/messages/env_not_found_variable.cr | 10 - src/messages/expected_end_of_file.cr | 26 - .../for_array_or_set_arguments_mismatch.cr | 10 - src/messages/for_condition_expected_body.cr | 14 - .../for_condition_expected_closing_bracket.cr | 7 - .../for_condition_expected_opening_bracket.cr | 7 - src/messages/for_condition_type_mismatch.cr | 11 - src/messages/for_expected_body.cr | 14 - src/messages/for_expected_closing_bracket.cr | 7 - .../for_expected_closing_parentheses.cr | 15 - src/messages/for_expected_of.cr | 14 - src/messages/for_expected_opening_bracket.cr | 7 - src/messages/for_expected_subject.cr | 15 - src/messages/for_map_arguments_mismatch.cr | 10 - src/messages/for_type_mismatch.cr | 17 - ...rmat_directive_expected_closing_bracket.cr | 7 - .../format_directive_expected_expression.cr | 12 - ...rmat_directive_expected_opening_bracket.cr | 7 - src/messages/function_argument_conflict.cr | 12 - ...tion_argument_must_have_a_default_value.cr | 15 - .../function_expected_closing_bracket.cr | 7 - .../function_expected_closing_parentheses.cr | 15 - src/messages/function_expected_expression.cr | 15 - src/messages/function_expected_name.cr | 7 - .../function_expected_opening_bracket.cr | 7 - .../function_expected_type_or_variable.cr | 13 - src/messages/function_type_mismatch.cr | 11 - src/messages/function_type_needed.cr | 13 - src/messages/get_expected_closing_bracket.cr | 7 - src/messages/get_expected_colon.cr | 17 - src/messages/get_expected_expression.cr | 15 - src/messages/get_expected_name.cr | 7 - src/messages/get_expected_opening_bracket.cr | 7 - src/messages/get_expected_type.cr | 13 - src/messages/get_type_mismatch.cr | 11 - src/messages/global_name_conflict.cr | 13 - src/messages/here_doc_expected_end.cr | 7 - src/messages/here_doc_expected_start.cr | 7 - .../here_doc_interpolation_type_mismatch.cr | 12 - ...l_attribute_component_key_type_mismatch.cr | 14 - ...ribute_component_property_type_mismatch.cr | 15 - ...tribute_element_attribute_type_mismatch.cr | 21 - ...html_attribute_expected_closing_bracket.cr | 22 - .../html_attribute_expected_equal_sign.cr | 17 - .../html_attribute_expected_expression.cr | 14 - ...html_attribute_expected_opening_bracket.cr | 22 - ...ml_attribute_fragment_key_type_mismatch.cr | 14 - ..._attribute_not_found_component_property.cr | 15 - .../html_component_attribute_required.cr | 10 - ...html_component_expected_closing_bracket.cr | 23 - .../html_component_expected_closing_tag.cr | 14 - .../html_component_expected_reference.cr | 15 - src/messages/html_component_expected_type.cr | 18 - .../html_component_global_component.cr | 15 - .../html_component_not_found_component.cr | 11 - ...omponent_reference_outside_of_component.cr | 9 - src/messages/html_content_type_mismatch.cr | 17 - .../html_element_class_name_forbidden.cr | 15 - .../html_element_expected_closing_bracket.cr | 17 - .../html_element_expected_closing_tag.cr | 14 - .../html_element_expected_reference.cr | 15 - src/messages/html_element_expected_style.cr | 14 - src/messages/html_element_ref_forbidden.cr | 13 - ..._element_reference_outside_of_component.cr | 9 - ...html_element_style_outside_of_component.cr | 9 - .../html_expression_expected_closing_tag.cr | 11 - .../html_fragment_expected_closing_bracket.cr | 13 - .../html_fragment_expected_closing_tag.cr | 14 - .../html_style_argument_size_mismatch.cr | 12 - .../html_style_argument_type_mismatch.cr | 14 - ...html_style_expected_closing_parentheses.cr | 15 - src/messages/html_style_not_found.cr | 11 - src/messages/if_condition_type_mismatch.cr | 13 - src/messages/if_else_type_mismatch.cr | 13 - .../if_expected_closing_parentheses.cr | 15 - src/messages/if_expected_condition.cr | 14 - src/messages/if_expected_else.cr | 19 - .../if_expected_falsy_closing_bracket.cr | 7 - src/messages/if_expected_falsy_expression.cr | 13 - .../if_expected_falsy_opening_bracket.cr | 7 - .../if_expected_truthy_closing_bracket.cr | 7 - src/messages/if_expected_truthy_expression.cr | 13 - .../if_expected_truthy_opening_bracket.cr | 7 - ..._directive_expected_closing_parentheses.cr | 15 - .../inline_directive_expected_file.cr | 14 - ..._directive_expected_opening_parentheses.cr | 16 - .../inline_directive_expected_path.cr | 11 - ...nline_function_expected_closing_bracket.cr | 7 - ...e_function_expected_closing_parentheses.cr | 15 - .../inline_function_expected_expression.cr | 15 - ...nline_function_expected_opening_bracket.cr | 7 - src/messages/inline_function_expected_type.cr | 13 - src/messages/inline_function_type_mismatch.cr | 11 - src/messages/installer_failed_to_install.cr | 33 - .../interpolation_expected_closing_bracket.cr | 11 - .../interpolation_expected_expression.cr | 13 - src/messages/invalid_browser.cr | 14 - src/messages/invalid_reporter.cr | 14 - src/messages/invalid_self_reference.cr | 10 - src/messages/js_expected_closing_tick.cr | 14 - src/messages/js_expected_type_or_variable.cr | 15 - .../locale_expected_closing_bracket.cr | 7 - src/messages/locale_expected_language.cr | 13 - .../locale_expected_opening_bracket.cr | 7 - .../member_access_expected_variable.cr | 11 - src/messages/mint_json_application_invalid.cr | 13 - .../mint_json_application_invalid_key.cr | 14 - .../mint_json_application_name_invalid.cr | 13 - src/messages/mint_json_css_prefix_invalid.cr | 13 - .../mint_json_dependencies_invalid.cr | 17 - ...mint_json_dependency_constraint_invalid.cr | 11 - src/messages/mint_json_dependency_invalid.cr | 11 - ...mint_json_dependency_invalid_constraint.cr | 30 - .../mint_json_dependency_not_installed.cr | 23 - src/messages/mint_json_display_invalid.cr | 13 - src/messages/mint_json_external_invalid.cr | 25 - .../mint_json_external_javascript_invalid.cr | 11 - ...int_json_external_javascript_not_exists.cr | 11 - .../mint_json_external_javascripts_invalid.cr | 18 - .../mint_json_external_stylesheet_invalid.cr | 11 - ...int_json_external_stylesheet_not_exists.cr | 11 - .../mint_json_external_stylesheets_invalid.cr | 18 - .../mint_json_formatter_config_invalid.cr | 13 - .../mint_json_formatter_config_invalid_key.cr | 14 - src/messages/mint_json_head_not_exists.cr | 25 - src/messages/mint_json_head_not_string.cr | 13 - src/messages/mint_json_icon_not_exists.cr | 23 - src/messages/mint_json_icon_not_string.cr | 13 - src/messages/mint_json_indent_size_invalid.cr | 13 - src/messages/mint_json_invalid_file.cr | 18 - src/messages/mint_json_invalid_json.cr | 11 - src/messages/mint_json_keyword_not_string.cr | 11 - src/messages/mint_json_keywords_invalid.cr | 11 - src/messages/mint_json_meta_invalid.cr | 13 - .../mint_json_meta_value_not_string.cr | 13 - src/messages/mint_json_mint_version_empty.cr | 13 - .../mint_json_mint_version_invalid.cr | 18 - .../mint_json_mint_version_mismatch.cr | 22 - .../mint_json_mint_version_not_string.cr | 13 - src/messages/mint_json_name_empty.cr | 13 - src/messages/mint_json_name_not_string.cr | 13 - src/messages/mint_json_orientation_invalid.cr | 13 - src/messages/mint_json_root_invalid_key.cr | 12 - src/messages/mint_json_root_not_an_object.cr | 11 - .../mint_json_source_directories_empty.cr | 18 - .../mint_json_source_directories_invalid.cr | 18 - .../mint_json_source_directory_invalid.cr | 11 - .../mint_json_source_directory_not_exists.cr | 11 - .../mint_json_test_directories_invalid.cr | 18 - .../mint_json_test_directory_invalid.cr | 11 - .../mint_json_test_directory_not_exists.cr | 11 - src/messages/mint_json_theme_invalid.cr | 13 - src/messages/mint_json_title_empty.cr | 13 - src/messages/mint_json_title_invalid.cr | 13 - .../mint_json_web_components_invalid.cr | 10 - .../module_access_expected_function.cr | 13 - .../module_access_not_found_function.cr | 12 - .../module_access_not_found_module.cr | 10 - src/messages/module_entity_name_conflict.cr | 14 - .../module_expected_closing_bracket.cr | 7 - src/messages/module_expected_name.cr | 18 - .../module_expected_opening_bracket.cr | 7 - .../negated_expression_expected_expression.cr | 11 - src/messages/negated_expression_not_bool.cr | 11 - src/messages/next_call_expected_record.cr | 15 - src/messages/next_call_invalid_invocation.cr | 11 - src/messages/next_call_state_not_found.cr | 11 - src/messages/next_call_state_type_mismatch.cr | 20 - .../number_literal_expected_decimal.cr | 15 - src/messages/operation_expected_expression.cr | 15 - .../operation_numeric_type_mismatch.cr | 14 - .../operation_or_not_maybe_or_result.cr | 15 - src/messages/operation_or_type_mismatch.cr | 12 - src/messages/operation_pipe_ambiguous.cr | 13 - src/messages/operation_plus_type_mismatch.cr | 20 - src/messages/operation_type_mismatch.cr | 12 - src/messages/pipe_expected_call.cr | 11 - .../property_expected_default_value.cr | 13 - src/messages/property_expected_name.cr | 7 - src/messages/property_expected_type.cr | 11 - src/messages/property_type_mismatch.cr | 13 - .../property_type_or_default_needed.cr | 13 - src/messages/property_with_type_variables.cr | 13 - src/messages/provider_entity_name_conflict.cr | 14 - src/messages/provider_expected_body.cr | 7 - .../provider_expected_closing_bracket.cr | 7 - src/messages/provider_expected_colon.cr | 17 - src/messages/provider_expected_name.cr | 7 - .../provider_expected_opening_bracket.cr | 7 - .../provider_expected_subscription.cr | 15 - .../provider_not_found_subscription.cr | 11 - ...cord_constructor_argument_size_mismatch.cr | 14 - ...cord_constructor_argument_type_mismatch.cr | 13 - .../record_constructor_not_found_record.cr | 10 - ...ord_definition_expected_closing_bracket.cr | 7 - .../record_definition_expected_name.cr | 7 - ...ord_definition_expected_opening_bracket.cr | 7 - .../record_definition_field_expected_colon.cr | 17 - ...ecord_definition_field_expected_mapping.cr | 16 - .../record_definition_field_expected_type.cr | 11 - src/messages/record_fields_conflict.cr | 12 - src/messages/record_name_conflict.cr | 13 - ...rd_not_found_matching_record_definition.cr | 11 - .../record_update_expected_closing_bracket.cr | 13 - src/messages/record_update_expected_fields.cr | 13 - src/messages/record_update_not_found_key.cr | 13 - .../record_update_not_updating_record.cr | 14 - src/messages/record_update_type_mismatch.cr | 12 - src/messages/record_with_holes.cr | 9 - src/messages/recursion.cr | 11 - .../regexp_literal_expected_closing_slash.cr | 16 - src/messages/repository_could_not_checkout.cr | 18 - src/messages/repository_could_not_clone.cr | 16 - .../repository_could_not_get_versions.cr | 16 - src/messages/repository_could_not_update.cr | 16 - src/messages/repository_invalid_mint_json.cr | 10 - src/messages/repository_no_mint_json.cr | 10 - .../return_call_expected_expression.cr | 15 - src/messages/return_call_invalid.cr | 11 - src/messages/return_call_type_mismatch.cr | 11 - .../route_expected_closing_bracket.cr | 7 - .../route_expected_closing_parentheses.cr | 15 - src/messages/route_expected_expression.cr | 12 - .../route_expected_opening_bracket.cr | 7 - src/messages/route_param_invalid.cr | 22 - .../routes_expected_closing_bracket.cr | 7 - .../routes_expected_opening_bracket.cr | 7 - src/messages/routes_expected_route.cr | 13 - src/messages/runtime_file_not_found.cr | 9 - src/messages/spread_expected_variable.cr | 13 - src/messages/state_expected_default_value.cr | 13 - src/messages/state_expected_equal_sign.cr | 16 - src/messages/state_expected_name.cr | 7 - src/messages/state_expected_type.cr | 11 - src/messages/state_type_mismatch.cr | 13 - src/messages/statement_last_target.cr | 13 - src/messages/statement_return_required.cr | 13 - src/messages/store_entity_name_conflict.cr | 14 - src/messages/store_expected_body.cr | 13 - .../store_expected_closing_bracket.cr | 7 - src/messages/store_expected_name.cr | 18 - .../store_expected_opening_bracket.cr | 7 - src/messages/string_expected_end_quote.cr | 16 - src/messages/string_expected_other_string.cr | 16 - ...ing_literal_interpolation_type_mismatch.cr | 12 - .../style_expected_closing_bracket.cr | 7 - .../style_expected_closing_parentheses.cr | 15 - src/messages/style_expected_name.cr | 13 - .../style_expected_opening_bracket.cr | 7 - .../suite_expected_closing_bracket.cr | 7 - src/messages/suite_expected_name.cr | 15 - .../suite_expected_opening_bracket.cr | 7 - src/messages/suite_expected_tests.cr | 15 - ..._directive_expected_closing_parentheses.cr | 15 - .../svg_directive_expected_dimensions.cr | 11 - src/messages/svg_directive_expected_file.cr | 13 - ..._directive_expected_opening_parentheses.cr | 16 - src/messages/svg_directive_expected_path.cr | 11 - src/messages/svg_directive_expected_svg.cr | 11 - .../svg_directive_expected_svg_tag.cr | 9 - src/messages/test_expected_closing_bracket.cr | 7 - src/messages/test_expected_expression.cr | 19 - src/messages/test_expected_name.cr | 15 - src/messages/test_expected_opening_bracket.cr | 7 - src/messages/test_type_mismatch.cr | 17 - src/messages/translation_mismatch.cr | 15 - src/messages/translation_missing.cr | 10 - src/messages/translation_not_translated.cr | 12 - .../type_expected_closing_parentheses.cr | 13 - src/messages/type_expected_type.cr | 13 - .../type_expected_type_or_variable.cr | 11 - src/messages/unary_minus_not_number.cr | 11 - src/messages/use_condition_mismatch.cr | 13 - src/messages/use_expected_closing_bracket.cr | 15 - src/messages/use_expected_expression.cr | 15 - src/messages/use_expected_opening_bracket.cr | 15 - src/messages/use_expected_provider.cr | 15 - src/messages/use_expected_record.cr | 15 - src/messages/use_not_found_provider.cr | 10 - src/messages/use_subscription_mismatch.cr | 11 - src/messages/variable_missing.cr | 10 - src/messages/variable_reserved.cr | 11 - src/messages/variable_taken.cr | 11 - src/mint_json.cr | 923 +++++++++++++----- src/parser.cr | 435 +++++---- src/parser/file.cr | 14 + src/parser/top_level.cr | 54 + src/parsers/access.cr | 34 +- src/parsers/argument.cr | 51 +- src/parsers/array_access.cr | 38 +- src/parsers/array_destructuring.cr | 27 +- src/parsers/array_literal.cr | 48 +- src/parsers/base_expression.cr | 103 ++ src/parsers/basic_expression.cr | 51 - src/parsers/block.cr | 65 +- src/parsers/bool_literal.cr | 10 +- src/parsers/call.cr | 34 +- src/parsers/call_expression.cr | 27 - src/parsers/case.cr | 57 +- src/parsers/case_branch.cr | 30 +- src/parsers/code_block.cr | 52 - src/parsers/comment.cr | 45 +- src/parsers/component.cr | 104 +- src/parsers/connect.cr | 52 +- src/parsers/connect_variable.cr | 32 +- src/parsers/constant.cr | 29 +- src/parsers/constant_access.cr | 28 - src/parsers/css_definition.cr | 40 +- src/parsers/css_font_face.cr | 33 +- src/parsers/css_keyframes.cr | 40 +- src/parsers/css_nested_at.cr | 55 +- src/parsers/css_node.cr | 14 + src/parsers/css_selector.cr | 64 +- src/parsers/css_selector_name.cr | 25 + src/parsers/decode.cr | 33 +- src/parsers/destructuring.cr | 5 +- src/parsers/directives/asset.cr | 30 +- src/parsers/directives/documentation.cr | 29 +- src/parsers/directives/format.cr | 32 +- src/parsers/directives/highlight.cr | 32 +- src/parsers/directives/inline.cr | 30 +- src/parsers/directives/svg.cr | 30 +- src/parsers/encode.cr | 25 +- src/parsers/enum.cr | 63 -- src/parsers/enum_destructuring.cr | 38 - src/parsers/enum_id.cr | 50 - src/parsers/enum_option.cr | 36 - src/parsers/enum_record.cr | 23 - src/parsers/enum_record_definition.cr | 23 - src/parsers/env.cr | 22 +- src/parsers/expression.cr | 31 +- src/parsers/field.cr | 31 + src/parsers/for.cr | 80 +- src/parsers/for_condition.cr | 26 - src/parsers/function.cr | 69 +- src/parsers/get.cr | 43 +- src/parsers/here_doc.cr | 50 - src/parsers/here_document.cr | 36 + src/parsers/html_attribute.cr | 47 +- src/parsers/html_body.cr | 86 +- src/parsers/html_component.cr | 56 +- src/parsers/html_element.cr | 66 +- src/parsers/html_expression.cr | 15 +- src/parsers/html_fragment.cr | 34 +- src/parsers/html_style.cr | 21 +- src/parsers/id.cr | 15 + src/parsers/if.cr | 89 +- src/parsers/inline_function.cr | 44 +- src/parsers/interpolation.cr | 21 +- src/parsers/js.cr | 61 +- src/parsers/locale.cr | 45 +- src/parsers/locale_key.cr | 9 +- src/parsers/member_access.cr | 11 +- src/parsers/module.cr | 48 +- src/parsers/module_access.cr | 27 - src/parsers/negated_expression.cr | 16 +- src/parsers/next_call.cr | 16 +- src/parsers/number_literal.cr | 24 +- src/parsers/operation.cr | 98 +- src/parsers/operator.cr | 62 ++ src/parsers/option.cr | 15 - src/parsers/parenthesized_expression.cr | 10 +- src/parsers/pipe.cr | 18 +- src/parsers/property.cr | 40 +- src/parsers/provider.cr | 76 +- src/parsers/record.cr | 13 +- src/parsers/record_definition.cr | 40 - src/parsers/record_definition_field.cr | 39 - src/parsers/record_field.cr | 25 - src/parsers/record_update.cr | 27 +- src/parsers/regexp_literal.cr | 18 +- src/parsers/return.cr | 16 +- src/parsers/route.cr | 50 +- src/parsers/routes.cr | 43 +- src/parsers/spread.cr | 13 +- src/parsers/state.cr | 37 +- src/parsers/statement.cr | 24 +- src/parsers/store.cr | 54 +- src/parsers/string_literal.cr | 64 +- src/parsers/style.cr | 75 +- src/parsers/suite.cr | 58 +- src/parsers/test.cr | 40 +- src/parsers/top_level.cr | 61 -- src/parsers/tuple_destructuring.cr | 37 +- src/parsers/tuple_literal.cr | 30 +- src/parsers/type.cr | 58 +- src/parsers/type_definition.cr | 65 ++ src/parsers/type_definition_field.cr | 50 + src/parsers/type_destructuring.cr | 72 ++ src/parsers/type_id.cr | 67 -- src/parsers/type_variable.cr | 14 +- src/parsers/type_variant.cr | 40 + src/parsers/unary_minus.cr | 9 +- src/parsers/use.cr | 57 +- src/parsers/value.cr | 17 + src/parsers/variable.cr | 79 +- src/parsers/void.cr | 14 - src/render/terminal.cr | 66 +- src/sandbox_server.cr | 4 +- src/scope.cr | 370 +++++++ src/semantic_tokenizer.cr | 28 +- src/test_runner.cr | 48 +- src/type_checker.cr | 222 ++--- src/type_checker/artifacts.cr | 8 +- src/type_checker/scope.cr | 333 ------- src/type_checker/static_type_signature.cr | 62 ++ src/type_checkers/access.cr | 138 ++- src/type_checkers/array_access.cr | 64 +- src/type_checkers/array_literal.cr | 35 +- src/type_checkers/block.cr | 76 +- src/type_checkers/call.cr | 98 +- src/type_checkers/case.cr | 132 +-- src/type_checkers/case_branch.cr | 8 +- src/type_checkers/component.cr | 266 +++-- src/type_checkers/connect.cr | 34 +- src/type_checkers/constant.cr | 2 +- src/type_checkers/css_definition.cr | 31 +- src/type_checkers/css_font_face.cr | 10 +- src/type_checkers/decode.cr | 42 +- src/type_checkers/destructuring.cr | 201 ++-- src/type_checkers/directives/asset.cr | 11 +- src/type_checkers/directives/documentation.cr | 15 +- src/type_checkers/directives/inline.cr | 11 +- src/type_checkers/directives/svg.cr | 64 +- src/type_checkers/encode.cr | 27 +- src/type_checkers/enum.cr | 49 - src/type_checkers/enum_id.cr | 102 -- src/type_checkers/enum_record_definition.cr | 17 - src/type_checkers/env.cr | 10 +- .../{record_field.cr => field.cr} | 4 +- src/type_checkers/for_expression.cr | 77 +- src/type_checkers/function.cr | 105 +- src/type_checkers/get.cr | 19 +- src/type_checkers/here_doc.cr | 34 +- src/type_checkers/html_attribute.cr | 132 ++- src/type_checkers/html_component.cr | 43 +- src/type_checkers/html_content.cr | 14 +- src/type_checkers/html_element.cr | 21 +- src/type_checkers/html_fragment.cr | 2 - src/type_checkers/html_style.cr | 53 +- src/type_checkers/if.cr | 94 +- src/type_checkers/inline_function.cr | 72 +- src/type_checkers/locale.cr | 8 +- src/type_checkers/locale_key.cr | 88 +- src/type_checkers/module.cr | 9 +- src/type_checkers/module_access.cr | 79 -- src/type_checkers/negated_expression.cr | 12 +- src/type_checkers/next_call.cr | 57 +- src/type_checkers/operation.cr | 186 ++-- src/type_checkers/property.cr | 48 +- src/type_checkers/provider.cr | 32 +- src/type_checkers/record.cr | 40 +- src/type_checkers/record_constructor.cr | 37 - src/type_checkers/record_definition.cr | 22 - src/type_checkers/record_update.cr | 58 +- src/type_checkers/return_call.cr | 16 +- src/type_checkers/route.cr | 22 +- src/type_checkers/state.cr | 18 +- src/type_checkers/statement.cr | 41 +- src/type_checkers/store.cr | 18 +- src/type_checkers/string_literal.cr | 49 +- src/type_checkers/style.cr | 6 +- src/type_checkers/suite.cr | 6 +- src/type_checkers/test.cr | 14 +- src/type_checkers/top_level.cr | 10 +- src/type_checkers/tuple_literal.cr | 2 - src/type_checkers/type_definition.cr | 58 ++ ...tion_field.cr => type_definition_field.cr} | 2 +- .../{enum_option.cr => type_variant.cr} | 2 +- src/type_checkers/unary_minus.cr | 12 +- src/type_checkers/use.cr | 37 +- src/type_checkers/variable.cr | 96 +- src/utils/html_snippet.cr | 4 +- src/utils/terminal_snippet.cr | 128 ++- 1448 files changed, 17711 insertions(+), 16892 deletions(-) rename spec/compilers/{case_with_enum_destructuring => case_with_type_destructuring} (86%) create mode 100644 spec/compilers/css_with_if_with_interpolation create mode 100644 spec/compilers/directives/highlight rename spec/compilers/{record_field => field} (100%) delete mode 100644 spec/compilers/record_constructor delete mode 100644 spec/compilers/record_constructor_partial rename spec/compilers/{enum => type} (88%) rename spec/compilers/{enum_record => type_with_variants} (57%) create mode 100644 spec/errors/access_expected_field create mode 100644 spec/errors/access_field_not_found create mode 100644 spec/errors/access_not_record create mode 100644 spec/errors/argument_expected_colon create mode 100644 spec/errors/argument_expected_default_value create mode 100644 spec/errors/argument_expected_type create mode 100644 spec/errors/array_access_expected_closing_bracket create mode 100644 spec/errors/array_access_expected_index create mode 100644 spec/errors/array_access_index_not_number create mode 100644 spec/errors/array_access_invalid_tuple create mode 100644 spec/errors/array_access_not_an_array create mode 100644 spec/errors/array_destructuring_expected_closing_bracket create mode 100644 spec/errors/array_expected_closing_bracket create mode 100644 spec/errors/array_expected_type_or_variable create mode 100644 spec/errors/array_not_matches create mode 100644 spec/errors/array_not_matches_defined_type create mode 100644 spec/errors/asset_directive_expected_closing_parenthesis create mode 100644 spec/errors/asset_directive_expected_file create mode 100644 spec/errors/asset_directive_expected_opening_parenthesis create mode 100644 spec/errors/asset_directive_expected_path create mode 100644 spec/errors/block_no_expressions create mode 100644 spec/errors/call_argument_size_mismatch create mode 100644 spec/errors/call_argument_type_mismatch create mode 100644 spec/errors/call_expected_closing_parenthesis create mode 100644 spec/errors/call_not_a_function create mode 100644 spec/errors/call_not_found_argument create mode 100644 spec/errors/call_with_mixed_arguments create mode 100644 spec/errors/case_branch_expected_expression create mode 100644 spec/errors/case_branch_not_matches create mode 100644 spec/errors/case_expected_branches create mode 100644 spec/errors/case_expected_closing_bracket create mode 100644 spec/errors/case_expected_closing_parenthesis create mode 100644 spec/errors/case_expected_condition create mode 100644 spec/errors/case_expected_opening_bracket create mode 100644 spec/errors/case_not_covered create mode 100644 spec/errors/case_type_not_covered create mode 100644 spec/errors/case_unnecessary_all create mode 100644 spec/errors/component_expected_body create mode 100644 spec/errors/component_expected_closing_bracket create mode 100644 spec/errors/component_expected_name create mode 100644 spec/errors/component_expected_opening_bracket create mode 100644 spec/errors/component_exposed_name_conflict create mode 100644 spec/errors/component_lifecycle_function_mismatch create mode 100644 spec/errors/component_main_properties create mode 100644 spec/errors/component_multiple_exposed create mode 100644 spec/errors/component_multiple_providers create mode 100644 spec/errors/component_multiple_stores create mode 100644 spec/errors/component_no_render_function create mode 100644 spec/errors/component_reference_name_conflict create mode 100644 spec/errors/component_render_function_mismatch create mode 100644 spec/errors/component_style_name_conflict create mode 100644 spec/errors/connect_expected_closing_bracket create mode 100644 spec/errors/connect_expected_exposing create mode 100644 spec/errors/connect_expected_keys create mode 100644 spec/errors/connect_expected_opening_bracket create mode 100644 spec/errors/connect_expected_store create mode 100644 spec/errors/connect_not_found_member create mode 100644 spec/errors/connect_not_found_store create mode 100644 spec/errors/connect_variable_expected_as create mode 100644 spec/errors/constant_expected_equal_sign create mode 100644 spec/errors/constant_expected_expression create mode 100644 spec/errors/constant_expected_name create mode 100644 spec/errors/css_definition_expected_semicolon create mode 100644 spec/errors/css_definition_no_property create mode 100644 spec/errors/css_definition_type_mismatch create mode 100644 spec/errors/css_font_face_expected_closing_bracket create mode 100644 spec/errors/css_font_face_expected_definitions create mode 100644 spec/errors/css_font_face_expected_opening_bracket create mode 100644 spec/errors/css_font_face_interpolation create mode 100644 spec/errors/css_keyframes_expected_closing_bracket create mode 100644 spec/errors/css_keyframes_expected_name create mode 100644 spec/errors/css_keyframes_expected_opening_bracket create mode 100644 spec/errors/css_keyframes_expected_selectors create mode 100644 spec/errors/css_nested_at_expected_body create mode 100644 spec/errors/css_nested_at_expected_closing_bracket create mode 100644 spec/errors/css_nested_at_expected_condition create mode 100644 spec/errors/css_nested_at_expected_opening_bracket create mode 100644 spec/errors/css_selector_expected_body create mode 100644 spec/errors/css_selector_expected_closing_bracket create mode 100644 spec/errors/decode_complex_type create mode 100644 spec/errors/decode_expected_as create mode 100644 spec/errors/decode_expected_object create mode 100644 spec/errors/decode_expected_subject create mode 100644 spec/errors/decode_expected_type create mode 100644 spec/errors/destructuring_multiple_spreads create mode 100644 spec/errors/destructuring_tuple_mismatch create mode 100644 spec/errors/destructuring_type_field_missing create mode 100644 spec/errors/destructuring_type_mismatch create mode 100644 spec/errors/destructuring_type_missing create mode 100644 spec/errors/destructuring_type_variant_missing create mode 100644 spec/errors/documentation_directive_entity_not_found create mode 100644 spec/errors/documentation_directive_expected_closing_parenthesis create mode 100644 spec/errors/documentation_directive_expected_entity create mode 100644 spec/errors/documentation_directive_expected_opening_parenthesis create mode 100644 spec/errors/encode_complex_type create mode 100644 spec/errors/encode_expected_expression create mode 100644 spec/errors/entity_name_conflict create mode 100644 spec/errors/env_expected_name create mode 100644 spec/errors/env_not_found_variable create mode 100644 spec/errors/for_array_or_set_arguments_mismatch create mode 100644 spec/errors/for_condition_type_mismatch create mode 100644 spec/errors/for_expected_body create mode 100644 spec/errors/for_expected_closing_bracket create mode 100644 spec/errors/for_expected_closing_parenthesis create mode 100644 spec/errors/for_expected_of create mode 100644 spec/errors/for_expected_opening_bracket create mode 100644 spec/errors/for_expected_subject create mode 100644 spec/errors/for_map_arguments_mismatch create mode 100644 spec/errors/for_type_mismatch create mode 100644 spec/errors/format_directive_expected_body create mode 100644 spec/errors/format_directive_expected_closing_bracket create mode 100644 spec/errors/format_directive_expected_opening_bracket create mode 100644 spec/errors/function_argument_conflict create mode 100644 spec/errors/function_argument_must_have_a_default_value create mode 100644 spec/errors/function_expected_closing_bracket create mode 100644 spec/errors/function_expected_closing_parenthesis create mode 100644 spec/errors/function_expected_expression create mode 100644 spec/errors/function_expected_name create mode 100644 spec/errors/function_expected_opening_bracket create mode 100644 spec/errors/function_expected_type_or_variable create mode 100644 spec/errors/function_type_mismatch create mode 100644 spec/errors/get_expected_closing_bracket create mode 100644 spec/errors/get_expected_expression create mode 100644 spec/errors/get_expected_name create mode 100644 spec/errors/get_expected_opening_bracket create mode 100644 spec/errors/get_expected_type create mode 100644 spec/errors/get_type_mismatch create mode 100644 spec/errors/here_doc_expected_end create mode 100644 spec/errors/here_doc_interpolation_type_mismatch create mode 100644 spec/errors/here_document_expected_start create mode 100644 spec/errors/highlight_directive_expected_body create mode 100644 spec/errors/highlight_directive_expected_closing_bracket create mode 100644 spec/errors/highlight_directive_expected_opening_bracket create mode 100644 spec/errors/html_attribute_component_key_type_mismatch create mode 100644 spec/errors/html_attribute_component_property_type_mismatch create mode 100644 spec/errors/html_attribute_element_attribute_type_mismatch create mode 100644 spec/errors/html_attribute_expected_closing_bracket create mode 100644 spec/errors/html_attribute_expected_equal_sign create mode 100644 spec/errors/html_attribute_expected_expression create mode 100644 spec/errors/html_attribute_expected_opening_bracket create mode 100644 spec/errors/html_attribute_not_found_component_property create mode 100644 spec/errors/html_component_attribute_required create mode 100644 spec/errors/html_component_expected_closing_bracket create mode 100644 spec/errors/html_component_expected_closing_tag create mode 100644 spec/errors/html_component_expected_reference create mode 100644 spec/errors/html_component_global_component create mode 100644 spec/errors/html_component_not_found_component create mode 100644 spec/errors/html_component_reference_outside_of_component create mode 100644 spec/errors/html_content_type_mismatch create mode 100644 spec/errors/html_element_expected_closing_bracket create mode 100644 spec/errors/html_element_expected_closing_tag create mode 100644 spec/errors/html_element_expected_reference create mode 100644 spec/errors/html_element_expected_style create mode 100644 spec/errors/html_element_ref_forbidden create mode 100644 spec/errors/html_element_reference_outside_of_component create mode 100644 spec/errors/html_element_style_outside_of_component create mode 100644 spec/errors/html_expression_expected_closing_tag create mode 100644 spec/errors/html_fragment_expected_closing_tag create mode 100644 spec/errors/html_style_argument_size_mismatch create mode 100644 spec/errors/html_style_argument_type_mismatch create mode 100644 spec/errors/html_style_expected_closing_parenthesis create mode 100644 spec/errors/html_style_not_found create mode 100644 spec/errors/if_condition_type_mismatch create mode 100644 spec/errors/if_else_type_mismatch create mode 100644 spec/errors/if_expected_closing_parenthesis create mode 100644 spec/errors/if_expected_condition create mode 100644 spec/errors/if_expected_else_closing_bracket create mode 100644 spec/errors/if_expected_else_expression create mode 100644 spec/errors/if_expected_else_opening_bracket create mode 100644 spec/errors/if_expected_truthy_closing_bracket create mode 100644 spec/errors/if_expected_truthy_expression create mode 100644 spec/errors/if_expected_truthy_opening_bracket create mode 100644 spec/errors/inline_directive_expected_closing_parenthesis create mode 100644 spec/errors/inline_directive_expected_file create mode 100644 spec/errors/inline_directive_expected_opening_parenthesis create mode 100644 spec/errors/inline_directive_expected_path create mode 100644 spec/errors/inline_function_expected_body create mode 100644 spec/errors/inline_function_expected_closing_bracket create mode 100644 spec/errors/inline_function_expected_closing_parenthesis create mode 100644 spec/errors/inline_function_expected_opening_bracket create mode 100644 spec/errors/inline_function_expected_type create mode 100644 spec/errors/inline_function_type_mismatch create mode 100644 spec/errors/interpolation_expected_closing_bracket create mode 100644 spec/errors/interpolation_expected_expression create mode 100644 spec/errors/invalid_self_reference create mode 100644 spec/errors/locale_expected_closing_bracket create mode 100644 spec/errors/locale_expected_language create mode 100644 spec/errors/locale_expected_opening_bracket create mode 100644 spec/errors/member_access_expected_variable create mode 100644 spec/errors/module_expected_body create mode 100644 spec/errors/module_expected_closing_bracket create mode 100644 spec/errors/module_expected_name create mode 100644 spec/errors/module_expected_opening_bracket create mode 100644 spec/errors/negated_expression_expected_expression create mode 100644 spec/errors/negated_expression_not_bool create mode 100644 spec/errors/next_call_expected_fields create mode 100644 spec/errors/next_call_invalid_invocation create mode 100644 spec/errors/next_call_state_not_found create mode 100644 spec/errors/next_call_state_type_mismatch create mode 100644 spec/errors/number_literal_expected_decimal create mode 100644 spec/errors/operation_expected_expression create mode 100644 spec/errors/operation_numeric_type_mismatch create mode 100644 spec/errors/operation_or_not_maybe_or_result create mode 100644 spec/errors/operation_or_type_mismatch create mode 100644 spec/errors/operation_pipe_ambiguous create mode 100644 spec/errors/operation_plus_type_mismatch create mode 100644 spec/errors/property_expected_default_value create mode 100644 spec/errors/property_expected_name create mode 100644 spec/errors/property_expected_type create mode 100644 spec/errors/property_type_mismatch create mode 100644 spec/errors/property_type_or_default_needed create mode 100644 spec/errors/property_with_type_variables create mode 100644 spec/errors/provider_expeceted_colon create mode 100644 spec/errors/provider_expected_body create mode 100644 spec/errors/provider_expected_closing_bracket create mode 100644 spec/errors/provider_expected_name create mode 100644 spec/errors/provider_expected_opening_bracket create mode 100644 spec/errors/provider_expected_subscription create mode 100644 spec/errors/provider_not_found_subscription create mode 100644 spec/errors/record_not_found_matching_record_definition create mode 100644 spec/errors/record_update_expected_closing_bracket create mode 100644 spec/errors/record_update_expected_fields create mode 100644 spec/errors/record_update_not_found_key create mode 100644 spec/errors/record_update_not_updating_record create mode 100644 spec/errors/record_update_type_mismatch create mode 100644 spec/errors/record_with_holes create mode 100644 spec/errors/recursion create mode 100644 spec/errors/regexp_literal_expected_closing_slash create mode 100644 spec/errors/return_call_expected_expression create mode 100644 spec/errors/return_call_invalid create mode 100644 spec/errors/route_expected_body create mode 100644 spec/errors/route_expected_closing_bracket create mode 100644 spec/errors/route_expected_closing_parenthesis create mode 100644 spec/errors/route_expected_opening_bracket create mode 100644 spec/errors/route_param_invalid create mode 100644 spec/errors/routes_expected_body create mode 100644 spec/errors/routes_expected_closing_bracket create mode 100644 spec/errors/routes_expected_opening_bracket create mode 100644 spec/errors/spread_expected_variable create mode 100644 spec/errors/state_expected_default_value create mode 100644 spec/errors/state_expected_equal_sign create mode 100644 spec/errors/state_expected_name create mode 100644 spec/errors/state_expected_type create mode 100644 spec/errors/state_type_mismatch create mode 100644 spec/errors/statement_last_target create mode 100644 spec/errors/statement_return_required create mode 100644 spec/errors/statement_return_type_mismatch create mode 100644 spec/errors/store_expected_body create mode 100644 spec/errors/store_expected_closing_bracket create mode 100644 spec/errors/store_expected_name create mode 100644 spec/errors/store_expected_opening_bracket create mode 100644 spec/errors/string_expected_closing_quote create mode 100644 spec/errors/string_expected_other_string create mode 100644 spec/errors/string_literal_interpolation_type_mismatch create mode 100644 spec/errors/style_expected_body create mode 100644 spec/errors/style_expected_closing_bracket create mode 100644 spec/errors/style_expected_closing_parenthesis create mode 100644 spec/errors/style_expected_name create mode 100644 spec/errors/style_expected_opening_bracket create mode 100644 spec/errors/suite_expected_body create mode 100644 spec/errors/suite_expected_closing_bracket create mode 100644 spec/errors/suite_expected_name create mode 100644 spec/errors/suite_expected_opening_bracket create mode 100644 spec/errors/svg_directive_expected_closing_parenthesis create mode 100644 spec/errors/svg_directive_expected_dimensions create mode 100644 spec/errors/svg_directive_expected_file create mode 100644 spec/errors/svg_directive_expected_opening_parenthesis create mode 100644 spec/errors/svg_directive_expected_path create mode 100644 spec/errors/svg_directive_expected_svg create mode 100644 spec/errors/svg_directive_expected_svg_tag create mode 100644 spec/errors/test_expected_body create mode 100644 spec/errors/test_expected_closing_bracket create mode 100644 spec/errors/test_expected_name create mode 100644 spec/errors/test_expected_opening_bracket create mode 100644 spec/errors/test_type_mismatch create mode 100644 spec/errors/translation_mismatch create mode 100644 spec/errors/translation_missing create mode 100644 spec/errors/translation_not_translated create mode 100644 spec/errors/tuple_destructuring_expected_closing_parenthesis create mode 100644 spec/errors/tuple_literal_expected_closing_parenthesis rename spec/{formatters/enum => errors/type_definition_expected_closing_bracket} (52%) create mode 100644 spec/errors/type_definition_expected_closing_parenthesis create mode 100644 spec/errors/type_definition_expected_name create mode 100644 spec/errors/type_definition_field_expected_colon create mode 100644 spec/errors/type_definition_field_expected_mapping create mode 100644 spec/errors/type_definition_field_expected_type create mode 100644 spec/errors/type_definition_not_defined_parameter create mode 100644 spec/errors/type_definition_unused_parameter create mode 100644 spec/errors/type_destructuring_expected_closing_parenthesis create mode 100644 spec/errors/type_destructuring_expected_variant create mode 100644 spec/errors/type_expected_closing_parenthesis create mode 100644 spec/errors/type_expected_type_or_type_variable create mode 100644 spec/errors/type_variant_expected_closing_parenthesis create mode 100644 spec/errors/unary_minus_not_number create mode 100644 spec/errors/use_condition_mismatch create mode 100644 spec/errors/use_expected_condition create mode 100644 spec/errors/use_expected_condition_closing_bracket create mode 100644 spec/errors/use_expected_condition_opening_bracket create mode 100644 spec/errors/use_expected_provider create mode 100644 spec/errors/use_expected_record create mode 100644 spec/errors/use_not_found_provider create mode 100644 spec/errors/use_subscription_mismatch create mode 100644 spec/errors/variable_missing create mode 100644 spec/errors/variable_reserved create mode 100644 spec/errors_spec.cr create mode 100644 spec/examples/access rename spec/{type_checking => examples}/access_call (100%) create mode 100644 spec/examples/argument rename spec/{type_checking => examples}/array_access (55%) create mode 100644 spec/examples/array_destructuring rename spec/{type_checking => examples}/array_literal (53%) create mode 100644 spec/examples/bool_literal create mode 100644 spec/examples/call create mode 100644 spec/examples/case rename spec/{type_checking => examples}/case_array (75%) rename spec/{type_checking => examples}/case_tuple (68%) create mode 100644 spec/examples/comment create mode 100644 spec/examples/component create mode 100644 spec/examples/connect create mode 100644 spec/examples/constant rename spec/{type_checking => examples}/css_definition (52%) create mode 100644 spec/examples/css_font_face create mode 100644 spec/examples/css_keyframes create mode 100644 spec/examples/css_nested_at create mode 100644 spec/examples/css_selector create mode 100644 spec/examples/decode create mode 100644 spec/examples/destructuring create mode 100644 spec/examples/directives/asset create mode 100644 spec/examples/directives/documentation create mode 100644 spec/examples/directives/format create mode 100644 spec/examples/directives/highlight create mode 100644 spec/examples/directives/inline create mode 100644 spec/examples/directives/svg create mode 100644 spec/examples/encode create mode 100644 spec/examples/env rename spec/{type_checking/for => examples/for_expression} (53%) create mode 100644 spec/examples/function create mode 100644 spec/examples/get create mode 100644 spec/examples/here_document create mode 100644 spec/examples/html_attribute create mode 100644 spec/examples/html_component create mode 100644 spec/examples/html_element rename spec/{type_checking/html_element_string_style => examples/html_expression} (56%) create mode 100644 spec/examples/html_fragment create mode 100644 spec/examples/html_style create mode 100644 spec/examples/if create mode 100644 spec/examples/inline_function create mode 100644 spec/examples/interpolation rename spec/{type_checking => examples}/js (50%) create mode 100644 spec/examples/locale create mode 100644 spec/examples/member_access create mode 100644 spec/examples/module create mode 100644 spec/examples/negated_expression create mode 100644 spec/examples/next_call create mode 100644 spec/examples/number_literal create mode 100644 spec/examples/operation create mode 100644 spec/examples/parenthesized_expression rename spec/{type_checking => examples}/pipe (76%) rename spec/{type_checking => examples}/property (52%) create mode 100644 spec/examples/provider create mode 100644 spec/examples/record rename spec/{type_checking => examples}/record_update (60%) rename spec/{type_checking/recursive => examples/recursion} (76%) create mode 100644 spec/examples/regexp_literal rename spec/{type_checking/return => examples/return_call} (50%) create mode 100644 spec/examples/route create mode 100644 spec/examples/routes rename spec/{type_checking/state_own_reference => examples/self_reference} (57%) create mode 100644 spec/examples/spread create mode 100644 spec/examples/state create mode 100644 spec/examples/statement create mode 100644 spec/examples/store create mode 100644 spec/examples/string_literal create mode 100644 spec/examples/style create mode 100644 spec/examples/suite create mode 100644 spec/examples/test create mode 100644 spec/examples/tuple create mode 100644 spec/examples/type create mode 100644 spec/examples/type_definition create mode 100644 spec/examples/type_definition_field create mode 100644 spec/examples/type_destructuring create mode 100644 spec/examples/type_variable create mode 100644 spec/examples/type_variant create mode 100644 spec/examples/unary_minus rename spec/{type_checking => examples}/use (51%) create mode 100644 spec/examples/variable rename spec/{type_checking => examples}/void (100%) create mode 100644 spec/examples_spec.cr delete mode 100644 spec/formatters/enum_with_comments delete mode 100644 spec/formatters/enum_with_options rename spec/formatters/{record_field => field} (88%) rename spec/formatters/{record_field_multiline => field_multiline} (94%) rename spec/formatters/{record_field_with_comments => field_with_comments} (92%) delete mode 100644 spec/formatters/record_constructor delete mode 100644 spec/formatters/record_constructor_with_new_line rename spec/formatters/{record_definition => type_definition} (72%) rename spec/formatters/{record_definition_with_comments => type_definition_with_comments} (65%) rename spec/formatters/{record_definition_with_from => type_definition_with_using} (66%) rename spec/formatters/{enum_record => type_record} (78%) rename spec/formatters/{enum_record_multiline => type_record_multiline} (95%) rename spec/language_server/definition/location/{enum_id_name => type_definition} (100%) rename spec/language_server/definition/location/{enum_destructuring_name => type_destructuring_name} (100%) rename spec/language_server/definition/location/{enum_destructuring_option => type_destructuring_option} (100%) rename spec/language_server/definition/location/{type_enum => type_type} (100%) rename spec/language_server/definition/location/{enum_id_option => type_variant} (100%) rename spec/language_server/definition/location/{variable_casebranch_enumdestructuring => variable_casebranch_typedestructuring} (100%) rename spec/language_server/definition/location_link/{enum_destructuring_name => type_destructuring_name} (100%) rename spec/language_server/definition/location_link/{enum_destructuring_option => type_destructuring_option} (100%) rename spec/language_server/definition/location_link/{variable_casebranch_enumdestructuring => variable_casebranch_typedestructuring} (100%) rename spec/language_server/hover/{enum => type_definition} (100%) rename spec/language_server/hover/{enum_destructuring => type_destructuring} (100%) rename spec/language_server/hover/{type_enum => type_type} (90%) rename spec/language_server/hover/{enum_id => type_variant} (100%) rename spec/language_server/hover/{enum_option => type_variant_2} (100%) delete mode 100644 spec/messages_spec.cr delete mode 100644 spec/parsers/access_spec.cr delete mode 100644 spec/parsers/argument_spec.cr delete mode 100644 spec/parsers/array_access_spec.cr delete mode 100644 spec/parsers/array_destructuring.cr delete mode 100644 spec/parsers/array_literal_spec.cr delete mode 100644 spec/parsers/bool_literal_spec.cr delete mode 100644 spec/parsers/call_spec.cr delete mode 100644 spec/parsers/case_branch_spec.cr delete mode 100644 spec/parsers/case_spec.cr delete mode 100644 spec/parsers/comment_spec.cr delete mode 100644 spec/parsers/component_spec.cr delete mode 100644 spec/parsers/connect_spec.cr delete mode 100644 spec/parsers/connect_variable_spec.cr delete mode 100644 spec/parsers/constant_spec.cr delete mode 100644 spec/parsers/css_definition_spec.cr delete mode 100644 spec/parsers/css_interpolation_spec.cr delete mode 100644 spec/parsers/css_keyframes.cr delete mode 100644 spec/parsers/css_selector_spec.cr delete mode 100644 spec/parsers/decode.cr delete mode 100644 spec/parsers/directives/documentation.cr delete mode 100644 spec/parsers/directives/format_spec.cr delete mode 100644 spec/parsers/env_spec.cr delete mode 100644 spec/parsers/for_spec.cr delete mode 100644 spec/parsers/function_spec.cr delete mode 100644 spec/parsers/get_spec.cr delete mode 100644 spec/parsers/html_attribute_spec.cr delete mode 100644 spec/parsers/html_component_spec.cr delete mode 100644 spec/parsers/html_element_spec.cr delete mode 100644 spec/parsers/html_expression_spec.cr delete mode 100644 spec/parsers/html_fragment_spec.cr delete mode 100644 spec/parsers/if_spec.cr delete mode 100644 spec/parsers/inline_function_spec.cr delete mode 100644 spec/parsers/js_spec.cr delete mode 100644 spec/parsers/locale_key_spec.cr delete mode 100644 spec/parsers/locale_spec.cr delete mode 100644 spec/parsers/member_access_spec.cr delete mode 100644 spec/parsers/module_access_spec.cr delete mode 100644 spec/parsers/module_spec.cr delete mode 100644 spec/parsers/negated_expression_spec.cr delete mode 100644 spec/parsers/next_call_spec.cr delete mode 100644 spec/parsers/number_literal_spec.cr delete mode 100644 spec/parsers/operation_spec.cr delete mode 100644 spec/parsers/parenthesized_expression_spec.cr delete mode 100644 spec/parsers/pipe_spec.cr delete mode 100644 spec/parsers/property_spec.cr delete mode 100644 spec/parsers/provider_spec.cr delete mode 100644 spec/parsers/record_definition_field_spec.cr delete mode 100644 spec/parsers/record_definition_spec.cr delete mode 100644 spec/parsers/record_field_spec.cr delete mode 100644 spec/parsers/record_spec.cr delete mode 100644 spec/parsers/record_update_spec.cr delete mode 100644 spec/parsers/regexp_literal_spec.cr delete mode 100644 spec/parsers/return_call_spec.cr delete mode 100644 spec/parsers/route_spec.cr delete mode 100644 spec/parsers/routes_spec.cr delete mode 100644 spec/parsers/spread.cr delete mode 100644 spec/parsers/state_spec.cr delete mode 100644 spec/parsers/statement_spec.cr delete mode 100644 spec/parsers/store_spec.cr delete mode 100644 spec/parsers/string_literal_spec.cr delete mode 100644 spec/parsers/style_spec.cr delete mode 100644 spec/parsers/tuple_destructuring_spec.cr delete mode 100644 spec/parsers/tuple_literal_spec.cr delete mode 100644 spec/parsers/type_spec.cr delete mode 100644 spec/parsers/type_variable_spec.cr delete mode 100644 spec/parsers/unary_minus_spec.cr delete mode 100644 spec/parsers/use_spec.cr delete mode 100644 spec/parsers/variable_spec.cr delete mode 100644 spec/parsers/void_spec.cr delete mode 100644 spec/recursion_spec.cr delete mode 100644 spec/type_checking/access delete mode 100644 spec/type_checking/argument delete mode 100644 spec/type_checking/argument_with_default_value delete mode 100644 spec/type_checking/argument_with_default_value_inline_function delete mode 100644 spec/type_checking/bool_literal_false delete mode 100644 spec/type_checking/bool_literal_true delete mode 100644 spec/type_checking/case delete mode 100644 spec/type_checking/case_branch delete mode 100644 spec/type_checking/case_type_unification delete mode 100644 spec/type_checking/component delete mode 100644 spec/type_checking/connect delete mode 100644 spec/type_checking/css_font_face delete mode 100644 spec/type_checking/css_selector delete mode 100644 spec/type_checking/css_string delete mode 100644 spec/type_checking/css_with_arguments delete mode 100644 spec/type_checking/decode delete mode 100644 spec/type_checking/directives/documentation delete mode 100644 spec/type_checking/directives/format delete mode 100644 spec/type_checking/directives/svg delete mode 100644 spec/type_checking/enum delete mode 100644 spec/type_checking/enum_id delete mode 100644 spec/type_checking/enum_record delete mode 100644 spec/type_checking/env delete mode 100644 spec/type_checking/function delete mode 100644 spec/type_checking/function_call delete mode 100644 spec/type_checking/function_call_labelled delete mode 100644 spec/type_checking/function_returning_argument delete mode 100644 spec/type_checking/function_returning_variable_argument delete mode 100644 spec/type_checking/get delete mode 100644 spec/type_checking/global_component_inside_call delete mode 100644 spec/type_checking/html_attribute delete mode 100644 spec/type_checking/html_attribute_array delete mode 100644 spec/type_checking/html_attribute_disabled delete mode 100644 spec/type_checking/html_attribute_event delete mode 100644 spec/type_checking/html_attribute_key delete mode 100644 spec/type_checking/html_attribute_not_found delete mode 100644 spec/type_checking/html_attribute_readonly delete mode 100644 spec/type_checking/html_attribute_ref delete mode 100644 spec/type_checking/html_attribute_type_mismatch delete mode 100644 spec/type_checking/html_component delete mode 100644 spec/type_checking/html_element_not_in_component delete mode 100644 spec/type_checking/html_element_style delete mode 100644 spec/type_checking/html_expression delete mode 100644 spec/type_checking/html_style delete mode 100644 spec/type_checking/if delete mode 100644 spec/type_checking/if_in_html delete mode 100644 spec/type_checking/if_let delete mode 100644 spec/type_checking/inline_function delete mode 100644 spec/type_checking/locale_key delete mode 100644 spec/type_checking/member_access delete mode 100644 spec/type_checking/module delete mode 100644 spec/type_checking/module_access delete mode 100644 spec/type_checking/module_access_get delete mode 100644 spec/type_checking/module_access_provider delete mode 100644 spec/type_checking/module_access_subscriptions delete mode 100644 spec/type_checking/module_call delete mode 100644 spec/type_checking/negated_bool delete mode 100644 spec/type_checking/negated_expression delete mode 100644 spec/type_checking/next_call delete mode 100644 spec/type_checking/number_literal delete mode 100644 spec/type_checking/open_module delete mode 100644 spec/type_checking/operation_bool delete mode 100644 spec/type_checking/operation_numeric delete mode 100644 spec/type_checking/operation_or delete mode 100644 spec/type_checking/operation_plus delete mode 100644 spec/type_checking/operation_with_pipe delete mode 100644 spec/type_checking/parenthesized_expression delete mode 100644 spec/type_checking/provider_const delete mode 100644 spec/type_checking/record delete mode 100644 spec/type_checking/record_constructor delete mode 100644 spec/type_checking/record_definition_not_found delete mode 100644 spec/type_checking/record_field delete mode 100644 spec/type_checking/record_same delete mode 100644 spec/type_checking/route delete mode 100644 spec/type_checking/routes delete mode 100644 spec/type_checking/state delete mode 100644 spec/type_checking/statement delete mode 100644 spec/type_checking/store delete mode 100644 spec/type_checking/store_call_with_next delete mode 100644 spec/type_checking/string_literal delete mode 100644 spec/type_checking/suite_const delete mode 100644 spec/type_checking/tuple_with_pipe delete mode 100644 spec/type_checking/type_normalize delete mode 100644 spec/type_checking/unary_minus delete mode 100644 spec/type_checking/uncapitalized_type delete mode 100644 spec/type_checking/variable delete mode 100644 spec/type_checking_spec.cr delete mode 100644 src/ast/call_expression.cr delete mode 100644 src/ast/data.cr delete mode 100644 src/ast/directives/asset.cr create mode 100644 src/ast/directives/file_based.cr delete mode 100644 src/ast/directives/inline.cr delete mode 100644 src/ast/directives/svg.cr delete mode 100644 src/ast/enum.cr delete mode 100644 src/ast/enum_destructuring.cr delete mode 100644 src/ast/enum_id.cr delete mode 100644 src/ast/enum_option.cr delete mode 100644 src/ast/enum_record.cr delete mode 100644 src/ast/enum_record_definition.cr create mode 100644 src/ast/field.cr delete mode 100644 src/ast/for_condition.cr delete mode 100644 src/ast/here_doc.cr create mode 100644 src/ast/here_document.cr create mode 100644 src/ast/id.cr delete mode 100644 src/ast/module_access.cr delete mode 100644 src/ast/option.cr delete mode 100644 src/ast/record_definition.cr delete mode 100644 src/ast/record_field.cr create mode 100644 src/ast/type_definition.cr rename src/ast/{record_definition_field.cr => type_definition_field.cr} (54%) create mode 100644 src/ast/type_destructuring.cr delete mode 100644 src/ast/type_id.cr create mode 100644 src/ast/type_variant.cr delete mode 100644 src/ast/void.cr delete mode 100644 src/compilers/call_expression.cr delete mode 100644 src/compilers/enum.cr delete mode 100644 src/compilers/enum_id.cr create mode 100644 src/compilers/field.cr delete mode 100644 src/compilers/module_access.cr delete mode 100644 src/compilers/record_constructor.cr delete mode 100644 src/compilers/record_definition.cr delete mode 100644 src/compilers/record_field.cr create mode 100644 src/compilers/type_definition.cr delete mode 100644 src/compilers/void.cr delete mode 100644 src/documentation_generator/enum.cr rename src/documentation_generator/{type_id.cr => id.cr} (55%) rename src/documentation_generator/{record_definition.cr => type_definition.cr} (81%) rename src/documentation_generator/{record_definition_field.cr => type_definition_field.cr} (56%) rename src/documentation_generator/{enum_option.cr => type_variant.cr} (83%) create mode 100644 src/errorable.cr delete mode 100644 src/errors/error.cr delete mode 100644 src/errors/install_error.cr delete mode 100644 src/errors/json_error.cr delete mode 100644 src/errors/syntax_error.cr delete mode 100644 src/errors/top_level.cr delete mode 100644 src/errors/type_error.cr delete mode 100644 src/formatters/call_expression.cr delete mode 100644 src/formatters/enum.cr delete mode 100644 src/formatters/enum_destructuring.cr delete mode 100644 src/formatters/enum_id.cr delete mode 100644 src/formatters/enum_option.cr delete mode 100644 src/formatters/enum_record_definition.cr create mode 100644 src/formatters/field.cr rename src/formatters/{type_id.cr => id.cr} (59%) delete mode 100644 src/formatters/module_access.cr delete mode 100644 src/formatters/record_definition.cr delete mode 100644 src/formatters/record_field.cr create mode 100644 src/formatters/type_definition.cr rename src/formatters/{record_definition_field.cr => type_definition_field.cr} (86%) create mode 100644 src/formatters/type_destructuring.cr create mode 100644 src/formatters/type_variant.cr delete mode 100644 src/formatters/void.cr create mode 100644 src/helpers.cr delete mode 100644 src/ls/completions/enum.cr create mode 100644 src/ls/completions/type_definition.cr delete mode 100644 src/ls/definition/enum_destructuring.cr delete mode 100644 src/ls/definition/enum_id.cr create mode 100644 src/ls/definition/id.cr delete mode 100644 src/ls/definition/module_access.cr create mode 100644 src/ls/definition/type_destructuring.cr delete mode 100644 src/ls/definition/type_id.cr create mode 100644 src/ls/hover/access.cr delete mode 100644 src/ls/hover/enum.cr delete mode 100644 src/ls/hover/enum_id.cr delete mode 100644 src/ls/hover/enum_option.cr delete mode 100644 src/ls/hover/module_access.cr create mode 100644 src/ls/hover/type_definition.cr rename src/ls/hover/{enum_destructuring.cr => type_destructuring.cr} (54%) create mode 100644 src/ls/hover/type_variant.cr delete mode 100644 src/macros.cr delete mode 100644 src/message.cr delete mode 100644 src/messages/access_expected_variable.cr delete mode 100644 src/messages/access_field_not_found.cr delete mode 100644 src/messages/access_not_record.cr delete mode 100644 src/messages/argument_expected_colon.cr delete mode 100644 src/messages/argument_expected_default_value.cr delete mode 100644 src/messages/argument_expected_type_or_variable.cr delete mode 100644 src/messages/array_access_expected_closing_bracket.cr delete mode 100644 src/messages/array_access_expected_index.cr delete mode 100644 src/messages/array_access_index_not_number.cr delete mode 100644 src/messages/array_access_invalid_tuple.cr delete mode 100644 src/messages/array_access_not_an_array.cr delete mode 100644 src/messages/array_destructuring_expected_closing_bracket.cr delete mode 100644 src/messages/array_expected_closing_bracket.cr delete mode 100644 src/messages/array_literal_expected_type_or_variable.cr delete mode 100644 src/messages/array_not_matches.cr delete mode 100644 src/messages/array_not_matches_defined_type.cr delete mode 100644 src/messages/asset_directive_expected_closing_parentheses.cr delete mode 100644 src/messages/asset_directive_expected_file.cr delete mode 100644 src/messages/asset_directive_expected_opening_parentheses.cr delete mode 100644 src/messages/asset_directive_expected_path.cr delete mode 100644 src/messages/browser_not_found.cr delete mode 100644 src/messages/call_argument_size_mismatch.cr delete mode 100644 src/messages/call_argument_type_mismatch.cr delete mode 100644 src/messages/call_expected_closing_parentheses.cr delete mode 100644 src/messages/call_not_a_function.cr delete mode 100644 src/messages/call_not_found_argument.cr delete mode 100644 src/messages/call_type_mismatch.cr delete mode 100644 src/messages/call_with_mixed_arguments.cr delete mode 100644 src/messages/case_branch_expected_expression.cr delete mode 100644 src/messages/case_branch_not_matches.cr delete mode 100644 src/messages/case_enum_not_covered.cr delete mode 100644 src/messages/case_expected_branches.cr delete mode 100644 src/messages/case_expected_closing_bracket.cr delete mode 100644 src/messages/case_expected_closing_parentheses.cr delete mode 100644 src/messages/case_expected_condition.cr delete mode 100644 src/messages/case_expected_opening_bracket.cr delete mode 100644 src/messages/case_not_covered.cr delete mode 100644 src/messages/case_unnecessary_all.cr delete mode 100644 src/messages/component_entity_name_conflict.cr delete mode 100644 src/messages/component_expected_body.cr delete mode 100644 src/messages/component_expected_closing_bracket.cr delete mode 100644 src/messages/component_expected_name.cr delete mode 100644 src/messages/component_expected_opening_bracket.cr delete mode 100644 src/messages/component_exposed_name_conflict.cr delete mode 100644 src/messages/component_function_type_mismatch.cr delete mode 100644 src/messages/component_main_property.cr delete mode 100644 src/messages/component_multiple_connects.cr delete mode 100644 src/messages/component_multiple_exposed.cr delete mode 100644 src/messages/component_multiple_uses.cr delete mode 100644 src/messages/component_not_found_render.cr delete mode 100644 src/messages/component_reference_name_conflict.cr delete mode 100644 src/messages/component_render_type_mismatch.cr delete mode 100644 src/messages/component_state_name_conflict.cr delete mode 100644 src/messages/component_style_name_conflict.cr delete mode 100644 src/messages/connect_expected_closing_bracket.cr delete mode 100644 src/messages/connect_expected_exposing.cr delete mode 100644 src/messages/connect_expected_keys.cr delete mode 100644 src/messages/connect_expected_opening_bracket.cr delete mode 100644 src/messages/connect_expected_type.cr delete mode 100644 src/messages/connect_not_found_member.cr delete mode 100644 src/messages/connect_not_found_store.cr delete mode 100644 src/messages/connect_variable_expected_as.cr delete mode 100644 src/messages/constant_expected_equal_sign.cr delete mode 100644 src/messages/constant_expected_name.cr delete mode 100644 src/messages/constant_expected_value.cr delete mode 100644 src/messages/css_definition_expected_semicolon.cr delete mode 100644 src/messages/css_definition_type_mismatch.cr delete mode 100644 src/messages/css_font_face_expected_closing_bracket.cr delete mode 100644 src/messages/css_font_face_expected_opening_bracket.cr delete mode 100644 src/messages/css_font_face_interpolation.cr delete mode 100644 src/messages/css_keyframes_expected_closing_bracket.cr delete mode 100644 src/messages/css_keyframes_expected_name.cr delete mode 100644 src/messages/css_keyframes_expected_opening_bracket.cr delete mode 100644 src/messages/css_nested_at_expected_closing_bracket.cr delete mode 100644 src/messages/css_nested_at_expected_condition.cr delete mode 100644 src/messages/css_nested_at_expected_opening_bracket.cr delete mode 100644 src/messages/css_nested_at_expected_space_after_keyword.cr delete mode 100644 src/messages/css_no_property.cr delete mode 100644 src/messages/css_selector_expected_closing_bracket.cr delete mode 100644 src/messages/css_selector_expected_opening_bracket.cr delete mode 100644 src/messages/decode_complex_type.cr delete mode 100644 src/messages/decode_expected_as.cr delete mode 100644 src/messages/decode_expected_expression.cr delete mode 100644 src/messages/decode_expected_object.cr delete mode 100644 src/messages/decode_expected_type.cr delete mode 100644 src/messages/destructuring_multiple_spreads.cr delete mode 100644 src/messages/destructuring_no_parameter.cr delete mode 100644 src/messages/destructuring_tuple_mismatch.cr delete mode 100644 src/messages/destructuring_type_mismatch.cr delete mode 100644 src/messages/documentation_directive_entity_not_found.cr delete mode 100644 src/messages/documentation_directive_expected_closing_parentheses.cr delete mode 100644 src/messages/documentation_directive_expected_entity.cr delete mode 100644 src/messages/documentation_directive_expected_opening_parentheses.cr delete mode 100644 src/messages/encode_complex_type.cr delete mode 100644 src/messages/encode_expected_expression.cr delete mode 100644 src/messages/enum_destructuring_expected_closing_parentheses.cr delete mode 100644 src/messages/enum_destructuring_expected_double_colon.cr delete mode 100644 src/messages/enum_destructuring_expected_option.cr delete mode 100644 src/messages/enum_expected_closing_bracket.cr delete mode 100644 src/messages/enum_expected_closing_parentheses.cr delete mode 100644 src/messages/enum_expected_name.cr delete mode 100644 src/messages/enum_expected_opening_bracket.cr delete mode 100644 src/messages/enum_id_enum_missing.cr delete mode 100644 src/messages/enum_id_expected_closing_parentheses.cr delete mode 100644 src/messages/enum_id_expected_double_colon.cr delete mode 100644 src/messages/enum_id_expected_option.cr delete mode 100644 src/messages/enum_id_type_mismatch.cr delete mode 100644 src/messages/enum_id_type_missing.cr delete mode 100644 src/messages/enum_not_defined_parameter.cr delete mode 100644 src/messages/enum_option_expected_closing_parentheses.cr delete mode 100644 src/messages/enum_unused_parameter.cr delete mode 100644 src/messages/env_expected_name.cr delete mode 100644 src/messages/env_file_not_found.cr delete mode 100644 src/messages/env_not_found_variable.cr delete mode 100644 src/messages/expected_end_of_file.cr delete mode 100644 src/messages/for_array_or_set_arguments_mismatch.cr delete mode 100644 src/messages/for_condition_expected_body.cr delete mode 100644 src/messages/for_condition_expected_closing_bracket.cr delete mode 100644 src/messages/for_condition_expected_opening_bracket.cr delete mode 100644 src/messages/for_condition_type_mismatch.cr delete mode 100644 src/messages/for_expected_body.cr delete mode 100644 src/messages/for_expected_closing_bracket.cr delete mode 100644 src/messages/for_expected_closing_parentheses.cr delete mode 100644 src/messages/for_expected_of.cr delete mode 100644 src/messages/for_expected_opening_bracket.cr delete mode 100644 src/messages/for_expected_subject.cr delete mode 100644 src/messages/for_map_arguments_mismatch.cr delete mode 100644 src/messages/for_type_mismatch.cr delete mode 100644 src/messages/format_directive_expected_closing_bracket.cr delete mode 100644 src/messages/format_directive_expected_expression.cr delete mode 100644 src/messages/format_directive_expected_opening_bracket.cr delete mode 100644 src/messages/function_argument_conflict.cr delete mode 100644 src/messages/function_argument_must_have_a_default_value.cr delete mode 100644 src/messages/function_expected_closing_bracket.cr delete mode 100644 src/messages/function_expected_closing_parentheses.cr delete mode 100644 src/messages/function_expected_expression.cr delete mode 100644 src/messages/function_expected_name.cr delete mode 100644 src/messages/function_expected_opening_bracket.cr delete mode 100644 src/messages/function_expected_type_or_variable.cr delete mode 100644 src/messages/function_type_mismatch.cr delete mode 100644 src/messages/function_type_needed.cr delete mode 100644 src/messages/get_expected_closing_bracket.cr delete mode 100644 src/messages/get_expected_colon.cr delete mode 100644 src/messages/get_expected_expression.cr delete mode 100644 src/messages/get_expected_name.cr delete mode 100644 src/messages/get_expected_opening_bracket.cr delete mode 100644 src/messages/get_expected_type.cr delete mode 100644 src/messages/get_type_mismatch.cr delete mode 100644 src/messages/global_name_conflict.cr delete mode 100644 src/messages/here_doc_expected_end.cr delete mode 100644 src/messages/here_doc_expected_start.cr delete mode 100644 src/messages/here_doc_interpolation_type_mismatch.cr delete mode 100644 src/messages/html_attribute_component_key_type_mismatch.cr delete mode 100644 src/messages/html_attribute_component_property_type_mismatch.cr delete mode 100644 src/messages/html_attribute_element_attribute_type_mismatch.cr delete mode 100644 src/messages/html_attribute_expected_closing_bracket.cr delete mode 100644 src/messages/html_attribute_expected_equal_sign.cr delete mode 100644 src/messages/html_attribute_expected_expression.cr delete mode 100644 src/messages/html_attribute_expected_opening_bracket.cr delete mode 100644 src/messages/html_attribute_fragment_key_type_mismatch.cr delete mode 100644 src/messages/html_attribute_not_found_component_property.cr delete mode 100644 src/messages/html_component_attribute_required.cr delete mode 100644 src/messages/html_component_expected_closing_bracket.cr delete mode 100644 src/messages/html_component_expected_closing_tag.cr delete mode 100644 src/messages/html_component_expected_reference.cr delete mode 100644 src/messages/html_component_expected_type.cr delete mode 100644 src/messages/html_component_global_component.cr delete mode 100644 src/messages/html_component_not_found_component.cr delete mode 100644 src/messages/html_component_reference_outside_of_component.cr delete mode 100644 src/messages/html_content_type_mismatch.cr delete mode 100644 src/messages/html_element_class_name_forbidden.cr delete mode 100644 src/messages/html_element_expected_closing_bracket.cr delete mode 100644 src/messages/html_element_expected_closing_tag.cr delete mode 100644 src/messages/html_element_expected_reference.cr delete mode 100644 src/messages/html_element_expected_style.cr delete mode 100644 src/messages/html_element_ref_forbidden.cr delete mode 100644 src/messages/html_element_reference_outside_of_component.cr delete mode 100644 src/messages/html_element_style_outside_of_component.cr delete mode 100644 src/messages/html_expression_expected_closing_tag.cr delete mode 100644 src/messages/html_fragment_expected_closing_bracket.cr delete mode 100644 src/messages/html_fragment_expected_closing_tag.cr delete mode 100644 src/messages/html_style_argument_size_mismatch.cr delete mode 100644 src/messages/html_style_argument_type_mismatch.cr delete mode 100644 src/messages/html_style_expected_closing_parentheses.cr delete mode 100644 src/messages/html_style_not_found.cr delete mode 100644 src/messages/if_condition_type_mismatch.cr delete mode 100644 src/messages/if_else_type_mismatch.cr delete mode 100644 src/messages/if_expected_closing_parentheses.cr delete mode 100644 src/messages/if_expected_condition.cr delete mode 100644 src/messages/if_expected_else.cr delete mode 100644 src/messages/if_expected_falsy_closing_bracket.cr delete mode 100644 src/messages/if_expected_falsy_expression.cr delete mode 100644 src/messages/if_expected_falsy_opening_bracket.cr delete mode 100644 src/messages/if_expected_truthy_closing_bracket.cr delete mode 100644 src/messages/if_expected_truthy_expression.cr delete mode 100644 src/messages/if_expected_truthy_opening_bracket.cr delete mode 100644 src/messages/inline_directive_expected_closing_parentheses.cr delete mode 100644 src/messages/inline_directive_expected_file.cr delete mode 100644 src/messages/inline_directive_expected_opening_parentheses.cr delete mode 100644 src/messages/inline_directive_expected_path.cr delete mode 100644 src/messages/inline_function_expected_closing_bracket.cr delete mode 100644 src/messages/inline_function_expected_closing_parentheses.cr delete mode 100644 src/messages/inline_function_expected_expression.cr delete mode 100644 src/messages/inline_function_expected_opening_bracket.cr delete mode 100644 src/messages/inline_function_expected_type.cr delete mode 100644 src/messages/inline_function_type_mismatch.cr delete mode 100644 src/messages/installer_failed_to_install.cr delete mode 100644 src/messages/interpolation_expected_closing_bracket.cr delete mode 100644 src/messages/interpolation_expected_expression.cr delete mode 100644 src/messages/invalid_browser.cr delete mode 100644 src/messages/invalid_reporter.cr delete mode 100644 src/messages/invalid_self_reference.cr delete mode 100644 src/messages/js_expected_closing_tick.cr delete mode 100644 src/messages/js_expected_type_or_variable.cr delete mode 100644 src/messages/locale_expected_closing_bracket.cr delete mode 100644 src/messages/locale_expected_language.cr delete mode 100644 src/messages/locale_expected_opening_bracket.cr delete mode 100644 src/messages/member_access_expected_variable.cr delete mode 100644 src/messages/mint_json_application_invalid.cr delete mode 100644 src/messages/mint_json_application_invalid_key.cr delete mode 100644 src/messages/mint_json_application_name_invalid.cr delete mode 100644 src/messages/mint_json_css_prefix_invalid.cr delete mode 100644 src/messages/mint_json_dependencies_invalid.cr delete mode 100644 src/messages/mint_json_dependency_constraint_invalid.cr delete mode 100644 src/messages/mint_json_dependency_invalid.cr delete mode 100644 src/messages/mint_json_dependency_invalid_constraint.cr delete mode 100644 src/messages/mint_json_dependency_not_installed.cr delete mode 100644 src/messages/mint_json_display_invalid.cr delete mode 100644 src/messages/mint_json_external_invalid.cr delete mode 100644 src/messages/mint_json_external_javascript_invalid.cr delete mode 100644 src/messages/mint_json_external_javascript_not_exists.cr delete mode 100644 src/messages/mint_json_external_javascripts_invalid.cr delete mode 100644 src/messages/mint_json_external_stylesheet_invalid.cr delete mode 100644 src/messages/mint_json_external_stylesheet_not_exists.cr delete mode 100644 src/messages/mint_json_external_stylesheets_invalid.cr delete mode 100644 src/messages/mint_json_formatter_config_invalid.cr delete mode 100644 src/messages/mint_json_formatter_config_invalid_key.cr delete mode 100644 src/messages/mint_json_head_not_exists.cr delete mode 100644 src/messages/mint_json_head_not_string.cr delete mode 100644 src/messages/mint_json_icon_not_exists.cr delete mode 100644 src/messages/mint_json_icon_not_string.cr delete mode 100644 src/messages/mint_json_indent_size_invalid.cr delete mode 100644 src/messages/mint_json_invalid_file.cr delete mode 100644 src/messages/mint_json_invalid_json.cr delete mode 100644 src/messages/mint_json_keyword_not_string.cr delete mode 100644 src/messages/mint_json_keywords_invalid.cr delete mode 100644 src/messages/mint_json_meta_invalid.cr delete mode 100644 src/messages/mint_json_meta_value_not_string.cr delete mode 100644 src/messages/mint_json_mint_version_empty.cr delete mode 100644 src/messages/mint_json_mint_version_invalid.cr delete mode 100644 src/messages/mint_json_mint_version_mismatch.cr delete mode 100644 src/messages/mint_json_mint_version_not_string.cr delete mode 100644 src/messages/mint_json_name_empty.cr delete mode 100644 src/messages/mint_json_name_not_string.cr delete mode 100644 src/messages/mint_json_orientation_invalid.cr delete mode 100644 src/messages/mint_json_root_invalid_key.cr delete mode 100644 src/messages/mint_json_root_not_an_object.cr delete mode 100644 src/messages/mint_json_source_directories_empty.cr delete mode 100644 src/messages/mint_json_source_directories_invalid.cr delete mode 100644 src/messages/mint_json_source_directory_invalid.cr delete mode 100644 src/messages/mint_json_source_directory_not_exists.cr delete mode 100644 src/messages/mint_json_test_directories_invalid.cr delete mode 100644 src/messages/mint_json_test_directory_invalid.cr delete mode 100644 src/messages/mint_json_test_directory_not_exists.cr delete mode 100644 src/messages/mint_json_theme_invalid.cr delete mode 100644 src/messages/mint_json_title_empty.cr delete mode 100644 src/messages/mint_json_title_invalid.cr delete mode 100644 src/messages/mint_json_web_components_invalid.cr delete mode 100644 src/messages/module_access_expected_function.cr delete mode 100644 src/messages/module_access_not_found_function.cr delete mode 100644 src/messages/module_access_not_found_module.cr delete mode 100644 src/messages/module_entity_name_conflict.cr delete mode 100644 src/messages/module_expected_closing_bracket.cr delete mode 100644 src/messages/module_expected_name.cr delete mode 100644 src/messages/module_expected_opening_bracket.cr delete mode 100644 src/messages/negated_expression_expected_expression.cr delete mode 100644 src/messages/negated_expression_not_bool.cr delete mode 100644 src/messages/next_call_expected_record.cr delete mode 100644 src/messages/next_call_invalid_invocation.cr delete mode 100644 src/messages/next_call_state_not_found.cr delete mode 100644 src/messages/next_call_state_type_mismatch.cr delete mode 100644 src/messages/number_literal_expected_decimal.cr delete mode 100644 src/messages/operation_expected_expression.cr delete mode 100644 src/messages/operation_numeric_type_mismatch.cr delete mode 100644 src/messages/operation_or_not_maybe_or_result.cr delete mode 100644 src/messages/operation_or_type_mismatch.cr delete mode 100644 src/messages/operation_pipe_ambiguous.cr delete mode 100644 src/messages/operation_plus_type_mismatch.cr delete mode 100644 src/messages/operation_type_mismatch.cr delete mode 100644 src/messages/pipe_expected_call.cr delete mode 100644 src/messages/property_expected_default_value.cr delete mode 100644 src/messages/property_expected_name.cr delete mode 100644 src/messages/property_expected_type.cr delete mode 100644 src/messages/property_type_mismatch.cr delete mode 100644 src/messages/property_type_or_default_needed.cr delete mode 100644 src/messages/property_with_type_variables.cr delete mode 100644 src/messages/provider_entity_name_conflict.cr delete mode 100644 src/messages/provider_expected_body.cr delete mode 100644 src/messages/provider_expected_closing_bracket.cr delete mode 100644 src/messages/provider_expected_colon.cr delete mode 100644 src/messages/provider_expected_name.cr delete mode 100644 src/messages/provider_expected_opening_bracket.cr delete mode 100644 src/messages/provider_expected_subscription.cr delete mode 100644 src/messages/provider_not_found_subscription.cr delete mode 100644 src/messages/record_constructor_argument_size_mismatch.cr delete mode 100644 src/messages/record_constructor_argument_type_mismatch.cr delete mode 100644 src/messages/record_constructor_not_found_record.cr delete mode 100644 src/messages/record_definition_expected_closing_bracket.cr delete mode 100644 src/messages/record_definition_expected_name.cr delete mode 100644 src/messages/record_definition_expected_opening_bracket.cr delete mode 100644 src/messages/record_definition_field_expected_colon.cr delete mode 100644 src/messages/record_definition_field_expected_mapping.cr delete mode 100644 src/messages/record_definition_field_expected_type.cr delete mode 100644 src/messages/record_fields_conflict.cr delete mode 100644 src/messages/record_name_conflict.cr delete mode 100644 src/messages/record_not_found_matching_record_definition.cr delete mode 100644 src/messages/record_update_expected_closing_bracket.cr delete mode 100644 src/messages/record_update_expected_fields.cr delete mode 100644 src/messages/record_update_not_found_key.cr delete mode 100644 src/messages/record_update_not_updating_record.cr delete mode 100644 src/messages/record_update_type_mismatch.cr delete mode 100644 src/messages/record_with_holes.cr delete mode 100644 src/messages/recursion.cr delete mode 100644 src/messages/regexp_literal_expected_closing_slash.cr delete mode 100644 src/messages/repository_could_not_checkout.cr delete mode 100644 src/messages/repository_could_not_clone.cr delete mode 100644 src/messages/repository_could_not_get_versions.cr delete mode 100644 src/messages/repository_could_not_update.cr delete mode 100644 src/messages/repository_invalid_mint_json.cr delete mode 100644 src/messages/repository_no_mint_json.cr delete mode 100644 src/messages/return_call_expected_expression.cr delete mode 100644 src/messages/return_call_invalid.cr delete mode 100644 src/messages/return_call_type_mismatch.cr delete mode 100644 src/messages/route_expected_closing_bracket.cr delete mode 100644 src/messages/route_expected_closing_parentheses.cr delete mode 100644 src/messages/route_expected_expression.cr delete mode 100644 src/messages/route_expected_opening_bracket.cr delete mode 100644 src/messages/route_param_invalid.cr delete mode 100644 src/messages/routes_expected_closing_bracket.cr delete mode 100644 src/messages/routes_expected_opening_bracket.cr delete mode 100644 src/messages/routes_expected_route.cr delete mode 100644 src/messages/runtime_file_not_found.cr delete mode 100644 src/messages/spread_expected_variable.cr delete mode 100644 src/messages/state_expected_default_value.cr delete mode 100644 src/messages/state_expected_equal_sign.cr delete mode 100644 src/messages/state_expected_name.cr delete mode 100644 src/messages/state_expected_type.cr delete mode 100644 src/messages/state_type_mismatch.cr delete mode 100644 src/messages/statement_last_target.cr delete mode 100644 src/messages/statement_return_required.cr delete mode 100644 src/messages/store_entity_name_conflict.cr delete mode 100644 src/messages/store_expected_body.cr delete mode 100644 src/messages/store_expected_closing_bracket.cr delete mode 100644 src/messages/store_expected_name.cr delete mode 100644 src/messages/store_expected_opening_bracket.cr delete mode 100644 src/messages/string_expected_end_quote.cr delete mode 100644 src/messages/string_expected_other_string.cr delete mode 100644 src/messages/string_literal_interpolation_type_mismatch.cr delete mode 100644 src/messages/style_expected_closing_bracket.cr delete mode 100644 src/messages/style_expected_closing_parentheses.cr delete mode 100644 src/messages/style_expected_name.cr delete mode 100644 src/messages/style_expected_opening_bracket.cr delete mode 100644 src/messages/suite_expected_closing_bracket.cr delete mode 100644 src/messages/suite_expected_name.cr delete mode 100644 src/messages/suite_expected_opening_bracket.cr delete mode 100644 src/messages/suite_expected_tests.cr delete mode 100644 src/messages/svg_directive_expected_closing_parentheses.cr delete mode 100644 src/messages/svg_directive_expected_dimensions.cr delete mode 100644 src/messages/svg_directive_expected_file.cr delete mode 100644 src/messages/svg_directive_expected_opening_parentheses.cr delete mode 100644 src/messages/svg_directive_expected_path.cr delete mode 100644 src/messages/svg_directive_expected_svg.cr delete mode 100644 src/messages/svg_directive_expected_svg_tag.cr delete mode 100644 src/messages/test_expected_closing_bracket.cr delete mode 100644 src/messages/test_expected_expression.cr delete mode 100644 src/messages/test_expected_name.cr delete mode 100644 src/messages/test_expected_opening_bracket.cr delete mode 100644 src/messages/test_type_mismatch.cr delete mode 100644 src/messages/translation_mismatch.cr delete mode 100644 src/messages/translation_missing.cr delete mode 100644 src/messages/translation_not_translated.cr delete mode 100644 src/messages/type_expected_closing_parentheses.cr delete mode 100644 src/messages/type_expected_type.cr delete mode 100644 src/messages/type_expected_type_or_variable.cr delete mode 100644 src/messages/unary_minus_not_number.cr delete mode 100644 src/messages/use_condition_mismatch.cr delete mode 100644 src/messages/use_expected_closing_bracket.cr delete mode 100644 src/messages/use_expected_expression.cr delete mode 100644 src/messages/use_expected_opening_bracket.cr delete mode 100644 src/messages/use_expected_provider.cr delete mode 100644 src/messages/use_expected_record.cr delete mode 100644 src/messages/use_not_found_provider.cr delete mode 100644 src/messages/use_subscription_mismatch.cr delete mode 100644 src/messages/variable_missing.cr delete mode 100644 src/messages/variable_reserved.cr delete mode 100644 src/messages/variable_taken.cr create mode 100644 src/parser/file.cr create mode 100644 src/parser/top_level.cr create mode 100644 src/parsers/base_expression.cr delete mode 100644 src/parsers/basic_expression.cr delete mode 100644 src/parsers/call_expression.cr delete mode 100644 src/parsers/code_block.cr delete mode 100644 src/parsers/constant_access.cr create mode 100644 src/parsers/css_node.cr create mode 100644 src/parsers/css_selector_name.cr delete mode 100644 src/parsers/enum.cr delete mode 100644 src/parsers/enum_destructuring.cr delete mode 100644 src/parsers/enum_id.cr delete mode 100644 src/parsers/enum_option.cr delete mode 100644 src/parsers/enum_record.cr delete mode 100644 src/parsers/enum_record_definition.cr create mode 100644 src/parsers/field.cr delete mode 100644 src/parsers/for_condition.cr delete mode 100644 src/parsers/here_doc.cr create mode 100644 src/parsers/here_document.cr create mode 100644 src/parsers/id.cr delete mode 100644 src/parsers/module_access.cr create mode 100644 src/parsers/operator.cr delete mode 100644 src/parsers/option.cr delete mode 100644 src/parsers/record_definition.cr delete mode 100644 src/parsers/record_definition_field.cr delete mode 100644 src/parsers/record_field.cr delete mode 100644 src/parsers/top_level.cr create mode 100644 src/parsers/type_definition.cr create mode 100644 src/parsers/type_definition_field.cr create mode 100644 src/parsers/type_destructuring.cr delete mode 100644 src/parsers/type_id.cr create mode 100644 src/parsers/type_variant.cr create mode 100644 src/parsers/value.cr delete mode 100644 src/parsers/void.cr create mode 100644 src/scope.cr delete mode 100644 src/type_checker/scope.cr create mode 100644 src/type_checker/static_type_signature.cr delete mode 100644 src/type_checkers/enum.cr delete mode 100644 src/type_checkers/enum_id.cr delete mode 100644 src/type_checkers/enum_record_definition.cr rename src/type_checkers/{record_field.cr => field.cr} (57%) delete mode 100644 src/type_checkers/module_access.cr delete mode 100644 src/type_checkers/record_constructor.cr delete mode 100644 src/type_checkers/record_definition.cr create mode 100644 src/type_checkers/type_definition.cr rename src/type_checkers/{record_definition_field.cr => type_definition_field.cr} (54%) rename src/type_checkers/{enum_option.cr => type_variant.cr} (74%) diff --git a/spec/compilers/block_with_early_return b/spec/compilers/block_with_early_return index 7f70289f0..b334f6be1 100644 --- a/spec/compilers/block_with_early_return +++ b/spec/compilers/block_with_early_return @@ -2,6 +2,7 @@ enum Test { A(String) B(String) } + component Main { fun render : String { let Test::A(a) = @@ -11,7 +12,7 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -19,7 +20,7 @@ class B extends _E { } }; -class C extends _E { +class B extends _E { constructor(_0) { super(); this._0 = _0; @@ -27,9 +28,9 @@ class C extends _E { } }; -class A extends _C { +class C extends _C { render() { - const b = __match(new B(`Some string...`), _PE(B,[ + const b = __match(_n(A)(`Some string...`), _PE(A,[ _PV ])); @@ -42,4 +43,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/block_with_early_return_await b/spec/compilers/block_with_early_return_await index a90974d5f..086018cf1 100644 --- a/spec/compilers/block_with_early_return_await +++ b/spec/compilers/block_with_early_return_await @@ -16,7 +16,7 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -24,7 +24,7 @@ class B extends _E { } }; -class C extends _E { +class B extends _E { constructor(_0) { super(); this._0 = _0; @@ -32,10 +32,10 @@ class C extends _E { } }; -class A extends _C { +class C extends _C { render() { (async () => { - const b = __match(await new B(`Some string...`), _PE(B,[ + const b = __match(await _n(A)(`Some string...`), _PE(A,[ _PV ])); @@ -51,4 +51,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/case_with_enum_destructuring b/spec/compilers/case_with_type_destructuring similarity index 86% rename from spec/compilers/case_with_enum_destructuring rename to spec/compilers/case_with_type_destructuring index 67cf775be..38b0343d1 100644 --- a/spec/compilers/case_with_enum_destructuring +++ b/spec/compilers/case_with_type_destructuring @@ -26,7 +26,7 @@ component Main { } } -------------------------------------------------------------------------------- -class C extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -34,7 +34,7 @@ class C extends _E { } }; -class D extends _E { +class B extends _E { constructor(_0) { super(); this._0 = _0; @@ -42,30 +42,30 @@ class D extends _E { } }; -class B extends _E { +class C extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class D extends _C { a(b) { return _match(b,[ [ - _PE(B,[]), + _PE(C,[]), () => { return `` } ], [ - _PE(D,[ + _PE(B,[ _PV ]), (c) => { return _match(c,[ [ - _PE(C,[ + _PE(A,[ _PV ]), (d) => { @@ -79,9 +79,9 @@ class A extends _C { } render() { - this.a(new D(new C(``))); + this.a(_n(B)(_n(A)(``))); return ``; } }; -A.displayName = "Main"; +D.displayName = "Main"; diff --git a/spec/compilers/component_instance_access b/spec/compilers/component_instance_access index 962096e56..b40f516e3 100644 --- a/spec/compilers/component_instance_access +++ b/spec/compilers/component_instance_access @@ -28,7 +28,7 @@ component Main { } } -------------------------------------------------------------------------------- -class C extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -36,14 +36,14 @@ class C extends _E { } }; -class D extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class C extends _C { get a() { return `Instance` } @@ -53,17 +53,17 @@ class A extends _C { } }; -A.displayName = "Instance"; +C.displayName = "Instance"; -class B extends _C { +class D extends _C { get c() { - return (this._instance ? new C(this._instance) : new D); + return (this._instance ? new A(this._instance) : new B); } b() { return _match(this.c,[ [ - _PE(C,[ + _PE(A,[ _PV ]), (d) => { @@ -71,7 +71,7 @@ class B extends _C { } ], [ - _PE(D,[]), + _PE(B,[]), () => { return `` } @@ -83,11 +83,11 @@ class B extends _C { return _h("div", { "onClick": (event => (this.b)(_normalizeEvent(event))) }, [ - _h(A, { + _h(C, { ref: (instance) => { this._instance = instance } }) ]); } }; -B.displayName = "Main"; +D.displayName = "Main"; diff --git a/spec/compilers/css_with_if_with_interpolation b/spec/compilers/css_with_if_with_interpolation new file mode 100644 index 000000000..7e70b4bf9 --- /dev/null +++ b/spec/compilers/css_with_if_with_interpolation @@ -0,0 +1,44 @@ +component Main { + style test { + color: yellow; + + if (true) { + color: #{"red"}; + } else { + color: blue; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +class A extends _C { + $Main_test() { + const _ = {}; + + (true ? Object.assign(_, { + [`--a-a`]: `red` + }) : Object.assign(_, { + [`--a-a`]: `blue` + })); + + return _; + } + + render() { + return _h("div", { + className: `Main_test`, + style: _style([this.$Main_test()]) + }); + } +}; + +A.displayName = "Main"; + +_insertStyles(` +.Main_test { + color: var(--a-a, yellow); +} +`); diff --git a/spec/compilers/destructuring b/spec/compilers/destructuring index 3d5874db0..1cbcbcde2 100644 --- a/spec/compilers/destructuring +++ b/spec/compilers/destructuring @@ -23,39 +23,45 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { - constructor(_0) { +class A extends _E { + constructor(_0, _1, _2) { super(); this._0 = _0; - this.length = 1; + this._1 = _1; + this._2 = _2; + this.length = 3; + + this._mapping = { + matchString: "_0", + content: "_1", + key: "_2" + }; } }; -class C extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class C extends _C { a(b) { return _match(b,[ [ - _PE(B,[ - _PR([ - [ - "content", - _PV - ] - ]) - ]), + _PE(A,_PR([ + [ + "content", + _PV + ] + ])), (c) => { return c } ], [ - _PE(C,[]), + _PE(B,[]), () => { return `` } @@ -64,12 +70,8 @@ class A extends _C { } render() { - return this.a(new B(new Record({ - matchString: `MATCHSTRING`, - content: `CONTENT`, - key: `KEY` - }))); + return this.a(_n(A)(`MATCHSTRING`, `CONTENT`, `KEY`)); } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/directives/highlight b/spec/compilers/directives/highlight new file mode 100644 index 000000000..943124de4 --- /dev/null +++ b/spec/compilers/directives/highlight @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + @highlight { + "Test" + }[1] + } +} +-------------------------------------------------------------------------------- +class A extends _C { + render() { + return [`Test`, _h(React.Fragment, {}, [_h('span', { className: 'string' }, [`"Test"`])])][1]; + } +}; + +A.displayName = "Main"; diff --git a/spec/compilers/encode b/spec/compilers/encode index 63f284e44..999142955 100644 --- a/spec/compilers/encode +++ b/spec/compilers/encode @@ -4,12 +4,12 @@ record Test { } component Main { - fun encode : Object { + fun test : Object { encode { name: "Hello", age: 20 } } fun render : String { - encode() + test() "" } diff --git a/spec/compilers/record_field b/spec/compilers/field similarity index 100% rename from spec/compilers/record_field rename to spec/compilers/field diff --git a/spec/compilers/html_attribute_ref b/spec/compilers/html_attribute_ref index 86d45d399..7d8b5daf5 100644 --- a/spec/compilers/html_attribute_ref +++ b/spec/compilers/html_attribute_ref @@ -10,7 +10,7 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -18,16 +18,16 @@ class B extends _E { } }; -class C extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class C extends _C { get a() { - return (this._input ? new B(this._input) : new C); + return (this._input ? new A(this._input) : new B); } render() { @@ -37,4 +37,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/html_fragment b/spec/compilers/html_fragment index 34b76bb81..45724458d 100644 --- a/spec/compilers/html_fragment +++ b/spec/compilers/html_fragment @@ -3,7 +3,6 @@ component Main {
<> <{ "A" }> - < key="something">
} @@ -13,10 +12,7 @@ class A extends _C { render() { return _h("div", {}, [ _h(React.Fragment, {}, [ - `A`, - _h(React.Fragment, { - key: `something` - }, []) + `A` ]) ]); } diff --git a/spec/compilers/if_let b/spec/compilers/if_let index 8916c7ff3..ffb6c5639 100644 --- a/spec/compilers/if_let +++ b/spec/compilers/if_let @@ -13,7 +13,7 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -21,18 +21,18 @@ class B extends _E { } }; -class C extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class C extends _C { render() { - return _match(new B(``),[ + return _match(_n(A)(``),[ [ - _PE(B,[ + _PE(A,[ _PV ]), (a) => { @@ -49,4 +49,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/if_let_await b/spec/compilers/if_let_await index 41ed06d1e..f04a7da60 100644 --- a/spec/compilers/if_let_await +++ b/spec/compilers/if_let_await @@ -13,7 +13,7 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor(_0) { super(); this._0 = _0; @@ -21,21 +21,21 @@ class B extends _E { } }; -class C extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class C extends _C { render() { return (async () => { - let b = await new B(``); + let b = await _n(A)(``); return _match(b,[ [ - _PE(B,[ + _PE(A,[ _PV ]), (a) => { @@ -53,4 +53,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/operation_or b/spec/compilers/operation_or index 8607708ff..0deb365aa 100644 --- a/spec/compilers/operation_or +++ b/spec/compilers/operation_or @@ -15,14 +15,14 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor() { super(); this.length = 0; } }; -class C extends _E { +class B extends _E { constructor(_0) { super(); this._0 = _0; @@ -30,9 +30,9 @@ class C extends _E { } }; -class A extends _C { +class C extends _C { a() { - return _o(new B()._0, `Hello`); + return _o(new A()._0, `Hello`); } render() { @@ -41,4 +41,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers/record_constructor b/spec/compilers/record_constructor deleted file mode 100644 index 48c13a390..000000000 --- a/spec/compilers/record_constructor +++ /dev/null @@ -1,36 +0,0 @@ -record Test { - a : String, - b : Number -} - -component Main { - fun render : Html { - Test("A", 0) - -
- } -} --------------------------------------------------------------------------------- -const A = _R({ - a: [ - "a", - Decoder.string - ], - b: [ - "b", - Decoder.number - ] -}); - -class B extends _C { - render() { - new A({ - a: `A`, - b: 0 - }); - - return _h("div", {}); - } -}; - -B.displayName = "Main"; diff --git a/spec/compilers/record_constructor_partial b/spec/compilers/record_constructor_partial deleted file mode 100644 index 522625b9e..000000000 --- a/spec/compilers/record_constructor_partial +++ /dev/null @@ -1,44 +0,0 @@ -record Test { - a : String, - b : Number, - c : Bool -} - -component Main { - fun render : Html { - Test("A") - -
- } -} --------------------------------------------------------------------------------- -const A = _R({ - a: [ - "a", - Decoder.string - ], - b: [ - "b", - Decoder.number - ], - c: [ - "c", - Decoder.boolean - ] -}); - -class B extends _C { - render() { - (_0, _1) => { - return new A({ - a: `A`, - b: _0, - c: _1 - }) - }; - - return _h("div", {}); - } -}; - -B.displayName = "Main"; diff --git a/spec/compilers/enum b/spec/compilers/type similarity index 88% rename from spec/compilers/enum rename to spec/compilers/type index 09094fe99..f9fc00de1 100644 --- a/spec/compilers/enum +++ b/spec/compilers/type @@ -32,21 +32,21 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { +class A extends _E { constructor() { super(); this.length = 0; } }; -class F extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class D extends _E { +class C extends _E { constructor(_0) { super(); this._0 = _0; @@ -54,7 +54,7 @@ class D extends _E { } }; -class E extends _E { +class D extends _E { constructor(_0) { super(); this._0 = _0; @@ -62,7 +62,7 @@ class E extends _E { } }; -class G extends _E { +class E extends _E { constructor(_0) { super(); this._0 = _0; @@ -70,7 +70,7 @@ class G extends _E { } }; -class C extends _E { +class F extends _E { constructor(_0, _1) { super(); this._0 = _0; @@ -79,17 +79,17 @@ class C extends _E { } }; -class A extends _C { +class G extends _C { a() { - return new B(); + return new A(); } b() { - return new C(``,``); + return _n(F)(``, ``); } c() { - return new D(new E(``)); + return _n(C)(_n(D)(``)); } render() { @@ -100,4 +100,4 @@ class A extends _C { } }; -A.displayName = "Main"; +G.displayName = "Main"; diff --git a/spec/compilers/enum_record b/spec/compilers/type_with_variants similarity index 57% rename from spec/compilers/enum_record rename to spec/compilers/type_with_variants index 9b757e8f0..58d9ee4cb 100644 --- a/spec/compilers/enum_record +++ b/spec/compilers/type_with_variants @@ -12,46 +12,47 @@ component Main { } } -------------------------------------------------------------------------------- -class B extends _E { - constructor(_0) { +class A extends _E { + constructor(_0, _1) { super(); this._0 = _0; - this.length = 1; + this._1 = _1; + this.length = 2; + + this._mapping = { + name: "_0", + color: "_1" + }; } }; -class C extends _E { +class B extends _E { constructor() { super(); this.length = 0; } }; -class A extends _C { +class C extends _C { render() { - return _match(new B(new Record({ - name: `Joe`, - color: `Blue` - })),[ + return _match(_n(A)(`Joe`, `Blue`),[ [ - _PE(B,[ - _PR([ - [ - "color", - _PV - ], - [ - "name", - _PV - ] - ]) - ]), + _PE(A,_PR([ + [ + "color", + _PV + ], + [ + "name", + _PV + ] + ])), (a, b) => { return a } ], [ - _PE(C,[]), + _PE(B,[]), () => { return `` } @@ -60,4 +61,4 @@ class A extends _C { } }; -A.displayName = "Main"; +C.displayName = "Main"; diff --git a/spec/compilers_spec.cr b/spec/compilers_spec.cr index 19c02864a..bb15d815a 100644 --- a/spec/compilers_spec.cr +++ b/spec/compilers_spec.cr @@ -6,25 +6,35 @@ Dir .sort! .each do |file| it file do - # Read and separate sample from expected - sample, expected = File.read(file).split("-" * 80) + begin + # Read and separate sample from expected + sample, expected = File.read(file).split("-" * 80) - # Parse the sample - ast = Mint::Parser.parse(sample, file) - ast.class.should eq(Mint::Ast) + # Parse the sample + ast = Mint::Parser.parse(sample, file) + ast.class.should eq(Mint::Ast) - # Compare results - result = Mint::Compiler.compile_bare(Mint::TypeChecker.check(ast), { - css_prefix: nil, - optimize: false, - relative: false, - build: true, - }) + begin + artifacts = Mint::TypeChecker.check(ast) - begin - result.should eq(expected.strip) - rescue error - fail diff(expected, result) + # Compare results + result = Mint::Compiler.compile_bare(artifacts, { + css_prefix: nil, + optimize: false, + relative: false, + build: true, + }) + rescue error : Mint::Error + fail error.to_terminal.to_s + end + + begin + result.should eq(expected.strip) + rescue error + fail diff(expected, result) + end + rescue error : Mint::Error + fail error.to_terminal.to_s end end end diff --git a/spec/errors/access_expected_field b/spec/errors/access_expected_field new file mode 100644 index 000000000..b182776f2 --- /dev/null +++ b/spec/errors/access_expected_field @@ -0,0 +1,14 @@ +component Main { + fun render : String { + "". +-------------------------------------------------------------------------------- +░ ERROR (ACCESS_EXPECTED_FIELD) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of the accessed entity but I found "a space" instead: + + ┌ ./spec/errors/access_expected_field:3:7 + ├──────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ "". + │ ⌃⌃⌃⌃ diff --git a/spec/errors/access_field_not_found b/spec/errors/access_field_not_found new file mode 100644 index 000000000..7153471a5 --- /dev/null +++ b/spec/errors/access_field_not_found @@ -0,0 +1,31 @@ +record Blah { + blah : String +} + +component Main { + fun render : Bool { + let blah = + { blah: "Hello" } + + blah.blaha + } +} +-------------------------------------------------------------------------------- +░ ERROR (ACCESS_FIELD_NOT_FOUND) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The accessed field "blaha" does not exists on the entity: + + Blah(blah: String) + +The access in question is here: + + ┌ ./spec/errors/access_field_not_found:10:5 + ├────────────────────────────────────────── + 6│ fun render : Bool { + 7│ let blah = + 8│ { blah: "Hello" } + 9│ + 10│ blah.blaha + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 11│ } + 12│ } diff --git a/spec/errors/access_not_record b/spec/errors/access_not_record new file mode 100644 index 000000000..56cbdce60 --- /dev/null +++ b/spec/errors/access_not_record @@ -0,0 +1,26 @@ +component Main { + fun render : Bool { + let blah = "" + + blah.blah.blah + } +} +-------------------------------------------------------------------------------- +░ ERROR (ACCESS_NOT_RECORD) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +You are trying to access a field on an entity which is not a record: + + String + +The access in question is here: + + ┌ ./spec/errors/access_not_record:5:5 + ├──────────────────────────────────── + 1│ component Main { + 2│ fun render : Bool { + 3│ let blah = "" + 4│ + 5│ blah.blah.blah + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 6│ } + 7│ } diff --git a/spec/errors/argument_expected_colon b/spec/errors/argument_expected_colon new file mode 100644 index 000000000..f49daf839 --- /dev/null +++ b/spec/errors/argument_expected_colon @@ -0,0 +1,16 @@ +component Main { + fun render (a +-------------------------------------------------------------------------------- +░ ERROR (ARGUMENT_EXPECTED_COLON) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A colon must separate the arguments name from its type, here is an example: + + name : String + +I was expecting the colon of the argument but I found "a space" instead: + + ┌ ./spec/errors/argument_expected_colon:2:15 + ├─────────────────────────────────────────── + 1│ component Main { + 2│ fun render (a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/argument_expected_default_value b/spec/errors/argument_expected_default_value new file mode 100644 index 000000000..612377ac4 --- /dev/null +++ b/spec/errors/argument_expected_default_value @@ -0,0 +1,17 @@ +component Main { + fun render (a : String = +-------------------------------------------------------------------------------- +░ ERROR (ARGUMENT_EXPECTED_DEFAULT_VALUE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The default value of an argument must be defined after the equal sign, here is +an example: + + name : String = "Joe" + +I was expecting the default value of the argument but I found "a space" instead: + + ┌ ./spec/errors/argument_expected_default_value:2:26 + ├─────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render (a : String = + │ ⌃⌃⌃⌃ diff --git a/spec/errors/argument_expected_type b/spec/errors/argument_expected_type new file mode 100644 index 000000000..8cb32bf8e --- /dev/null +++ b/spec/errors/argument_expected_type @@ -0,0 +1,16 @@ +component Main { + fun render (a : +-------------------------------------------------------------------------------- +░ ERROR (ARGUMENT_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +An argument must have its type defined, here is an example: + + name : Type + +I was expecting the type of the argument but I found "a space" instead: + + ┌ ./spec/errors/argument_expected_type:2:17 + ├────────────────────────────────────────── + 1│ component Main { + 2│ fun render (a : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/array_access_expected_closing_bracket b/spec/errors/array_access_expected_closing_bracket new file mode 100644 index 000000000..1e230f46b --- /dev/null +++ b/spec/errors/array_access_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + array[0 +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_ACCESS_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of an array access but I found "a space" +instead: + + ┌ ./spec/errors/array_access_expected_closing_bracket:3:11 + ├───────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ array[0 + │ ⌃⌃⌃⌃ diff --git a/spec/errors/array_access_expected_index b/spec/errors/array_access_expected_index new file mode 100644 index 000000000..d015ccb70 --- /dev/null +++ b/spec/errors/array_access_expected_index @@ -0,0 +1,14 @@ +component Main { + fun render : String { + array[ +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_ACCESS_EXPECTED_INDEX) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the index of an array access but I found "a space" instead: + + ┌ ./spec/errors/array_access_expected_index:3:10 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ array[ + │ ⌃⌃⌃⌃ diff --git a/spec/errors/array_access_index_not_number b/spec/errors/array_access_index_not_number new file mode 100644 index 000000000..51b0e6625 --- /dev/null +++ b/spec/errors/array_access_index_not_number @@ -0,0 +1,42 @@ +component Main { + fun test : Maybe(String) { + [ + "Hello", + "Blah", + "Joe" + ]["asd"] + } + + fun render : Html { + test() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_ACCESS_INDEX_NOT_NUMBER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the index of an array access is not a number. + +I was expecting: + + Number + +Instead it is: + + String + +The index in question is here: + + ┌ ./spec/errors/array_access_index_not_number:7:7 + ├──────────────────────────────────────────────── + 3│ [ + 4│ "Hello", + 5│ "Blah", + 6│ "Joe" + 7│ ]["asd"] + │ ⌃⌃⌃⌃⌃ + 8│ } + 9│ + 10│ fun render : Html { + 11│ test() diff --git a/spec/errors/array_access_invalid_tuple b/spec/errors/array_access_invalid_tuple new file mode 100644 index 000000000..1ad006344 --- /dev/null +++ b/spec/errors/array_access_invalid_tuple @@ -0,0 +1,31 @@ +component Main { + fun test : Maybe(String) { + {"Hello"}[1] + } + + fun render : Html { + test() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_ACCESS_INVALID_TUPLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The tuple have only 1 members, but you wanted to access the 2nd. The exact type +of the tuple is: + + Tuple(String) + +The tuple in question is here: + + ┌ ./spec/errors/array_access_invalid_tuple:3:5 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ fun test : Maybe(String) { + 3│ {"Hello"}[1] + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : Html { + 7│ test() diff --git a/spec/errors/array_access_not_an_array b/spec/errors/array_access_not_an_array new file mode 100644 index 000000000..54bf00b9b --- /dev/null +++ b/spec/errors/array_access_not_an_array @@ -0,0 +1,36 @@ +component Main { + fun test : Maybe(String) { + {}[0] + } + + fun render : Html { + test() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_ACCESS_NOT_AN_ARRAY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The entity you are trying to access an item from is not an array or a tuple. + +I was expecting: + + Array(a), Tuple(...) + +Instead it is: + + Unit + +The array in question is here: + + ┌ ./spec/errors/array_access_not_an_array:3:5 + ├──────────────────────────────────────────── + 1│ component Main { + 2│ fun test : Maybe(String) { + 3│ {}[0] + │ ⌃⌃ + 4│ } + 5│ + 6│ fun render : Html { + 7│ test() diff --git a/spec/errors/array_destructuring_expected_closing_bracket b/spec/errors/array_destructuring_expected_closing_bracket new file mode 100644 index 000000000..8834a4273 --- /dev/null +++ b/spec/errors/array_destructuring_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + let [x +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_DESTRUCTURING_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of an array destructuring but I found "a +space" instead: + + ┌ ./spec/errors/array_destructuring_expected_closing_bracket:3:10 + ├──────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ let [x + │ ⌃⌃⌃⌃ diff --git a/spec/errors/array_expected_closing_bracket b/spec/errors/array_expected_closing_bracket new file mode 100644 index 000000000..4e3099123 --- /dev/null +++ b/spec/errors/array_expected_closing_bracket @@ -0,0 +1,14 @@ +component Main { + fun render : Array(String) { + ["A" +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of an array but I found "a space" instead: + + ┌ ./spec/errors/array_expected_closing_bracket:3:8 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(String) { + 3│ ["A" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/array_expected_type_or_variable b/spec/errors/array_expected_type_or_variable new file mode 100644 index 000000000..9f2d4fe7b --- /dev/null +++ b/spec/errors/array_expected_type_or_variable @@ -0,0 +1,19 @@ +component Main { + fun render : Array(String) { + [] of +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_EXPECTED_TYPE_OR_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of an array literal must be defined after the of keyword, here is an +example: + + [] of String + +I was expecting the type but I found "a space" instead: + + ┌ ./spec/errors/array_expected_type_or_variable:3:9 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(String) { + 3│ [] of + │ ⌃⌃⌃⌃ diff --git a/spec/errors/array_not_matches b/spec/errors/array_not_matches new file mode 100644 index 000000000..817d9b56f --- /dev/null +++ b/spec/errors/array_not_matches @@ -0,0 +1,41 @@ +component Main { + fun test : Array(String) { + [ + "Hello", + true, + "Joe" + ] + } + + fun render : Html { + test() + +
+ } +} +--------------------------------------------------------------------------------░ ERROR (ARRAY_NOT_MATCHES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The 2nd item of an array does not match the type of the 1st item. + +I was expecting the type of the 1st item: + + String + +Instead it is: + + Bool + +The item in question is here: + + ┌ ./spec/errors/array_not_matches:5:7 + ├──────────────────────────────────── + 1│ component Main { + 2│ fun test : Array(String) { + 3│ [ + 4│ "Hello", + 5│ true, + │ ⌃⌃⌃⌃ + 6│ "Joe" + 7│ ] + 8│ } + 9│ diff --git a/spec/errors/array_not_matches_defined_type b/spec/errors/array_not_matches_defined_type new file mode 100644 index 000000000..3a8e40083 --- /dev/null +++ b/spec/errors/array_not_matches_defined_type @@ -0,0 +1,41 @@ +component Main { + fun test : Array(String) { + [ + "Hello", + "Joe" + ] of Number + } + + fun render : Html { + test() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (ARRAY_NOT_MATCHES_DEFINED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The defined type of an array does not match the type of its items. + +I was expecting: + + Array(Number) + +Instead it is: + + Array(String) + +The array in question is here: + + ┌ ./spec/errors/array_not_matches_defined_type:6:10 + ├────────────────────────────────────────────────── + 2│ fun test : Array(String) { + 3│ [ + 4│ "Hello", + 5│ "Joe" + 6│ ] of Number + │ ⌃⌃⌃⌃⌃⌃ + 7│ } + 8│ + 9│ fun render : Html { + 10│ test() diff --git a/spec/errors/asset_directive_expected_closing_parenthesis b/spec/errors/asset_directive_expected_closing_parenthesis new file mode 100644 index 000000000..2645aa861 --- /dev/null +++ b/spec/errors/asset_directive_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @asset(path +-------------------------------------------------------------------------------- +░ ERROR (ASSET_DIRECTIVE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of an asset directive but I found "a +space" instead: + + ┌ ./spec/errors/asset_directive_expected_closing_parenthesis:3:15 + ├──────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @asset(path + │ ⌃⌃⌃⌃ diff --git a/spec/errors/asset_directive_expected_file b/spec/errors/asset_directive_expected_file new file mode 100644 index 000000000..35d00a993 --- /dev/null +++ b/spec/errors/asset_directive_expected_file @@ -0,0 +1,23 @@ +component Main { + fun render : String { + @asset(path) + } +} +-------------------------------------------------------------------------------- +░ ERROR (ASSET_DIRECTIVE_EXPECTED_FILE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The path specified for an asset directive does not exist: + + /home/gus/Projects/mint-lang/mint/spec/errors/path + +The asset directive in question is here: + + ┌ ./spec/errors/asset_directive_expected_file:3:5 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @asset(path) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } + diff --git a/spec/errors/asset_directive_expected_opening_parenthesis b/spec/errors/asset_directive_expected_opening_parenthesis new file mode 100644 index 000000000..2276d4fe8 --- /dev/null +++ b/spec/errors/asset_directive_expected_opening_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @asset +-------------------------------------------------------------------------------- +░ ERROR (ASSET_DIRECTIVE_EXPECTED_OPENING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening parenthesis of an asset directive but I found "a +space" instead: + + ┌ ./spec/errors/asset_directive_expected_opening_parenthesis:3:10 + ├──────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @asset + │ ⌃⌃⌃⌃ diff --git a/spec/errors/asset_directive_expected_path b/spec/errors/asset_directive_expected_path new file mode 100644 index 000000000..163981ca5 --- /dev/null +++ b/spec/errors/asset_directive_expected_path @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @asset( +-------------------------------------------------------------------------------- +░ ERROR (ASSET_DIRECTIVE_EXPECTED_PATH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the path (to the asset) of an asset directive but I found "a +space" instead: + + ┌ ./spec/errors/asset_directive_expected_path:3:11 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @asset( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/block_no_expressions b/spec/errors/block_no_expressions new file mode 100644 index 000000000..0ec8703d7 --- /dev/null +++ b/spec/errors/block_no_expressions @@ -0,0 +1,26 @@ +component Main { + fun componentDidUpdate { + // "" + } + + fun render : Html { +
"main"
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (BLOCK_NO_EXPRESSIONS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +This block doesn't have any statements. It should have at least one. + + ┌ ./spec/errors/block_no_expressions:2:26 + ├──────────────────────────────────────── + 1│ component Main { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 2│ fun componentDidUpdate { + 3│ // "" + 4│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ + 6│ fun render : Html { + 7│
"main"
+ 8│ } diff --git a/spec/errors/call_argument_size_mismatch b/spec/errors/call_argument_size_mismatch new file mode 100644 index 000000000..2964bd5b0 --- /dev/null +++ b/spec/errors/call_argument_size_mismatch @@ -0,0 +1,40 @@ +component Main { + fun a (input : String) : String { + input + } + + fun b : String { + a("Hello", "There") + } + + fun render : Html { + b() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (CALL_ARGUMENT_SIZE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The function you called takes 1 arguments, while you tried to call it with 2. + +The type of the function is: + + Function( + input: String, + String) + +The call in question is here: + + ┌ ./spec/errors/call_argument_size_mismatch:7:6 + ├────────────────────────────────────────────── + 3│ input + 4│ } + 5│ + 6│ fun b : String { + 7│ a("Hello", "There") + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ + 10│ fun render : Html { + 11│ b() diff --git a/spec/errors/call_argument_type_mismatch b/spec/errors/call_argument_type_mismatch new file mode 100644 index 000000000..36dca9cd0 --- /dev/null +++ b/spec/errors/call_argument_type_mismatch @@ -0,0 +1,42 @@ +component Main { + fun a (input : String) : String { + input + } + + fun b : String { + a(0) + } + + fun render : Html { + b() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (CALL_ARGUMENT_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The 1st argument to a function is causing a mismatch. + +The function is expecting the 1st argument to be: + + String + +Instead it is: + + Number + +The call in question is here: + + ┌ ./spec/errors/call_argument_type_mismatch:7:6 + ├────────────────────────────────────────────── + 3│ input + 4│ } + 5│ + 6│ fun b : String { + 7│ a(0) + │ ⌃⌃⌃ + 8│ } + 9│ + 10│ fun render : Html { + 11│ b() diff --git a/spec/errors/call_expected_closing_parenthesis b/spec/errors/call_expected_closing_parenthesis new file mode 100644 index 000000000..97ba42f19 --- /dev/null +++ b/spec/errors/call_expected_closing_parenthesis @@ -0,0 +1,18 @@ +component Main { + fun render : String { + test("A" +-------------------------------------------------------------------------------- +░ ERROR (CALL_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The arguments of a call must be enclosed by parenthesis, here is an example: + + greet("Joe") + +I was expecting the closing parenthesis of a call but I found "a space" instead: + + ┌ ./spec/errors/call_expected_closing_parenthesis:3:12 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ test("A" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/call_not_a_function b/spec/errors/call_not_a_function new file mode 100644 index 000000000..d81120c4f --- /dev/null +++ b/spec/errors/call_not_a_function @@ -0,0 +1,34 @@ +component Main { + state x : String = "" + + fun b : String { + x() + } + + fun render : Html { + b() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (CALL_NOT_A_FUNCTION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The entity you called is not a function, instead it is: + + String + +The call in question is here: + + ┌ ./spec/errors/call_not_a_function:5:6 + ├────────────────────────────────────── + 1│ component Main { + 2│ state x : String = "" + 3│ + 4│ fun b : String { + 5│ x() + │ ⌃⌃ + 6│ } + 7│ + 8│ fun render : Html { + 9│ b() diff --git a/spec/errors/call_not_found_argument b/spec/errors/call_not_found_argument new file mode 100644 index 000000000..712d84153 --- /dev/null +++ b/spec/errors/call_not_found_argument @@ -0,0 +1,35 @@ +component Main { + fun test (argument1 : String, argument2: Number) : Html { +
+ } + + fun render : Html { + test(argument3: 0, argument1: "") + } +} +-------------------------------------------------------------------------------- +░ ERROR (CALL_NOT_FOUND_ARGUMENT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for a named argument but I can't find it: + + argument3 + +The type of the function is: + + Function( + argument1: String, + argument2: Number, + Html) + +The call in question is here: + + ┌ ./spec/errors/call_not_found_argument:7:9 + ├────────────────────────────────────────── + 3│
+ 4│ } + 5│ + 6│ fun render : Html { + 7│ test(argument3: 0, argument1: "") + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/call_with_mixed_arguments b/spec/errors/call_with_mixed_arguments new file mode 100644 index 000000000..9d6e5cd8c --- /dev/null +++ b/spec/errors/call_with_mixed_arguments @@ -0,0 +1,27 @@ +component Main { + fun test (argument1 : String, argument2: Number) : Html { +
+ } + + fun render : Html { + test(0, argument1: "") + } +} +-------------------------------------------------------------------------------- +░ ERROR (CALL_WITH_MIXED_ARGUMENTS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A call cannot have named and unamed arguments at the same time because in +specific cases I cannot pair the arguments with the values. + +The call in question is here: + + ┌ ./spec/errors/call_with_mixed_arguments:7:9 + ├──────────────────────────────────────────── + 3│
+ 4│ } + 5│ + 6│ fun render : Html { + 7│ test(0, argument1: "") + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/case_branch_expected_expression b/spec/errors/case_branch_expected_expression new file mode 100644 index 000000000..f78d18e82 --- /dev/null +++ b/spec/errors/case_branch_expected_expression @@ -0,0 +1,20 @@ +component Main { + fun render : String { + case ("a") { + => +-------------------------------------------------------------------------------- +░ ERROR (CASE_BRANCH_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A case branch must have an value, here is an example: + + => value + +I was expecting the value of a case branch but I found "a space" instead: + + ┌ ./spec/errors/case_branch_expected_expression:4:8 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case ("a") { + 4│ => + │ ⌃⌃⌃⌃ diff --git a/spec/errors/case_branch_not_matches b/spec/errors/case_branch_not_matches new file mode 100644 index 000000000..78dd7b4dc --- /dev/null +++ b/spec/errors/case_branch_not_matches @@ -0,0 +1,37 @@ +component Main { + fun render : String { + case ("x") { + "a" => "a" + "b" => true + => "c" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (CASE_BRANCH_NOT_MATCHES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The return type of the 2nd branch of a case expression does not match the type +of the 1st branch. + +I was expecting the type of the 1st branch: + + String + +Instead it is: + + Bool + +The branch in question is here: + + ┌ ./spec/errors/case_branch_not_matches:5:7 + ├────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case ("x") { + 4│ "a" => "a" + 5│ "b" => true + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 6│ => "c" + 7│ } + 8│ } + 9│ } diff --git a/spec/errors/case_expected_branches b/spec/errors/case_expected_branches new file mode 100644 index 000000000..dce37f868 --- /dev/null +++ b/spec/errors/case_expected_branches @@ -0,0 +1,14 @@ +component Main { + fun render : String { + case ("a") { +-------------------------------------------------------------------------------- +░ ERROR (CASE_EXPECTED_BRANCHES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the branches of a case but I found "a space" instead: + + ┌ ./spec/errors/case_expected_branches:3:16 + ├────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case ("a") { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/case_expected_closing_bracket b/spec/errors/case_expected_closing_bracket new file mode 100644 index 000000000..70c3d7376 --- /dev/null +++ b/spec/errors/case_expected_closing_bracket @@ -0,0 +1,16 @@ +component Main { + fun render : String { + case ("a") { + => "a" +-------------------------------------------------------------------------------- +░ ERROR (CASE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a case but I found "a space" instead: + + ┌ ./spec/errors/case_expected_closing_bracket:4:12 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case ("a") { + 4│ => "a" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/case_expected_closing_parenthesis b/spec/errors/case_expected_closing_parenthesis new file mode 100644 index 000000000..6fed9f4ec --- /dev/null +++ b/spec/errors/case_expected_closing_parenthesis @@ -0,0 +1,14 @@ +component Main { + fun render : String { + case ("a" +-------------------------------------------------------------------------------- +░ ERROR (CASE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a case but I found "a space" instead: + + ┌ ./spec/errors/case_expected_closing_parenthesis:3:13 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case ("a" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/case_expected_condition b/spec/errors/case_expected_condition new file mode 100644 index 000000000..ffe675cb7 --- /dev/null +++ b/spec/errors/case_expected_condition @@ -0,0 +1,14 @@ +component Main { + fun render : String { + case +-------------------------------------------------------------------------------- +░ ERROR (CASE_EXPECTED_CONDITION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the condition of a case but I found "a space" instead: + + ┌ ./spec/errors/case_expected_condition:3:8 + ├────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case + │ ⌃⌃⌃⌃ diff --git a/spec/errors/case_expected_opening_bracket b/spec/errors/case_expected_opening_bracket new file mode 100644 index 000000000..434cdcf59 --- /dev/null +++ b/spec/errors/case_expected_opening_bracket @@ -0,0 +1,14 @@ +component Main { + fun render : String { + case ("a") +-------------------------------------------------------------------------------- +░ ERROR (CASE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a case but I found "a space" instead: + + ┌ ./spec/errors/case_expected_opening_bracket:3:14 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case ("a") + │ ⌃⌃⌃⌃ diff --git a/spec/errors/case_not_covered b/spec/errors/case_not_covered new file mode 100644 index 000000000..aeabb8a2e --- /dev/null +++ b/spec/errors/case_not_covered @@ -0,0 +1,28 @@ +component Main { + fun render : String { + case ("a") { + "a" => "a" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (CASE_NOT_COVERED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Not all possibilities of a case expression are covered. To cover all remaining +possibilities add an empty case branch: + + => returnValue + +The case in question is here: + + ┌ ./spec/errors/case_not_covered:3:5 + ├─────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 3│ case ("a") { + 4│ "a" => "a" + 5│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 6│ } + 7│ } diff --git a/spec/errors/case_type_not_covered b/spec/errors/case_type_not_covered new file mode 100644 index 000000000..71cb92627 --- /dev/null +++ b/spec/errors/case_type_not_covered @@ -0,0 +1,38 @@ +enum A { + B + C + D +} + +component Main { + fun render : String { + case (A::B) { + A::B => "a" + A::C => "c" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (CASE_TYPE_NOT_COVERED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Not all possibilities of a case expression are covered. To cover all remaining +possibilities create branches for the following cases: + + A::D + +The case in question is here: + + ┌ ./spec/errors/case_type_not_covered:9:5 + ├──────────────────────────────────────── + 5│ } + 6│ + 7│ component Main { + 8│ fun render : String { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 9│ case (A::B) { + 10│ A::B => "a" + 11│ A::C => "c" + 12│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 13│ } + 14│ } diff --git a/spec/errors/case_unnecessary_all b/spec/errors/case_unnecessary_all new file mode 100644 index 000000000..173d53028 --- /dev/null +++ b/spec/errors/case_unnecessary_all @@ -0,0 +1,31 @@ +enum A { + B + C +} + +component Main { + fun render : String { + case (A::B) { + A::B => "a" + A::C => "c" + => "x" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (CASE_UNNECESSARY_ALL) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +All possibilities of the case expression are covered so this branch is not +needed and can be safely removed. + + ┌ ./spec/errors/case_unnecessary_all:11:7 + ├──────────────────────────────────────── + 7│ fun render : String { + 8│ case (A::B) { + 9│ A::B => "a" + 10│ A::C => "c" + 11│ => "x" + │ ⌃⌃⌃⌃⌃⌃ + 12│ } + 13│ } + 14│ } diff --git a/spec/errors/component_expected_body b/spec/errors/component_expected_body new file mode 100644 index 000000000..b23f93865 --- /dev/null +++ b/spec/errors/component_expected_body @@ -0,0 +1,10 @@ +component Main { +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a component but I found "a space" instead: + + ┌ ./spec/errors/component_expected_body:1:16 + ├─────────────────────────────────────────── + 1│ component Main { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/component_expected_closing_bracket b/spec/errors/component_expected_closing_bracket new file mode 100644 index 000000000..1842b15fa --- /dev/null +++ b/spec/errors/component_expected_closing_bracket @@ -0,0 +1,13 @@ +component Main { + state test : String = "" +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of the component but I found "a space" +instead: + + ┌ ./spec/errors/component_expected_closing_bracket:2:26 + ├────────────────────────────────────────────────────── + 1│ component Main { + 2│ state test : String = "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/component_expected_name b/spec/errors/component_expected_name new file mode 100644 index 000000000..3546c2890 --- /dev/null +++ b/spec/errors/component_expected_name @@ -0,0 +1,13 @@ +component +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The name of a component must start with an uppercase letter and only contain +lowercase, uppercase letters and numbers. + +I was expecting name of the component but I found "a space" instead: + + ┌ ./spec/errors/component_expected_name:1:9 + ├────────────────────────────────────────── + 1│ component + │ ⌃⌃⌃⌃ diff --git a/spec/errors/component_expected_opening_bracket b/spec/errors/component_expected_opening_bracket new file mode 100644 index 000000000..3f2230dd6 --- /dev/null +++ b/spec/errors/component_expected_opening_bracket @@ -0,0 +1,11 @@ +component Main +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of the component but I found "a space" +instead: + + ┌ ./spec/errors/component_expected_opening_bracket:1:14 + ├────────────────────────────────────────────────────── + 1│ component Main + │ ⌃⌃⌃⌃ diff --git a/spec/errors/component_exposed_name_conflict b/spec/errors/component_exposed_name_conflict new file mode 100644 index 000000000..828657f2e --- /dev/null +++ b/spec/errors/component_exposed_name_conflict @@ -0,0 +1,44 @@ +component A { + connect Test exposing { x } + + get x : String { + "" + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_EXPOSED_NAME_CONFLICT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +You cannot expose "x" from the store because the name is already taken. + +The entity with the same name is here: + + ┌ ./spec/errors/component_exposed_name_conflict:4:3 + ├────────────────────────────────────────────────── + 1│ component A { + 2│ connect Test exposing { x } + 3│ + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 4│ get x : String { + 5│ "" + 6│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 7│ + 8│ fun render : Html { + 9│
+ 10│ } + +The expose in question is here: + + ┌ ./spec/errors/component_exposed_name_conflict:2:27 + ├─────────────────────────────────────────────────── + 1│ component A { + 2│ connect Test exposing { x } + │ ⌃ + 3│ + 4│ get x : String { + 5│ "" + 6│ } diff --git a/spec/errors/component_lifecycle_function_mismatch b/spec/errors/component_lifecycle_function_mismatch new file mode 100644 index 000000000..04d39963e --- /dev/null +++ b/spec/errors/component_lifecycle_function_mismatch @@ -0,0 +1,36 @@ +component Main { + fun componentDidUpdate (a : String) : String { + "" + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_LIFECYCLE_FUNCTION_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the function "componentDidUpdate" of a component must be: + + Function(a) + +Instead it is: + + Function( + a: String, + String) + +The function in question is here: + + ┌ ./spec/errors/component_lifecycle_function_mismatch:2:3 + ├──────────────────────────────────────────────────────── + 1│ component Main { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 2│ fun componentDidUpdate (a : String) : String { + 3│ "" + 4│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ + 6│ fun render : Html { + 7│
+ 8│ } diff --git a/spec/errors/component_main_properties b/spec/errors/component_main_properties new file mode 100644 index 000000000..e6c1b85e9 --- /dev/null +++ b/spec/errors/component_main_properties @@ -0,0 +1,36 @@ +component Main { + property name : String = "Joe" + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_MAIN_PROPERTIES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The Main component cannot have properties because there is no way to pass values +to them. + +A property is defined here: + + ┌ ./spec/errors/component_main_properties:2:3 + ├──────────────────────────────────────────── + 1│ component Main { + 2│ property name : String = "Joe" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } + +The component in question is here: + + ┌ ./spec/errors/component_main_properties:1:1 + ├──────────────────────────────────────────── + 1│ component Main { + 2│ property name : String = "Joe" + 3│ + 4│ fun render : Html { + 5│
+ 6│ } + 7│ } diff --git a/spec/errors/component_multiple_exposed b/spec/errors/component_multiple_exposed new file mode 100644 index 000000000..b0bdfe742 --- /dev/null +++ b/spec/errors/component_multiple_exposed @@ -0,0 +1,35 @@ +component A { + connect Test exposing { x, x } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_MULTIPLE_EXPOSED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The entity "x" from a store is exposed multiple times. + +It is exposed here: + + ┌ ./spec/errors/component_multiple_exposed:2:27 + ├────────────────────────────────────────────── + 1│ component A { + 2│ connect Test exposing { x, x } + │ ⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } + +It is also exposed here: + + ┌ ./spec/errors/component_multiple_exposed:2:30 + ├────────────────────────────────────────────── + 1│ component A { + 2│ connect Test exposing { x, x } + │ ⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } diff --git a/spec/errors/component_multiple_providers b/spec/errors/component_multiple_providers new file mode 100644 index 000000000..fb6327a7d --- /dev/null +++ b/spec/errors/component_multiple_providers @@ -0,0 +1,38 @@ +component Main { + use Provider { a: "" } + use Provider { a: "" } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_MULTIPLE_PROVIDERS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +You are subcribing to the provider "Provider" in a component multiple times. + +A subscription is here: + + ┌ ./spec/errors/component_multiple_providers:3:3 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ use Provider { a: "" } + 3│ use Provider { a: "" } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ + 5│ fun render : Html { + 6│
+ 7│ } + +An other subscription is here: + + ┌ ./spec/errors/component_multiple_providers:2:3 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ use Provider { a: "" } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ use Provider { a: "" } + 4│ + 5│ fun render : Html { + 6│
+ diff --git a/spec/errors/component_multiple_stores b/spec/errors/component_multiple_stores new file mode 100644 index 000000000..a5606766a --- /dev/null +++ b/spec/errors/component_multiple_stores @@ -0,0 +1,38 @@ +component A { + connect Test exposing { x } + connect Test exposing { x } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_MULTIPLE_STORES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The component is connected to the store "Test" multiple times. + +It is connected here: + + ┌ ./spec/errors/component_multiple_stores:3:3 + ├──────────────────────────────────────────── + 1│ component A { + 2│ connect Test exposing { x } + 3│ connect Test exposing { x } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ + 5│ fun render : Html { + 6│
+ 7│ } + +It is also connected here: + + ┌ ./spec/errors/component_multiple_stores:2:3 + ├──────────────────────────────────────────── + 1│ component A { + 2│ connect Test exposing { x } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ connect Test exposing { x } + 4│ + 5│ fun render : Html { + 6│
+ diff --git a/spec/errors/component_no_render_function b/spec/errors/component_no_render_function new file mode 100644 index 000000000..07a8d12ee --- /dev/null +++ b/spec/errors/component_no_render_function @@ -0,0 +1,17 @@ +component Main { + fun a : String { + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_NO_RENDER_FUNCTION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A component must have a render function. This component does not have one: + + ┌ ./spec/errors/component_no_render_function:1:1 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun a : String { + 3│ "" + 4│ } + 5│ } diff --git a/spec/errors/component_reference_name_conflict b/spec/errors/component_reference_name_conflict new file mode 100644 index 000000000..45d9d2d50 --- /dev/null +++ b/spec/errors/component_reference_name_conflict @@ -0,0 +1,39 @@ +component Main { + fun render : Html { +
+
+
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_REFERENCE_NAME_CONFLICT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +There are multiple references with the name: + + myDiv + +One reference is here: + + ┌ ./spec/errors/component_reference_name_conflict:3:13 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│
+ │ ⌃⌃⌃⌃⌃ + 4│
+ 5│
+ 6│ } + 7│ } + +The other reference is here: + + ┌ ./spec/errors/component_reference_name_conflict:4:15 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│
+ 4│
+ │ ⌃⌃⌃⌃⌃ + 5│
+ 6│ } + 7│ } diff --git a/spec/errors/component_render_function_mismatch b/spec/errors/component_render_function_mismatch new file mode 100644 index 000000000..4a154a5cf --- /dev/null +++ b/spec/errors/component_render_function_mismatch @@ -0,0 +1,30 @@ +component Main { + fun render : Bool { + true + } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_RENDER_FUNCTION_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of the render function to match one of these types: + + Function(Array(String)) + Function(Array(Html)) + Function(String) + Function(Html) + +Instead the type of the function is: + + Bool + +The function in question is here: + + ┌ ./spec/errors/component_render_function_mismatch:2:3 + ├───────────────────────────────────────────────────── + 1│ component Main { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 2│ fun render : Bool { + 3│ true + 4│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ } diff --git a/spec/errors/component_style_name_conflict b/spec/errors/component_style_name_conflict new file mode 100644 index 000000000..6a40fc56e --- /dev/null +++ b/spec/errors/component_style_name_conflict @@ -0,0 +1,52 @@ +component Main { + style title { + color: red; + } + + style title { + color: blue; + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (COMPONENT_STYLE_NAME_CONFLICT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +There are multiple styles with the name: + + title + +One style is here: + + ┌ ./spec/errors/component_style_name_conflict:6:3 + ├──────────────────────────────────────────────── + 2│ style title { + 3│ color: red; + 4│ } + 5│ + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 6│ style title { + 7│ color: blue; + 8│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 9│ + 10│ fun render : Html { + 11│
+ 12│ } + +An other style is here: + + ┌ ./spec/errors/component_style_name_conflict:2:3 + ├──────────────────────────────────────────────── + 1│ component Main { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 2│ style title { + 3│ color: red; + 4│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ + 6│ style title { + 7│ color: blue; + 8│ } diff --git a/spec/errors/connect_expected_closing_bracket b/spec/errors/connect_expected_closing_bracket new file mode 100644 index 000000000..2b0afcd29 --- /dev/null +++ b/spec/errors/connect_expected_closing_bracket @@ -0,0 +1,12 @@ +component Main { + connect Test exposing { item +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a connect but I found "a space" instead: + + ┌ ./spec/errors/connect_expected_closing_bracket:2:30 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ connect Test exposing { item + │ ⌃⌃⌃⌃ diff --git a/spec/errors/connect_expected_exposing b/spec/errors/connect_expected_exposing new file mode 100644 index 000000000..029c37fe4 --- /dev/null +++ b/spec/errors/connect_expected_exposing @@ -0,0 +1,13 @@ +component Main { + connect Test +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_EXPECTED_EXPOSING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the "exposing" keyword for a connect but I found "a space" +instead: + + ┌ ./spec/errors/connect_expected_exposing:2:14 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ connect Test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/connect_expected_keys b/spec/errors/connect_expected_keys new file mode 100644 index 000000000..398ccead0 --- /dev/null +++ b/spec/errors/connect_expected_keys @@ -0,0 +1,12 @@ +component Main { + connect Test exposing { +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_EXPECTED_KEYS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the exposed entities of a connect but I found "a space" instead: + + ┌ ./spec/errors/connect_expected_keys:2:25 + ├───────────────────────────────────────── + 1│ component Main { + 2│ connect Test exposing { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/connect_expected_opening_bracket b/spec/errors/connect_expected_opening_bracket new file mode 100644 index 000000000..b6ba10fea --- /dev/null +++ b/spec/errors/connect_expected_opening_bracket @@ -0,0 +1,12 @@ +component Main { + connect Test exposing +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a connect but I found "a space" instead: + + ┌ ./spec/errors/connect_expected_opening_bracket:2:23 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ connect Test exposing + │ ⌃⌃⌃⌃ diff --git a/spec/errors/connect_expected_store b/spec/errors/connect_expected_store new file mode 100644 index 000000000..e09f4d7db --- /dev/null +++ b/spec/errors/connect_expected_store @@ -0,0 +1,13 @@ +component Main { + connect +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_EXPECTED_STORE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of the store for a connect but I found "a space" +instead: + + ┌ ./spec/errors/connect_expected_store:2:9 + ├───────────────────────────────────────── + 1│ component Main { + 2│ connect + │ ⌃⌃⌃⌃ diff --git a/spec/errors/connect_not_found_member b/spec/errors/connect_not_found_member new file mode 100644 index 000000000..1c01f0919 --- /dev/null +++ b/spec/errors/connect_not_found_member @@ -0,0 +1,30 @@ +store Test { + state x : String = "" +} + +component Main { + connect Test exposing { x, y } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_NOT_FOUND_MEMBER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The entity "y" does not exist in the connected store. + +The connect in question is here: + + ┌ ./spec/errors/connect_not_found_member:6:3 + ├─────────────────────────────────────────── + 2│ state x : String = "" + 3│ } + 4│ + 5│ component Main { + 6│ connect Test exposing { x, y } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 7│ + 8│ fun render : Html { + 9│
+ 10│ } diff --git a/spec/errors/connect_not_found_store b/spec/errors/connect_not_found_store new file mode 100644 index 000000000..5be02a9ee --- /dev/null +++ b/spec/errors/connect_not_found_store @@ -0,0 +1,21 @@ +component Main { + connect Test exposing { x, y } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_NOT_FOUND_STORE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for the store Test but could not find it. + + ┌ ./spec/errors/connect_not_found_store:2:11 + ├─────────────────────────────────────────── + 1│ component Main { + 2│ connect Test exposing { x, y } + │ ⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } diff --git a/spec/errors/connect_variable_expected_as b/spec/errors/connect_variable_expected_as new file mode 100644 index 000000000..f01470d6a --- /dev/null +++ b/spec/errors/connect_variable_expected_as @@ -0,0 +1,16 @@ +component Main { + connect Test exposing { item as +-------------------------------------------------------------------------------- +░ ERROR (CONNECT_VARIABLE_EXPECTED_AS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The exposed name of a connection must be specified, here is an example: + + connect Store exposing { item as name } + +I was expecting the exposed name but I found "a space" instead: + + ┌ ./spec/errors/connect_variable_expected_as:2:33 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ connect Test exposing { item as + │ ⌃⌃⌃⌃ diff --git a/spec/errors/constant_expected_equal_sign b/spec/errors/constant_expected_equal_sign new file mode 100644 index 000000000..51fa79414 --- /dev/null +++ b/spec/errors/constant_expected_equal_sign @@ -0,0 +1,12 @@ +component Main { + const TEST +-------------------------------------------------------------------------------- +░ ERROR (CONSTANT_EXPECTED_EQUAL_SIGN) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the equal sign of a constant but I found "a space" instead: + + ┌ ./spec/errors/constant_expected_equal_sign:2:12 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ const TEST + │ ⌃⌃⌃⌃ diff --git a/spec/errors/constant_expected_expression b/spec/errors/constant_expected_expression new file mode 100644 index 000000000..95f4b4001 --- /dev/null +++ b/spec/errors/constant_expected_expression @@ -0,0 +1,12 @@ +component Main { + const TEST = +-------------------------------------------------------------------------------- +░ ERROR (CONSTANT_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the expression of a constant but I found "a space" instead: + + ┌ ./spec/errors/constant_expected_expression:2:14 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ const TEST = + │ ⌃⌃⌃⌃ diff --git a/spec/errors/constant_expected_name b/spec/errors/constant_expected_name new file mode 100644 index 000000000..83bee230f --- /dev/null +++ b/spec/errors/constant_expected_name @@ -0,0 +1,12 @@ +component Main { + const +-------------------------------------------------------------------------------- +░ ERROR (CONSTANT_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a constant but I found "a space" instead: + + ┌ ./spec/errors/constant_expected_name:2:7 + ├───────────────────────────────────────── + 1│ component Main { + 2│ const + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_definition_expected_semicolon b/spec/errors/css_definition_expected_semicolon new file mode 100644 index 000000000..acfbc602f --- /dev/null +++ b/spec/errors/css_definition_expected_semicolon @@ -0,0 +1,14 @@ +component Main { + style root { + background: red +-------------------------------------------------------------------------------- +░ ERROR (CSS_DEFINITION_EXPECTED_SEMICOLON) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the semicolon of a CSS definition but I found "a space" instead: + + ┌ ./spec/errors/css_definition_expected_semicolon:3:19 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ background: red + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_definition_no_property b/spec/errors/css_definition_no_property new file mode 100644 index 000000000..4d89252a5 --- /dev/null +++ b/spec/errors/css_definition_no_property @@ -0,0 +1,24 @@ +component Main { + style test { + colorasd: hello; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (CSS_DEFINITION_NO_PROPERTY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +There is no CSS property with the name: "colorasd" + + ┌ ./spec/errors/css_definition_no_property:3:5 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ style test { + 3│ colorasd: hello; + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : Html { + 7│ diff --git a/spec/errors/css_definition_type_mismatch b/spec/errors/css_definition_type_mismatch new file mode 100644 index 000000000..2e5ce51a3 --- /dev/null +++ b/spec/errors/css_definition_type_mismatch @@ -0,0 +1,35 @@ +component Main { + style test { + color: #{true}; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (CSS_DEFINITION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the value for the CSS property "color" is invalid. + +I was expecting one of these types: + + String + Number + +Instead it is: + + Bool + +The css definition in question is here: + + ┌ ./spec/errors/css_definition_type_mismatch:3:5 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ style test { + 3│ color: #{true}; + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : Html { + 7│ diff --git a/spec/errors/css_font_face_expected_closing_bracket b/spec/errors/css_font_face_expected_closing_bracket new file mode 100644 index 000000000..198daac3d --- /dev/null +++ b/spec/errors/css_font_face_expected_closing_bracket @@ -0,0 +1,17 @@ +component Main { + style root { + @font-face { + color: red; +-------------------------------------------------------------------------------- +░ ERROR (CSS_FONT_FACE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a CSS font-face rule but I found "a +space" instead: + + ┌ ./spec/errors/css_font_face_expected_closing_bracket:4:17 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @font-face { + 4│ color: red; + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_font_face_expected_definitions b/spec/errors/css_font_face_expected_definitions new file mode 100644 index 000000000..4495b64c5 --- /dev/null +++ b/spec/errors/css_font_face_expected_definitions @@ -0,0 +1,15 @@ +component Main { + style root { + @font-face { +-------------------------------------------------------------------------------- +░ ERROR (CSS_FONT_FACE_EXPECTED_DEFINITIONS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the definitions of a CSS font-face rule but I found "a space" +instead: + + ┌ ./spec/errors/css_font_face_expected_definitions:3:16 + ├────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @font-face { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_font_face_expected_opening_bracket b/spec/errors/css_font_face_expected_opening_bracket new file mode 100644 index 000000000..0a6150291 --- /dev/null +++ b/spec/errors/css_font_face_expected_opening_bracket @@ -0,0 +1,16 @@ +component Main { + style root { + @font-face +-------------------------------------------------------------------------------- +░ ERROR (CSS_FONT_FACE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a CSS font-face rule but I found "a +space" instead: + + ┌ ./spec/errors/css_font_face_expected_opening_bracket:3:14 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @font-face + │ ⌃⌃⌃⌃ + diff --git a/spec/errors/css_font_face_interpolation b/spec/errors/css_font_face_interpolation new file mode 100644 index 000000000..f437a86bf --- /dev/null +++ b/spec/errors/css_font_face_interpolation @@ -0,0 +1,29 @@ +component Main { + style test { + @font-face { + src: url(sansation_light.woff); + font-family: #{"myFirstFont"}; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (CSS_FONT_FACE_INTERPOLATION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Interpolations are not allowed inside a font-face rule. + + ┌ ./spec/errors/css_font_face_interpolation:5:20 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ style test { + 3│ @font-face { + 4│ src: url(sansation_light.woff); + 5│ font-family: #{"myFirstFont"}; + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 6│ } + 7│ } + 8│ + 9│ fun render : Html { diff --git a/spec/errors/css_keyframes_expected_closing_bracket b/spec/errors/css_keyframes_expected_closing_bracket new file mode 100644 index 000000000..7e226be4f --- /dev/null +++ b/spec/errors/css_keyframes_expected_closing_bracket @@ -0,0 +1,20 @@ +component Main { + style root { + @keyframes name { + 0% { + color: red; + } +-------------------------------------------------------------------------------- +░ ERROR (CSS_KEYFRAMES_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a CSS keyframes rule but I found "a +space" instead: + + ┌ ./spec/errors/css_keyframes_expected_closing_bracket:6:7 + ├───────────────────────────────────────────────────────── + 2│ style root { + 3│ @keyframes name { + 4│ 0% { + 5│ color: red; + 6│ } + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_keyframes_expected_name b/spec/errors/css_keyframes_expected_name new file mode 100644 index 000000000..526f00156 --- /dev/null +++ b/spec/errors/css_keyframes_expected_name @@ -0,0 +1,14 @@ +component Main { + style root { + @keyframes +-------------------------------------------------------------------------------- +░ ERROR (CSS_KEYFRAMES_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a CSS keyframes rule but I found "a space" instead: + + ┌ ./spec/errors/css_keyframes_expected_name:3:14 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @keyframes + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_keyframes_expected_opening_bracket b/spec/errors/css_keyframes_expected_opening_bracket new file mode 100644 index 000000000..c09ded1a0 --- /dev/null +++ b/spec/errors/css_keyframes_expected_opening_bracket @@ -0,0 +1,15 @@ +component Main { + style root { + @keyframes name +-------------------------------------------------------------------------------- +░ ERROR (CSS_KEYFRAMES_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a CSS keyframes rule but I found "a +space" instead: + + ┌ ./spec/errors/css_keyframes_expected_opening_bracket:3:19 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @keyframes name + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_keyframes_expected_selectors b/spec/errors/css_keyframes_expected_selectors new file mode 100644 index 000000000..e8b1bfbac --- /dev/null +++ b/spec/errors/css_keyframes_expected_selectors @@ -0,0 +1,15 @@ +component Main { + style root { + @keyframes name { +-------------------------------------------------------------------------------- +░ ERROR (CSS_KEYFRAMES_EXPECTED_SELECTORS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the selectors of a CSS keyframes rule but I found "a space" +instead: + + ┌ ./spec/errors/css_keyframes_expected_selectors:3:21 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @keyframes name { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_nested_at_expected_body b/spec/errors/css_nested_at_expected_body new file mode 100644 index 000000000..2eb511768 --- /dev/null +++ b/spec/errors/css_nested_at_expected_body @@ -0,0 +1,14 @@ +component Main { + style root { + @media (max-width: 100px) { +-------------------------------------------------------------------------------- +░ ERROR (CSS_NESTED_AT_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a CSS at rule but I found "a space" instead: + + ┌ ./spec/errors/css_nested_at_expected_body:3:31 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @media (max-width: 100px) { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_nested_at_expected_closing_bracket b/spec/errors/css_nested_at_expected_closing_bracket new file mode 100644 index 000000000..9698faa85 --- /dev/null +++ b/spec/errors/css_nested_at_expected_closing_bracket @@ -0,0 +1,17 @@ +component Main { + style root { + @media (max-width: 100px) { + color: red; +-------------------------------------------------------------------------------- +░ ERROR (CSS_NESTED_AT_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a CSS at rule but I found "a space" +instead: + + ┌ ./spec/errors/css_nested_at_expected_closing_bracket:4:17 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @media (max-width: 100px) { + 4│ color: red; + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_nested_at_expected_condition b/spec/errors/css_nested_at_expected_condition new file mode 100644 index 000000000..0a6f364e0 --- /dev/null +++ b/spec/errors/css_nested_at_expected_condition @@ -0,0 +1,14 @@ +component Main { + style root { + @media +-------------------------------------------------------------------------------- +░ ERROR (CSS_NESTED_AT_EXPECTED_CONDITION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the condition of a CSS at rule but I found "a space" instead: + + ┌ ./spec/errors/css_nested_at_expected_condition:3:10 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @media + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_nested_at_expected_opening_bracket b/spec/errors/css_nested_at_expected_opening_bracket new file mode 100644 index 000000000..5b0a139c7 --- /dev/null +++ b/spec/errors/css_nested_at_expected_opening_bracket @@ -0,0 +1,15 @@ +component Main { + style root { + @media (max-width: 100px) +-------------------------------------------------------------------------------- +░ ERROR (CSS_NESTED_AT_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a CSS at rule but I found "a space" +instead: + + ┌ ./spec/errors/css_nested_at_expected_opening_bracket:3:29 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ @media (max-width: 100px) + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_selector_expected_body b/spec/errors/css_selector_expected_body new file mode 100644 index 000000000..183cf033d --- /dev/null +++ b/spec/errors/css_selector_expected_body @@ -0,0 +1,14 @@ +component Main { + style root { + div { +-------------------------------------------------------------------------------- +░ ERROR (CSS_SELECTOR_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a CSS selector but I found "a space" instead: + + ┌ ./spec/errors/css_selector_expected_body:3:9 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ div { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/css_selector_expected_closing_bracket b/spec/errors/css_selector_expected_closing_bracket new file mode 100644 index 000000000..ac9a7bbcb --- /dev/null +++ b/spec/errors/css_selector_expected_closing_bracket @@ -0,0 +1,17 @@ +component Main { + style root { + div { + color: red; +-------------------------------------------------------------------------------- +░ ERROR (CSS_SELECTOR_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening closing of a CSS selector but I found "a space" +instead: + + ┌ ./spec/errors/css_selector_expected_closing_bracket:4:17 + ├───────────────────────────────────────────────────────── + 1│ component Main { + 2│ style root { + 3│ div { + 4│ color: red; + │ ⌃⌃⌃⌃ diff --git a/spec/errors/decode_complex_type b/spec/errors/decode_complex_type new file mode 100644 index 000000000..08e8d9e87 --- /dev/null +++ b/spec/errors/decode_complex_type @@ -0,0 +1,43 @@ +record X { + name : Blah +} + +component Main { + fun render : Html { + decode (`{}`) as X + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (DECODE_COMPLEX_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +This type cannot be automatically decoded: + + X(name: Blah) + +Only these types and records containing them cantext be automatically decoded: + + Map(String, a) + Array(a) + Maybe(a) + String + Number + Object + Time + Bool + +The decode question is here: + + ┌ ./spec/errors/decode_complex_type:7:5 + ├────────────────────────────────────── + 3│ } + 4│ + 5│ component Main { + 6│ fun render : Html { + 7│ decode (`{}`) as X + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ + 9│
+ 10│ } + 11│ } diff --git a/spec/errors/decode_expected_as b/spec/errors/decode_expected_as new file mode 100644 index 000000000..e5e6c7529 --- /dev/null +++ b/spec/errors/decode_expected_as @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + decode "" +-------------------------------------------------------------------------------- +░ ERROR (DECODE_EXPECTED_AS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the "as" keyword of a decode expression but I found "a space" +instead: + + ┌ ./spec/errors/decode_expected_as:3:13 + ├────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ decode "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/decode_expected_object b/spec/errors/decode_expected_object new file mode 100644 index 000000000..2002e53e9 --- /dev/null +++ b/spec/errors/decode_expected_object @@ -0,0 +1,32 @@ +record X { + name : String +} + +component Main { + fun render : Html { + decode "" as X + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (DECODE_EXPECTED_OBJECT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Only the "Object" type can be decoded but you tried to decode: + + String + +The decode question is here: + + ┌ ./spec/errors/decode_expected_object:7:5 + ├───────────────────────────────────────── + 3│ } + 4│ + 5│ component Main { + 6│ fun render : Html { + 7│ decode "" as X + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ + 9│
+ 10│ } + 11│ } diff --git a/spec/errors/decode_expected_subject b/spec/errors/decode_expected_subject new file mode 100644 index 000000000..9bf42fbe8 --- /dev/null +++ b/spec/errors/decode_expected_subject @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + decode +-------------------------------------------------------------------------------- +░ ERROR (DECODE_EXPECTED_SUBJECT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the subject of a decode expression but I found "a space" +instead: + + ┌ ./spec/errors/decode_expected_subject:3:10 + ├─────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ decode + │ ⌃⌃⌃⌃ diff --git a/spec/errors/decode_expected_type b/spec/errors/decode_expected_type new file mode 100644 index 000000000..47d927588 --- /dev/null +++ b/spec/errors/decode_expected_type @@ -0,0 +1,14 @@ +component Main { + fun render : Html { + decode "" as +-------------------------------------------------------------------------------- +░ ERROR (DECODE_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of a decode expression but I found "a space" instead: + + ┌ ./spec/errors/decode_expected_type:3:16 + ├──────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ decode "" as + │ ⌃⌃⌃⌃ diff --git a/spec/errors/destructuring_multiple_spreads b/spec/errors/destructuring_multiple_spreads new file mode 100644 index 000000000..4d50dbf60 --- /dev/null +++ b/spec/errors/destructuring_multiple_spreads @@ -0,0 +1,25 @@ +component Main { + fun render : String { + case [] { + [...a,...b] => "a" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (DESTRUCTURING_MULTIPLE_SPREADS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +An array destructuring can only contain one spread notation because otherwise I +don't know how to distribute the leftover items. + +This array destructuring contains 2 spread notations: + + ┌ ./spec/errors/destructuring_multiple_spreads:4:7 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case [] { + 4│ [...a,...b] => "a" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ } + 6│ } + 7│ } diff --git a/spec/errors/destructuring_tuple_mismatch b/spec/errors/destructuring_tuple_mismatch new file mode 100644 index 000000000..c1fefd40a --- /dev/null +++ b/spec/errors/destructuring_tuple_mismatch @@ -0,0 +1,31 @@ +component Main { + fun render : String { + case {"a", "b"} { + {a, b, c} => "a" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (DESTRUCTURING_TUPLE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +This destructuring of a tuple does not match the given tuple. I was expecting a +tuple with 3 items. + +Instead it is this: + + Tuple( + String, + String) + +The destructuring in question is here: + + ┌ ./spec/errors/destructuring_tuple_mismatch:4:7 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case {"a", "b"} { + 4│ {a, b, c} => "a" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ } + 6│ } + 7│ } diff --git a/spec/errors/destructuring_type_field_missing b/spec/errors/destructuring_type_field_missing new file mode 100644 index 000000000..ab0109b0d --- /dev/null +++ b/spec/errors/destructuring_type_field_missing @@ -0,0 +1,30 @@ +enum Maybe { + Just(item : String) +} + +component Main { + fun render : String { + let Maybe::Just(key) = Maybe::Just(item: "") or return "" + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (DESTRUCTURING_TYPE_FIELD_MISSING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I could not find a field for a destructuring: + + key + +The destructuring in question is here: + + ┌ ./spec/errors/destructuring_type_field_missing:7:21 + ├──────────────────────────────────────────────────── + 3│ } + 4│ + 5│ component Main { + 6│ fun render : String { + 7│ let Maybe::Just(key) = Maybe::Just(item: "") or return "" + │ ⌃⌃⌃ + 8│ "" + 9│ } + 10│ } diff --git a/spec/errors/destructuring_type_mismatch b/spec/errors/destructuring_type_mismatch new file mode 100644 index 000000000..8af440f2b --- /dev/null +++ b/spec/errors/destructuring_type_mismatch @@ -0,0 +1,35 @@ +component Main { + fun render : String { + case "x" { + true => "a" + "b" => "b" + => "c" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (DESTRUCTURING_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A value does not match its supposed type in a destructuring. + +I was expecting: + + String + +Instead it is: + + Bool + +The destructuring in question is here: + + ┌ ./spec/errors/destructuring_type_mismatch:4:7 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case "x" { + 4│ true => "a" + │ ⌃⌃⌃⌃ + 5│ "b" => "b" + 6│ => "c" + 7│ } + 8│ } diff --git a/spec/errors/destructuring_type_missing b/spec/errors/destructuring_type_missing new file mode 100644 index 000000000..e9c004e0e --- /dev/null +++ b/spec/errors/destructuring_type_missing @@ -0,0 +1,24 @@ +component Main { + fun render : String { + let Maybe::Just(a) = "" or return "" + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (DESTRUCTURING_TYPE_MISSING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I could not find the type for a destructuring with the name: + + Maybe + +The destructuring in question is here: + + ┌ ./spec/errors/destructuring_type_missing:3:9 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ let Maybe::Just(a) = "" or return "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ "" + 5│ } + 6│ } diff --git a/spec/errors/destructuring_type_variant_missing b/spec/errors/destructuring_type_variant_missing new file mode 100644 index 000000000..b2deed6e5 --- /dev/null +++ b/spec/errors/destructuring_type_variant_missing @@ -0,0 +1,40 @@ +enum Maybe { + Nothing +} + +component Main { + fun render : String { + let Maybe::Just(a) = "" or return "" + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (DESTRUCTURING_TYPE_VARIANT_MISSING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I could not find the variant "Just" of type "Maybe" for a destructuring: + + ┌ ./spec/errors/destructuring_type_variant_missing:7:9 + ├───────────────────────────────────────────────────── + 3│ } + 4│ + 5│ component Main { + 6│ fun render : String { + 7│ let Maybe::Just(a) = "" or return "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ "" + 9│ } + 10│ } + +The type is defined here: + + ┌ ./spec/errors/destructuring_type_variant_missing:1:1 + ├───────────────────────────────────────────────────── + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 1│ enum Maybe { + 2│ Nothing + 3│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ + 5│ component Main { + 6│ fun render : String { + 7│ let Maybe::Just(a) = "" or return "" diff --git a/spec/errors/documentation_directive_entity_not_found b/spec/errors/documentation_directive_entity_not_found new file mode 100644 index 000000000..5229c88f4 --- /dev/null +++ b/spec/errors/documentation_directive_entity_not_found @@ -0,0 +1,26 @@ +component Main { + fun render : String { + @documentation(SomeComponent) + + "Hello There" + } +} +-------------------------------------------------------------------------------- +░ ERROR (DOCUMENTATION_DIRECTIVE_ENTITY_NOT_FOUND) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The entity for the documentation directive does not exist: + + SomeComponent + +The documentation directive in question is here: + + ┌ ./spec/errors/documentation_directive_entity_not_found:3:5 + ├─────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @documentation(SomeComponent) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ + 5│ "Hello There" + 6│ } + 7│ } diff --git a/spec/errors/documentation_directive_expected_closing_parenthesis b/spec/errors/documentation_directive_expected_closing_parenthesis new file mode 100644 index 000000000..cec10a904 --- /dev/null +++ b/spec/errors/documentation_directive_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @documentation(Test +-------------------------------------------------------------------------------- +░ ERROR (DOCUMENTATION_DIRECTIVE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a documentation directive but I found +"a space" instead: + + ┌ ./spec/errors/documentation_directive_expected_closing_parenthesis:3:23 + ├──────────────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @documentation(Test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/documentation_directive_expected_entity b/spec/errors/documentation_directive_expected_entity new file mode 100644 index 000000000..aebcba05a --- /dev/null +++ b/spec/errors/documentation_directive_expected_entity @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @documentation( +-------------------------------------------------------------------------------- +░ ERROR (DOCUMENTATION_DIRECTIVE_EXPECTED_ENTITY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the entity (component, module, etc...) of a documentation +directive but I found "a space" instead: + + ┌ ./spec/errors/documentation_directive_expected_entity:3:19 + ├─────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @documentation( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/documentation_directive_expected_opening_parenthesis b/spec/errors/documentation_directive_expected_opening_parenthesis new file mode 100644 index 000000000..300ffdcee --- /dev/null +++ b/spec/errors/documentation_directive_expected_opening_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @documentation +-------------------------------------------------------------------------------- +░ ERROR (DOCUMENTATION_DIRECTIVE_EXPECTED_OPENING_PARENTHESIS) ░░░░░░░░░░░░░░░░░ + +I was expecting the opening parenthesis of a documentation directive but I found +"a space" instead: + + ┌ ./spec/errors/documentation_directive_expected_opening_parenthesis:3:18 + ├──────────────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @documentation + │ ⌃⌃⌃⌃ diff --git a/spec/errors/encode_complex_type b/spec/errors/encode_complex_type new file mode 100644 index 000000000..ae9aeadf9 --- /dev/null +++ b/spec/errors/encode_complex_type @@ -0,0 +1,39 @@ +enum Maybe { + Just(String) +} + +component Main { + fun render : Html { + encode Maybe::Just("") + } +} +-------------------------------------------------------------------------------- +░ ERROR (ENCODE_COMPLEX_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +This type cannot be automatically encoded: + + Maybe + +Only these types and records containing them can be automatically decoded: + + Map(String, a) + Array(a) + Maybe(a) + String + Number + Object + Time + Bool + +The encode in question is here: + + ┌ ./spec/errors/encode_complex_type:7:5 + ├────────────────────────────────────── + 3│ } + 4│ + 5│ component Main { + 6│ fun render : Html { + 7│ encode Maybe::Just("") + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/encode_expected_expression b/spec/errors/encode_expected_expression new file mode 100644 index 000000000..6d075a8df --- /dev/null +++ b/spec/errors/encode_expected_expression @@ -0,0 +1,18 @@ +component Main { + fun render : Html { + encode +-------------------------------------------------------------------------------- +░ ERROR (ENCODE_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The object to be encoded must come from an expression, here is an example: + + encode "A string for example!" + +I was expecting the expression but I found "a space" instead: + + ┌ ./spec/errors/encode_expected_expression:3:10 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ encode + │ ⌃⌃⌃⌃ diff --git a/spec/errors/entity_name_conflict b/spec/errors/entity_name_conflict new file mode 100644 index 000000000..66b6a790e --- /dev/null +++ b/spec/errors/entity_name_conflict @@ -0,0 +1,35 @@ +component Main { + property render : String = "" + + fun render : Bool { + true + } +} +-------------------------------------------------------------------------------- +░ ERROR (ENTITY_NAME_CONFLICT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +There is already a property with the name "render" in this component: + + ┌ ./spec/errors/entity_name_conflict:2:3 + ├─────────────────────────────────────── + 1│ component Main { + 2│ property render : String = "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Bool { + 5│ true + 6│ } + +You are trying to define something with the same name here: + + ┌ ./spec/errors/entity_name_conflict:4:3 + ├─────────────────────────────────────── + 1│ component Main { + 2│ property render : String = "" + 3│ + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 4│ fun render : Bool { + 5│ true + 6│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 7│ } diff --git a/spec/errors/env_expected_name b/spec/errors/env_expected_name new file mode 100644 index 000000000..9544095d5 --- /dev/null +++ b/spec/errors/env_expected_name @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @ +-------------------------------------------------------------------------------- +░ ERROR (ENV_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of the environment variable but I found "a space" +instead: + + ┌ ./spec/errors/env_expected_name:3:5 + ├──────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @ + │ ⌃⌃⌃⌃ diff --git a/spec/errors/env_not_found_variable b/spec/errors/env_not_found_variable new file mode 100644 index 000000000..f8b2e9770 --- /dev/null +++ b/spec/errors/env_not_found_variable @@ -0,0 +1,22 @@ +component Main { + fun render : String { + @XXX + } +} +-------------------------------------------------------------------------------- +░ ERROR (ENV_NOT_FOUND_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I cannot find the environment variable with the name: + + XXX + +Here is where it is referenced: + + ┌ ./spec/errors/env_not_found_variable:3:5 + ├───────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @XXX + │ ⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/for_array_or_set_arguments_mismatch b/spec/errors/for_array_or_set_arguments_mismatch new file mode 100644 index 000000000..73bc663e1 --- /dev/null +++ b/spec/errors/for_array_or_set_arguments_mismatch @@ -0,0 +1,25 @@ +component Main { + fun render : Array(Html) { + for (item, item2, item3 of ["A", "B"]) { +
+ <{ item }> +
+ } + } +} +-------------------------------------------------------------------------------- +░ ERROR (FOR_ARRAY_OR_SET_ARGUMENTS_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +If the iterable object of a for expression is a set or an array. Then it needs +to the have only 1 argument: + + ┌ ./spec/errors/for_array_or_set_arguments_mismatch:3:10 + ├─────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (item, item2, item3 of ["A", "B"]) { + │ ⌃⌃⌃⌃ + 4│
+ 5│ <{ item }> + 6│
+ 7│ } diff --git a/spec/errors/for_condition_type_mismatch b/spec/errors/for_condition_type_mismatch new file mode 100644 index 000000000..737053451 --- /dev/null +++ b/spec/errors/for_condition_type_mismatch @@ -0,0 +1,35 @@ +component Main { + fun render : Array(Html) { + for (item of ["A", "B"]) { +
+ <{ item }> +
+ } when { + item + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (FOR_CONDITION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The condition of a for expression has an invalid type. I was expecting: + + Bool + +Instead it is: + + String + +The value in question is here: + + ┌ ./spec/errors/for_condition_type_mismatch:8:7 + ├────────────────────────────────────────────── + 4│
+ 5│ <{ item }> + 6│
+ 7│ } when { + 8│ item + │ ⌃⌃⌃⌃ + 9│ } + 10│ } + 11│ } diff --git a/spec/errors/for_expected_body b/spec/errors/for_expected_body new file mode 100644 index 000000000..f50c1d579 --- /dev/null +++ b/spec/errors/for_expected_body @@ -0,0 +1,14 @@ +component Main { + fun render : Array(Html) { + for (a, b of c) { +-------------------------------------------------------------------------------- +░ ERROR (FOR_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a for expression but I found "a space" instead: + + ┌ ./spec/errors/for_expected_body:3:21 + ├───────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (a, b of c) { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/for_expected_closing_bracket b/spec/errors/for_expected_closing_bracket new file mode 100644 index 000000000..d69d1706b --- /dev/null +++ b/spec/errors/for_expected_closing_bracket @@ -0,0 +1,17 @@ +component Main { + fun render : Array(Html) { + for (a, b of c) { + a +-------------------------------------------------------------------------------- +░ ERROR (FOR_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a for expression but I found "a space" +instead: + + ┌ ./spec/errors/for_expected_closing_bracket:4:7 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (a, b of c) { + 4│ a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/for_expected_closing_parenthesis b/spec/errors/for_expected_closing_parenthesis new file mode 100644 index 000000000..9b19b1496 --- /dev/null +++ b/spec/errors/for_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : Array(Html) { + for (a, b of c +-------------------------------------------------------------------------------- +░ ERROR (FOR_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a for expression but I found "a +space" instead: + + ┌ ./spec/errors/for_expected_closing_parenthesis:3:18 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (a, b of c + │ ⌃⌃⌃⌃ diff --git a/spec/errors/for_expected_of b/spec/errors/for_expected_of new file mode 100644 index 000000000..65c4d3d70 --- /dev/null +++ b/spec/errors/for_expected_of @@ -0,0 +1,15 @@ +component Main { + fun render : Array(Html) { + for (a, b +-------------------------------------------------------------------------------- +░ ERROR (FOR_EXPECTED_OF) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the "of" keyword of a for expression but I found "a space" +instead: + + ┌ ./spec/errors/for_expected_of:3:13 + ├─────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (a, b + │ ⌃⌃⌃⌃ diff --git a/spec/errors/for_expected_opening_bracket b/spec/errors/for_expected_opening_bracket new file mode 100644 index 000000000..fee8beff7 --- /dev/null +++ b/spec/errors/for_expected_opening_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : Array(Html) { + for (a, b of c) +-------------------------------------------------------------------------------- +░ ERROR (FOR_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a for expression but I found "a space" +instead: + + ┌ ./spec/errors/for_expected_opening_bracket:3:19 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (a, b of c) + │ ⌃⌃⌃⌃ diff --git a/spec/errors/for_expected_subject b/spec/errors/for_expected_subject new file mode 100644 index 000000000..e7e07da6b --- /dev/null +++ b/spec/errors/for_expected_subject @@ -0,0 +1,14 @@ +component Main { + fun render : Array(Html) { + for (a, b of +-------------------------------------------------------------------------------- +░ ERROR (FOR_EXPECTED_SUBJECT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the subject of a for expression but I found "a space" instead: + + ┌ ./spec/errors/for_expected_subject:3:16 + ├──────────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (a, b of + │ ⌃⌃⌃⌃ diff --git a/spec/errors/for_map_arguments_mismatch b/spec/errors/for_map_arguments_mismatch new file mode 100644 index 000000000..fc5136b5d --- /dev/null +++ b/spec/errors/for_map_arguments_mismatch @@ -0,0 +1,31 @@ +component Main { + get map : Map(String, String) { + `` + } + + fun render : Array(Html) { + for (item of map) { +
+ <{ item }> +
+ } + } +} +-------------------------------------------------------------------------------- +░ ERROR (FOR_MAP_ARGUMENTS_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +If the iterable object of a for expression is a map, then it needs to the have 2 +arguments: + + ┌ ./spec/errors/for_map_arguments_mismatch:7:10 + ├────────────────────────────────────────────── + 3│ `` + 4│ } + 5│ + 6│ fun render : Array(Html) { + 7│ for (item of map) { + │ ⌃⌃⌃⌃ + 8│
+ 9│ <{ item }> + 10│
+ 11│ } diff --git a/spec/errors/for_type_mismatch b/spec/errors/for_type_mismatch new file mode 100644 index 000000000..f3e18b487 --- /dev/null +++ b/spec/errors/for_type_mismatch @@ -0,0 +1,34 @@ +component Main { + fun render : Array(Html) { + for (item of "A") { +
+ <{ item }> +
+ } + } +} +-------------------------------------------------------------------------------- +░ ERROR (FOR_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The iterable object of a for expression has an invalid type. + +I was expecting one of the following types: + + Array(a), Set(a), Map(a, b) + +Instead it is: + + String + +The iterable object in question is here: + + ┌ ./spec/errors/for_type_mismatch:3:18 + ├───────────────────────────────────── + 1│ component Main { + 2│ fun render : Array(Html) { + 3│ for (item of "A") { + │ ⌃⌃⌃ + 4│
+ 5│ <{ item }> + 6│
+ 7│ } diff --git a/spec/errors/format_directive_expected_body b/spec/errors/format_directive_expected_body new file mode 100644 index 000000000..c33667761 --- /dev/null +++ b/spec/errors/format_directive_expected_body @@ -0,0 +1,14 @@ +component Main { + fun render : String { + @format { +-------------------------------------------------------------------------------- +░ ERROR (FORMAT_DIRECTIVE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a format directive but I found "a space" instead: + + ┌ ./spec/errors/format_directive_expected_body:3:13 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @format { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/format_directive_expected_closing_bracket b/spec/errors/format_directive_expected_closing_bracket new file mode 100644 index 000000000..b6c21c0f0 --- /dev/null +++ b/spec/errors/format_directive_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @format { test +-------------------------------------------------------------------------------- +░ ERROR (FORMAT_DIRECTIVE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a format directive but I found "a space" +instead: + + ┌ ./spec/errors/format_directive_expected_closing_bracket:3:18 + ├───────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @format { test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/format_directive_expected_opening_bracket b/spec/errors/format_directive_expected_opening_bracket new file mode 100644 index 000000000..ff570291f --- /dev/null +++ b/spec/errors/format_directive_expected_opening_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @format +-------------------------------------------------------------------------------- +░ ERROR (FORMAT_DIRECTIVE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a format directive but I found "a space" +instead: + + ┌ ./spec/errors/format_directive_expected_opening_bracket:3:11 + ├───────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @format + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_argument_conflict b/spec/errors/function_argument_conflict new file mode 100644 index 000000000..87f1dfd35 --- /dev/null +++ b/spec/errors/function_argument_conflict @@ -0,0 +1,39 @@ +component Main { + fun test (a : String, a : String) : Bool { + "hello" + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_ARGUMENT_CONFLICT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The argument "a" is declared multiple times. + +It is declared here: + + ┌ ./spec/errors/function_argument_conflict:2:25 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun test (a : String, a : String) : Bool { + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ "hello" + 4│ } + 5│ + 6│ fun render : String { + +It is also declared here: + + ┌ ./spec/errors/function_argument_conflict:2:13 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun test (a : String, a : String) : Bool { + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ "hello" + 4│ } + 5│ + 6│ fun render : String { diff --git a/spec/errors/function_argument_must_have_a_default_value b/spec/errors/function_argument_must_have_a_default_value new file mode 100644 index 000000000..dba3b6d30 --- /dev/null +++ b/spec/errors/function_argument_must_have_a_default_value @@ -0,0 +1,28 @@ +component Main { + fun test (a : String = "Hello", b : String) : Number { + a + } + + fun render : String { + test() + } +} +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_ARGUMENT_MUST_HAVE_A_DEFAULT_VALUE) ░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The argument "b" is declared after one that had a default value. + +Arguments that come after ones that have a default value must also have a +default value. + +The argument in question is here: + + ┌ ./spec/errors/function_argument_must_have_a_default_value:2:35 + ├─────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun test (a : String = "Hello", b : String) : Number { + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ a + 4│ } + 5│ + 6│ fun render : String { diff --git a/spec/errors/function_expected_closing_bracket b/spec/errors/function_expected_closing_bracket new file mode 100644 index 000000000..292c18bd3 --- /dev/null +++ b/spec/errors/function_expected_closing_bracket @@ -0,0 +1,12 @@ +component Main { + fun render { a +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a function but I found "a space" instead: + + ┌ ./spec/errors/function_expected_closing_bracket:2:16 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render { a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_expected_closing_parenthesis b/spec/errors/function_expected_closing_parenthesis new file mode 100644 index 000000000..f93e3df9b --- /dev/null +++ b/spec/errors/function_expected_closing_parenthesis @@ -0,0 +1,13 @@ +component Main { + fun render ( +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a function but I found "a space" +instead: + + ┌ ./spec/errors/function_expected_closing_parenthesis:2:14 + ├───────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render ( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_expected_expression b/spec/errors/function_expected_expression new file mode 100644 index 000000000..bbd9ba85a --- /dev/null +++ b/spec/errors/function_expected_expression @@ -0,0 +1,12 @@ +component Main { + fun render { +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a function but I found "a space" instead: + + ┌ ./spec/errors/function_expected_expression:2:14 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ fun render { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_expected_name b/spec/errors/function_expected_name new file mode 100644 index 000000000..1a90fcd33 --- /dev/null +++ b/spec/errors/function_expected_name @@ -0,0 +1,12 @@ +component Main { + fun +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of the function but I found "a space" instead: + + ┌ ./spec/errors/function_expected_name:2:5 + ├───────────────────────────────────────── + 1│ component Main { + 2│ fun + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_expected_opening_bracket b/spec/errors/function_expected_opening_bracket new file mode 100644 index 000000000..a533150aa --- /dev/null +++ b/spec/errors/function_expected_opening_bracket @@ -0,0 +1,12 @@ +component Main { + fun render +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a function but I found "a space" instead: + + ┌ ./spec/errors/function_expected_opening_bracket:2:12 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_expected_type_or_variable b/spec/errors/function_expected_type_or_variable new file mode 100644 index 000000000..3970bfdae --- /dev/null +++ b/spec/errors/function_expected_type_or_variable @@ -0,0 +1,12 @@ +component Main { + fun render : +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_EXPECTED_TYPE_OR_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of a function but I found "a space" instead: + + ┌ ./spec/errors/function_expected_type_or_variable:2:14 + ├────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/function_type_mismatch b/spec/errors/function_type_mismatch new file mode 100644 index 000000000..f3424b0b7 --- /dev/null +++ b/spec/errors/function_type_mismatch @@ -0,0 +1,49 @@ +component Main { + fun test : Bool { + "hello" + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (FUNCTION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The return type of a function does not match its type definition. + +I was expecting: + + Bool + +Which is defined here: + + ┌ ./spec/errors/function_type_mismatch:2:14 + ├────────────────────────────────────────── + 1│ component Main { + 2│ fun test : Bool { + │ ⌃⌃⌃⌃ + 3│ "hello" + 4│ } + 5│ + 6│ fun render : String { + +Instead it is: + + String + +Which is returned here: + + ┌ ./spec/errors/function_type_mismatch:3:5 + ├───────────────────────────────────────── + 1│ component Main { + 2│ fun test : Bool { + 3│ "hello" + │ ⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : String { + 7│ test() + diff --git a/spec/errors/get_expected_closing_bracket b/spec/errors/get_expected_closing_bracket new file mode 100644 index 000000000..d828dc0e9 --- /dev/null +++ b/spec/errors/get_expected_closing_bracket @@ -0,0 +1,12 @@ +component Main { + get name { a +-------------------------------------------------------------------------------- +░ ERROR (GET_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a get but I found "a space" instead: + + ┌ ./spec/errors/get_expected_closing_bracket:2:14 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ get name { a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/get_expected_expression b/spec/errors/get_expected_expression new file mode 100644 index 000000000..660ae5ab2 --- /dev/null +++ b/spec/errors/get_expected_expression @@ -0,0 +1,12 @@ +component Main { + get name { +-------------------------------------------------------------------------------- +░ ERROR (GET_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a get but I found "a space" instead: + + ┌ ./spec/errors/get_expected_expression:2:12 + ├─────────────────────────────────────────── + 1│ component Main { + 2│ get name { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/get_expected_name b/spec/errors/get_expected_name new file mode 100644 index 000000000..ec8be3ff5 --- /dev/null +++ b/spec/errors/get_expected_name @@ -0,0 +1,12 @@ +component Main { + get +-------------------------------------------------------------------------------- +░ ERROR (GET_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a get but I found "a space" instead: + + ┌ ./spec/errors/get_expected_name:2:5 + ├──────────────────────────────────── + 1│ component Main { + 2│ get + │ ⌃⌃⌃⌃ diff --git a/spec/errors/get_expected_opening_bracket b/spec/errors/get_expected_opening_bracket new file mode 100644 index 000000000..88ddd188d --- /dev/null +++ b/spec/errors/get_expected_opening_bracket @@ -0,0 +1,12 @@ +component Main { + get name +-------------------------------------------------------------------------------- +░ ERROR (GET_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a get but I found "a space" instead: + + ┌ ./spec/errors/get_expected_opening_bracket:2:10 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ get name + │ ⌃⌃⌃⌃ diff --git a/spec/errors/get_expected_type b/spec/errors/get_expected_type new file mode 100644 index 000000000..e11dc8cf3 --- /dev/null +++ b/spec/errors/get_expected_type @@ -0,0 +1,12 @@ +component Main { + get name : +-------------------------------------------------------------------------------- +░ ERROR (GET_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of a get but I found "a space" instead: + + ┌ ./spec/errors/get_expected_type:2:12 + ├───────────────────────────────────── + 1│ component Main { + 2│ get name : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/get_type_mismatch b/spec/errors/get_type_mismatch new file mode 100644 index 000000000..3c6d551e5 --- /dev/null +++ b/spec/errors/get_type_mismatch @@ -0,0 +1,48 @@ +component Main { + get test : Number { + "asd" + } + + fun render : Html { + test() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (GET_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The return type of a get does not match its type definition. + +I was expecting: + + Number + +Which is defined here: + + ┌ ./spec/errors/get_type_mismatch:2:14 + ├───────────────────────────────────── + 1│ component Main { + 2│ get test : Number { + │ ⌃⌃⌃⌃⌃⌃ + 3│ "asd" + 4│ } + 5│ + 6│ fun render : Html { + +Instead it is: + + String + +Which is returned here: + + ┌ ./spec/errors/get_type_mismatch:3:5 + ├──────────────────────────────────── + 1│ component Main { + 2│ get test : Number { + 3│ "asd" + │ ⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : Html { + 7│ test() diff --git a/spec/errors/here_doc_expected_end b/spec/errors/here_doc_expected_end new file mode 100644 index 000000000..44a0a7604 --- /dev/null +++ b/spec/errors/here_doc_expected_end @@ -0,0 +1,14 @@ +component Main { + fun render { + <<-TEST +-------------------------------------------------------------------------------- +░ ERROR (HERE_DOC_EXPECTED_END) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the end tag of a here document but I found "a space" instead: + + ┌ ./spec/errors/here_doc_expected_end:3:11 + ├───────────────────────────────────────── + 1│ component Main { + 2│ fun render { + 3│ <<-TEST + │ ⌃⌃⌃⌃ diff --git a/spec/errors/here_doc_interpolation_type_mismatch b/spec/errors/here_doc_interpolation_type_mismatch new file mode 100644 index 000000000..2538fadbd --- /dev/null +++ b/spec/errors/here_doc_interpolation_type_mismatch @@ -0,0 +1,32 @@ +component Main { + fun render { + <<-TEST + #{<>} + TEST + } +} +-------------------------------------------------------------------------------- +░ ERROR (HERE_DOC_INTERPOLATION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +An interpolation in here document is causing a mismatch. + +I was expecting: + + String + +Instead it is: + + Html + +The interpolation in question is here: + + ┌ ./spec/errors/here_doc_interpolation_type_mismatch:4:7 + ├─────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render { + 3│ <<-TEST + 4│ #{<>} + │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ TEST + 6│ } + 7│ } diff --git a/spec/errors/here_document_expected_start b/spec/errors/here_document_expected_start new file mode 100644 index 000000000..49f0bf1c3 --- /dev/null +++ b/spec/errors/here_document_expected_start @@ -0,0 +1,14 @@ +component Main { + fun render { + <<- +-------------------------------------------------------------------------------- +░ ERROR (HERE_DOCUMENT_EXPECTED_START) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the start tag of a here document but I found "a space" instead: + + ┌ ./spec/errors/here_document_expected_start:3:7 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render { + 3│ <<- + │ ⌃⌃⌃⌃ diff --git a/spec/errors/highlight_directive_expected_body b/spec/errors/highlight_directive_expected_body new file mode 100644 index 000000000..a2542dfb1 --- /dev/null +++ b/spec/errors/highlight_directive_expected_body @@ -0,0 +1,14 @@ +component Main { + fun render : String { + @highlight { +-------------------------------------------------------------------------------- +░ ERROR (HIGHLIGHT_DIRECTIVE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a highlight directive but I found "a space" instead: + + ┌ ./spec/errors/highlight_directive_expected_body:3:16 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @highlight { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/highlight_directive_expected_closing_bracket b/spec/errors/highlight_directive_expected_closing_bracket new file mode 100644 index 000000000..f76253f2b --- /dev/null +++ b/spec/errors/highlight_directive_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @highlight { test +-------------------------------------------------------------------------------- +░ ERROR (HIGHLIGHT_DIRECTIVE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a highlight directive but I found "a +space" instead: + + ┌ ./spec/errors/highlight_directive_expected_closing_bracket:3:21 + ├──────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @highlight { test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/highlight_directive_expected_opening_bracket b/spec/errors/highlight_directive_expected_opening_bracket new file mode 100644 index 000000000..11830cd65 --- /dev/null +++ b/spec/errors/highlight_directive_expected_opening_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @highlight +-------------------------------------------------------------------------------- +░ ERROR (HIGHLIGHT_DIRECTIVE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a highlight directive but I found "a +space" instead: + + ┌ ./spec/errors/highlight_directive_expected_opening_bracket:3:14 + ├──────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @highlight + │ ⌃⌃⌃⌃ diff --git a/spec/errors/html_attribute_component_key_type_mismatch b/spec/errors/html_attribute_component_key_type_mismatch new file mode 100644 index 000000000..4c0ffaf6c --- /dev/null +++ b/spec/errors/html_attribute_component_key_type_mismatch @@ -0,0 +1,36 @@ +component X { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ATTRIBUTE_COMPONENT_KEY_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The "key" attribute of a component has an invalid type. + +I was expecting: + + String + +Instead it is: + + Number + +The attribute in question is here: + + ┌ ./spec/errors/html_attribute_component_key_type_mismatch:9:8 + ├───────────────────────────────────────────────────────────── + 5│ } + 6│ + 7│ component Main { + 8│ fun render : Html { + 9│ + │ ⌃⌃⌃⌃⌃⌃⌃ + 10│ } + 11│ } diff --git a/spec/errors/html_attribute_component_property_type_mismatch b/spec/errors/html_attribute_component_property_type_mismatch new file mode 100644 index 000000000..3c48e1801 --- /dev/null +++ b/spec/errors/html_attribute_component_property_type_mismatch @@ -0,0 +1,39 @@ +component Test { + property things : Array(String) = [] + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ATTRIBUTE_COMPONENT_PROPERTY_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░ + +The type of the value for the property "things" of the component "Test" does not +match its definition. + +I was expecting: + + Array(String) + +Instead it is: + + Array(Number) + +The attribute in question is here: + + ┌ ./spec/errors/html_attribute_component_property_type_mismatch:11:11 + ├──────────────────────────────────────────────────────────────────── + 7│ } + 8│ + 9│ component Main { + 10│ fun render : Html { + 11│ + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 12│ } + 13│ } diff --git a/spec/errors/html_attribute_element_attribute_type_mismatch b/spec/errors/html_attribute_element_attribute_type_mismatch new file mode 100644 index 000000000..45cb58bc6 --- /dev/null +++ b/spec/errors/html_attribute_element_attribute_type_mismatch @@ -0,0 +1,29 @@ +component Main { + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ATTRIBUTE_ELEMENT_ATTRIBUTE_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the value for the property "name" of element "div" does not match +its type. + +I was expecting: + + String + +Instead it is: + + Number + +The attribute in question is here: + + ┌ ./spec/errors/html_attribute_element_attribute_type_mismatch:3:10 + ├────────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│
+ │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/html_attribute_expected_closing_bracket b/spec/errors/html_attribute_expected_closing_bracket new file mode 100644 index 000000000..571dc99a2 --- /dev/null +++ b/spec/errors/html_attribute_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ATTRIBUTE_NOT_FOUND_COMPONENT_PROPERTY) ░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for a property in component "X" but could not find it: + + test2 + +Maybe you want one of its properties: + + test + +The attribute in question is here: + + ┌ ./spec/errors/html_attribute_not_found_component_property:11:18 + ├──────────────────────────────────────────────────────────────── + 7│ } + 8│ + 9│ component Main { + 10│ fun render : Html { + 11│ + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 12│ } + 13│ } diff --git a/spec/errors/html_component_attribute_required b/spec/errors/html_component_attribute_required new file mode 100644 index 000000000..7a5a4a9a9 --- /dev/null +++ b/spec/errors/html_component_attribute_required @@ -0,0 +1,40 @@ +component Test { + property name : String + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_COMPONENT_ATTRIBUTE_REQUIRED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +One of the required properties were not specified for a component: + + ┌ ./spec/errors/html_component_attribute_required:2:3 + ├──────────────────────────────────────────────────── + 1│ component Test { + 2│ property name : String + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } + +The component was referenced here: + + ┌ ./spec/errors/html_component_attribute_required:11:5 + ├───────────────────────────────────────────────────── + 7│ } + 8│ + 9│ component Main { + 10│ fun render : Html { + 11│ + │ ⌃⌃⌃⌃⌃⌃⌃ + 12│ } + 13│ } diff --git a/spec/errors/html_component_expected_closing_bracket b/spec/errors/html_component_expected_closing_bracket new file mode 100644 index 000000000..2a9d82626 --- /dev/null +++ b/spec/errors/html_component_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + +-------------------------------------------------------------------------------- +░ ERROR (HTML_COMPONENT_EXPECTED_CLOSING_TAG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing tag of a HTML component but I found "a space" +instead: + + ┌ ./spec/errors/html_component_expected_closing_tag:3:10 + ├─────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ + │ ⌃⌃⌃⌃ diff --git a/spec/errors/html_component_expected_reference b/spec/errors/html_component_expected_reference new file mode 100644 index 000000000..b974c1089 --- /dev/null +++ b/spec/errors/html_component_expected_reference @@ -0,0 +1,15 @@ +component Main { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_COMPONENT_GLOBAL_COMPONENT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Global components are added to the body and always rendered and cannot be used +as regular components: + + ┌ ./spec/errors/html_component_global_component:9:5 + ├────────────────────────────────────────────────── + 5│ } + 6│ + 7│ component Main { + 8│ fun render : Html { + 9│ + │ ⌃⌃⌃⌃ + 10│ } + 11│ } + diff --git a/spec/errors/html_component_not_found_component b/spec/errors/html_component_not_found_component new file mode 100644 index 000000000..84ae2590e --- /dev/null +++ b/spec/errors/html_component_not_found_component @@ -0,0 +1,22 @@ +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_COMPONENT_NOT_FOUND_COMPONENT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for a component but could not find one with the name: + + X + +It's used here: + + ┌ ./spec/errors/html_component_not_found_component:3:5 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ + │ ⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/html_component_reference_outside_of_component b/spec/errors/html_component_reference_outside_of_component new file mode 100644 index 000000000..fcca965e1 --- /dev/null +++ b/spec/errors/html_component_reference_outside_of_component @@ -0,0 +1,32 @@ +module X { + fun render : Html { + + } +} + +component Test { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + X.render() + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_COMPONENT_REFERENCE_OUTSIDE_OF_COMPONENT) ░░░░░░░░░░░░░░░░░░░░░░░░ + +Referencing components outside of components is not allowed: + + ┌ ./spec/errors/html_component_reference_outside_of_component:3:14 + ├───────────────────────────────────────────────────────────────── + 1│ module X { + 2│ fun render : Html { + 3│ + │ ⌃ + 4│ } + 5│ } + 6│ + 7│ component Test { diff --git a/spec/errors/html_content_type_mismatch b/spec/errors/html_content_type_mismatch new file mode 100644 index 000000000..7567dfd75 --- /dev/null +++ b/spec/errors/html_content_type_mismatch @@ -0,0 +1,29 @@ +component Main { + fun render : Html { +
<{ 0 }>
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_CONTENT_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A child node of an element or component has an invalid type. + +I was expecting one of the following types: + + Array(String) + Array(Html) + String + Html + +Instead it is: + + Number + + ┌ ./spec/errors/html_content_type_mismatch:3:13 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│
<{ 0 }>
+ │ ⌃ + 4│ } + 5│ } diff --git a/spec/errors/html_element_expected_closing_bracket b/spec/errors/html_element_expected_closing_bracket new file mode 100644 index 000000000..a7b89a0e1 --- /dev/null +++ b/spec/errors/html_element_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ELEMENT_EXPECTED_CLOSING_TAG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing tag of an HTML element but I found "}" instead: + + ┌ ./spec/errors/html_element_expected_closing_tag:4:3 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ + 4│ } + │ ⌃ + 5│ } diff --git a/spec/errors/html_element_expected_reference b/spec/errors/html_element_expected_reference new file mode 100644 index 000000000..85f238df7 --- /dev/null +++ b/spec/errors/html_element_expected_reference @@ -0,0 +1,14 @@ +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ELEMENT_REF_FORBIDDEN) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The use of "ref" attribute is forbidden: + + ┌ ./spec/errors/html_element_ref_forbidden:3:10 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│
+ │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } + +If you want to assign a variable to an element, use the as keyword: + +
diff --git a/spec/errors/html_element_reference_outside_of_component b/spec/errors/html_element_reference_outside_of_component new file mode 100644 index 000000000..61a0959ea --- /dev/null +++ b/spec/errors/html_element_reference_outside_of_component @@ -0,0 +1,26 @@ +module X { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + X.render() + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ELEMENT_REFERENCE_OUTSIDE_OF_COMPONENT) ░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Referencing elements outside of components is not allowed: + + ┌ ./spec/errors/html_element_reference_outside_of_component:3:13 + ├─────────────────────────────────────────────────────────────── + 1│ module X { + 2│ fun render : Html { + 3│
+ │ ⌃ + 4│ } + 5│ } + 6│ + 7│ component Main { diff --git a/spec/errors/html_element_style_outside_of_component b/spec/errors/html_element_style_outside_of_component new file mode 100644 index 000000000..84582ae7f --- /dev/null +++ b/spec/errors/html_element_style_outside_of_component @@ -0,0 +1,26 @@ +module X { + fun render : Html { + + } +} + +component Main { + fun render : Html { + X.render() + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_ELEMENT_STYLE_OUTSIDE_OF_COMPONENT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Styling of elements outside of components is not allowed: + + ┌ ./spec/errors/html_element_style_outside_of_component:3:5 + ├────────────────────────────────────────────────────────── + 1│ module X { + 2│ fun render : Html { + 3│ + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } + 6│ + 7│ component Main { diff --git a/spec/errors/html_expression_expected_closing_tag b/spec/errors/html_expression_expected_closing_tag new file mode 100644 index 000000000..2ef487e1c --- /dev/null +++ b/spec/errors/html_expression_expected_closing_tag @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + <{ +-------------------------------------------------------------------------------- +░ ERROR (HTML_EXPRESSION_EXPECTED_CLOSING_TAG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing tag of an HTML expression but I found "a space" +instead: + + ┌ ./spec/errors/html_expression_expected_closing_tag:3:6 + ├─────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ <{ + │ ⌃⌃⌃⌃ diff --git a/spec/errors/html_fragment_expected_closing_tag b/spec/errors/html_fragment_expected_closing_tag new file mode 100644 index 000000000..40820ca08 --- /dev/null +++ b/spec/errors/html_fragment_expected_closing_tag @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + <> +-------------------------------------------------------------------------------- +░ ERROR (HTML_FRAGMENT_EXPECTED_CLOSING_TAG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing tag of an HTML fragment but I found "a space" +instead: + + ┌ ./spec/errors/html_fragment_expected_closing_tag:3:6 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ <> + │ ⌃⌃⌃⌃ diff --git a/spec/errors/html_style_argument_size_mismatch b/spec/errors/html_style_argument_size_mismatch new file mode 100644 index 000000000..4db2dfb6a --- /dev/null +++ b/spec/errors/html_style_argument_size_mismatch @@ -0,0 +1,24 @@ +component Main { + style base (name : String, active : Bool) { + color: red; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_STYLE_ARGUMENT_SIZE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The style call takes 2 arguments, while you tried to call it with 1: + + ┌ ./spec/errors/html_style_argument_size_mismatch:7:9 + ├──────────────────────────────────────────────────── + 3│ color: red; + 4│ } + 5│ + 6│ fun render : Html { + 7│ + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/html_style_argument_type_mismatch b/spec/errors/html_style_argument_type_mismatch new file mode 100644 index 000000000..51cb32b88 --- /dev/null +++ b/spec/errors/html_style_argument_type_mismatch @@ -0,0 +1,34 @@ +component Main { + style base (name : String, active : Bool) { + color: red; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_STYLE_ARGUMENT_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The 1st argument to a style call is causing a mismatch. + +The style is expecting the 1st argument to be: + + String + +Instead it is: + + Bool + +The style call in question is here: + + ┌ ./spec/errors/html_style_argument_type_mismatch:7:9 + ├──────────────────────────────────────────────────── + 3│ color: red; + 4│ } + 5│ + 6│ fun render : Html { + 7│ + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/html_style_expected_closing_parenthesis b/spec/errors/html_style_expected_closing_parenthesis new file mode 100644 index 000000000..1d714f02b --- /dev/null +++ b/spec/errors/html_style_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (HTML_STYLE_NOT_FOUND) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for a style but it's not defined in the component: + + ┌ ./spec/errors/html_style_not_found:3:9 + ├─────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ + │ ⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/if_condition_type_mismatch b/spec/errors/if_condition_type_mismatch new file mode 100644 index 000000000..3a3791858 --- /dev/null +++ b/spec/errors/if_condition_type_mismatch @@ -0,0 +1,29 @@ +component Main { + fun render : String { + if ("a") { + "x" + } else { + "y" + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (IF_CONDITION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the condition of an if expression is not a boolean but instead it +is: + + String + +The condition in question is here: + + ┌ ./spec/errors/if_condition_type_mismatch:3:9 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("a") { + │ ⌃⌃⌃ + 4│ "x" + 5│ } else { + 6│ "y" + 7│ } diff --git a/spec/errors/if_else_type_mismatch b/spec/errors/if_else_type_mismatch new file mode 100644 index 000000000..2adf3a3bf --- /dev/null +++ b/spec/errors/if_else_type_mismatch @@ -0,0 +1,37 @@ +component Main { + fun render : String { + if ("a" == "b") { + "x" + } else { + 10 + } + } +} +-------------------------------------------------------------------------------- +░ ERROR (IF_ELSE_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The falsy (else) branch of an if expression does not match the type of the +truthy branch. + +I was expecting: + + String + +Instead it is: + + Number + +The value for the else branch is here: + + ┌ ./spec/errors/if_else_type_mismatch:6:7 + ├──────────────────────────────────────── + 2│ fun render : String { + 3│ if ("a" == "b") { + 4│ "x" + 5│ } else { + 6│ 10 + │ ⌃⌃ + 7│ } + 8│ } + 9│ } + diff --git a/spec/errors/if_expected_closing_parenthesis b/spec/errors/if_expected_closing_parenthesis new file mode 100644 index 000000000..17879a542 --- /dev/null +++ b/spec/errors/if_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + if ("" +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of the condition of an if expression but +I found "a space" instead: + + ┌ ./spec/errors/if_expected_closing_parenthesis:3:10 + ├─────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_condition b/spec/errors/if_expected_condition new file mode 100644 index 000000000..c604a823b --- /dev/null +++ b/spec/errors/if_expected_condition @@ -0,0 +1,14 @@ +component Main { + fun render : String { + if ( +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_CONDITION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the condition but I found "a space" instead: + + ┌ ./spec/errors/if_expected_condition:3:8 + ├──────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_else_closing_bracket b/spec/errors/if_expected_else_closing_bracket new file mode 100644 index 000000000..d300fb0bb --- /dev/null +++ b/spec/errors/if_expected_else_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + if ("") { "a" } else { a +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_ELSE_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of the else branch but I found "a space" +instead: + + ┌ ./spec/errors/if_expected_else_closing_bracket:3:28 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("") { "a" } else { a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_else_expression b/spec/errors/if_expected_else_expression new file mode 100644 index 000000000..ed13ebcef --- /dev/null +++ b/spec/errors/if_expected_else_expression @@ -0,0 +1,14 @@ +component Main { + fun render : String { + if ("") { "a" } else { +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_ELSE_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting an expression for the else branch but I found "a space" instead: + + ┌ ./spec/errors/if_expected_else_expression:3:26 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("") { "a" } else { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_else_opening_bracket b/spec/errors/if_expected_else_opening_bracket new file mode 100644 index 000000000..d80084b05 --- /dev/null +++ b/spec/errors/if_expected_else_opening_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + if ("") { "a" } else +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_ELSE_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of the else branch but I found "a space" +instead: + + ┌ ./spec/errors/if_expected_else_opening_bracket:3:24 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("") { "a" } else + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_truthy_closing_bracket b/spec/errors/if_expected_truthy_closing_bracket new file mode 100644 index 000000000..45deb1d79 --- /dev/null +++ b/spec/errors/if_expected_truthy_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + if ("") { a +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_TRUTHY_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of the truthy branch but I found "a space" +instead: + + ┌ ./spec/errors/if_expected_truthy_closing_bracket:3:15 + ├────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("") { a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_truthy_expression b/spec/errors/if_expected_truthy_expression new file mode 100644 index 000000000..b9d4f7e2e --- /dev/null +++ b/spec/errors/if_expected_truthy_expression @@ -0,0 +1,15 @@ +component Main { + fun render : String { + if ("") { +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_TRUTHY_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting an expression for the truthy branch but I found "a space" +instead: + + ┌ ./spec/errors/if_expected_truthy_expression:3:13 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("") { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/if_expected_truthy_opening_bracket b/spec/errors/if_expected_truthy_opening_bracket new file mode 100644 index 000000000..7215e43ed --- /dev/null +++ b/spec/errors/if_expected_truthy_opening_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + if ("") +-------------------------------------------------------------------------------- +░ ERROR (IF_EXPECTED_TRUTHY_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of the truthy branch but I found "a space" +instead: + + ┌ ./spec/errors/if_expected_truthy_opening_bracket:3:11 + ├────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ if ("") + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_directive_expected_closing_parenthesis b/spec/errors/inline_directive_expected_closing_parenthesis new file mode 100644 index 000000000..28570de56 --- /dev/null +++ b/spec/errors/inline_directive_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @inline(path +-------------------------------------------------------------------------------- +░ ERROR (INLINE_DIRECTIVE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of an inline directive but I found "a +space" instead: + + ┌ ./spec/errors/inline_directive_expected_closing_parenthesis:3:16 + ├───────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @inline(path + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_directive_expected_file b/spec/errors/inline_directive_expected_file new file mode 100644 index 000000000..870184e60 --- /dev/null +++ b/spec/errors/inline_directive_expected_file @@ -0,0 +1,22 @@ +component Main { + fun render : String { + @inline(path) + } +} +-------------------------------------------------------------------------------- +░ ERROR (INLINE_DIRECTIVE_EXPECTED_FILE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The path specified for an inline directive does not exist: + + /home/gus/Projects/mint-lang/mint/spec/errors/path + +The inline directive in question is here: + + ┌ ./spec/errors/inline_directive_expected_file:3:5 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @inline(path) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/inline_directive_expected_opening_parenthesis b/spec/errors/inline_directive_expected_opening_parenthesis new file mode 100644 index 000000000..f25b2cbe4 --- /dev/null +++ b/spec/errors/inline_directive_expected_opening_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @inline +-------------------------------------------------------------------------------- +░ ERROR (INLINE_DIRECTIVE_EXPECTED_OPENING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening parenthesis of an inline directive but I found "a +space" instead: + + ┌ ./spec/errors/inline_directive_expected_opening_parenthesis:3:11 + ├───────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @inline + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_directive_expected_path b/spec/errors/inline_directive_expected_path new file mode 100644 index 000000000..fb3b9d9bd --- /dev/null +++ b/spec/errors/inline_directive_expected_path @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @inline( +-------------------------------------------------------------------------------- +░ ERROR (INLINE_DIRECTIVE_EXPECTED_PATH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the path (to the file to be inlined) of an inline directive but +I found "a space" instead: + + ┌ ./spec/errors/inline_directive_expected_path:3:12 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @inline( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_function_expected_body b/spec/errors/inline_function_expected_body new file mode 100644 index 000000000..52bab722c --- /dev/null +++ b/spec/errors/inline_function_expected_body @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + () { +-------------------------------------------------------------------------------- +░ ERROR (INLINE_FUNCTION_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of an inline function but I found "a space" instead: + + ┌ ./spec/errors/inline_function_expected_body:3:8 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ () { + │ ⌃⌃⌃⌃ + diff --git a/spec/errors/inline_function_expected_closing_bracket b/spec/errors/inline_function_expected_closing_bracket new file mode 100644 index 000000000..ff8641f27 --- /dev/null +++ b/spec/errors/inline_function_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + () { a +-------------------------------------------------------------------------------- +░ ERROR (INLINE_FUNCTION_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of an inline function but I found "a space" +instead: + + ┌ ./spec/errors/inline_function_expected_closing_bracket:3:10 + ├──────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ () { a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_function_expected_closing_parenthesis b/spec/errors/inline_function_expected_closing_parenthesis new file mode 100644 index 000000000..342161b42 --- /dev/null +++ b/spec/errors/inline_function_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + ( +-------------------------------------------------------------------------------- +░ ERROR (INLINE_FUNCTION_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of an inline function but I found "a +space" instead: + + ┌ ./spec/errors/inline_function_expected_closing_parenthesis:3:5 + ├─────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ ( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_function_expected_opening_bracket b/spec/errors/inline_function_expected_opening_bracket new file mode 100644 index 000000000..f2aaedfbb --- /dev/null +++ b/spec/errors/inline_function_expected_opening_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + () +-------------------------------------------------------------------------------- +░ ERROR (INLINE_FUNCTION_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of an inline function but I found "a space" +instead: + + ┌ ./spec/errors/inline_function_expected_opening_bracket:3:6 + ├─────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ () + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_function_expected_type b/spec/errors/inline_function_expected_type new file mode 100644 index 000000000..771be3afc --- /dev/null +++ b/spec/errors/inline_function_expected_type @@ -0,0 +1,14 @@ +component Main { + fun render : Html { + () : +-------------------------------------------------------------------------------- +░ ERROR (INLINE_FUNCTION_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of an inline function but I found "a space" instead: + + ┌ ./spec/errors/inline_function_expected_type:3:8 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ () : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/inline_function_type_mismatch b/spec/errors/inline_function_type_mismatch new file mode 100644 index 000000000..6a9e1e248 --- /dev/null +++ b/spec/errors/inline_function_type_mismatch @@ -0,0 +1,52 @@ +component Main { + fun test : String { + let a = + () : String { true } + + a() + } + + fun render : String { + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (INLINE_FUNCTION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The return type of an anonymous function does not match its type definition. + +I was expecting: + + String + +Which is defined here: + + ┌ ./spec/errors/inline_function_type_mismatch:4:12 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun test : String { + 3│ let a = + 4│ () : String { true } + │ ⌃⌃⌃⌃⌃⌃ + 5│ + 6│ a() + 7│ } + 8│ + +Instead it is: + + Bool + +Which is returned here: + + ┌ ./spec/errors/inline_function_type_mismatch:4:21 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun test : String { + 3│ let a = + 4│ () : String { true } + │ ⌃⌃⌃⌃ + 5│ + 6│ a() + 7│ } + 8│ diff --git a/spec/errors/interpolation_expected_closing_bracket b/spec/errors/interpolation_expected_closing_bracket new file mode 100644 index 000000000..764319708 --- /dev/null +++ b/spec/errors/interpolation_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + fun render : String { + "#{a +-------------------------------------------------------------------------------- +░ ERROR (INTERPOLATION_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of an interpolation but I found "a space" +instead: + + ┌ ./spec/errors/interpolation_expected_closing_bracket:3:8 + ├───────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ "#{a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/interpolation_expected_expression b/spec/errors/interpolation_expected_expression new file mode 100644 index 000000000..ca3998311 --- /dev/null +++ b/spec/errors/interpolation_expected_expression @@ -0,0 +1,15 @@ +component Main { + fun render : String { + "#{ +-------------------------------------------------------------------------------- +░ ERROR (INTERPOLATION_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the expression of an interpolation but I found "a space" +instead: + + ┌ ./spec/errors/interpolation_expected_expression:3:7 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ "#{ + │ ⌃⌃⌃⌃ diff --git a/spec/errors/invalid_self_reference b/spec/errors/invalid_self_reference new file mode 100644 index 000000000..d6160dced --- /dev/null +++ b/spec/errors/invalid_self_reference @@ -0,0 +1,38 @@ +component Main { + state c : String = b + state b : String = "" + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (INVALID_SELF_REFERENCE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +You are trying to reference an other entity in a top level entity before it is +initialized. + +Then entity you are referencing: + + ┌ ./spec/errors/invalid_self_reference:2:3 + ├───────────────────────────────────────── + 1│ component Main { + 2│ state c : String = b + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ state b : String = "" + 4│ + 5│ fun render : Html { + 6│
+ +The entity you are referencing it from: + + ┌ ./spec/errors/invalid_self_reference:3:3 + ├───────────────────────────────────────── + 1│ component Main { + 2│ state c : String = b + 3│ state b : String = "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ + 5│ fun render : Html { + 6│
+ 7│ } diff --git a/spec/errors/locale_expected_closing_bracket b/spec/errors/locale_expected_closing_bracket new file mode 100644 index 000000000..dc81ae8d7 --- /dev/null +++ b/spec/errors/locale_expected_closing_bracket @@ -0,0 +1,10 @@ +locale en { +-------------------------------------------------------------------------------- +░ ERROR (LOCALE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a locale but I found "a space" instead: + + ┌ ./spec/errors/locale_expected_closing_bracket:1:11 + ├─────────────────────────────────────────────────── + 1│ locale en { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/locale_expected_language b/spec/errors/locale_expected_language new file mode 100644 index 000000000..d0076252c --- /dev/null +++ b/spec/errors/locale_expected_language @@ -0,0 +1,10 @@ +locale +-------------------------------------------------------------------------------- +░ ERROR (LOCALE_EXPECTED_LANGUAGE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the language code of the locale but I found "a space" instead: + + ┌ ./spec/errors/locale_expected_language:1:6 + ├─────────────────────────────────────────── + 1│ locale + │ ⌃⌃⌃⌃ diff --git a/spec/errors/locale_expected_opening_bracket b/spec/errors/locale_expected_opening_bracket new file mode 100644 index 000000000..6244b9eea --- /dev/null +++ b/spec/errors/locale_expected_opening_bracket @@ -0,0 +1,10 @@ +locale en +-------------------------------------------------------------------------------- +░ ERROR (LOCALE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a locale but I found "a space" instead: + + ┌ ./spec/errors/locale_expected_opening_bracket:1:9 + ├────────────────────────────────────────────────── + 1│ locale en + │ ⌃⌃⌃⌃ diff --git a/spec/errors/member_access_expected_variable b/spec/errors/member_access_expected_variable new file mode 100644 index 000000000..294425144 --- /dev/null +++ b/spec/errors/member_access_expected_variable @@ -0,0 +1,14 @@ +component Main { + fun render : Html { + . +-------------------------------------------------------------------------------- +░ ERROR (MEMBER_ACCESS_EXPECTED_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the field of the accessed entity but I found "a space" instead: + + ┌ ./spec/errors/member_access_expected_variable:3:5 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ . + │ ⌃⌃⌃⌃ diff --git a/spec/errors/module_expected_body b/spec/errors/module_expected_body new file mode 100644 index 000000000..35ef8593b --- /dev/null +++ b/spec/errors/module_expected_body @@ -0,0 +1,10 @@ +module Test { +-------------------------------------------------------------------------------- +░ ERROR (MODULE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of the module but I found "a space" instead: + + ┌ ./spec/errors/module_expected_body:1:13 + ├──────────────────────────────────────── + 1│ module Test { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/module_expected_closing_bracket b/spec/errors/module_expected_closing_bracket new file mode 100644 index 000000000..9382601b4 --- /dev/null +++ b/spec/errors/module_expected_closing_bracket @@ -0,0 +1,12 @@ +module Test { + const TEST = "" +-------------------------------------------------------------------------------- +░ ERROR (MODULE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a module but I found "a space" instead: + + ┌ ./spec/errors/module_expected_closing_bracket:2:17 + ├─────────────────────────────────────────────────── + 1│ module Test { + 2│ const TEST = "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/module_expected_name b/spec/errors/module_expected_name new file mode 100644 index 000000000..86a448a23 --- /dev/null +++ b/spec/errors/module_expected_name @@ -0,0 +1,13 @@ +module +-------------------------------------------------------------------------------- +░ ERROR (MODULE_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The name of a module must start with an uppercase letter and only contain +lowercase, uppercase letters and numbers. + +I was expecting name of the module but I found "a space" instead: + + ┌ ./spec/errors/module_expected_name:1:6 + ├─────────────────────────────────────── + 1│ module + │ ⌃⌃⌃⌃ diff --git a/spec/errors/module_expected_opening_bracket b/spec/errors/module_expected_opening_bracket new file mode 100644 index 000000000..288d69609 --- /dev/null +++ b/spec/errors/module_expected_opening_bracket @@ -0,0 +1,10 @@ +module Test +-------------------------------------------------------------------------------- +░ ERROR (MODULE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a module but I found "a space" instead: + + ┌ ./spec/errors/module_expected_opening_bracket:1:11 + ├─────────────────────────────────────────────────── + 1│ module Test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/negated_expression_expected_expression b/spec/errors/negated_expression_expected_expression new file mode 100644 index 000000000..67ab02d71 --- /dev/null +++ b/spec/errors/negated_expression_expected_expression @@ -0,0 +1,14 @@ +component Main { + fun render : String { + ! +--------------------------------------------------------------------------------░ ERROR (NEGATED_EXPRESSION_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the expression of a negated expression but I found "a space" +instead: + + ┌ ./spec/errors/negated_expression_expected_expression:3:5 + ├───────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ ! + │ ⌃⌃⌃⌃ diff --git a/spec/errors/negated_expression_not_bool b/spec/errors/negated_expression_not_bool new file mode 100644 index 000000000..2096e9961 --- /dev/null +++ b/spec/errors/negated_expression_not_bool @@ -0,0 +1,33 @@ +module Test { + fun test : Bool { + !"asd" + } +} + +component Main { + fun render : String { + if (Test.test()) { + "Hello" + } else { + "Hello" + } + } +} +--------------------------------------------------------------------------------░ ERROR (NEGATED_EXPRESSION_NOT_BOOL) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A negated expressions expression must evaluate to a boolean, but it is: + + String + +The negated expression in question is here: + + ┌ ./spec/errors/negated_expression_not_bool:3:5 + ├────────────────────────────────────────────── + 1│ module Test { + 2│ fun test : Bool { + 3│ !"asd" + │ ⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } + 6│ + 7│ component Main { diff --git a/spec/errors/next_call_expected_fields b/spec/errors/next_call_expected_fields new file mode 100644 index 000000000..a65c0acef --- /dev/null +++ b/spec/errors/next_call_expected_fields @@ -0,0 +1,14 @@ +component Main { + fun render : String { + next a +-------------------------------------------------------------------------------- +░ ERROR (NEXT_CALL_EXPECTED_FIELDS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the fields for a next call but I found "a" instead: + + ┌ ./spec/errors/next_call_expected_fields:3:10 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ next a + │ ⌃ diff --git a/spec/errors/next_call_invalid_invocation b/spec/errors/next_call_invalid_invocation new file mode 100644 index 000000000..f5045dd85 --- /dev/null +++ b/spec/errors/next_call_invalid_invocation @@ -0,0 +1,30 @@ +module Test { + fun test : Promise(Void) { + next { age: 30 } + } +} + +component Main { + fun render : Html { + let test = + Test.test() + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (NEXT_CALL_INVALID_INVOCATION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A next call can only called inside a component, store or provider but you tried +to call it here: + + ┌ ./spec/errors/next_call_invalid_invocation:3:5 + ├─────────────────────────────────────────────── + 1│ module Test { + 2│ fun test : Promise(Void) { + 3│ next { age: 30 } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } + 6│ + 7│ component Main { diff --git a/spec/errors/next_call_state_not_found b/spec/errors/next_call_state_not_found new file mode 100644 index 000000000..033cc0d4a --- /dev/null +++ b/spec/errors/next_call_state_not_found @@ -0,0 +1,30 @@ +component Main { + state name : String = "Joe" + + fun render : Html { + next { age: 30 } + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (NEXT_CALL_STATE_NOT_FOUND) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for a state but could not find it: + + age + +The next call in question is here: + + ┌ ./spec/errors/next_call_state_not_found:5:5 + ├──────────────────────────────────────────── + 1│ component Main { + 2│ state name : String = "Joe" + 3│ + 4│ fun render : Html { + 5│ next { age: 30 } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 6│ + 7│
+ 8│ } + 9│ } diff --git a/spec/errors/next_call_state_type_mismatch b/spec/errors/next_call_state_type_mismatch new file mode 100644 index 000000000..ab47fe553 --- /dev/null +++ b/spec/errors/next_call_state_type_mismatch @@ -0,0 +1,50 @@ +component Main { + state name : String = "Joe" + + fun render : Html { + next { name: 30 } + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (NEXT_CALL_STATE_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +You were trying to assign an incompatible value to the state: + + name + +The type of the state is: + + String + +But the type you are trying to assign to it is: + + Number + +Here is where you did the assignment: + + ┌ ./spec/errors/next_call_state_type_mismatch:5:12 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ state name : String = "Joe" + 3│ + 4│ fun render : Html { + 5│ next { name: 30 } + │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 6│ + 7│
+ 8│ } + 9│ } + +And here is where the state is defined: + + ┌ ./spec/errors/next_call_state_type_mismatch:2:3 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ state name : String = "Joe" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│ next { name: 30 } + 6│ diff --git a/spec/errors/number_literal_expected_decimal b/spec/errors/number_literal_expected_decimal new file mode 100644 index 000000000..4c40f8f47 --- /dev/null +++ b/spec/errors/number_literal_expected_decimal @@ -0,0 +1,14 @@ +component Main { + fun render : String { + 0. +-------------------------------------------------------------------------------- +░ ERROR (NUMBER_LITERAL_EXPECTED_DECIMAL) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the decimals for a number literal but I found "a space" instead: + + ┌ ./spec/errors/number_literal_expected_decimal:3:6 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ 0. + │ ⌃⌃⌃⌃ diff --git a/spec/errors/operation_expected_expression b/spec/errors/operation_expected_expression new file mode 100644 index 000000000..0f0cc1de0 --- /dev/null +++ b/spec/errors/operation_expected_expression @@ -0,0 +1,15 @@ +component Main { + fun render : String { + "A" + { +-------------------------------------------------------------------------------- +░ ERROR (OPERATION_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the right side expression of an operation but I found "{" +instead: + + ┌ ./spec/errors/operation_expected_expression:3:11 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ "A" + { + │ ⌃ diff --git a/spec/errors/operation_numeric_type_mismatch b/spec/errors/operation_numeric_type_mismatch new file mode 100644 index 000000000..b0e417b6d --- /dev/null +++ b/spec/errors/operation_numeric_type_mismatch @@ -0,0 +1,34 @@ +component Main { + fun test : Number { + "Hello" * 0 + } + + fun render : String { + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (OPERATION_NUMERIC_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the left operand does not match the type of an operation. + +I was expecting: + + Number + +Instead it is: + + String + +The operation in question is here: + + ┌ ./spec/errors/operation_numeric_type_mismatch:3:5 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ fun test : Number { + 3│ "Hello" * 0 + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : String { + 7│ "" diff --git a/spec/errors/operation_or_not_maybe_or_result b/spec/errors/operation_or_not_maybe_or_result new file mode 100644 index 000000000..7b909839b --- /dev/null +++ b/spec/errors/operation_or_not_maybe_or_result @@ -0,0 +1,35 @@ +enum Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : String { + 0 or "Hello" + } +} +-------------------------------------------------------------------------------- +░ ERROR (OPERATION_OR_NOT_MAYBE_OR_RESULT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +For the or operation the left operand is invalid. + +I was expecting: + + Maybe(a) + +Instead it is: + + Number + +The operation in question is here: + + ┌ ./spec/errors/operation_or_not_maybe_or_result:8:5 + ├─────────────────────────────────────────────────── + 4│ } + 5│ + 6│ component Main { + 7│ fun render : String { + 8│ 0 or "Hello" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 9│ } + 10│ } diff --git a/spec/errors/operation_or_type_mismatch b/spec/errors/operation_or_type_mismatch new file mode 100644 index 000000000..ce9c05574 --- /dev/null +++ b/spec/errors/operation_or_type_mismatch @@ -0,0 +1,36 @@ +enum Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : String { + Maybe::Just(0) or "Hello" + } +} +-------------------------------------------------------------------------------- +░ ERROR (OPERATION_OR_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the default value does not match the type of the parameter of the +maybe. + +I was expecting: + + Number + +Instead it is: + + String + +The operation in question is here: + + ┌ ./spec/errors/operation_or_type_mismatch:8:16 + ├────────────────────────────────────────────── + 4│ } + 5│ + 6│ component Main { + 7│ fun render : String { + 8│ Maybe::Just(0) or "Hello" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 9│ } + 10│ } diff --git a/spec/errors/operation_pipe_ambiguous b/spec/errors/operation_pipe_ambiguous new file mode 100644 index 000000000..705e54443 --- /dev/null +++ b/spec/errors/operation_pipe_ambiguous @@ -0,0 +1,27 @@ +component Main { + fun toString(value : Number) : String { + "" + } + + fun render : String { + "" + 0 |> toString + "" + 0 |> toString + } +} +-------------------------------------------------------------------------------- +░ ERROR (OPERATION_PIPE_AMBIGUOUS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I cannot determine the order of the operands because the pipe makes it +ambiguous. Wrap operands in parentheses to avoid ambiguity. + +The piped call in question is here: + + ┌ ./spec/errors/operation_pipe_ambiguous:7:15 + ├──────────────────────────────────────────── + 3│ "" + 4│ } + 5│ + 6│ fun render : String { + 7│ "" + 0 |> toString + "" + 0 |> toString + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/operation_plus_type_mismatch b/spec/errors/operation_plus_type_mismatch new file mode 100644 index 000000000..b376472ae --- /dev/null +++ b/spec/errors/operation_plus_type_mismatch @@ -0,0 +1,28 @@ +component Main { + fun render : String { + "Hello" + void + } +} +-------------------------------------------------------------------------------- +░ ERROR (OPERATION_PLUS_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the right operand does not match the type of an operation. + +I was expecting one of these types: + + Number, String + +Instead it is: + + Void + +The operation in question is here: + + ┌ ./spec/errors/operation_plus_type_mismatch:3:5 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ "Hello" + void + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/property_expected_default_value b/spec/errors/property_expected_default_value new file mode 100644 index 000000000..b86864785 --- /dev/null +++ b/spec/errors/property_expected_default_value @@ -0,0 +1,12 @@ +component Test { + property test = +-------------------------------------------------------------------------------- +░ ERROR (PROPERTY_EXPECTED_DEFAULT_VALUE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the default value of a property but I found "a space" instead: + + ┌ ./spec/errors/property_expected_default_value:2:17 + ├─────────────────────────────────────────────────── + 1│ component Test { + 2│ property test = + │ ⌃⌃⌃⌃ diff --git a/spec/errors/property_expected_name b/spec/errors/property_expected_name new file mode 100644 index 000000000..1c5046a73 --- /dev/null +++ b/spec/errors/property_expected_name @@ -0,0 +1,12 @@ +component Test { + property +-------------------------------------------------------------------------------- +░ ERROR (PROPERTY_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a property but I found "a space" instead: + + ┌ ./spec/errors/property_expected_name:2:10 + ├────────────────────────────────────────── + 1│ component Test { + 2│ property + │ ⌃⌃⌃⌃ diff --git a/spec/errors/property_expected_type b/spec/errors/property_expected_type new file mode 100644 index 000000000..5dfade58c --- /dev/null +++ b/spec/errors/property_expected_type @@ -0,0 +1,12 @@ +component Test { + property test : +-------------------------------------------------------------------------------- +░ ERROR (PROPERTY_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of a property but I found "a space" instead: + + ┌ ./spec/errors/property_expected_type:2:17 + ├────────────────────────────────────────── + 1│ component Test { + 2│ property test : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/property_type_mismatch b/spec/errors/property_type_mismatch new file mode 100644 index 000000000..5a016cb21 --- /dev/null +++ b/spec/errors/property_type_mismatch @@ -0,0 +1,37 @@ +component Test { + property name : String = true + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (PROPERTY_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the default value of a property does not match its type annotation. + +I was expecting: + + String + +Instead it is: + + Bool + +The property in question is here: + + ┌ ./spec/errors/property_type_mismatch:2:3 + ├───────────────────────────────────────── + 1│ component Test { + 2│ property name : String = true + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } diff --git a/spec/errors/property_type_or_default_needed b/spec/errors/property_type_or_default_needed new file mode 100644 index 000000000..9e2ebf458 --- /dev/null +++ b/spec/errors/property_type_or_default_needed @@ -0,0 +1,27 @@ +component Test { + property name + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (PROPERTY_TYPE_OR_DEFAULT_NEEDED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type or default value of a property needs to be defined, but neither was. + + ┌ ./spec/errors/property_type_or_default_needed:2:3 + ├────────────────────────────────────────────────── + 1│ component Test { + 2│ property name + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } diff --git a/spec/errors/property_with_type_variables b/spec/errors/property_with_type_variables new file mode 100644 index 000000000..9d4046114 --- /dev/null +++ b/spec/errors/property_with_type_variables @@ -0,0 +1,43 @@ +type Maybe(a) { + Nothing + Just(a) +} + +component Test { + property name : Maybe(a) = Maybe::Nothing + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (PROPERTY_WITH_TYPE_VARIABLES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of a property contains type variables. Type variables in properties are +not allow at this time since that would make the compoennt generic and it is not +supported this time. + +The type is: + + Maybe(a) + +The property in question is here: + + ┌ ./spec/errors/property_with_type_variables:7:3 + ├─────────────────────────────────────────────── + 3│ Just(a) + 4│ } + 5│ + 6│ component Test { + 7│ property name : Maybe(a) = Maybe::Nothing + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ + 9│ fun render : Html { + 10│
+ 11│ } diff --git a/spec/errors/provider_expeceted_colon b/spec/errors/provider_expeceted_colon new file mode 100644 index 000000000..e81090450 --- /dev/null +++ b/spec/errors/provider_expeceted_colon @@ -0,0 +1,10 @@ +provider Test +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_EXPECETED_COLON) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the colon of a provider but I found "a space" instead: + + ┌ ./spec/errors/provider_expeceted_colon:1:13 + ├──────────────────────────────────────────── + 1│ provider Test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/provider_expected_body b/spec/errors/provider_expected_body new file mode 100644 index 000000000..59ab00d47 --- /dev/null +++ b/spec/errors/provider_expected_body @@ -0,0 +1,10 @@ +provider Test : Test { +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a provider but I found "a space" instead: + + ┌ ./spec/errors/provider_expected_body:1:22 + ├────────────────────────────────────────── + 1│ provider Test : Test { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/provider_expected_closing_bracket b/spec/errors/provider_expected_closing_bracket new file mode 100644 index 000000000..f92f39e07 --- /dev/null +++ b/spec/errors/provider_expected_closing_bracket @@ -0,0 +1,12 @@ +provider Test : Test { + const TEST = "" +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a provider but I found "a space" instead: + + ┌ ./spec/errors/provider_expected_closing_bracket:2:17 + ├───────────────────────────────────────────────────── + 1│ provider Test : Test { + 2│ const TEST = "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/provider_expected_name b/spec/errors/provider_expected_name new file mode 100644 index 000000000..5218728fb --- /dev/null +++ b/spec/errors/provider_expected_name @@ -0,0 +1,10 @@ +provider +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a provider but I found "a space" instead: + + ┌ ./spec/errors/provider_expected_name:1:8 + ├───────────────────────────────────────── + 1│ provider + │ ⌃⌃⌃⌃ diff --git a/spec/errors/provider_expected_opening_bracket b/spec/errors/provider_expected_opening_bracket new file mode 100644 index 000000000..17fb11dc7 --- /dev/null +++ b/spec/errors/provider_expected_opening_bracket @@ -0,0 +1,10 @@ +provider Test : Test +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a provider but I found "a space" instead: + + ┌ ./spec/errors/provider_expected_opening_bracket:1:20 + ├───────────────────────────────────────────────────── + 1│ provider Test : Test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/provider_expected_subscription b/spec/errors/provider_expected_subscription new file mode 100644 index 000000000..4ebf4c3b1 --- /dev/null +++ b/spec/errors/provider_expected_subscription @@ -0,0 +1,11 @@ +provider Test : +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_EXPECTED_SUBSCRIPTION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the subscription type of a provider but I found "a space" +instead: + + ┌ ./spec/errors/provider_expected_subscription:1:15 + ├────────────────────────────────────────────────── + 1│ provider Test : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/provider_not_found_subscription b/spec/errors/provider_not_found_subscription new file mode 100644 index 000000000..4a68a68c2 --- /dev/null +++ b/spec/errors/provider_not_found_subscription @@ -0,0 +1,18 @@ +provider Provider : Subscription { + fun test : Bool { + true + } +} +-------------------------------------------------------------------------------- +░ ERROR (PROVIDER_NOT_FOUND_SUBSCRIPTION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was looking for the record type of the subscription "Subscription" but could +not find it: + + ┌ ./spec/errors/provider_not_found_subscription:1:1 + ├────────────────────────────────────────────────── + 1│ provider Provider : Subscription { + 2│ fun test : Bool { + 3│ true + 4│ } + 5│ } diff --git a/spec/errors/record_not_found_matching_record_definition b/spec/errors/record_not_found_matching_record_definition new file mode 100644 index 000000000..ceffa3971 --- /dev/null +++ b/spec/errors/record_not_found_matching_record_definition @@ -0,0 +1,27 @@ +component Main { + state data = { name: "" } + + fun render : Html { +
+ <{ data.name }> +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (RECORD_NOT_FOUND_MATCHING_RECORD_DEFINITION) ░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I could not find a record that matches this structure: + + (name: String) + +It was used here: + + ┌ ./spec/errors/record_not_found_matching_record_definition:2:16 + ├─────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ state data = { name: "" } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ <{ data.name }> diff --git a/spec/errors/record_update_expected_closing_bracket b/spec/errors/record_update_expected_closing_bracket new file mode 100644 index 000000000..10765aa0b --- /dev/null +++ b/spec/errors/record_update_expected_closing_bracket @@ -0,0 +1,15 @@ +component Main { + get record : Record(String, Bool) { + { a | a: "" +-------------------------------------------------------------------------------- +░ ERROR (RECORD_UPDATE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a record update but I found "a space" +instead: + + ┌ ./spec/errors/record_update_expected_closing_bracket:3:15 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ get record : Record(String, Bool) { + 3│ { a | a: "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/record_update_expected_fields b/spec/errors/record_update_expected_fields new file mode 100644 index 000000000..22dbce7f0 --- /dev/null +++ b/spec/errors/record_update_expected_fields @@ -0,0 +1,14 @@ +component Main { + get record : Record(String, Bool) { + { a | +-------------------------------------------------------------------------------- +░ ERROR (RECORD_UPDATE_EXPECTED_FIELDS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the fields for a record update but I found "a space" instead: + + ┌ ./spec/errors/record_update_expected_fields:3:9 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ get record : Record(String, Bool) { + 3│ { a | + │ ⌃⌃⌃⌃ diff --git a/spec/errors/record_update_not_found_key b/spec/errors/record_update_not_found_key new file mode 100644 index 000000000..9088a2687 --- /dev/null +++ b/spec/errors/record_update_not_found_key @@ -0,0 +1,46 @@ +record Test { + a : String, + b : Number +} + +component Main { + fun test : Test { + let x = + { + a: "Blah", + b: 0 + } + + { x | + a: "Hello", + c: "Hello" + } + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (RECORD_UPDATE_NOT_FOUND_KEY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The field "c" does not exists on the target record: + + Test(a: String, b: Number) + +Here is where you tried to assign a value to it: + + ┌ ./spec/errors/record_update_not_found_key:16:7 + ├─────────────────────────────────────────────── + 12│ } + 13│ + 14│ { x | + 15│ a: "Hello", + 16│ c: "Hello" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 17│ } + 18│ } + 19│ + 20│ fun render : String { diff --git a/spec/errors/record_update_not_updating_record b/spec/errors/record_update_not_updating_record new file mode 100644 index 000000000..dd5c7325c --- /dev/null +++ b/spec/errors/record_update_not_updating_record @@ -0,0 +1,61 @@ +record Test { + a : String, + b : Number +} + +component Main { + fun test : Test { + let x = "" + + { x | + a: "Hello", + b: 0 + } + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (RECORD_UPDATE_NOT_UPDATING_RECORD) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The target of a record update is not a record, instead it is: + + String + +Here is where you want to update it: + + ┌ ./spec/errors/record_update_not_updating_record:10:5 + ├───────────────────────────────────────────────────── + 6│ component Main { + 7│ fun test : Test { + 8│ let x = "" + 9│ + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 10│ { x | + 11│ a: "Hello", + 12│ b: 0 + 13│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 14│ } + 15│ + 16│ fun render : String { + 17│ test() + +Here is where the target is defined: + + ┌ ./spec/errors/record_update_not_updating_record:8:9 + ├──────────────────────────────────────────────────── + 4│ } + 5│ + 6│ component Main { + 7│ fun test : Test { + 8│ let x = "" + │ ⌃ + 9│ + 10│ { x | + 11│ a: "Hello", + 12│ b: 0 diff --git a/spec/errors/record_update_type_mismatch b/spec/errors/record_update_type_mismatch new file mode 100644 index 000000000..28cfaa571 --- /dev/null +++ b/spec/errors/record_update_type_mismatch @@ -0,0 +1,65 @@ +record Test { + a : String, + b : Number +} + +component Main { + fun test : Test { + let x = + { + a: "Blah", + b: 0 + } + + { x | + a: "Hello", + b: "Hello" + } + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (RECORD_UPDATE_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +One of the updated fields of a record do not match its type: + + ┌ ./spec/errors/record_update_type_mismatch:16:7 + ├─────────────────────────────────────────────── + 12│ } + 13│ + 14│ { x | + 15│ a: "Hello", + 16│ b: "Hello" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 17│ } + 18│ } + 19│ + 20│ fun render : String { + +I was expecting: + + Number + +Instead it is: + + String + +The record is here: + + ┌ ./spec/errors/record_update_type_mismatch:8:9 + ├────────────────────────────────────────────── + 4│ } + 5│ + 6│ component Main { + 7│ fun test : Test { + 8│ let x = + │ ⌃ + 9│ { + 10│ a: "Blah", + 11│ b: 0 + 12│ } diff --git a/spec/errors/record_with_holes b/spec/errors/record_with_holes new file mode 100644 index 000000000..72013224b --- /dev/null +++ b/spec/errors/record_with_holes @@ -0,0 +1,15 @@ +record Test { + a : Array(a), + b : Number +} +-------------------------------------------------------------------------------- +░ ERROR (RECORD_WITH_HOLES) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Records with type variables are not allow at this time. I found one here: + + ┌ ./spec/errors/record_with_holes:1:1 + ├──────────────────────────────────── + 1│ record Test { + 2│ a : Array(a), + 3│ b : Number + 4│ } diff --git a/spec/errors/recursion b/spec/errors/recursion new file mode 100644 index 000000000..10a26665c --- /dev/null +++ b/spec/errors/recursion @@ -0,0 +1,40 @@ +component Test { + property greeting : String = greeting + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +░ ERROR (RECURSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Recursion is only supported in specific cases at this time. Unfortunatly here is +not supported: + + ┌ ./spec/errors/recursion:2:3 + ├──────────────────────────── + 1│ component Test { + 2│ property greeting : String = greeting + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } + +The previous step in the recursion was here: + + ┌ ./spec/errors/recursion:2:32 + ├───────────────────────────── + 1│ component Test { + 2│ property greeting : String = greeting + │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } diff --git a/spec/errors/regexp_literal_expected_closing_slash b/spec/errors/regexp_literal_expected_closing_slash new file mode 100644 index 000000000..7a0a6a638 --- /dev/null +++ b/spec/errors/regexp_literal_expected_closing_slash @@ -0,0 +1,15 @@ +component Main { + fun render : String { + /asd +-------------------------------------------------------------------------------- +░ ERROR (REGEXP_LITERAL_EXPECTED_CLOSING_SLASH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing slash of a regexp literal but I found "a space" +instead: + + ┌ ./spec/errors/regexp_literal_expected_closing_slash:3:8 + ├──────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ /asd + │ ⌃⌃⌃⌃ diff --git a/spec/errors/return_call_expected_expression b/spec/errors/return_call_expected_expression new file mode 100644 index 000000000..821eed7d8 --- /dev/null +++ b/spec/errors/return_call_expected_expression @@ -0,0 +1,14 @@ +component Main { + fun render { + let x = "" or return +-------------------------------------------------------------------------------- +░ ERROR (RETURN_CALL_EXPECTED_EXPRESSION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the expression of a return call but I found "a space" instead: + + ┌ ./spec/errors/return_call_expected_expression:3:24 + ├─────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render { + 3│ let x = "" or return + │ ⌃⌃⌃⌃ diff --git a/spec/errors/return_call_invalid b/spec/errors/return_call_invalid new file mode 100644 index 000000000..1ae0d2662 --- /dev/null +++ b/spec/errors/return_call_invalid @@ -0,0 +1,22 @@ +component Main { + state test : String = return "" + + fun render : String { + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (RETURN_CALL_INVALID) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +A return call can only appear in a block as part of an or operation while +destructuring or as a standalone expression. + + ┌ ./spec/errors/return_call_invalid:2:25 + ├─────────────────────────────────────── + 1│ component Main { + 2│ state test : String = return "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ + 4│ fun render : String { + 5│ "" + 6│ } diff --git a/spec/errors/route_expected_body b/spec/errors/route_expected_body new file mode 100644 index 000000000..03874f6e1 --- /dev/null +++ b/spec/errors/route_expected_body @@ -0,0 +1,12 @@ +routes { + * { +-------------------------------------------------------------------------------- +░ ERROR (ROUTE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a route but I found "a space" instead: + + ┌ ./spec/errors/route_expected_body:2:5 + ├────────────────────────────────────── + 1│ routes { + 2│ * { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/route_expected_closing_bracket b/spec/errors/route_expected_closing_bracket new file mode 100644 index 000000000..f1e808b3d --- /dev/null +++ b/spec/errors/route_expected_closing_bracket @@ -0,0 +1,14 @@ +routes { + * { + "" +-------------------------------------------------------------------------------- +░ ERROR (ROUTE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a route but I found "a space" instead: + + ┌ ./spec/errors/route_expected_closing_bracket:3:6 + ├───────────────────────────────────────────────── + 1│ routes { + 2│ * { + 3│ "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/route_expected_closing_parenthesis b/spec/errors/route_expected_closing_parenthesis new file mode 100644 index 000000000..0efdc9e77 --- /dev/null +++ b/spec/errors/route_expected_closing_parenthesis @@ -0,0 +1,13 @@ +routes { + * ( +-------------------------------------------------------------------------------- +░ ERROR (ROUTE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a route but I found "a space" +instead: + + ┌ ./spec/errors/route_expected_closing_parenthesis:2:5 + ├───────────────────────────────────────────────────── + 1│ routes { + 2│ * ( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/route_expected_opening_bracket b/spec/errors/route_expected_opening_bracket new file mode 100644 index 000000000..d8fb04ca6 --- /dev/null +++ b/spec/errors/route_expected_opening_bracket @@ -0,0 +1,12 @@ +routes { + * +-------------------------------------------------------------------------------- +░ ERROR (ROUTE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a route but I found "a space" instead: + + ┌ ./spec/errors/route_expected_opening_bracket:2:3 + ├───────────────────────────────────────────────── + 1│ routes { + 2│ * + │ ⌃⌃⌃⌃ diff --git a/spec/errors/route_param_invalid b/spec/errors/route_param_invalid new file mode 100644 index 000000000..f8d2227cf --- /dev/null +++ b/spec/errors/route_param_invalid @@ -0,0 +1,24 @@ +routes { + /:name (name : Array(String)) { + void + } +} +-------------------------------------------------------------------------------- +░ ERROR (ROUTE_PARAM_INVALID) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of a route parameter cannot be used in routes: + + ┌ ./spec/errors/route_param_invalid:2:18 + ├─────────────────────────────────────── + 1│ routes { + 2│ /:name (name : Array(String)) { + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ void + 4│ } + 5│ } + +Only these types can be used as route parameters: + + String + Number + diff --git a/spec/errors/routes_expected_body b/spec/errors/routes_expected_body new file mode 100644 index 000000000..97c1f6d86 --- /dev/null +++ b/spec/errors/routes_expected_body @@ -0,0 +1,10 @@ +routes { +-------------------------------------------------------------------------------- +░ ERROR (ROUTES_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a routes block but I found "a space" instead: + + ┌ ./spec/errors/routes_expected_body:1:8 + ├─────────────────────────────────────── + 1│ routes { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/routes_expected_closing_bracket b/spec/errors/routes_expected_closing_bracket new file mode 100644 index 000000000..f74f2c231 --- /dev/null +++ b/spec/errors/routes_expected_closing_bracket @@ -0,0 +1,17 @@ +routes { + * { + "" + } +-------------------------------------------------------------------------------- +░ ERROR (ROUTES_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a routes block but I found "a space" +instead: + + ┌ ./spec/errors/routes_expected_closing_bracket:4:3 + ├────────────────────────────────────────────────── + 1│ routes { + 2│ * { + 3│ "" + 4│ } + │ ⌃⌃⌃⌃ diff --git a/spec/errors/routes_expected_opening_bracket b/spec/errors/routes_expected_opening_bracket new file mode 100644 index 000000000..43d67f397 --- /dev/null +++ b/spec/errors/routes_expected_opening_bracket @@ -0,0 +1,11 @@ +routes +-------------------------------------------------------------------------------- +░ ERROR (ROUTES_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a routes block but I found "a space" +instead: + + ┌ ./spec/errors/routes_expected_opening_bracket:1:6 + ├────────────────────────────────────────────────── + 1│ routes + │ ⌃⌃⌃⌃ diff --git a/spec/errors/spread_expected_variable b/spec/errors/spread_expected_variable new file mode 100644 index 000000000..2d879734a --- /dev/null +++ b/spec/errors/spread_expected_variable @@ -0,0 +1,14 @@ +component Main { + fun render : String { + let [x, ... +-------------------------------------------------------------------------------- +░ ERROR (SPREAD_EXPECTED_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a spread but I found "a space" instead: + + ┌ ./spec/errors/spread_expected_variable:3:15 + ├──────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ let [x, ... + │ ⌃⌃⌃⌃ diff --git a/spec/errors/state_expected_default_value b/spec/errors/state_expected_default_value new file mode 100644 index 000000000..bdaa4cd30 --- /dev/null +++ b/spec/errors/state_expected_default_value @@ -0,0 +1,12 @@ +component Main { + state test = +-------------------------------------------------------------------------------- +░ ERROR (STATE_EXPECTED_DEFAULT_VALUE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the default value of a state but I found "a space" instead: + + ┌ ./spec/errors/state_expected_default_value:2:14 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ state test = + │ ⌃⌃⌃⌃ diff --git a/spec/errors/state_expected_equal_sign b/spec/errors/state_expected_equal_sign new file mode 100644 index 000000000..2fd0fe36f --- /dev/null +++ b/spec/errors/state_expected_equal_sign @@ -0,0 +1,12 @@ +component Main { + state test +-------------------------------------------------------------------------------- +░ ERROR (STATE_EXPECTED_EQUAL_SIGN) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the equal sign of a state but I found "a space" instead: + + ┌ ./spec/errors/state_expected_equal_sign:2:12 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ state test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/state_expected_name b/spec/errors/state_expected_name new file mode 100644 index 000000000..b806fd347 --- /dev/null +++ b/spec/errors/state_expected_name @@ -0,0 +1,12 @@ +component Main { + state +-------------------------------------------------------------------------------- +░ ERROR (STATE_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a state but I found "a space" instead: + + ┌ ./spec/errors/state_expected_name:2:7 + ├────────────────────────────────────── + 1│ component Main { + 2│ state + │ ⌃⌃⌃⌃ diff --git a/spec/errors/state_expected_type b/spec/errors/state_expected_type new file mode 100644 index 000000000..de2b0398d --- /dev/null +++ b/spec/errors/state_expected_type @@ -0,0 +1,12 @@ +component Main { + state test : +-------------------------------------------------------------------------------- +░ ERROR (STATE_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type value of a state but I found "a space" instead: + + ┌ ./spec/errors/state_expected_type:2:14 + ├─────────────────────────────────────── + 1│ component Main { + 2│ state test : + │ ⌃⌃⌃⌃ diff --git a/spec/errors/state_type_mismatch b/spec/errors/state_type_mismatch new file mode 100644 index 000000000..985a9c291 --- /dev/null +++ b/spec/errors/state_type_mismatch @@ -0,0 +1,30 @@ +component Main { + state b : String = 0 + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (STATE_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the default value of the a state does not match its type annotation: + + ┌ ./spec/errors/state_type_mismatch:2:22 + ├─────────────────────────────────────── + 1│ component Main { + 2│ state b : String = 0 + │ ⌃ + 3│ + 4│ fun render : Html { + 5│
+ 6│ } + +I was expecting: + + String + +Instead it is: + + Number + diff --git a/spec/errors/statement_last_target b/spec/errors/statement_last_target new file mode 100644 index 000000000..896d477f9 --- /dev/null +++ b/spec/errors/statement_last_target @@ -0,0 +1,19 @@ +component Main { + fun render : String { + let a = "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (STATEMENT_LAST_TARGET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The last statement of a block cannot be an assignment: + + ┌ ./spec/errors/statement_last_target:2:23 + ├───────────────────────────────────────── + 1│ component Main { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 2│ fun render : String { + 3│ let a = "" + 4│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 5│ } diff --git a/spec/errors/statement_return_required b/spec/errors/statement_return_required new file mode 100644 index 000000000..0fe0fc7f1 --- /dev/null +++ b/spec/errors/statement_return_required @@ -0,0 +1,22 @@ +component Main { + fun render : String { + let [a, b] = [] + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (STATEMENT_RETURN_REQUIRED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +This statement needs a return call because the destructuring is not exhaustive: + + ┌ ./spec/errors/statement_return_required:3:5 + ├──────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ let [a, b] = [] + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ + 5│ "" + 6│ } + 7│ } diff --git a/spec/errors/statement_return_type_mismatch b/spec/errors/statement_return_type_mismatch new file mode 100644 index 000000000..9cf3f425d --- /dev/null +++ b/spec/errors/statement_return_type_mismatch @@ -0,0 +1,51 @@ +enum Test { + A(String) + B(String) +} + +component Main { + fun render : String { + let Test::B(x) = + Test::A("Hello") or return 0 + + x + } +} +-------------------------------------------------------------------------------- +░ ERROR (STATEMENT_RETURN_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of a return call does not match the return type of the block: + + Number + +I was expecting: + + String + +It return call in question is here: + + ┌ ./spec/errors/statement_return_type_mismatch:9:27 + ├────────────────────────────────────────────────── + 5│ + 6│ component Main { + 7│ fun render : String { + 8│ let Test::B(x) = + 9│ Test::A("Hello") or return 0 + │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 10│ + 11│ x + 12│ } + 13│ } + +The returned value of the block is here: + + ┌ ./spec/errors/statement_return_type_mismatch:11:5 + ├────────────────────────────────────────────────── + 7│ fun render : String { + 8│ let Test::B(x) = + 9│ Test::A("Hello") or return 0 + 10│ + 11│ x + │ ⌃ + 12│ } + 13│ } diff --git a/spec/errors/store_expected_body b/spec/errors/store_expected_body new file mode 100644 index 000000000..d72687fe6 --- /dev/null +++ b/spec/errors/store_expected_body @@ -0,0 +1,10 @@ +store X { +-------------------------------------------------------------------------------- +░ ERROR (STORE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a store but I found "a space" instead: + + ┌ ./spec/errors/store_expected_body:1:9 + ├────────────────────────────────────── + 1│ store X { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/store_expected_closing_bracket b/spec/errors/store_expected_closing_bracket new file mode 100644 index 000000000..b4f54331b --- /dev/null +++ b/spec/errors/store_expected_closing_bracket @@ -0,0 +1,12 @@ +store X { + state test : String = "" +-------------------------------------------------------------------------------- +░ ERROR (STORE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a store but I found "a space" instead: + + ┌ ./spec/errors/store_expected_closing_bracket:2:26 + ├────────────────────────────────────────────────── + 1│ store X { + 2│ state test : String = "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/store_expected_name b/spec/errors/store_expected_name new file mode 100644 index 000000000..dcd9f4bbb --- /dev/null +++ b/spec/errors/store_expected_name @@ -0,0 +1,10 @@ +store +-------------------------------------------------------------------------------- +░ ERROR (STORE_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a store but I found "a space" instead: + + ┌ ./spec/errors/store_expected_name:1:5 + ├────────────────────────────────────── + 1│ store + │ ⌃⌃⌃⌃ diff --git a/spec/errors/store_expected_opening_bracket b/spec/errors/store_expected_opening_bracket new file mode 100644 index 000000000..a148b9573 --- /dev/null +++ b/spec/errors/store_expected_opening_bracket @@ -0,0 +1,10 @@ +store X +-------------------------------------------------------------------------------- +░ ERROR (STORE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a store but I found "a space" instead: + + ┌ ./spec/errors/store_expected_opening_bracket:1:7 + ├───────────────────────────────────────────────── + 1│ store X + │ ⌃⌃⌃⌃ diff --git a/spec/errors/string_expected_closing_quote b/spec/errors/string_expected_closing_quote new file mode 100644 index 000000000..9c3e8b284 --- /dev/null +++ b/spec/errors/string_expected_closing_quote @@ -0,0 +1,15 @@ +component Main { + fun render : String { + " +-------------------------------------------------------------------------------- +░ ERROR (STRING_EXPECTED_CLOSING_QUOTE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing quoute of a string literal but I found "a space" +instead: + + ┌ ./spec/errors/string_expected_closing_quote:3:5 + ├──────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ " + │ ⌃⌃⌃⌃ diff --git a/spec/errors/string_expected_other_string b/spec/errors/string_expected_other_string new file mode 100644 index 000000000..d8ccb318c --- /dev/null +++ b/spec/errors/string_expected_other_string @@ -0,0 +1,15 @@ +component Main { + fun render : String { + "" \ +-------------------------------------------------------------------------------- +░ ERROR (STRING_EXPECTED_OTHER_STRING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting another string literal after a string separator but I found "a +space" instead: + + ┌ ./spec/errors/string_expected_other_string:3:8 + ├─────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ "" \ + │ ⌃⌃⌃⌃ diff --git a/spec/errors/string_literal_interpolation_type_mismatch b/spec/errors/string_literal_interpolation_type_mismatch new file mode 100644 index 000000000..d6395a71d --- /dev/null +++ b/spec/errors/string_literal_interpolation_type_mismatch @@ -0,0 +1,30 @@ +component Main { + fun render : String { + let name = {} + + "Hello There #{name}!" + } +} +-------------------------------------------------------------------------------- +░ ERROR (STRING_LITERAL_INTERPOLATION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +An interpolation in string is causing a mismatch. The expected type is: + + String + +Instead it is: + + Unit + +The interpolation in question is here: + + ┌ ./spec/errors/string_literal_interpolation_type_mismatch:5:18 + ├────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ let name = {} + 4│ + 5│ "Hello There #{name}!" + │ ⌃⌃⌃⌃⌃⌃⌃ + 6│ } + 7│ } diff --git a/spec/errors/style_expected_body b/spec/errors/style_expected_body new file mode 100644 index 000000000..88ef15613 --- /dev/null +++ b/spec/errors/style_expected_body @@ -0,0 +1,12 @@ +component Main { + style x { +-------------------------------------------------------------------------------- +░ ERROR (STYLE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a style but I found "a space" instead: + + ┌ ./spec/errors/style_expected_body:2:11 + ├─────────────────────────────────────── + 1│ component Main { + 2│ style x { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/style_expected_closing_bracket b/spec/errors/style_expected_closing_bracket new file mode 100644 index 000000000..1002cfe4f --- /dev/null +++ b/spec/errors/style_expected_closing_bracket @@ -0,0 +1,14 @@ +component Main { + style x { + color: red; +-------------------------------------------------------------------------------- +░ ERROR (STYLE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a style but I found "a space" instead: + + ┌ ./spec/errors/style_expected_closing_bracket:3:15 + ├────────────────────────────────────────────────── + 1│ component Main { + 2│ style x { + 3│ color: red; + │ ⌃⌃⌃⌃ diff --git a/spec/errors/style_expected_closing_parenthesis b/spec/errors/style_expected_closing_parenthesis new file mode 100644 index 000000000..8f8fe0331 --- /dev/null +++ b/spec/errors/style_expected_closing_parenthesis @@ -0,0 +1,13 @@ +component Main { + style x ( +-------------------------------------------------------------------------------- +░ ERROR (STYLE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a style but I found "a space" +instead: + + ┌ ./spec/errors/style_expected_closing_parenthesis:2:11 + ├────────────────────────────────────────────────────── + 1│ component Main { + 2│ style x ( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/style_expected_name b/spec/errors/style_expected_name new file mode 100644 index 000000000..5c6349bb6 --- /dev/null +++ b/spec/errors/style_expected_name @@ -0,0 +1,12 @@ +component Main { + style +-------------------------------------------------------------------------------- +░ ERROR (STYLE_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a style but I found "a space" instead: + + ┌ ./spec/errors/style_expected_name:2:7 + ├────────────────────────────────────── + 1│ component Main { + 2│ style + │ ⌃⌃⌃⌃ diff --git a/spec/errors/style_expected_opening_bracket b/spec/errors/style_expected_opening_bracket new file mode 100644 index 000000000..9ecc50a08 --- /dev/null +++ b/spec/errors/style_expected_opening_bracket @@ -0,0 +1,12 @@ +component Main { + style x +-------------------------------------------------------------------------------- +░ ERROR (STYLE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a style but I found "a space" instead: + + ┌ ./spec/errors/style_expected_opening_bracket:2:9 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ style x + │ ⌃⌃⌃⌃ diff --git a/spec/errors/suite_expected_body b/spec/errors/suite_expected_body new file mode 100644 index 000000000..233856928 --- /dev/null +++ b/spec/errors/suite_expected_body @@ -0,0 +1,10 @@ +suite "X" { +-------------------------------------------------------------------------------- +░ ERROR (SUITE_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a suite but I found "a space" instead: + + ┌ ./spec/errors/suite_expected_body:1:11 + ├─────────────────────────────────────── + 1│ suite "X" { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/suite_expected_closing_bracket b/spec/errors/suite_expected_closing_bracket new file mode 100644 index 000000000..cedb961bc --- /dev/null +++ b/spec/errors/suite_expected_closing_bracket @@ -0,0 +1,16 @@ +suite "X" { + test "X" { + true + } +-------------------------------------------------------------------------------- +░ ERROR (SUITE_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a suite but I found "a space" instead: + + ┌ ./spec/errors/suite_expected_closing_bracket:4:3 + ├───────────────────────────────────────────────── + 1│ suite "X" { + 2│ test "X" { + 3│ true + 4│ } + │ ⌃⌃⌃⌃ diff --git a/spec/errors/suite_expected_name b/spec/errors/suite_expected_name new file mode 100644 index 000000000..4118ef23f --- /dev/null +++ b/spec/errors/suite_expected_name @@ -0,0 +1,10 @@ +suite +-------------------------------------------------------------------------------- +░ ERROR (SUITE_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a suite but I found "a space" instead: + + ┌ ./spec/errors/suite_expected_name:1:5 + ├────────────────────────────────────── + 1│ suite + │ ⌃⌃⌃⌃ diff --git a/spec/errors/suite_expected_opening_bracket b/spec/errors/suite_expected_opening_bracket new file mode 100644 index 000000000..d93a520a5 --- /dev/null +++ b/spec/errors/suite_expected_opening_bracket @@ -0,0 +1,10 @@ +suite "X" +-------------------------------------------------------------------------------- +░ ERROR (SUITE_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a suite but I found "a space" instead: + + ┌ ./spec/errors/suite_expected_opening_bracket:1:9 + ├───────────────────────────────────────────────── + 1│ suite "X" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/svg_directive_expected_closing_parenthesis b/spec/errors/svg_directive_expected_closing_parenthesis new file mode 100644 index 000000000..a68618f1c --- /dev/null +++ b/spec/errors/svg_directive_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @svg(path +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of an svg directive but I found "a +space" instead: + + ┌ ./spec/errors/svg_directive_expected_closing_parenthesis:3:13 + ├────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @svg(path + │ ⌃⌃⌃⌃ diff --git a/spec/errors/svg_directive_expected_dimensions b/spec/errors/svg_directive_expected_dimensions new file mode 100644 index 000000000..4a392e2ca --- /dev/null +++ b/spec/errors/svg_directive_expected_dimensions @@ -0,0 +1,29 @@ +component Main { + fun render : Html { + @svg(../fixtures/icon-no-dimensions) + } +} +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_DIMENSIONS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I need certain attributes for an svg for it to render correctly. The specified +file for an svg directive does not have these required attributes: + + width, height, viewBox + +These are the first few lines of the file: + + + + + +The svg directive in question is here: + + ┌ ./spec/errors/svg_directive_expected_dimensions:3:5 + ├──────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ @svg(../fixtures/icon-no-dimensions) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/svg_directive_expected_file b/spec/errors/svg_directive_expected_file new file mode 100644 index 000000000..55c0c6d0e --- /dev/null +++ b/spec/errors/svg_directive_expected_file @@ -0,0 +1,22 @@ +component Main { + fun render : Html { + @svg(../../fixtures/icon-missing) + } +} +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_FILE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The specified file for an svg directive does not exist: + + /home/gus/Projects/mint-lang/mint/fixtures/icon-missing + +The svg directive in question is here: + + ┌ ./spec/errors/svg_directive_expected_file:3:5 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ @svg(../../fixtures/icon-missing) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/svg_directive_expected_opening_parenthesis b/spec/errors/svg_directive_expected_opening_parenthesis new file mode 100644 index 000000000..02940fe81 --- /dev/null +++ b/spec/errors/svg_directive_expected_opening_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @svg +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_OPENING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening parenthesis of an svg directive but I found "a +space" instead: + + ┌ ./spec/errors/svg_directive_expected_opening_parenthesis:3:8 + ├───────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @svg + │ ⌃⌃⌃⌃ diff --git a/spec/errors/svg_directive_expected_path b/spec/errors/svg_directive_expected_path new file mode 100644 index 000000000..f57365574 --- /dev/null +++ b/spec/errors/svg_directive_expected_path @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @svg( +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_PATH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the path (to the svg) of an svg directive but I found "a space" +instead: + + ┌ ./spec/errors/svg_directive_expected_path:3:9 + ├────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ @svg( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/svg_directive_expected_svg b/spec/errors/svg_directive_expected_svg new file mode 100644 index 000000000..894d55364 --- /dev/null +++ b/spec/errors/svg_directive_expected_svg @@ -0,0 +1,27 @@ +component Main { + fun render : Html { + @svg(../fixtures/icon-not-svg) + } +} +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_SVG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The specified file for an svg directive is not an SVG file because I could not +parse it. These are the errors I found: + + Opening and ending tag mismatch: people line 1 and foo + +These are the first few lines of the file: + + + +The svg directive in question is here: + + ┌ ./spec/errors/svg_directive_expected_svg:3:5 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ @svg(../fixtures/icon-not-svg) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/svg_directive_expected_svg_tag b/spec/errors/svg_directive_expected_svg_tag new file mode 100644 index 000000000..d104abef3 --- /dev/null +++ b/spec/errors/svg_directive_expected_svg_tag @@ -0,0 +1,23 @@ +component Main { + fun render : Html { + @svg(../fixtures/icon-no-svg-tag) + } +} +-------------------------------------------------------------------------------- +░ ERROR (SVG_DIRECTIVE_EXPECTED_SVG_TAG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The specified file for an svg directive does not contain an tag. These are +the first few lines of the file: + + + +The svg directive in question is here: + + ┌ ./spec/errors/svg_directive_expected_svg_tag:3:5 + ├───────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ @svg(../fixtures/icon-no-svg-tag) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/test_expected_body b/spec/errors/test_expected_body new file mode 100644 index 000000000..6d5cfdd13 --- /dev/null +++ b/spec/errors/test_expected_body @@ -0,0 +1,12 @@ +suite "X" { + test "X" { +-------------------------------------------------------------------------------- +░ ERROR (TEST_EXPECTED_BODY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the body of a test but I found "a space" instead: + + ┌ ./spec/errors/test_expected_body:2:12 + ├────────────────────────────────────── + 1│ suite "X" { + 2│ test "X" { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/test_expected_closing_bracket b/spec/errors/test_expected_closing_bracket new file mode 100644 index 000000000..250aea989 --- /dev/null +++ b/spec/errors/test_expected_closing_bracket @@ -0,0 +1,14 @@ +suite "X" { + test "X" { + "" +-------------------------------------------------------------------------------- +░ ERROR (TEST_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a test but I found "a space" instead: + + ┌ ./spec/errors/test_expected_closing_bracket:3:6 + ├──────────────────────────────────────────────── + 1│ suite "X" { + 2│ test "X" { + 3│ "" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/test_expected_name b/spec/errors/test_expected_name new file mode 100644 index 000000000..98da23eb0 --- /dev/null +++ b/spec/errors/test_expected_name @@ -0,0 +1,12 @@ +suite "X" { + test +-------------------------------------------------------------------------------- +░ ERROR (TEST_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a test but I found "a space" instead: + + ┌ ./spec/errors/test_expected_name:2:6 + ├───────────────────────────────────── + 1│ suite "X" { + 2│ test + │ ⌃⌃⌃⌃ diff --git a/spec/errors/test_expected_opening_bracket b/spec/errors/test_expected_opening_bracket new file mode 100644 index 000000000..b6164255e --- /dev/null +++ b/spec/errors/test_expected_opening_bracket @@ -0,0 +1,12 @@ +suite "X" { + test "X" +-------------------------------------------------------------------------------- +░ ERROR (TEST_EXPECTED_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a test but I found "a space" instead: + + ┌ ./spec/errors/test_expected_opening_bracket:2:10 + ├───────────────────────────────────────────────── + 1│ suite "X" { + 2│ test "X" + │ ⌃⌃⌃⌃ diff --git a/spec/errors/test_type_mismatch b/spec/errors/test_type_mismatch new file mode 100644 index 000000000..bb86efe16 --- /dev/null +++ b/spec/errors/test_type_mismatch @@ -0,0 +1,29 @@ +suite "X" { + test "X" { + "true" + } +} +-------------------------------------------------------------------------------- +░ ERROR (TEST_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of a test does not match any of the allowed types. + +I was expecting one of: + + Test.Context(a) + Bool + +Instead it is: + + String + +The test in question is here: + + ┌ ./spec/errors/test_type_mismatch:3:5 + ├───────────────────────────────────── + 1│ suite "X" { + 2│ test "X" { + 3│ "true" + │ ⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/translation_mismatch b/spec/errors/translation_mismatch new file mode 100644 index 000000000..ead7e2da0 --- /dev/null +++ b/spec/errors/translation_mismatch @@ -0,0 +1,66 @@ +locale en { + test: "" +} + +locale hu { + test: 0 +} + +component Main { + fun render : String { + :test + } +} +-------------------------------------------------------------------------------- +░ ERROR (TRANSLATION_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the key "test" in the language "hu" does not match the type in +language "en". + +I was expecting: + + String + +Instead it is: + + Number + +The defined value in language "hu" is here: + + ┌ ./spec/errors/translation_mismatch:6:9 + ├─────────────────────────────────────── + 2│ test: "" + 3│ } + 4│ + 5│ locale hu { + 6│ test: 0 + │ ⌃ + 7│ } + 8│ + 9│ component Main { + 10│ fun render : String { + +The defined value in language "en" is here: + + ┌ ./spec/errors/translation_mismatch:2:9 + ├─────────────────────────────────────── + 1│ locale en { + 2│ test: "" + │ ⌃⌃ + 3│ } + 4│ + 5│ locale hu { + 6│ test: 0 + +The locale key in question is here: + + ┌ ./spec/errors/translation_mismatch:11:5 + ├──────────────────────────────────────── + 7│ } + 8│ + 9│ component Main { + 10│ fun render : String { + 11│ :test + │ ⌃⌃⌃⌃⌃ + 12│ } + 13│ } diff --git a/spec/errors/translation_missing b/spec/errors/translation_missing new file mode 100644 index 000000000..276375c3c --- /dev/null +++ b/spec/errors/translation_missing @@ -0,0 +1,18 @@ +component Main { + fun render : String { + :test + } +} +-------------------------------------------------------------------------------- +░ ERROR (TRANSLATION_MISSING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Translations are not specified for this key: + + ┌ ./spec/errors/translation_missing:3:5 + ├────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ :test + │ ⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/translation_not_translated b/spec/errors/translation_not_translated new file mode 100644 index 000000000..78d740f47 --- /dev/null +++ b/spec/errors/translation_not_translated @@ -0,0 +1,30 @@ +locale en { + test: "" +} + +locale hu { + +} + +component Main { + fun render : String { + :test + } +} +-------------------------------------------------------------------------------- +░ ERROR (TRANSLATION_NOT_TRANSLATED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +There is no translation for the key "test" in the language "hu". + +The locale key in question is here: + + ┌ ./spec/errors/translation_not_translated:11:5 + ├────────────────────────────────────────────── + 7│ } + 8│ + 9│ component Main { + 10│ fun render : String { + 11│ :test + │ ⌃⌃⌃⌃⌃ + 12│ } + 13│ } diff --git a/spec/errors/tuple_destructuring_expected_closing_parenthesis b/spec/errors/tuple_destructuring_expected_closing_parenthesis new file mode 100644 index 000000000..9b80da1ef --- /dev/null +++ b/spec/errors/tuple_destructuring_expected_closing_parenthesis @@ -0,0 +1,17 @@ +component Main { + fun render : String { + case #("a", "b") { + #(a, b, c +-------------------------------------------------------------------------------- +░ ERROR (TUPLE_DESTRUCTURING_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a tuple destructuring but I found "a +space" instead: + + ┌ ./spec/errors/tuple_destructuring_expected_closing_parenthesis:4:15 + ├──────────────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ case #("a", "b") { + 4│ #(a, b, c + │ ⌃⌃⌃⌃ diff --git a/spec/errors/tuple_literal_expected_closing_parenthesis b/spec/errors/tuple_literal_expected_closing_parenthesis new file mode 100644 index 000000000..04ba5cbaf --- /dev/null +++ b/spec/errors/tuple_literal_expected_closing_parenthesis @@ -0,0 +1,6 @@ +component Main { + fun render : String { + {""}[0] + } +} +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/spec/formatters/enum b/spec/errors/type_definition_expected_closing_bracket similarity index 52% rename from spec/formatters/enum rename to spec/errors/type_definition_expected_closing_bracket index 54ef16f12..e0ecea629 100644 --- a/spec/formatters/enum +++ b/spec/errors/type_definition_expected_closing_bracket @@ -1,7 +1,2 @@ -enumText{X Y Z} --------------------------------------------------------------------------------- -enum Text { - X - Y - Z -} +type A +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/spec/errors/type_definition_expected_closing_parenthesis b/spec/errors/type_definition_expected_closing_parenthesis new file mode 100644 index 000000000..a5b24712f --- /dev/null +++ b/spec/errors/type_definition_expected_closing_parenthesis @@ -0,0 +1,11 @@ +type A { +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a type definition but I found "a space" +instead: + + ┌ ./spec/errors/type_definition_expected_closing_parenthesis:1:8 + ├─────────────────────────────────────────────────────────────── + 1│ type A { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_definition_expected_name b/spec/errors/type_definition_expected_name new file mode 100644 index 000000000..019378281 --- /dev/null +++ b/spec/errors/type_definition_expected_name @@ -0,0 +1,10 @@ +type +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_EXPECTED_NAME) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the name of a type but I found "a space" instead: + + ┌ ./spec/errors/type_definition_expected_name:1:4 + ├──────────────────────────────────────────────── + 1│ type + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_definition_field_expected_colon b/spec/errors/type_definition_field_expected_colon new file mode 100644 index 000000000..b5fa0c608 --- /dev/null +++ b/spec/errors/type_definition_field_expected_colon @@ -0,0 +1,13 @@ +type A { + x +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_FIELD_EXPECTED_COLON) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the colon separating a type field from the type but I found "a +space" instead: + + ┌ ./spec/errors/type_definition_field_expected_colon:2:3 + ├─────────────────────────────────────────────────────── + 1│ type A { + 2│ x + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_definition_field_expected_mapping b/spec/errors/type_definition_field_expected_mapping new file mode 100644 index 000000000..7430bd85e --- /dev/null +++ b/spec/errors/type_definition_field_expected_mapping @@ -0,0 +1,12 @@ +type A { + x: String using +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_FIELD_EXPECTED_MAPPING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the mapping of a record field but I found "a space" instead: + + ┌ ./spec/errors/type_definition_field_expected_mapping:2:17 + ├────────────────────────────────────────────────────────── + 1│ type A { + 2│ x: String using + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_definition_field_expected_type b/spec/errors/type_definition_field_expected_type new file mode 100644 index 000000000..f6a940d0a --- /dev/null +++ b/spec/errors/type_definition_field_expected_type @@ -0,0 +1,12 @@ +type A { + x: +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_FIELD_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of a type field but I found "a space" instead: + + ┌ ./spec/errors/type_definition_field_expected_type:2:4 + ├────────────────────────────────────────────────────── + 1│ type A { + 2│ x: + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_definition_not_defined_parameter b/spec/errors/type_definition_not_defined_parameter new file mode 100644 index 000000000..48cf097de --- /dev/null +++ b/spec/errors/type_definition_not_defined_parameter @@ -0,0 +1,15 @@ +enum A { + B(a) +} +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_NOT_DEFINED_PARAMETER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Parameters used by options must be defined in the the type definition. This +parameter was not defined in the type definition: + + ┌ ./spec/errors/type_definition_not_defined_parameter:2:5 + ├──────────────────────────────────────────────────────── + 1│ enum A { + 2│ B(a) + │ ⌃ + 3│ } diff --git a/spec/errors/type_definition_unused_parameter b/spec/errors/type_definition_unused_parameter new file mode 100644 index 000000000..9c3ee2d9c --- /dev/null +++ b/spec/errors/type_definition_unused_parameter @@ -0,0 +1,17 @@ +enum A(a, b, c) { + B + C +} +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DEFINITION_UNUSED_PARAMETER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +Type parameters must be used by at least one option. This parameter was not used +by any of the options: + + ┌ ./spec/errors/type_definition_unused_parameter:1:8 + ├─────────────────────────────────────────────────── + 1│ enum A(a, b, c) { + │ ⌃ + 2│ B + 3│ C + 4│ } diff --git a/spec/errors/type_destructuring_expected_closing_parenthesis b/spec/errors/type_destructuring_expected_closing_parenthesis new file mode 100644 index 000000000..8cc5d0332 --- /dev/null +++ b/spec/errors/type_destructuring_expected_closing_parenthesis @@ -0,0 +1,18 @@ +module Test { + fun toString (status : Status) : String { + case (status) { + A::B( +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DESTRUCTURING_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of an type destructuring but I found "a +space" instead: + + ┌ ./spec/errors/type_destructuring_expected_closing_parenthesis:4:11 + ├─────────────────────────────────────────────────────────────────── + 1│ module Test { + 2│ fun toString (status : Status) : String { + 3│ case (status) { + 4│ A::B( + │ ⌃⌃⌃⌃ + diff --git a/spec/errors/type_destructuring_expected_variant b/spec/errors/type_destructuring_expected_variant new file mode 100644 index 000000000..174e2ac2c --- /dev/null +++ b/spec/errors/type_destructuring_expected_variant @@ -0,0 +1,16 @@ +module Test { + fun toString (status : Status) : String { + case (status) { + A:: +-------------------------------------------------------------------------------- +░ ERROR (TYPE_DESTRUCTURING_EXPECTED_VARIANT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of an type destructuring but I found "a space" instead: + + ┌ ./spec/errors/type_destructuring_expected_variant:4:9 + ├────────────────────────────────────────────────────── + 1│ module Test { + 2│ fun toString (status : Status) : String { + 3│ case (status) { + 4│ A:: + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_expected_closing_parenthesis b/spec/errors/type_expected_closing_parenthesis new file mode 100644 index 000000000..243406bf6 --- /dev/null +++ b/spec/errors/type_expected_closing_parenthesis @@ -0,0 +1,12 @@ +component Main { + fun render : X(Y +-------------------------------------------------------------------------------- +░ ERROR (TYPE_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of a type but I found "a space" instead: + + ┌ ./spec/errors/type_expected_closing_parenthesis:2:18 + ├───────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : X(Y + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_expected_type_or_type_variable b/spec/errors/type_expected_type_or_type_variable new file mode 100644 index 000000000..ae24987e2 --- /dev/null +++ b/spec/errors/type_expected_type_or_type_variable @@ -0,0 +1,12 @@ +component Main { + fun render : X( +-------------------------------------------------------------------------------- +░ ERROR (TYPE_EXPECTED_TYPE_OR_TYPE_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting a type or a type variable but I found "a space" instead: + + ┌ ./spec/errors/type_expected_type_or_type_variable:2:17 + ├─────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : X( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_variant_expected_closing_parenthesis b/spec/errors/type_variant_expected_closing_parenthesis new file mode 100644 index 000000000..5b4a61d6b --- /dev/null +++ b/spec/errors/type_variant_expected_closing_parenthesis @@ -0,0 +1,13 @@ +enum Test { + A( +-------------------------------------------------------------------------------- +░ ERROR (TYPE_VARIANT_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parenthesis of an type variant but I found "a space" +instead: + + ┌ ./spec/errors/type_variant_expected_closing_parenthesis:2:4 + ├──────────────────────────────────────────────────────────── + 1│ enum Test { + 2│ A( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/unary_minus_not_number b/spec/errors/unary_minus_not_number new file mode 100644 index 000000000..e62a14ca5 --- /dev/null +++ b/spec/errors/unary_minus_not_number @@ -0,0 +1,26 @@ +component Main { + fun render : String { + -"ASD" + + "" + } +} +-------------------------------------------------------------------------------- +░ ERROR (UNARY_MINUS_NOT_NUMBER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +An unary minuses expression must evaluate to number. Instead it is: + + String + +The unary minus in question is here: + + ┌ ./spec/errors/unary_minus_not_number:3:5 + ├───────────────────────────────────────── + 1│ component Main { + 2│ fun render : String { + 3│ -"ASD" + │ ⌃⌃⌃⌃⌃⌃ + 4│ + 5│ "" + 6│ } + 7│ } diff --git a/spec/errors/use_condition_mismatch b/spec/errors/use_condition_mismatch new file mode 100644 index 000000000..92c136947 --- /dev/null +++ b/spec/errors/use_condition_mismatch @@ -0,0 +1,45 @@ +record Provider.Data { + a : String, + b : String +} + +provider Provider : Provider.Data { + fun attach : Void { + void + } +} + +component Main { + use Provider { + a: "Hello", + b: "Blah" + } when { + "asd" + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (USE_CONDITION_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The expression of the where condition must evaluate to a boolean value. Instead +it is: + + String + +The condition in question is here: + + ┌ ./spec/errors/use_condition_mismatch:17:5 + ├────────────────────────────────────────── + 13│ use Provider { + 14│ a: "Hello", + 15│ b: "Blah" + 16│ } when { + 17│ "asd" + │ ⌃⌃⌃⌃⌃ + 18│ } + 19│ + 20│ fun render : Html { + 21│
diff --git a/spec/errors/use_expected_condition b/spec/errors/use_expected_condition new file mode 100644 index 000000000..5018a77d9 --- /dev/null +++ b/spec/errors/use_expected_condition @@ -0,0 +1,12 @@ +component Main { + use A { a: "" } when { +-------------------------------------------------------------------------------- +░ ERROR (USE_EXPECTED_CONDITION) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the condition of a use but I found "a space" instead: + + ┌ ./spec/errors/use_expected_condition:2:24 + ├────────────────────────────────────────── + 1│ component Main { + 2│ use A { a: "" } when { + │ ⌃⌃⌃⌃ diff --git a/spec/errors/use_expected_condition_closing_bracket b/spec/errors/use_expected_condition_closing_bracket new file mode 100644 index 000000000..a9f273c35 --- /dev/null +++ b/spec/errors/use_expected_condition_closing_bracket @@ -0,0 +1,13 @@ +component Main { + use A { a: "" } when { true +-------------------------------------------------------------------------------- +░ ERROR (USE_EXPECTED_CONDITION_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing bracket of a use condition but I found "a space" +instead: + + ┌ ./spec/errors/use_expected_condition_closing_bracket:2:29 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ use A { a: "" } when { true + │ ⌃⌃⌃⌃ diff --git a/spec/errors/use_expected_condition_opening_bracket b/spec/errors/use_expected_condition_opening_bracket new file mode 100644 index 000000000..57ffdb9eb --- /dev/null +++ b/spec/errors/use_expected_condition_opening_bracket @@ -0,0 +1,13 @@ +component Main { + use A { a: "" } when +-------------------------------------------------------------------------------- +░ ERROR (USE_EXPECTED_CONDITION_OPENING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening bracket of a use condition but I found "a space" +instead: + + ┌ ./spec/errors/use_expected_condition_opening_bracket:2:22 + ├────────────────────────────────────────────────────────── + 1│ component Main { + 2│ use A { a: "" } when + │ ⌃⌃⌃⌃ diff --git a/spec/errors/use_expected_provider b/spec/errors/use_expected_provider new file mode 100644 index 000000000..62d30c6c5 --- /dev/null +++ b/spec/errors/use_expected_provider @@ -0,0 +1,12 @@ +component Main { + use +-------------------------------------------------------------------------------- +░ ERROR (USE_EXPECTED_PROVIDER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the provider of a use but I found "a space" instead: + + ┌ ./spec/errors/use_expected_provider:2:5 + ├──────────────────────────────────────── + 1│ component Main { + 2│ use + │ ⌃⌃⌃⌃ diff --git a/spec/errors/use_expected_record b/spec/errors/use_expected_record new file mode 100644 index 000000000..77734c64b --- /dev/null +++ b/spec/errors/use_expected_record @@ -0,0 +1,12 @@ +component Main { + use A +-------------------------------------------------------------------------------- +░ ERROR (USE_EXPECTED_RECORD) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the record of a use but I found "a space" instead: + + ┌ ./spec/errors/use_expected_record:2:7 + ├────────────────────────────────────── + 1│ component Main { + 2│ use A + │ ⌃⌃⌃⌃ diff --git a/spec/errors/use_not_found_provider b/spec/errors/use_not_found_provider new file mode 100644 index 000000000..1c9e76561 --- /dev/null +++ b/spec/errors/use_not_found_provider @@ -0,0 +1,26 @@ +component Main { + use Provider { + a: "Hello", + b: "Blah" + } when { + true + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (USE_NOT_FOUND_PROVIDER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I could not find a provider: + + ┌ ./spec/errors/use_not_found_provider:2:7 + ├───────────────────────────────────────── + 1│ component Main { + 2│ use Provider { + │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ a: "Hello", + 4│ b: "Blah" + 5│ } when { + 6│ true diff --git a/spec/errors/use_subscription_mismatch b/spec/errors/use_subscription_mismatch new file mode 100644 index 000000000..9658bef43 --- /dev/null +++ b/spec/errors/use_subscription_mismatch @@ -0,0 +1,61 @@ +record Provider.Data { + a : String, + b : Bool +} + +record Test { + a : String, + b : String +} + +provider Provider : Provider.Data { + fun attach : Void { + void + } +} + +component Main { + use Provider { + a: "Hello", + b: "Blah" + } when { + true + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (USE_SUBSCRIPTION_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The subsctipion of a provider does not match its definition. + +I was expecting: + + Provider.Data(a: String, b: Bool) + +Instead it is: + + Test(a: String, b: String) + +The provider in question is here: + + ┌ ./spec/errors/use_subscription_mismatch:18:3 + ├───────────────────────────────────────────── + 14│ } + 15│ } + 16│ + 17│ component Main { + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 18│ use Provider { + 19│ a: "Hello", + 20│ b: "Blah" + 21│ } when { + 22│ true + 23│ } + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 24│ + 25│ fun render : Html { + 26│
+ 27│ } diff --git a/spec/errors/variable_missing b/spec/errors/variable_missing new file mode 100644 index 000000000..afc24537f --- /dev/null +++ b/spec/errors/variable_missing @@ -0,0 +1,30 @@ +module Test { + fun b : Function(String) { + XTest.a + } +} + +component Main { + fun render : String { + Test.b() + } +} +-------------------------------------------------------------------------------- +░ ERROR (VARIABLE_MISSING) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I can't find the entity with the name: + + XTest + +Here is where it is referenced: + + ┌ ./spec/errors/variable_missing:3:5 + ├─────────────────────────────────── + 1│ module Test { + 2│ fun b : Function(String) { + 3│ XTest.a + │ ⌃⌃⌃⌃⌃ + 4│ } + 5│ } + 6│ + 7│ component Main { diff --git a/spec/errors/variable_reserved b/spec/errors/variable_reserved new file mode 100644 index 000000000..ffdca7dc6 --- /dev/null +++ b/spec/errors/variable_reserved @@ -0,0 +1,24 @@ +component Main { + fun b(default : String) : String { + default + } + + fun render : Html { + b("") + } +} +-------------------------------------------------------------------------------- +░ ERROR (VARIABLE_RESERVED) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +This name for a variable is a reserved word please use something else: + + ┌ ./spec/errors/variable_reserved:3:5 + ├──────────────────────────────────── + 1│ component Main { + 2│ fun b(default : String) : String { + 3│ default + │ ⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ + 6│ fun render : Html { + 7│ b("") diff --git a/spec/errors_spec.cr b/spec/errors_spec.cr new file mode 100644 index 000000000..6f616712a --- /dev/null +++ b/spec/errors_spec.cr @@ -0,0 +1,25 @@ +require "./spec_helper" + +Dir + .glob("./spec/errors/**/*") + .select! { |file| File.file?(file) } + .sort! + .each do |file| + it file do + # Read and separate source from expected + source, expected = File.read(file).split("-" * 80) + + begin + # Parse the source + ast = Mint::Parser.parse(source.strip, file) + ast.class.should eq(Mint::Ast) + + Mint::TypeChecker.check(ast) + rescue error : Mint::Error + result = + error.to_terminal.to_s.uncolorize + + fail diff(expected, result) unless result == expected.strip + end + end + end diff --git a/spec/examples/access b/spec/examples/access new file mode 100644 index 000000000..b3cdd33e0 --- /dev/null +++ b/spec/examples/access @@ -0,0 +1,157 @@ +----------------------------------------------------------access_expected_field +component Main { + fun render : String { + "". +----------------------------------------------------------access_expected_field +component Main { + fun render { + A:: +---------------------------------------------------------access_field_not_found +record Blah { + blah : String +} + +component Main { + fun render : Bool { + let blah = + { blah: "Hello" } + + blah.blaha + } +} +--------------------------------------------------------------access_not_record +component Main { + fun render : Bool { + let blah = "" + + blah.blah.blah + } +} +--------------------------------------------------------------access_not_record +record Blah { + blah : String +} + +component Main { + fun render : Bool { + let blah = + { blah: "Blah" } + + blah.blah.blah + } +} +----------------------------------------------------------access_expected_field +component Main { + fun render : String { + A. +--------------------------------------------------------------access_not_record +module Test { + fun b : Function(String) { + Test.a + } +} + +component Main { + fun render : String { + Test.b() + } +} +---------------------------------------------------------------variable_missing +module Test { + fun b : Function(String) { + XTest.a + } +} + +component Main { + fun render : String { + Test.b() + } +} +------------------------------------------------------------------------------- +record Blah1 { + blah : String +} + +record Blah { + blah : Blah1 +} + +component Main { + fun render : String { + let blah = + { blah: { blah: "Helllo" } } + + blah.blah.blah + } +} +------------------------------------------------------------------------------- +module Test { + fun a : String { + "Hello" + } + + fun b : Function(String) { + Test.a + } +} + +component Main { + fun render : String { + let x = + Test.b() + + x() + } +} +------------------------------------------------------------------------------- +store Test { + get a : String { + "Hello" + } + + fun b : String { + Test.a + } +} +------------------------------------------------------------------------------- +record Test { + test : String +} + +provider Test : Test { + fun print (a : String) : String { + a + } +} + +component Main { + use Test { + test: "" + } + + fun render : String { + Test.print("x") + } +} +------------------------------------------------------------------------------- +record Test { + test : String +} + +provider Test : Test { + fun print (a : String) : String { + a + } +} + +component Main { + use Test { + test: "" + } + + fun render : String { + Test.subscriptions + Test.print("a") + } +} diff --git a/spec/type_checking/access_call b/spec/examples/access_call similarity index 100% rename from spec/type_checking/access_call rename to spec/examples/access_call diff --git a/spec/examples/argument b/spec/examples/argument new file mode 100644 index 000000000..fad73a51a --- /dev/null +++ b/spec/examples/argument @@ -0,0 +1,41 @@ +--------------------------------------------------------argument_expected_colon +component Main { + fun render (a +---------------------------------------------------------argument_expected_type +component Main { + fun render (a : +------------------------------------------------argument_expected_default_value +component Main { + fun render (a : String = +------------------------------------------------------------------------------- +component Main { + fun test (a : String) : String { + a + } + + fun render : String { + test("") + } +} +------------------------------------------------------------------------------- +component Main { + fun test (a : String = "Hello") : String { + a + } + + fun render : String { + test() + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + let test = + (a : String = "Hello") : String { + a + } + + test() + } +} + diff --git a/spec/type_checking/array_access b/spec/examples/array_access similarity index 55% rename from spec/type_checking/array_access rename to spec/examples/array_access index 7ad4fc17f..300379e51 100644 --- a/spec/type_checking/array_access +++ b/spec/examples/array_access @@ -1,17 +1,12 @@ +----------------------------------------------------array_access_expected_index component Main { - fun test : Maybe(String) { - [ - "Hello", - "Blah", - "Joe" - ][1] - } - fun render : String { - "" - } -} --------------------------------------------------------ArrayAccessIndexNotNumber + array[ +------------------------------------------array_access_expected_closing_bracket +component Main { + fun render : String { + array[0 +--------------------------------------------------array_access_index_not_number component Main { fun test : Maybe(String) { [ @@ -27,7 +22,7 @@ component Main {
} } ------------------------------------------------------------ArrayAccessNotAnArray +------------------------------------------------------array_access_not_an_array component Main { fun test : Maybe(String) { {}[0] @@ -39,10 +34,10 @@ component Main {
} } --------------------------------------------------------------------------------- +-----------------------------------------------------array_access_invalid_tuple component Main { - fun test : String { - {"Hello"}[0] + fun test : Maybe(String) { + {"Hello"}[1] } fun render : Html { @@ -51,10 +46,24 @@ component Main {
} } ----------------------------------------------------------ArrayAccessInvalidTuple +------------------------------------------------------------------------------- component Main { fun test : Maybe(String) { - {"Hello"}[1] + [ + "Hello", + "Blah", + "Joe" + ][1] + } + + fun render : String { + "" + } +} +-------------------------------------------------------------------------------- +component Main { + fun test : String { + {"Hello"}[0] } fun render : Html { diff --git a/spec/examples/array_destructuring b/spec/examples/array_destructuring new file mode 100644 index 000000000..ce1d421a0 --- /dev/null +++ b/spec/examples/array_destructuring @@ -0,0 +1,4 @@ +-----------------------------------array_destructuring_expected_closing_bracket +component Main { + fun render : String { + let [x diff --git a/spec/type_checking/array_literal b/spec/examples/array_literal similarity index 53% rename from spec/type_checking/array_literal rename to spec/examples/array_literal index 6981706b6..a22bdd787 100644 --- a/spec/type_checking/array_literal +++ b/spec/examples/array_literal @@ -1,8 +1,17 @@ +-------------------------------------------------array_expected_closing_bracket +component Main { + fun render : Array(String) { + ["A" +------------------------------------------------array_expected_type_or_variable +component Main { + fun render : Array(String) { + [] of +--------------------------------------------------------------array_not_matches component Main { fun test : Array(String) { [ "Hello", - "Blah", + true, "Joe" ] } @@ -13,14 +22,13 @@ component Main {
} } ------------------------------------------------------------------ArrayNotMatches +-------------------------------------------------array_not_matches_defined_type component Main { fun test : Array(String) { [ "Hello", - true, "Joe" - ] + ] of Number } fun render : Html { @@ -29,13 +37,14 @@ component Main {
} } -------------------------------------------------------ArrayNotMatchesDefinedType +------------------------------------------------------------------------------- component Main { fun test : Array(String) { [ "Hello", + "Blah", "Joe" - ] of Number + ] } fun render : Html { diff --git a/spec/examples/bool_literal b/spec/examples/bool_literal new file mode 100644 index 000000000..63a215894 --- /dev/null +++ b/spec/examples/bool_literal @@ -0,0 +1,19 @@ +component Main { + fun render : String { + if (true) { + "" + } else { + "" + } + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + if (false) { + "" + } else { + "" + } + } +} diff --git a/spec/examples/call b/spec/examples/call new file mode 100644 index 000000000..d9dd653d0 --- /dev/null +++ b/spec/examples/call @@ -0,0 +1,224 @@ +----------------------------------------------call_expected_closing_parenthesis +component Main { + fun render : String { + test("A" +------------------------------------------------------------call_not_a_function +component Main { + state x : String = "" + + fun b : String { + x() + } + + fun render : Html { + b() + +
+ } +} +----------------------------------------------------call_argument_type_mismatch +component Main { + fun a (input : String) : String { + input + } + + fun b : String { + a(0) + } + + fun render : Html { + b() + +
+ } +} +----------------------------------------------------call_argument_type_mismatch +enum A { + B(String) + C +} + +component Main { + fun render : String { + case (A::B(0)) { + => "" + } + } +} +----------------------------------------------------call_argument_size_mismatch +component Main { + fun a (input : String) : String { + input + } + + fun b : String { + a("Hello", "There") + } + + fun render : Html { + b() + +
+ } +} +------------------------------------------------------call_with_mixed_arguments +component Main { + fun test (argument1 : String, argument2: Number) : Html { +
+ } + + fun render : Html { + test(0, argument1: "") + } +} +------------------------------------------------------call_with_mixed_arguments +component Main { + fun test (argument1 : String, argument2: Number) : Html { +
+ } + + fun render : Html { + test(argument2: 0, "") + } +} +--------------------------------------------------------call_not_found_argument +component Main { + fun test (argument1 : String, argument2: Number) : Html { +
+ } + + fun render : Html { + test(argument3: 0, argument1: "") + } +} +----------------------------------------------------call_argument_type_mismatch +module Test { + fun a (value : String, x : Bool) : String { + value + } + + fun b : String { + Test.a("test", "z") + } +} + +component Main { + fun render : String { + Test.b() + } +} +----------------------------------------------------call_argument_type_mismatch +module Test { + fun a (value : a, x : a) : String { + value + } + + fun b : String { + Test.a("test", 0) + } +} + +component Main { + fun render : String { + Test.b() + } +} +----------------------------------------------------call_argument_type_mismatch +record Test { + test : String +} + +component Main { + fun render : String { + .asd({test: "Hello"}) + } +} +------------------------------------------------------------call_not_a_function +component Main { + const A = "a" + + fun render : Html { + let a = + A("A is a String constant, but calling it like a function compiles") + +
+ <{ a }> +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun a : String { + "Hello" + } + + fun b : String { + a() + } + + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun test (argument1 : String, argument2: Number) : Html { +
+ } + + fun render : Html { + test(argument2: 0, argument1: "") + } +} +------------------------------------------------------------------------------- +module Test { + fun a (x : Bool, value : String) : String { + value + } + + fun b : String { + true + |> Test.a("test") + } +} + +component Main { + fun render : String { + Test.b() + } +} +------------------------------------------------------------------------------- +global component Test { + fun b : String { + "" + } + + fun render : Html { +
+ } +} + +component Main { + fun render : String { + Test.b() + } +} +------------------------------------------------------------------------------- +store Test { + fun set : Promise(Void) { + next {} + } +} + +component Main { + fun render : Html { + Test.set() +
+ } +} + +routes { + / { + Test.set() + } +} diff --git a/spec/examples/case b/spec/examples/case new file mode 100644 index 000000000..1f7454ac5 --- /dev/null +++ b/spec/examples/case @@ -0,0 +1,104 @@ +--------------------------------------------------------case_expected_condition +component Main { + fun render : String { + case +----------------------------------------------case_expected_closing_parenthesis +component Main { + fun render : String { + case ("a" +--------------------------------------------------case_expected_opening_bracket +component Main { + fun render : String { + case ("a") +---------------------------------------------------------case_expected_branches +component Main { + fun render : String { + case ("a") { +--------------------------------------------------case_expected_closing_bracket +component Main { + fun render : String { + case ("a") { + => "a" +------------------------------------------------case_branch_expected_expression +component Main { + fun render : String { + case ("a") { + => +--------------------------------------------------------case_branch_not_matches +component Main { + fun render : String { + case ("x") { + "a" => "a" + "b" => true + => "c" + } + } +} +-----------------------------------------------------------case_unnecessary_all +enum A { + B + C +} + +component Main { + fun render : String { + case (A::B) { + A::B => "a" + A::C => "c" + => "x" + } + } +} +---------------------------------------------------------------case_not_covered +component Main { + fun render : String { + case ("a") { + "a" => "a" + } + } +} +----------------------------------------------------------case_type_not_covered +enum A { + B + C + D +} + +component Main { + fun render : String { + case (A::B) { + A::B => "a" + A::C => "c" + } + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + case ("x") { + "a" => "a" + "b" => "b" + => "c" + } + } +} +------------------------------------------------------------------------------- +enum Maybe(value) { + Just(value) + Nothing +} + +component Main { + fun testCase : Maybe(Number) { + case (-1) { + -1 => Maybe::Nothing + => Maybe::Just(2) + } + } + + fun render : String { + testCase() + + "" + } +} diff --git a/spec/type_checking/case_array b/spec/examples/case_array similarity index 75% rename from spec/type_checking/case_array rename to spec/examples/case_array index f345c6eb0..9824e72fa 100644 --- a/spec/type_checking/case_array +++ b/spec/examples/case_array @@ -1,54 +1,54 @@ +-----------------------------------------------------------case_unnecessary_all component Main { fun render : String { case ([]) { + [...a] => "" [] => "" => "" } } } ---------------------------------------------------------------CaseUnnecessaryAll +---------------------------------------------------------------case_not_covered component Main { fun render : String { case ([]) { - [...a] => "" - [] => "" - => "" + [x, ...rest] => "" } } } -------------------------------------------------------------------CaseNotCovered +---------------------------------------------------------------case_not_covered component Main { fun render : String { case ([]) { [x, ...rest] => "" + [x] => "" } } } -------------------------------------------------------------------CaseNotCovered +---------------------------------------------------------------case_not_covered component Main { fun render : String { case ([]) { - [x, ...rest] => "" + [x, b, c, ...rest] => "" [x] => "" + [] => "" } } } --------------------------------------------------------------------------------- +---------------------------------------------------------------case_not_covered component Main { fun render : String { case ([]) { - [x, ...rest] => "" [] => "" } } } -------------------------------------------------------------------CaseNotCovered +------------------------------------------------------------------------------- component Main { fun render : String { case ([]) { - [x, b, c, ...rest] => "" - [x] => "" [] => "" + => "" } } } @@ -72,11 +72,13 @@ component Main { } } } -------------------------------------------------------------------CaseNotCovered +-------------------------------------------------------------------------------- component Main { fun render : String { case ([]) { + [x, ...rest] => "" [] => "" } } } + diff --git a/spec/type_checking/case_tuple b/spec/examples/case_tuple similarity index 68% rename from spec/type_checking/case_tuple rename to spec/examples/case_tuple index 16d6b89bf..cbb9e0cd9 100644 --- a/spec/type_checking/case_tuple +++ b/spec/examples/case_tuple @@ -1,25 +1,26 @@ +-----------------------------------------------------------case_unnecessary_all component Main { fun render : String { case ({"A","B"}) { - {"A","B"} => "" + {a, b} => "" => "" } } } ---------------------------------------------------------------CaseUnnecessaryAll +---------------------------------------------------------------case_not_covered component Main { fun render : String { case ({"A","B"}) { - {a, b} => "" - => "" + {"A","B"} => "" } } } -------------------------------------------------------------------CaseNotCovered +------------------------------------------------------------------------------- component Main { fun render : String { case ({"A","B"}) { {"A","B"} => "" + => "" } } } diff --git a/spec/examples/comment b/spec/examples/comment new file mode 100644 index 000000000..20a580c63 --- /dev/null +++ b/spec/examples/comment @@ -0,0 +1,4 @@ +------------------------------------------------------------------------------- +/* BLOCK COMMENT */ +------------------------------------------------------------------------------- +// LINE COMMENT diff --git a/spec/examples/component b/spec/examples/component new file mode 100644 index 000000000..bfd36a7f6 --- /dev/null +++ b/spec/examples/component @@ -0,0 +1,126 @@ +--------------------------------------------------------component_expected_name +component +---------------------------------------------component_expected_opening_bracket +component Main +--------------------------------------------------------component_expected_body +component Main { +--------------------------------------------------------component_expected_body +component Main { + /* Comment. */ +---------------------------------------------component_expected_closing_bracket +component Main { + state test : String = "" +------------------------------------------------------component_main_properties +component Main { + property name : String = "Joe" + + fun render : Html { +
+ } +} +---------------------------------------------component_render_function_mismatch +component Main { + fun render : Bool { + true + } +} +---------------------------------------------------component_no_render_function +component Main { + fun a : String { + "" + } +} +-----------------------------------------------------------entity_name_conflict +component Main { + property render : String = "" + + fun render : Bool { + true + } +} +----------------------------------------------component_reference_name_conflict +component Main { + fun render : Html { +
+
+
+ } +} +------------------------------------------component_lifecycle_function_mismatch +component Main { + fun componentDidUpdate (a : String) : String { + "" + } + + fun render : Html { +
+ } +} +------------------------------------------------component_exposed_name_conflict +store Test { + state x : String = "" +} + +component A { + connect Test exposing { x } + + get x : String { + "" + } + + fun render : Html { +
+ } +} +------------------------------------------------component_exposed_name_conflict +store Test { + state x : String = "" +} + +component A { + connect Test exposing { x as y } + + get y : String { + "" + } + + fun render : Html { +
+ } +} +-----------------------------------------------------------block_no_expressions +component Main { + fun componentDidUpdate { + // "" + } + + fun render : Html { +
"main"
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +global component Test { + fun c : String { + "" + } + + fun b : String { + c() + } + + fun render : Html { +
+ } +} + +component Main { + fun render : String { + Test.b() + } +} diff --git a/spec/examples/connect b/spec/examples/connect new file mode 100644 index 000000000..dbdc54804 --- /dev/null +++ b/spec/examples/connect @@ -0,0 +1,70 @@ +---------------------------------------------------------connect_expected_store +component Main { + connect +------------------------------------------------------connect_expected_exposing +component Main { + connect Test +-----------------------------------------------connect_expected_opening_bracket +component Main { + connect Test exposing +----------------------------------------------------------connect_expected_keys +component Main { + connect Test exposing { +-----------------------------------------------connect_expected_closing_bracket +component Main { + connect Test exposing { item +---------------------------------------------------connect_variable_expected_as +component Main { + connect Test exposing { item as +-------------------------------------------------------connect_not_found_member +store Test { + state x : String = "" +} + +component Main { + connect Test exposing { x, y } + + fun render : Html { +
+ } +} +--------------------------------------------------------connect_not_found_store +component Main { + connect Test exposing { x, y } + + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +store Test { + state x : String = "" +} + +component A { + connect Test exposing { x as y } + + get x : String { + "" + } + + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +store Test { + state x : String = "" + + fun y : String { + `hello` + } +} + +component Main { + connect Test exposing { x, y } + + fun render : Html { +
+ } +} diff --git a/spec/examples/constant b/spec/examples/constant new file mode 100644 index 000000000..c2445cc3e --- /dev/null +++ b/spec/examples/constant @@ -0,0 +1,17 @@ +---------------------------------------------------------constant_expected_name +component Main { + const +---------------------------------------------------constant_expected_equal_sign +component Main { + const TEST +---------------------------------------------------constant_expected_expression +component Main { + const TEST = +------------------------------------------------------------------------------- +component Main { + const TEST = "" + + fun render : String { + "" + } +} diff --git a/spec/type_checking/css_definition b/spec/examples/css_definition similarity index 52% rename from spec/type_checking/css_definition rename to spec/examples/css_definition index 5ca9bf6d2..569dbdae1 100644 --- a/spec/type_checking/css_definition +++ b/spec/examples/css_definition @@ -1,48 +1,69 @@ +----------------------------------------------css_definition_expected_semicolon +component Main { + style root { + background: red +---------------------------------------------------css_definition_type_mismatch component Main { style test { - color: #{"blue"}; - color: #{color}; - color: red; - color: #{0}; - top: #{top}; - } - - get color : String { - "blue" - } - - get top : Number { - 0 + color: #{true}; } fun render : Html { } } --------------------------------------------------------CssDefinitionTypeMismatch +-----------------------------------------------------css_definition_no_property component Main { style test { - color: #{true}; + colorasd: hello; } fun render : Html { } } --------------------------------------------------------------------CssNoProperty +------------------------------------------------------------------------------- component Main { style test { - colorasd: hello; + -colorasd: hello; } fun render : Html { } } --------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +component Main { + state name : String = "Joe" + + style unicode { + span::after { + content: "Here is some content; Thanks #{name}"; + } + } + + fun render { + + +
+ } +} +------------------------------------------------------------------------------- component Main { style test { - -colorasd: hello; + color: #{"blue"}; + color: #{color}; + color: red; + color: #{0}; + top: #{top}; + } + + get color : String { + "blue" + } + + get top : Number { + 0 } fun render : Html { diff --git a/spec/examples/css_font_face b/spec/examples/css_font_face new file mode 100644 index 000000000..7543a7a3d --- /dev/null +++ b/spec/examples/css_font_face @@ -0,0 +1,45 @@ +-----------------------------------------css_font_face_expected_opening_bracket +component Main { + style root { + @font-face +---------------------------------------------css_font_face_expected_definitions +component Main { + style root { + @font-face { +-----------------------------------------css_font_face_expected_closing_bracket +component Main { + style root { + @font-face { + color: red; +----------------------------------------------------css_font_face_interpolation +component Main { + style test { + @font-face { + src: url(sansation_light.woff); + font-family: #{"myFirstFont"}; + } + } + + fun render : Html { + + } +} +------------------------------------------------------------------------------- +component Main { + style test { + @font-face { + src: url(sansation_light.woff); + font-family: myFirstFont; + } + + @font-face { + src: url(sansation_light2.woff); + font-family: myFirstFont; + font-weight: bold; + } + } + + fun render : Html { + + } +} diff --git a/spec/examples/css_keyframes b/spec/examples/css_keyframes new file mode 100644 index 000000000..4592e24bd --- /dev/null +++ b/spec/examples/css_keyframes @@ -0,0 +1,37 @@ +----------------------------------------------------css_keyframes_expected_name +component Main { + style root { + @keyframes +-----------------------------------------css_keyframes_expected_opening_bracket +component Main { + style root { + @keyframes name +-----------------------------------------------css_keyframes_expected_selectors +component Main { + style root { + @keyframes name { +-----------------------------------------css_keyframes_expected_closing_bracket +component Main { + style root { + @keyframes name { + 0% { + color: red; + } +------------------------------------------------------------------------------- +component Main { + style root { + @keyframes slidein { + from { + transform: translateX(0%); + } + + to { + transform: translateX(100%); + } + } + } + + fun render : Html { + + } +} diff --git a/spec/examples/css_nested_at b/spec/examples/css_nested_at new file mode 100644 index 000000000..6c49bb3bc --- /dev/null +++ b/spec/examples/css_nested_at @@ -0,0 +1,29 @@ +-----------------------------------------------css_nested_at_expected_condition +component Main { + style root { + @media +-----------------------------------------css_nested_at_expected_opening_bracket +component Main { + style root { + @media (max-width: 100px) +----------------------------------------------------css_nested_at_expected_body +component Main { + style root { + @media (max-width: 100px) { +-----------------------------------------css_nested_at_expected_closing_bracket +component Main { + style root { + @media (max-width: 100px) { + color: red; +------------------------------------------------------------------------------- +component Main { + style root { + @media (max-width: 100px) { + color: red; + } + } + + fun render : Html { + + } +} diff --git a/spec/examples/css_selector b/spec/examples/css_selector new file mode 100644 index 000000000..b04f3d177 --- /dev/null +++ b/spec/examples/css_selector @@ -0,0 +1,41 @@ +-----------------------------------------------------css_selector_expected_body +component Main { + style root { + div { +------------------------------------------css_selector_expected_closing_bracket +component Main { + style root { + div { + color: red; +------------------------------------------------------------------------------- +component Main { + style root { + div { + color: red; + } + } + + fun render : Html { + + } +} +------------------------------------------------------------------------------- +component Main { + style test { + & div { + color: #{color}; + } + + &:focus { + color: red; + } + } + + get color : String { + "blue" + } + + fun render : Html { + + } +} diff --git a/spec/examples/decode b/spec/examples/decode new file mode 100644 index 000000000..b1f136913 --- /dev/null +++ b/spec/examples/decode @@ -0,0 +1,64 @@ +--------------------------------------------------------decode_expected_subject +component Main { + fun render : Html { + decode +-------------------------------------------------------------decode_expected_as +component Main { + fun render : Html { + decode "" +-----------------------------------------------------------decode_expected_type +component Main { + fun render : Html { + decode "" as +-----------------------------------------------------------decode_expected_type +component Main { + fun render : Html { + decode as +---------------------------------------------------------decode_expected_object +record X { + name : String +} + +component Main { + fun render : Html { + decode "" as X + +
+ } +} +------------------------------------------------------------decode_complex_type +record X { + name : Blah +} + +component Main { + fun render : Html { + decode (`{}`) as X + +
+ } +} +------------------------------------------------------------decode_complex_type +record X { + name : Maybe(Blah) +} + +component Main { + fun render : Html { + decode (`{}`) as X + +
+ } +} +------------------------------------------------------------------------------- +record X { + name : String +} + +component Main { + fun render : Html { + decode (`{}`) as X + +
+ } +} diff --git a/spec/examples/destructuring b/spec/examples/destructuring new file mode 100644 index 000000000..13cd097ed --- /dev/null +++ b/spec/examples/destructuring @@ -0,0 +1,143 @@ +----------------------------------------------------destructuring_type_mismatch +component Main { + fun render : String { + case "x" { + true => "a" + "b" => "b" + => "c" + } + } +} +-------------------------------------------------destructuring_multiple_spreads +component Main { + fun render : String { + case [] { + [...a,...b] => "a" + } + } +} +----------------------------------------------------destructuring_type_mismatch +component Main { + fun render : String { + case "" { + [...a,...b] => "a" + } + } +} +---------------------------------------------------destructuring_tuple_mismatch +component Main { + fun render : String { + case {"a", "b"} { + {a, b, c} => "a" + } + } +} +-------------------------------tuple_destructuring_expected_closing_parenthesis +component Main { + fun render : String { + case #("a", "b") { + #(a, b, c +----------------------------------------------------destructuring_type_mismatch +component Main { + fun render : String { + case ("") { + {a, b} => "a" + } + } +} +----------------------------------------------------destructuring_type_mismatch +component Main { + fun render : String { + case {"a", "b"} { + {"a", {"b"}} => "a" + } + } +} +----------------------------------------------------destructuring_type_mismatch +component Main { + fun render : String { + case {"a", "b"} { + {{a}, b} => "a" + } + } +} +----------------------------------------------------destructuring_type_mismatch +enum T { + A(String) + B +} + +component Main { + fun render : String { + if (let T::A(a) = "") { + a + } else { + "b" + } + } +} +----------------------------------------------------destructuring_type_mismatch +component Main { + fun render : String { + let {x, y, z} = "hello" + "" + } +} +---------------------------------------------------destructuring_tuple_mismatch +component Main { + fun render : String { + let {x, y, z} = {"hello", "a"} + "" + } +} +-----------------------------------------------------destructuring_type_missing +component Main { + fun render : String { + let Maybe::Just(a) = "" or return "" + "" + } +} +---------------------------------------------destructuring_type_variant_missing +enum Maybe { + Nothing +} + +component Main { + fun render : String { + let Maybe::Just(a) = "" or return "" + "" + } +} +-----------------------------------------------destructuring_type_field_missing +enum Maybe { + Just(item : String) +} + +component Main { + fun render : String { + let Maybe::Just(key) = Maybe::Just(item: "") or return "" + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + case "x" { + "a" => "a" + "b" => "b" + => "c" + } + } +} +------------------------------------------------------------------------------- +enum Maybe(a) { + Just(a) + Nothing +} + +component Main { + fun render : String { + let Just(a) = Maybe.Just("Hello") or return "" + a + } +} diff --git a/spec/examples/directives/asset b/spec/examples/directives/asset new file mode 100644 index 000000000..954fba080 --- /dev/null +++ b/spec/examples/directives/asset @@ -0,0 +1,18 @@ +-----------------------------------asset_directive_expected_opening_parenthesis +component Main { + fun render : String { + @asset +--------------------------------------------------asset_directive_expected_path +component Main { + fun render : String { + @asset( +-----------------------------------asset_directive_expected_closing_parenthesis +component Main { + fun render : String { + @asset(path +--------------------------------------------------asset_directive_expected_file +component Main { + fun render : String { + @asset(path) + } +} diff --git a/spec/examples/directives/documentation b/spec/examples/directives/documentation new file mode 100644 index 000000000..9007dbd35 --- /dev/null +++ b/spec/examples/directives/documentation @@ -0,0 +1,28 @@ +---------------------------documentation_directive_expected_opening_parenthesis +component Main { + fun render : String { + @documentation +----------------------------------------documentation_directive_expected_entity +component Main { + fun render : String { + @documentation( +---------------------------documentation_directive_expected_closing_parenthesis +component Main { + fun render : String { + @documentation(Test +---------------------------------------documentation_directive_entity_not_found +component Main { + fun render : String { + @documentation(X) + + "Hello There" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + @documentation(Main) + + "Hello There" + } +} diff --git a/spec/examples/directives/format b/spec/examples/directives/format new file mode 100644 index 000000000..34ac787e1 --- /dev/null +++ b/spec/examples/directives/format @@ -0,0 +1,23 @@ +--------------------------------------format_directive_expected_opening_bracket +component Main { + fun render : String { + @format +-------------------------------------------------format_directive_expected_body +component Main { + fun render : String { + @format { +--------------------------------------format_directive_expected_closing_bracket +component Main { + fun render : String { + @format { test +------------------------------------------------------------------------------- +component Main { + fun render : String { + let {result, formatted} = + @format { + "Hello" + } + + result + formatted + } +} diff --git a/spec/examples/directives/highlight b/spec/examples/directives/highlight new file mode 100644 index 000000000..34581f705 --- /dev/null +++ b/spec/examples/directives/highlight @@ -0,0 +1,12 @@ +-----------------------------------highlight_directive_expected_opening_bracket +component Main { + fun render : String { + @highlight +----------------------------------------------highlight_directive_expected_body +component Main { + fun render : String { + @highlight { +-----------------------------------highlight_directive_expected_closing_bracket +component Main { + fun render : String { + @highlight { test diff --git a/spec/examples/directives/inline b/spec/examples/directives/inline new file mode 100644 index 000000000..4669e82c4 --- /dev/null +++ b/spec/examples/directives/inline @@ -0,0 +1,18 @@ +----------------------------------inline_directive_expected_opening_parenthesis +component Main { + fun render : String { + @inline +-------------------------------------------------inline_directive_expected_path +component Main { + fun render : String { + @inline( +----------------------------------inline_directive_expected_closing_parenthesis +component Main { + fun render : String { + @inline(path +-------------------------------------------------inline_directive_expected_file +component Main { + fun render : String { + @inline(path) + } +} diff --git a/spec/examples/directives/svg b/spec/examples/directives/svg new file mode 100644 index 000000000..e925d91b7 --- /dev/null +++ b/spec/examples/directives/svg @@ -0,0 +1,42 @@ +-------------------------------------svg_directive_expected_opening_parenthesis +component Main { + fun render : String { + @svg +----------------------------------------------------svg_directive_expected_path +component Main { + fun render : String { + @svg( +-------------------------------------svg_directive_expected_closing_parenthesis +component Main { + fun render : String { + @svg(path +----------------------------------------------------svg_directive_expected_file +component Main { + fun render : Html { + @svg(../../fixtures/icon-missing) + } +} +-----------------------------------------------------svg_directive_expected_svg +component Main { + fun render : Html { + @svg(../../fixtures/icon-not-svg) + } +} +-------------------------------------------------svg_directive_expected_svg_tag +component Main { + fun render : Html { + @svg(../../fixtures/icon-no-svg-tag) + } +} +----------------------------------------------svg_directive_expected_dimensions +component Main { + fun render : Html { + @svg(../../fixtures/icon-no-dimensions) + } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { + @svg(../../fixtures/icon.svg) + } +} diff --git a/spec/examples/encode b/spec/examples/encode new file mode 100644 index 000000000..b08b4d8ba --- /dev/null +++ b/spec/examples/encode @@ -0,0 +1,14 @@ +-----------------------------------------------------encode_expected_expression +component Main { + fun render : Html { + encode +------------------------------------------------------------encode_complex_type +enum Maybe { + Just(String) +} + +component Main { + fun render : Html { + encode Maybe::Just("") + } +} diff --git a/spec/examples/env b/spec/examples/env new file mode 100644 index 000000000..c8c24e299 --- /dev/null +++ b/spec/examples/env @@ -0,0 +1,16 @@ +--------------------------------------------------------------env_expected_name +component Main { + fun render : String { + @ +---------------------------------------------------------env_not_found_variable +component Main { + fun render : String { + @XXX + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + @TEST + } +} diff --git a/spec/type_checking/for b/spec/examples/for_expression similarity index 53% rename from spec/type_checking/for rename to spec/examples/for_expression index 5d9706805..5e49b6142 100644 --- a/spec/type_checking/for +++ b/spec/examples/for_expression @@ -1,85 +1,111 @@ +----------------------------------------------------------------for_expected_of component Main { fun render : Array(Html) { - for (item of ["A", "B"]) { + for (a, b +-----------------------------------------------------------for_expected_subject +component Main { + fun render : Array(Html) { + for (a, b of +-----------------------------------------------for_expected_closing_parenthesis +component Main { + fun render : Array(Html) { + for (a, b of c +---------------------------------------------------for_expected_opening_bracket +component Main { + fun render : Array(Html) { + for (a, b of c) +--------------------------------------------------------------for_expected_body +component Main { + fun render : Array(Html) { + for (a, b of c) { +---------------------------------------------------for_expected_closing_bracket +component Main { + fun render : Array(Html) { + for (a, b of c) { + a +--------------------------------------------------------------for_type_mismatch +component Main { + fun render : Array(Html) { + for (item of "A") {
<{ item }>
} } } --------------------------------------------------------------------------------- +--------------------------------------------for_array_or_set_arguments_mismatch component Main { fun render : Array(Html) { - for (item, index of ["A", "B"]) { + for (item, item2, item3 of ["A", "B"]) {
<{ item }>
} } } --------------------------------------------------------------------------------- +-----------------------------------------------------for_map_arguments_mismatch component Main { + get map : Map(String, String) { + `` + } + fun render : Array(Html) { - for (key, value of `` as Map(String, String)) { + for (item of map) {
- <{ key }> + <{ item }>
} } } --------------------------------------------------------------------------------- +----------------------------------------------------for_condition_type_mismatch component Main { fun render : Array(Html) { - for (key, value, index of `` as Map(String, String)) { + for (item of ["A", "B"]) {
- <{ key }> + <{ item }>
+ } when { + item } } } ------------------------------------------------------------------ForTypeMismatch +------------------------------------------------------------------------------- component Main { fun render : Array(Html) { - for (item of "A") { + for (item of ["A", "B"]) {
<{ item }>
} } } ---------------------------------------------------ForArrayOrSetArgumentsMismatch +------------------------------------------------------------------------------- component Main { fun render : Array(Html) { - for (item, item2, item3 of ["A", "B"]) { + for (item, index of ["A", "B"]) {
<{ item }>
} } } ----------------------------------------------------------ForMapArgumentsMismatch +------------------------------------------------------------------------------- component Main { - get map : Map(String, String) { - `` - } - fun render : Array(Html) { - for (item of map) { + for (key, value of `` as Map(String, String)) {
- <{ item }> + <{ key }>
} } } ---------------------------------------------------------ForConditionTypeMismatch +------------------------------------------------------------------------------- component Main { fun render : Array(Html) { - for (item of ["A", "B"]) { + for (key, value, index of `` as Map(String, String)) {
- <{ item }> + <{ key }>
- } when { - item } } } diff --git a/spec/examples/function b/spec/examples/function new file mode 100644 index 000000000..aa36510a5 --- /dev/null +++ b/spec/examples/function @@ -0,0 +1,125 @@ +---------------------------------------------------------function_expected_name +component Main { + fun +------------------------------------------function_expected_closing_parenthesis +component Main { + fun render ( +---------------------------------------------function_expected_type_or_variable +component Main { + fun render : +----------------------------------------------function_expected_opening_bracket +component Main { + fun render +---------------------------------------------------function_expected_expression +component Main { + fun render { +----------------------------------------------function_expected_closing_bracket +component Main { + fun render { a +---------------------------------------------------------function_type_mismatch +component Main { + fun test : Bool { + "hello" + } + + fun render : String { + test() + + "" + } +} +---------------------------------------------------------function_type_mismatch +component Main { + fun test (a : String) : Bool { + a + } + + fun render : String { + "" + } +} +-----------------------------------------------------function_argument_conflict +component Main { + fun test (a : String, a : String) : Bool { + "hello" + } + + fun render : String { + test() + + "" + } +} +------------------------------------function_argument_must_have_a_default_value +component Main { + fun test (a : String = "Hello", b : String) : Number { + a + } + + fun render : String { + test() + } +} +------------------------------------function_argument_must_have_a_default_value +component Main { + fun render : String { + let test = + (a : String = "Hello", b : String) : Number { + a + } + + test() + } +} +---------------------------------------------------------function_type_mismatch +enum Maybe(value) { + Just(value) + Nothing +} + +component Main { + fun testCase : Maybe(String) { + case (-1) { + -1 => Maybe::Nothing + => Maybe::Just(2) + } + } + + fun render : String { + testCase() + + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun test : Bool { + true + } + + fun render : String { + test() + + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun test (a : Bool) : Bool { + a + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun test (a : a) : a { + a + } + + fun render : String { + "" + } +} diff --git a/spec/examples/get b/spec/examples/get new file mode 100644 index 000000000..dd06db55d --- /dev/null +++ b/spec/examples/get @@ -0,0 +1,39 @@ +--------------------------------------------------------------get_expected_name +component Main { + get +--------------------------------------------------------------get_expected_type +component Main { + get name : +---------------------------------------------------get_expected_opening_bracket +component Main { + get name +--------------------------------------------------------get_expected_expression +component Main { + get name { +---------------------------------------------------get_expected_closing_bracket +component Main { + get name { a +--------------------------------------------------------------get_type_mismatch +component Main { + get test : Number { + "asd" + } + + fun render : Html { + test() + +
+ } +} +------------------------------------------------------------------------------- +component Main { + get test : Number { + 0 + } + + fun render : Html { + test + +
+ } +} diff --git a/spec/examples/here_document b/spec/examples/here_document new file mode 100644 index 000000000..d63ac2a01 --- /dev/null +++ b/spec/examples/here_document @@ -0,0 +1,45 @@ +---------------------------------------------------here_document_expected_start +component Main { + fun render { + <<- +----------------------------------------------------------here_doc_expected_end +component Main { + fun render { + <<-TEST +-------------------------------------------here_doc_interpolation_type_mismatch +component Main { + fun render { + <<-TEST + #{<>} + TEST + } +} +-------------------------------------------here_doc_interpolation_type_mismatch +component Main { + fun render { + <<#TEST + #{void} + TEST + } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { + <<#TEST + TEST + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + <<-TEST + TEST + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + <<~TEST + TEST + } +} diff --git a/spec/examples/html_attribute b/spec/examples/html_attribute new file mode 100644 index 000000000..2be82bb3b --- /dev/null +++ b/spec/examples/html_attribute @@ -0,0 +1,190 @@ +---------------------------------------------html_attribute_expected_equal_sign +component Main { + fun render : Html { +
+ } +} +---------------------------------html_attribute_element_attribute_type_mismatch +component Main { + fun render : Html { +
+ } +} +---------------------------------html_attribute_element_attribute_type_mismatch +component Main { + fun render : Html { +
+ } +} +---------------------------------html_attribute_element_attribute_type_mismatch +component Main { + fun render : Html { +
+ } +} +---------------------------------html_attribute_element_attribute_type_mismatch +component Main { + fun render : Html { +
+ } +} +--------------------------------html_attribute_component_property_type_mismatch +component Test { + property things : Array(String) = [] + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------html_attribute_component_key_type_mismatch +component X { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +------------------------------------html_attribute_not_found_component_property +component X { + property test : String = "" + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +--------------------------------html_attribute_component_property_type_mismatch +component X { + property test : String = "" + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-----------------------------------------------------html_element_ref_forbidden +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Test { + property things : Array(String) = [] + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Test { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component X { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +------------------------------------------------------------------------------- +component X { + property test : String = "" + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +------------------------------------------------------------------------------- +component X { + property test : String = "" + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} diff --git a/spec/examples/html_component b/spec/examples/html_component new file mode 100644 index 000000000..2878a1774 --- /dev/null +++ b/spec/examples/html_component @@ -0,0 +1,75 @@ +----------------------------------------------html_component_expected_reference +component Main { + fun render : Html { + +---------------------------------------------html_component_not_found_component +component Main { + fun render : Html { + + } +} +------------------------------------------------html_component_global_component +global component X { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +----------------------------------------------html_component_attribute_required +component Test { + property name : String + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +----------------------------------html_component_reference_outside_of_component +module X { + fun render : Html { + + } +} + +component Test { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + X.render() + } +} + +------------------------------------------------------------------------------- +component Test { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} diff --git a/spec/examples/html_element b/spec/examples/html_element new file mode 100644 index 000000000..fd0d62b55 --- /dev/null +++ b/spec/examples/html_element @@ -0,0 +1,101 @@ +----------------------------------------------------html_element_expected_style +component Main { + fun render : Html { + + } +} +----------------------------------------html_element_style_outside_of_component +module X { + fun render : Html { + + } +} + +component Main { + fun render : Html { + X.render() + } +} +------------------------------------html_element_reference_outside_of_component +module X { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + X.render() + } +} +-----------------------------------------------------html_content_type_mismatch +component Main { + fun render : Html { +
<{ 0 }>
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
<{ "Hello" }>
+ } +} +------------------------------------------------------------------------------- +enum Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : Html { + case test { + Maybe::Just(item) => "" + Maybe::Nothing => "" + } + +
<{ "Hello" }>
+ } +} +------------------------------------------------------------------------------- +component Main { + style base { + color: red; + } + + fun render : Html { + +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Main { + style base { + color: red; + } + + fun render : Html { + + } +} diff --git a/spec/type_checking/html_element_string_style b/spec/examples/html_expression similarity index 56% rename from spec/type_checking/html_element_string_style rename to spec/examples/html_expression index 473b71bda..2f9ca1219 100644 --- a/spec/type_checking/html_element_string_style +++ b/spec/examples/html_expression @@ -1,14 +1,10 @@ +-------------------------------------------html_expression_expected_closing_tag component Main { fun render : Html { -
- } -} --------------------------------------------------------------------------------- + <{ +------------------------------------------------------------------------------- component Main { - style base { - } - fun render : Html { - + <{}> } } diff --git a/spec/examples/html_fragment b/spec/examples/html_fragment new file mode 100644 index 000000000..baa42f0d8 --- /dev/null +++ b/spec/examples/html_fragment @@ -0,0 +1,4 @@ +---------------------------------------------html_fragment_expected_closing_tag +component Main { + fun render : Html { + <> diff --git a/spec/examples/html_style b/spec/examples/html_style new file mode 100644 index 000000000..a5ae7364a --- /dev/null +++ b/spec/examples/html_style @@ -0,0 +1,61 @@ +----------------------------------------html_style_expected_closing_parenthesis +component Main { + fun render : Html { + + } +} +----------------------------------------------html_style_argument_size_mismatch +component Main { + style base (name : String, active : Bool) { + color: red; + } + + fun render : Html { + + } +} +----------------------------------------------html_style_argument_size_mismatch +component Main { + style base (name : String, active : Bool) { + color: red; + } + + fun render : Html { + + } +} +----------------------------------------------html_style_argument_type_mismatch +component Main { + style base (name : String, active : Bool) { + color: red; + } + + fun render : Html { + + } +} +------------------------------------------------------------------------------- +component Main { + style base { + color: red; + } + + fun render : Html { + +
+ } +} +------------------------------------------------------------------------------- +component Main { + style base (name : String, active : Bool) { + color: red; + } + + fun render : Html { + + } +} diff --git a/spec/examples/if b/spec/examples/if new file mode 100644 index 000000000..b958790ed --- /dev/null +++ b/spec/examples/if @@ -0,0 +1,145 @@ +----------------------------------------------------------if_expected_condition +component Main { + fun render : String { + if ( +------------------------------------------------if_expected_closing_parenthesis +component Main { + fun render : String { + if ("" +---------------------------------------------if_expected_truthy_opening_bracket +component Main { + fun render : String { + if ("") +--------------------------------------------------if_expected_truthy_expression +component Main { + fun render : String { + if ("") { +---------------------------------------------if_expected_truthy_closing_bracket +component Main { + fun render : String { + if ("") { a +-----------------------------------------------if_expected_else_opening_bracket +component Main { + fun render : String { + if ("") { "a" } else +----------------------------------------------------if_expected_else_expression +component Main { + fun render : String { + if ("") { "a" } else { +-----------------------------------------------if_expected_else_closing_bracket +component Main { + fun render : String { + if ("") { "a" } else { a +-----------------------------------------------------if_condition_type_mismatch +component Main { + fun render : String { + if ("a") { + "x" + } else { + "y" + } + } +} +----------------------------------------------------------if_else_type_mismatch +component Main { + fun render : String { + if ("a" == "b") { + "x" + } else { + 10 + } + } +} +----------------------------------------------------------if_else_type_mismatch +enum T { + A(String) + B(Number) +} + +component Main { + fun render : String { + if (let T::B(a) = T::B(0)) { + a + } else { + "b" + } + } +} + +------------------------------------------------------------------------------- +component Main { + fun render : String { + if ("a" == "b") { + "x" + } else { + "y" + } + } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ if ("a" == "b") { + "x" + } +
+ } +} +------------------------------------------------------------------------------- +component Main { + fun render : Html { +
+ if ("a" == "b") { + "x" + } else { + "x" + } +
+ } +} +------------------------------------------------------------------------------- +enum T { + A(String) + B +} + +component Main { + fun render : String { + if (let T::A(a) = T::A("")) { + a + } else { + "b" + } + } +} +------------------------------------------------------------------------------- +enum T { + A(String) + B +} + +component Main { + fun render : String { + if (let T::A(a) = T::B) { + a + } else { + "b" + } + } +} +------------------------------------------------------------------------------- +enum T { + A(String) + B +} + +component Main { + fun render : String { + if (let T.A(a) = T.B) { + a + } else { + "b" + } + } +} diff --git a/spec/examples/inline_function b/spec/examples/inline_function new file mode 100644 index 000000000..8a098cdf0 --- /dev/null +++ b/spec/examples/inline_function @@ -0,0 +1,46 @@ +-----------------------------------inline_function_expected_closing_parenthesis +component Main { + fun render : Html { + ( +--------------------------------------------------inline_function_expected_type +component Main { + fun render : Html { + () : +---------------------------------------inline_function_expected_opening_bracket +component Main { + fun render : Html { + () +--------------------------------------------------inline_function_expected_body +component Main { + fun render : Html { + () { +---------------------------------------inline_function_expected_closing_bracket +component Main { + fun render : Html { + () { a +--------------------------------------------------inline_function_type_mismatch +component Main { + fun test : String { + let a = + () : String { true } + + a() + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun test : String { + let a = + () : String { "Hello" } + + a() + } + + fun render : String { + "" + } +} diff --git a/spec/examples/interpolation b/spec/examples/interpolation new file mode 100644 index 000000000..0836b74d0 --- /dev/null +++ b/spec/examples/interpolation @@ -0,0 +1,14 @@ +----------------------------------------------interpolation_expected_expression +component Main { + fun render : String { + "#{ +-----------------------------------------interpolation_expected_closing_bracket +component Main { + fun render : String { + "#{a +------------------------------------------------------------------------------- +component Main { + fun render : String { + "#{"A"}" + } +} diff --git a/spec/type_checking/js b/spec/examples/js similarity index 50% rename from spec/type_checking/js rename to spec/examples/js index 5e96e7481..d5a11fd41 100644 --- a/spec/type_checking/js +++ b/spec/examples/js @@ -3,9 +3,9 @@ component Main { `"Hello"` } } -------------------------------------------------------------FunctionTypeMismatch +------------------------------------------------------------------------------- component Main { fun render : String { - `"Hello"` as Number + `"Hello"` as String } } diff --git a/spec/examples/locale b/spec/examples/locale new file mode 100644 index 000000000..ff1b8a8eb --- /dev/null +++ b/spec/examples/locale @@ -0,0 +1,58 @@ +-------------------------------------------------------locale_expected_language +locale +------------------------------------------------locale_expected_opening_bracket +locale en +------------------------------------------------locale_expected_closing_bracket +locale en { +------------------------------------------------------------------------------- +locale en { + item: "Hello", + subLevel: { + subItem: "World" + } +} +------------------------------------------------------------translation_missing +component Main { + fun render : String { + :test + } +} +-----------------------------------------------------------translation_mismatch +locale en { + test: "" +} + +locale hu { + test: 0 +} + +component Main { + fun render : String { + :test + } +} +-----------------------------------------------------translation_not_translated +locale en { + test: "" +} + +locale hu { + +} + +component Main { + fun render : String { + :test + } +} +------------------------------------------------------------------------------- +locale en { + test: "" +} + +component Main { + fun render : String { + :test + } +} + diff --git a/spec/examples/member_access b/spec/examples/member_access new file mode 100644 index 000000000..429575688 --- /dev/null +++ b/spec/examples/member_access @@ -0,0 +1,14 @@ +------------------------------------------------member_access_expected_variable +component Main { + fun render : Html { + . +------------------------------------------------------------------------------- +record Test { + test : String +} + +component Main { + fun render : String { + .test({test: "Hello"}) + } +} diff --git a/spec/examples/module b/spec/examples/module new file mode 100644 index 000000000..5c02fee46 --- /dev/null +++ b/spec/examples/module @@ -0,0 +1,63 @@ +-----------------------------------------------------------module_expected_name +module +------------------------------------------------module_expected_opening_bracket +module Test +-----------------------------------------------------------module_expected_body +module Test { + /* Comment. */ +} +------------------------------------------------module_expected_closing_bracket +module Test { + const TEST = "" +-----------------------------------------------------------entity_name_conflict +module Test { + fun hello : String { + "Hello" + } +} + +module Test { + fun hello : String { + "Overridden...." + } +} + +component Main { + fun render : String { + Test.hello() + } +} +------------------------------------------------------------------------------- +module Test { + const FIRST = "" + + fun hello : String { + "Hello" + } +} + +module Test { + const SECOND = "" + + fun greet : String { + "#{hello()} Bello" + } +} + +component Main { + fun render : String { + Test.greet() + Test:FIRST + Test:SECOND + } +} +------------------------------------------------------------------------------- +module A { + fun test : String { + "Hello" + } +} + +component Main { + fun render : String { + A.test() + } +} diff --git a/spec/examples/negated_expression b/spec/examples/negated_expression new file mode 100644 index 000000000..1235d03ad --- /dev/null +++ b/spec/examples/negated_expression @@ -0,0 +1,42 @@ +-----------------------------------------negated_expression_expected_expression +component Main { + fun render : String { + ! +----------------------------------------------------negated_expression_not_bool +module Test { + fun test : Bool { + !"asd" + } +} + +component Main { + fun render : String { + if (Test.test()) { + "Hello" + } else { + "Hello" + } + } +} +------------------------------------------------------------------------------- +module Test { + fun test : Bool { + !false + } +} + +component Main { + fun render : String { + if (Test.test()) { + "Hello" + } else { + "Hello" + } + } +} +------------------------------------------------------------------------------- +module A { + fun test : Bool { + !true && !false + } +} diff --git a/spec/examples/next_call b/spec/examples/next_call new file mode 100644 index 000000000..0890e58f2 --- /dev/null +++ b/spec/examples/next_call @@ -0,0 +1,67 @@ +------------------------------------------------------next_call_expected_fields +component Main { + fun render : String { + next a +---------------------------------------------------next_call_invalid_invocation +module Test { + fun test : Promise(Void) { + next { age: 30 } + } +} + +component Main { + fun render : Html { + let test = + Test.test() + +
+ } +} +--------------------------------------------------next_call_state_type_mismatch +component Main { + state name : String = "Joe" + + fun render : Html { + next { name: 30 } + +
+ } +} +------------------------------------------------------next_call_state_not_found +component Main { + state name : String = "Joe" + + fun render : Html { + next { age: 30 } + +
+ } +} +------------------------------------------------------next_call_state_not_found +store Test { + state a : String = "" + + fun b : Promise(Never, Void) { + next { b: "Blah" } + } +} + +component Main { + connect Test exposing { a, b } +} +------------------------------------------------------------------------------- +component Main { + state name : String = "Joe" + state age : Number = 24 + + fun test : Promise(Void) { + next { + name: "Hello", + age: 30 + } + } + + fun render : Html { +
+ } +} diff --git a/spec/examples/number_literal b/spec/examples/number_literal new file mode 100644 index 000000000..b2b44ce5a --- /dev/null +++ b/spec/examples/number_literal @@ -0,0 +1,14 @@ +------------------------------------------------number_literal_expected_decimal +component Main { + fun render : String { + 0. +------------------------------------------------------------------------------- +component Main { + fun test : Number { + 0 + } + + fun render : String { + "" + } +} diff --git a/spec/examples/operation b/spec/examples/operation new file mode 100644 index 000000000..158eeabed --- /dev/null +++ b/spec/examples/operation @@ -0,0 +1,142 @@ +--------------------------------------------------operation_expected_expression +component Main { + fun render : String { + "A" + +------------------------------------------------operation_numeric_type_mismatch +component Main { + fun test : Number { + "Hello" * 0 + } + + fun render : String { + "" + } +} +------------------------------------------------operation_numeric_type_mismatch +component Main { + fun test : Number { + 0 * "Hello" + } + + fun render : String { + "" + } +} +------------------------------------------------operation_numeric_type_mismatch +component Main { + fun test : Number { + "Blah" * "Hello" + } + + fun render : String { + "" + } +} +---------------------------------------------------operation_plus_type_mismatch +component Main { + fun render : String { + "Hello" + void + } +} +---------------------------------------------------operation_plus_type_mismatch +component Main { + fun render : String { + "Hello" + true + } +} +---------------------------------------------------operation_plus_type_mismatch +component Main { + fun render : String { + true + "Hello" + } +} + +-----------------------------------------------------operation_or_type_mismatch +enum Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : String { + Maybe::Just(0) or "Hello" + } +} +-----------------------------------------------operation_or_not_maybe_or_result +enum Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : String { + 0 or "Hello" + } +} +-------------------------------------------------------operation_pipe_ambiguous +component Main { + fun toString(value : Number) : String { + "" + } + + fun render : String { + "" + 0 |> toString + "" + 0 |> toString + } +} +------------------------------------------------operation_numeric_type_mismatch +module Test { + fun test1 : a { + "I'm a String" + } + + fun test2 : a { + 123 + } + + fun test3 : a { + [4, 5, 6, 7] + } + + fun test4 : String { + test1() * test2() * test3() + + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + 0 * 10 + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + "Hello" == "There" + "" + } +} +------------------------------------------------------------------------------- +enum Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : String { + Maybe::Nothing or "Hello" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + "A" + "B" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + "Hello" + "There" + } +} diff --git a/spec/examples/parenthesized_expression b/spec/examples/parenthesized_expression new file mode 100644 index 000000000..e3ae9b675 --- /dev/null +++ b/spec/examples/parenthesized_expression @@ -0,0 +1,6 @@ +------------------------------------------------------------------------------- +component Main { + fun render : String { + ("") + } +} diff --git a/spec/type_checking/pipe b/spec/examples/pipe similarity index 76% rename from spec/type_checking/pipe rename to spec/examples/pipe index b9ab8edbb..fde55e7fd 100644 --- a/spec/type_checking/pipe +++ b/spec/examples/pipe @@ -1,9 +1,4 @@ -module Test { - fun pipe (value : String) : String { - value - } -} - +------------------------------------------------------------call_not_a_function component Main { fun test (value : String) : String { value @@ -11,31 +6,37 @@ component Main { fun render : String { "Hello" - |> test - |> Test.pipe() - |> Test.pipe - |> (value : String) : String { value } + |> "B" } } -----------------------------------------------------------------CallNotAFunction +----------------------------------------------------call_argument_size_mismatch component Main { - fun test (value : String) : String { - value + fun test : String { + "X" } fun render : String { "Hello" - |> "B" + |> test + } +} +------------------------------------------------------------------------------- +module Test { + fun pipe (value : String) : String { + value } } ---------------------------------------------------------CallArgumentSizeMismatch + component Main { - fun test : String { - "X" + fun test (value : String) : String { + value } fun render : String { "Hello" |> test + |> Test.pipe() + |> Test.pipe + |> (value : String) : String { value } } } diff --git a/spec/type_checking/property b/spec/examples/property similarity index 52% rename from spec/type_checking/property rename to spec/examples/property index 9510ad5f6..7e6fec593 100644 --- a/spec/type_checking/property +++ b/spec/examples/property @@ -1,17 +1,13 @@ +---------------------------------------------------------property_expected_name component Test { - property name : String = "Joe" - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} -------------------------------------------------------------PropertyTypeMismatch + property +---------------------------------------------------------property_expected_type +component Test { + property test : +------------------------------------------------property_expected_default_value +component Test { + property test = +---------------------------------------------------------property_type_mismatch component Test { property name : String = true @@ -25,7 +21,7 @@ component Main { } } -------------------------------------------------------------PropertyTypeMismatch +---------------------------------------------------------property_type_mismatch component Test { property name : Test(a) = true @@ -39,7 +35,7 @@ component Main { } } --------------------------------------------------------PropertyWithTypeVariables +---------------------------------------------------property_with_type_variables component Test { property name = [] @@ -53,7 +49,7 @@ component Main { } } -------------------------------------------------------------PropertyTypeMismatch +---------------------------------------------------------property_type_mismatch record A { a : String } @@ -71,7 +67,7 @@ component Main { } } ------------------------------------------------------PropertyTypeOrDefaultNeeded +------------------------------------------------property_type_or_default_needed component Test { property name @@ -85,11 +81,17 @@ component Main { } } ------------------------------------------------------------ComponentMainProperty -component Main { +------------------------------------------------------------------------------- +component Test { property name : String = "Joe" fun render : Html {
} } + +component Main { + fun render : Html { + + } +} diff --git a/spec/examples/provider b/spec/examples/provider new file mode 100644 index 000000000..4e09d24d4 --- /dev/null +++ b/spec/examples/provider @@ -0,0 +1,71 @@ +---------------------------------------------------------provider_expected_name +provider +-------------------------------------------------------provider_expeceted_colon +provider Test +-------------------------------------------------provider_expected_subscription +provider Test : +----------------------------------------------provider_expected_opening_bracket +provider Test : Test +---------------------------------------------------------provider_expected_body +provider Test : Test { +----------------------------------------------provider_expected_closing_bracket +provider Test : Test { + const TEST = "" +------------------------------------------------provider_not_found_subscription +provider Provider : Subscription { + fun test : Bool { + true + } +} +------------------------------------------------------------------------------- +record Subscription { + a : Bool +} + +provider Provider : Subscription { + const ONE_PLUS_ONE = 1 + 1 + const TWO = 2 + + fun test : Bool { + ONE_PLUS_ONE == TWO + } +} +------------------------------------------------------------------------------- +record Subscription { + a : Bool +} + +provider Provider : Subscription { + fun test : Bool { + subscriptions + true + } +} +------------------------------------------------------------------------------- +record Subscription { + a : Bool +} + +provider Provider : Subscription { + state observers : Array(Tuple(String, String)) = [] + + fun update { + let currentObservers = + for item of observers { + "" + } + + subscriptions + true + } +} + +component Main { + use Provider { + a: true + } + + fun render : String { + "" + } +} diff --git a/spec/examples/record b/spec/examples/record new file mode 100644 index 000000000..041adf06e --- /dev/null +++ b/spec/examples/record @@ -0,0 +1,165 @@ +--------------------------------------------------------------record_with_holes +record Test { + a : Array(a), + b : Number +} +------------------------------------record_not_found_matching_record_definition +component Main { + state data = { name: "" } + + fun render : Html { +
+ <{ data.name }> +
+ } +} +------------------------------------record_not_found_matching_record_definition +component Test { + property data = { name: "" } + + fun render : Html { +
+ <{ data.name }> +
+ } +} + +component Main { + fun render : Html { + + } +} + +------------------------------------------------------------------------------- +component Main { + fun test : Object { + encode { + a: "Hello", + b: "Blah" + } + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun test : Object { + encode { + a: "Hello", + b: { + c: "Blah" + } + } + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +record Test { + string : String +} + +component Main { + fun render : String { + { string: "" }.string + } +} +------------------------------------------------------------------------------- +record Test { + a : String, + b : Number +} + +component Main { + fun test : Test { + { + a: "Hello", + b: 0 + } + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +record A { + name : String +} + +component Main { + state data = { name: "" } + + fun render : Html { +
+ <{ data.name }> +
+ } +} +------------------------------------------------------------------------------- +record Test { + a : String, + b : Number +} + +component Main { + fun test : Test { + { + a: "Hello", + b: 0 + } + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +record Test { + a : String, + b : Number +} + +record Test2 { + a : String, + b : Number +} + +component Main { + fun test : Test { + { + a: "Hello", + b: 0 + } + } + + fun render : String { + test().a + } +} +-------------------------------------------------------------------------------- +record Test { + a : String, + b : Number +} + +record Test2 { + a : String, + b : Number +} + +component Main { + state test : Test = + { + a: "Hello", + b: 0 + } + + fun render : String { + test.a + } +} diff --git a/spec/type_checking/record_update b/spec/examples/record_update similarity index 60% rename from spec/type_checking/record_update rename to spec/examples/record_update index bf95a5a4c..3efd158c4 100644 --- a/spec/type_checking/record_update +++ b/spec/examples/record_update @@ -1,3 +1,12 @@ +--------------------------------------------------record_update_expected_fields +component Main { + get record : Record(String, Bool) { + { a | +-----------------------------------------record_update_expected_closing_bracket +component Main { + get record : Record(String, Bool) { + { a | a: "" +----------------------------------------------record_update_not_updating_record record Test { a : String, b : Number @@ -5,11 +14,7 @@ record Test { component Main { fun test : Test { - let x = - { - a: "Blah", - b: 1 - } + let x = "" { x | a: "Hello", @@ -23,7 +28,7 @@ component Main { "" } } ----------------------------------------------------RecordUpdateNotUpdatingRecord +----------------------------------------------------record_update_type_mismatch record Test { a : String, b : Number @@ -31,11 +36,15 @@ record Test { component Main { fun test : Test { - let x = "" + let x = + { + a: "Blah", + b: 0 + } { x | a: "Hello", - b: 0 + b: "Hello" } } @@ -45,7 +54,7 @@ component Main { "" } } ---------------------------------------------------------RecordUpdateTypeMismatch +----------------------------------------------------record_update_not_found_key record Test { a : String, b : Number @@ -61,7 +70,7 @@ component Main { { x | a: "Hello", - b: "Hello" + c: "Hello" } } @@ -71,7 +80,7 @@ component Main { "" } } ----------------------------------------------------------RecordUpdateNotFoundKey +------------------------------------------------------------------------------- record Test { a : String, b : Number @@ -82,12 +91,12 @@ component Main { let x = { a: "Blah", - b: 0 + b: 1 } { x | a: "Hello", - c: "Hello" + b: 0 } } @@ -97,4 +106,3 @@ component Main { "" } } - diff --git a/spec/type_checking/recursive b/spec/examples/recursion similarity index 76% rename from spec/type_checking/recursive rename to spec/examples/recursion index e14c84b53..a714f7fbe 100644 --- a/spec/type_checking/recursive +++ b/spec/examples/recursion @@ -1,13 +1,26 @@ +----------------------------------------------------------------------recursion +component Test { + property greeting : String = greeting + + fun render : Html { +
+ } +} + component Main { - fun a : Void { - void + fun render : Html { + } +} +----------------------------------------------------------------------recursion +component Main { + state greeting : String = greeting - fun render : String { - "" + fun render : Html { +
} } --------------------------------------------------------------------------------- +------------------------------------------------------------------------------- module Test { fun factorial(n : Number) : Number { let helper = (n : Number, acc : Number) : Number { diff --git a/spec/examples/regexp_literal b/spec/examples/regexp_literal new file mode 100644 index 000000000..0210b7466 --- /dev/null +++ b/spec/examples/regexp_literal @@ -0,0 +1,4 @@ +------------------------------------------regexp_literal_expected_closing_slash +component Main { + fun render : String { + /asd diff --git a/spec/type_checking/return b/spec/examples/return_call similarity index 50% rename from spec/type_checking/return rename to spec/examples/return_call index f2e9b2399..bc5838c21 100644 --- a/spec/type_checking/return +++ b/spec/examples/return_call @@ -1,3 +1,22 @@ +------------------------------------------------return_call_expected_expression +component Main { + fun render { + let x = "" or return +------------------------------------------------------------return_call_invalid +component Main { + state test : String = return "" + + fun render : String { + "" + } +} +------------------------------------------------------------return_call_invalid +component Main { + fun render : String { + "" or return "" + } +} +------------------------------------------------------------------------------- enum Test { A(String) B(String) @@ -12,13 +31,6 @@ component Main { } } ------------------------------------------------------------------------------- -component Main { - fun render : String { - return "YES" - "NO" - } -} ----------------------------------------------------------ReturnCallTypeMismatch enum Test { A(String) B(String) @@ -26,31 +38,20 @@ enum Test { component Main { fun render : String { - let Test::B(x) = - Test::A("Hello") or return 0 + let value = { + let Test::B(x) = + Test::A("Hello") or return "YES" - x - } -} ---------------------------------------------------------------ReturnCallInvalid -component Main { - state test : String = return "" + "NO" + } - fun render : String { - "" - } -} ---------------------------------------------------------------ReturnCallInvalid -component Main { - fun render : String { - "" or return "" + value } } ---------------------------------------------------------StatementReturnRequired +------------------------------------------------------------------------------- component Main { fun render : String { - let [a, b] = [] - - "" + return "YES" + "NO" } } diff --git a/spec/examples/route b/spec/examples/route new file mode 100644 index 000000000..4ab150a16 --- /dev/null +++ b/spec/examples/route @@ -0,0 +1,31 @@ +---------------------------------------------route_expected_closing_parenthesis +routes { + * ( +-------------------------------------------------route_expected_opening_bracket +routes { + * +------------------------------------------------------------route_expected_body +routes { + * { +-------------------------------------------------route_expected_closing_bracket +routes { + * { + "" +------------------------------------------------------------route_param_invalid +routes { + /:name (name : Array(String)) { + void + } +} +------------------------------------------------------------route_param_invalid +routes { + /:name (name : string) { + "Hello" + } +} +------------------------------------------------------------------------------- +routes { + /:name (name : String) { + void + } +} diff --git a/spec/examples/routes b/spec/examples/routes new file mode 100644 index 000000000..089ad222e --- /dev/null +++ b/spec/examples/routes @@ -0,0 +1,19 @@ +------------------------------------------------routes_expected_opening_bracket +routes +-----------------------------------------------------------routes_expected_body +routes { +------------------------------------------------routes_expected_closing_bracket +routes { + * { + "" + } +------------------------------------------------------------------------------- +routes { + /test { + void + } + + * { + void + } +} diff --git a/spec/type_checking/state_own_reference b/spec/examples/self_reference similarity index 57% rename from spec/type_checking/state_own_reference rename to spec/examples/self_reference index e57e884bd..443d65bd9 100644 --- a/spec/type_checking/state_own_reference +++ b/spec/examples/self_reference @@ -1,12 +1,4 @@ -component Main { - state b : String = "" - state c : String = "" - - fun render : Html { -
- } -} -------------------------------------------------------------InvalidSelfReference +---------------------------------------------------------invalid_self_reference component Main { state c : String = b state b : String = "" @@ -15,7 +7,7 @@ component Main {
} } -------------------------------------------------------------InvalidSelfReference +---------------------------------------------------------invalid_self_reference component Main { state b : String = "" state c : String = b @@ -24,7 +16,7 @@ component Main {
} } -------------------------------------------------------------InvalidSelfReference +---------------------------------------------------------invalid_self_reference component Main { state c : String = hello @@ -36,7 +28,7 @@ component Main {
} } -------------------------------------------------------------InvalidSelfReference +---------------------------------------------------------invalid_self_reference component Test { property c : String = hello @@ -54,7 +46,7 @@ component Main { } } -------------------------------------------------------------InvalidSelfReference +---------------------------------------------------------invalid_self_reference component Test { property c : String = hello() diff --git a/spec/examples/spread b/spec/examples/spread new file mode 100644 index 000000000..d50373662 --- /dev/null +++ b/spec/examples/spread @@ -0,0 +1,4 @@ +-------------------------------------------------------spread_expected_variable +component Main { + fun render : String { + let [x, ... diff --git a/spec/examples/state b/spec/examples/state new file mode 100644 index 000000000..7f4b33460 --- /dev/null +++ b/spec/examples/state @@ -0,0 +1,41 @@ +------------------------------------------------------------state_expected_name +component Main { + state +------------------------------------------------------state_expected_equal_sign +component Main { + state test +------------------------------------------------------------state_expected_type +component Main { + state test : +---------------------------------------------------state_expected_default_value +component Main { + state test = +------------------------------------------------------------state_type_mismatch +component Main { + state b : String = 0 + + fun render : Html { +
+ } +} +------------------------------------------------------------state_type_mismatch +record A { + a : String +} + +component Main { + state name : Test = { a: "Hello" } + + fun render : Html { +
+ } +} +------------------------------------------------------------------------------- +component Main { + state b : String = "Hello" + state a : Number = 0 + + fun render : Html { +
+ } +} diff --git a/spec/examples/statement b/spec/examples/statement new file mode 100644 index 000000000..16823d724 --- /dev/null +++ b/spec/examples/statement @@ -0,0 +1,35 @@ +-------------------------------------------------statement_return_type_mismatch +enum Test { + A(String) + B(String) +} + +component Main { + fun render : String { + let Test::B(x) = + Test::A("Hello") or return 0 + + x + } +} +------------------------------------------------------statement_return_required +component Main { + fun render : String { + let [a, b] = [] + + "" + } +} +----------------------------------------------------------statement_last_target +component Main { + fun render : String { + let a = "" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + let x = "hello" + "" + } +} diff --git a/spec/examples/store b/spec/examples/store new file mode 100644 index 000000000..ef512ca4a --- /dev/null +++ b/spec/examples/store @@ -0,0 +1,43 @@ +------------------------------------------------------------store_expected_name +store +-------------------------------------------------store_expected_opening_bracket +store X +------------------------------------------------------------store_expected_body +store X { +-------------------------------------------------store_expected_closing_bracket +store X { + state test : String = "" +------------------------------------------------------------------------------- +store X { + state test : String = "" +} +-----------------------------------------------------------entity_name_conflict +store Test { + fun a : String { + "" + } + + fun a : String { + "" + } +} + +component Main { + connect Test exposing { a } +} +------------------------------------------------------------------------------- +store Test { + state a : String = "" + + fun b : Promise(Void) { + next { a: "Blah" } + } +} + +component Main { + connect Test exposing { a, b } + + fun render : String { + "" + } +} diff --git a/spec/examples/string_literal b/spec/examples/string_literal new file mode 100644 index 000000000..239f041aa --- /dev/null +++ b/spec/examples/string_literal @@ -0,0 +1,46 @@ +--------------------------------------------------string_expected_closing_quote +component Main { + fun render : String { + " +---------------------------------------------------string_expected_other_string +component Main { + fun render : String { + "" \ +-------------------------------------string_literal_interpolation_type_mismatch +component Main { + fun render : String { + let name = {} + + "Hello There #{name}!" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + "Hello There" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + let name = 0 + + "Hello There #{name}!" + } +} +------------------------------------------------------------------------------- +component Main { + state name : String = "Joe" + + style unicode { + span::after { + content: "Hi" blah #{name} "Here is some content; Thanks #{name}"; + } + } + + fun render { + + +
+ } +} diff --git a/spec/examples/style b/spec/examples/style new file mode 100644 index 000000000..dff30be85 --- /dev/null +++ b/spec/examples/style @@ -0,0 +1,36 @@ +------------------------------------------------------------style_expected_name +component Main { + style +---------------------------------------------style_expected_closing_parenthesis +component Main { + style x ( +-------------------------------------------------style_expected_opening_bracket +component Main { + style x +------------------------------------------------------------style_expected_body +component Main { + style x { +-------------------------------------------------style_expected_closing_bracket +component Main { + style x { + color: red; +------------------------------------------------------------------------------- +component Main { + style x { + color: red; + } + + fun render : String { + "" + } +} +------------------------------------------------------------------------------- +component Main { + style test(name : String) { + color: #{name}; + } + + fun render : Html { + + } +} diff --git a/spec/examples/suite b/spec/examples/suite new file mode 100644 index 000000000..55d1b26d6 --- /dev/null +++ b/spec/examples/suite @@ -0,0 +1,30 @@ +------------------------------------------------------------suite_expected_name +suite +-------------------------------------------------suite_expected_opening_bracket +suite "X" +------------------------------------------------------------suite_expected_body +suite "X" { +-------------------------------------------------suite_expected_closing_bracket +suite "X" { + test "X" { + true + } +------------------------------------------------------------------------------- +suite "X" { + test "X" { + true + } +} +------------------------------------------------------------------------------- +suite "Suite" { + test "Test" { + 1 + 1 == TWO + } + + const ONE_PLUS_ONE = 1 + 1 + const TWO = 2 + + test "Test 2" { + ONE_PLUS_ONE == TWO + } +} diff --git a/spec/examples/test b/spec/examples/test new file mode 100644 index 000000000..55c7c600a --- /dev/null +++ b/spec/examples/test @@ -0,0 +1,25 @@ +-------------------------------------------------------------test_expected_name +suite "X" { + test +--------------------------------------------------test_expected_opening_bracket +suite "X" { + test "X" +-------------------------------------------------------------test_expected_body +suite "X" { + test "X" { +--------------------------------------------------test_expected_closing_bracket +suite "X" { + test "X" { + "" +-------------------------------------------------------------test_type_mismatch +suite "X" { + test "X" { + "true" + } +} +------------------------------------------------------------------------------- +suite "X" { + test "X" { + true + } +} diff --git a/spec/examples/tuple b/spec/examples/tuple new file mode 100644 index 000000000..02b7aae8c --- /dev/null +++ b/spec/examples/tuple @@ -0,0 +1,30 @@ +------------------------------------------------------------------------------- +component Main { + fun render : String { + {""}[0] + } +} +------------------------------------------------------------------------------- +component Main { + fun pipe (value : String) : String { + value + } + + fun render : String { + let x = "" + + { x |> pipe }[0] + } +} +-------------------------------------tuple_literal_expected_closing_parenthesis +component Main { + fun render : String { + #("a", "b" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + #("a", "b")[0] + } +} diff --git a/spec/examples/type b/spec/examples/type new file mode 100644 index 000000000..28a49be72 --- /dev/null +++ b/spec/examples/type @@ -0,0 +1,46 @@ +--------------------------------------------type_expected_type_or_type_variable +component Main { + fun render : X( +----------------------------------------------type_expected_closing_parenthesis +component Main { + fun render : X(Y +------------------------------------------------------------------------------- +module Test { + fun test1 : a { + "I'm a String" + } + + fun test2 : a { + "I'm a string too!" + } + + fun test4 : String { + test1() + test2() + } +} +------------------------------------------------------------------------------- +enum A { + B + C +} + +component Main { + fun render : String { + case (A::B) { + => "" + } + } +} +------------------------------------------------------------------------------- +enum A { + B + C +} + +component Main { + fun render : String { + case (A.B) { + => "" + } + } +} diff --git a/spec/examples/type_definition b/spec/examples/type_definition new file mode 100644 index 000000000..10d4c2618 --- /dev/null +++ b/spec/examples/type_definition @@ -0,0 +1,47 @@ +--------------------------------------------------type_definition_expected_name +type +------------------------------------------------------------------------------- +type A +---------------------------------------type_definition_expected_closing_bracket +type A { +-----------------------------------type_definition_expected_closing_parenthesis +type Maybe(a +---------------------------------------type_definition_expected_closing_bracket +type Maybe(a) { + Nothing +--------------------------------------------------type_definition_expected_name +enum +-----------------------------------type_definition_expected_closing_parenthesis +enum Test ( +------------------------------------------------------------------------------- +enum Test +---------------------------------------type_definition_expected_closing_bracket +enum Test { +-----------------------------------------------type_definition_unused_parameter +enum A(a, b, c) { + B + C +} +------------------------------------------type_definition_not_defined_parameter +enum A { + B(a) +} +------------------------------------------type_definition_not_defined_parameter +enum A { + B(Maybe(a)) +} +------------------------------------------------------------------------------- +enum Result(error, value) { + Error(error) + Ok(value) +} +------------------------------------------------------------------------------- +type Maybe(a) { + Nothing + Just(a) +} +------------------------------------------------------------------------------- +type User { + name: String using "name", + id: String +} diff --git a/spec/examples/type_definition_field b/spec/examples/type_definition_field new file mode 100644 index 000000000..3d78d74d7 --- /dev/null +++ b/spec/examples/type_definition_field @@ -0,0 +1,9 @@ +-----------------------------------------type_definition_field_expected_colon +type A { + x +------------------------------------------type_definition_field_expected_type +type A { + x: +---------------------------------------type_definition_field_expected_mapping +type A { + x: String using diff --git a/spec/examples/type_destructuring b/spec/examples/type_destructuring new file mode 100644 index 000000000..06c0abee1 --- /dev/null +++ b/spec/examples/type_destructuring @@ -0,0 +1,14 @@ +--------------------------------------------type_destructuring_expected_variant +module Test { + fun toString (status : Status) : String { + case (status) { + A:: + } +} +--------------------------------type_destructuring_expected_closing_parenthesis +module Test { + fun toString (status : Status) : String { + case (status) { + A::B( + } +} diff --git a/spec/examples/type_variable b/spec/examples/type_variable new file mode 100644 index 000000000..248259430 --- /dev/null +++ b/spec/examples/type_variable @@ -0,0 +1,6 @@ +------------------------------------------------------------------------------- +component Main { + fun render : a { + "" + } +} diff --git a/spec/examples/type_variant b/spec/examples/type_variant new file mode 100644 index 000000000..371a386ab --- /dev/null +++ b/spec/examples/type_variant @@ -0,0 +1,3 @@ +--------------------------------------type_variant_expected_closing_parenthesis +enum Test { + A( diff --git a/spec/examples/unary_minus b/spec/examples/unary_minus new file mode 100644 index 000000000..4ef90db9b --- /dev/null +++ b/spec/examples/unary_minus @@ -0,0 +1,16 @@ +---------------------------------------------------------unary_minus_not_number +component Main { + fun render : String { + -"ASD" + + "" + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + -(10) + + "" + } +} diff --git a/spec/type_checking/use b/spec/examples/use similarity index 51% rename from spec/type_checking/use rename to spec/examples/use index 2c03fc20c..3f926ada2 100644 --- a/spec/type_checking/use +++ b/spec/examples/use @@ -1,14 +1,19 @@ -record Provider.Data { - a : String, - b : String -} - -provider Provider : Provider.Data { - fun attach : Void { - void - } -} - +----------------------------------------------------------use_expected_provider +component Main { + use +------------------------------------------------------------use_expected_record +component Main { + use A +-----------------------------------------use_expected_condition_opening_bracket +component Main { + use A { a: "" } when +---------------------------------------------------------use_expected_condition +component Main { + use A { a: "" } when { +-----------------------------------------use_expected_condition_closing_bracket +component Main { + use A { a: "" } when { true +---------------------------------------------------------use_not_found_provider component Main { use Provider { a: "Hello", @@ -21,21 +26,37 @@ component Main {
} } --------------------------------------------------------------UseNotFoundProvider +---------------------------------------------------------use_condition_mismatch +record Provider.Data { + a : String, + b : String +} + +provider Provider : Provider.Data { + fun attach : Void { + void + } +} + component Main { use Provider { a: "Hello", b: "Blah" } when { - true + "asd" } fun render : Html {
} } -------------------------------------------------------------UseConditionMismatch +------------------------------------------------------use_subscription_mismatch record Provider.Data { + a : String, + b : Bool +} + +record Test { a : String, b : String } @@ -51,20 +72,15 @@ component Main { a: "Hello", b: "Blah" } when { - "asd" + true } fun render : Html {
} } ----------------------------------------------------------UseSubscriptionMismatch +------------------------------------------------------------------------------- record Provider.Data { - a : String, - b : Bool -} - -record Test { a : String, b : String } diff --git a/spec/examples/variable b/spec/examples/variable new file mode 100644 index 000000000..3407c4cad --- /dev/null +++ b/spec/examples/variable @@ -0,0 +1,83 @@ +---------------------------------------------------------------variable_missing +component Main { + get a : String { + "Hello" + } + + fun b : String { + c + } + + fun render : Html { + b() + } +} +---------------------------------------------------------------variable_missing +component Main { + style test(name : String) { + color: #{name2}; + } + + fun render : Html { + + } +} +---------------------------------------------------------------variable_missing +suite "Suite" { + const TWO = 2 + + test "Test" { + 1 + 1 == THREE + } +} +---------------------------------------------------------------variable_missing +suite "Suite 2" { + test "Test" { + 1 + 1 == TWO + } +} +---------------------------------------------------------------variable_missing +enum A { + B(String) + C +} + +component Main { + fun render : String { + case (A::D(0)) { + => "" + } + } +} +---------------------------------------------------------------variable_missing +component Main { + fun render : String { + case (C::D(0)) { + => "" + } + } +} +--------------------------------------------------------------variable_reserved +component Main { + fun b(default : String) : String { + default + } + + fun render : Html { + b("") + } +} +------------------------------------------------------------------------------- +component Main { + get a : String { + "Hello" + } + + fun b : String { + a + } + + fun render : String { + b() + } +} diff --git a/spec/type_checking/void b/spec/examples/void similarity index 100% rename from spec/type_checking/void rename to spec/examples/void diff --git a/spec/examples_spec.cr b/spec/examples_spec.cr new file mode 100644 index 000000000..bebf2e8be --- /dev/null +++ b/spec/examples_spec.cr @@ -0,0 +1,67 @@ +require "./spec_helper" + +path = "./spec/examples/**/*" +example = nil + +ENV["EXAMPLE"]?.try do |item| + splitted = item.split(':', 2) + path = splitted[0] + example = splitted[1]? +end + +Dir + .glob(path) + .select! { |file| File.file?(file) } + .sort! + .each do |file| + # Read samples + samples = [] of Tuple(String, String?) + contents = File.read(file) + name = File.basename(file) + position = 0 + error = nil + + contents.scan(/^\-+([^-\n]+)?/m) do |match| + subject = contents[position, match.begin - position] + samples << {subject, error} + position = match.end + error = match[1]? + end + + samples << {contents[position, contents.size - position], error} + + samples.reject(&.first?.blank?).each_with_index do |sample, index| + next if example && example.to_i != index + + it "#{name} ##{index}" do + source, error = sample + + if error + begin + ast = Mint::Parser.parse(source, file) + + type_checker = Mint::TypeChecker.new(ast) + type_checker.check + rescue item : Mint::Error + if item.name.to_s != error + fail item.to_terminal.to_s + end + end + + item.should be_a(Mint::Error) + else + begin + ast = Mint::Parser.parse(source, file) + ast.class.should eq(Mint::Ast) + + type_checker = Mint::TypeChecker.new(ast) + type_checker.check + rescue item : Mint::Error + fail item.to_terminal.to_s + rescue item + fail item.to_s + '\n' + item.backtrace.join('\n') + end + end + end + end + end diff --git a/spec/formatters/access b/spec/formatters/access index d3f641a0e..e7cf8743c 100644 --- a/spec/formatters/access +++ b/spec/formatters/access @@ -1,8 +1,8 @@ -record Blah1 { +type Blah1 { blah : Bool } -record Blah { +type Blah { blah : Blah1 } @@ -12,11 +12,11 @@ module Test { } } -------------------------------------------------------------------------------- -record Blah1 { +type Blah1 { blah : Bool } -record Blah { +type Blah { blah : Blah1 } diff --git a/spec/formatters/constant_provider b/spec/formatters/constant_provider index 4e2eb6646..1f6d77933 100644 --- a/spec/formatters/constant_provider +++ b/spec/formatters/constant_provider @@ -1,4 +1,4 @@ -record Subscription { +type Subscription { a : Bool } @@ -10,7 +10,7 @@ provider Provider:Subscription { } } -------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } diff --git a/spec/formatters/decode b/spec/formatters/decode index 896d7ba2c..923e63e29 100644 --- a/spec/formatters/decode +++ b/spec/formatters/decode @@ -1,4 +1,4 @@ -record X { +type X { name : String } @@ -14,7 +14,7 @@ component A { } } -------------------------------------------------------------------------------- -record X { +type X { name : String } diff --git a/spec/formatters/directives/format b/spec/formatters/directives/format index 3d8cdc8bb..5f6105c9e 100644 --- a/spec/formatters/directives/format +++ b/spec/formatters/directives/format @@ -7,7 +7,7 @@ component Main { -------------------------------------------------------------------------------- component Main { fun render : String { - let {result, formatted} = + let #(result, formatted) = @format { "Hello" } diff --git a/spec/formatters/enum_with_comments b/spec/formatters/enum_with_comments deleted file mode 100644 index 279be6088..000000000 --- a/spec/formatters/enum_with_comments +++ /dev/null @@ -1,16 +0,0 @@ -enum Text { - /* Blah */ X - /* Lhab */ Y - /* Ablh */ Z -} --------------------------------------------------------------------------------- -enum Text { - /* Blah */ - X - - /* Lhab */ - Y - - /* Ablh */ - Z -} diff --git a/spec/formatters/enum_with_options b/spec/formatters/enum_with_options deleted file mode 100644 index 6d96ba87c..000000000 --- a/spec/formatters/enum_with_options +++ /dev/null @@ -1,29 +0,0 @@ -enum A(b,c) {B(b) C D(c)} - -module X { - fun y : A(String, String) { - A::B( "Hello" ) - } - - fun x : A(String, String) { - A::B( "Hello" - ) - } -} --------------------------------------------------------------------------------- -enum A(b, c) { - B(b) - C - D(c) -} - -module X { - fun y : A(String, String) { - A::B("Hello") - } - - fun x : A(String, String) { - A::B( - "Hello") - } -} diff --git a/spec/formatters/record_field b/spec/formatters/field similarity index 88% rename from spec/formatters/record_field rename to spec/formatters/field index 1afb82c00..3f32e8e72 100644 --- a/spec/formatters/record_field +++ b/spec/formatters/field @@ -1,4 +1,4 @@ -record Test { +type Test { a : String } @@ -8,7 +8,7 @@ module Test { } } -------------------------------------------------------------------------------- -record Test { +type Test { a : String } diff --git a/spec/formatters/record_field_multiline b/spec/formatters/field_multiline similarity index 94% rename from spec/formatters/record_field_multiline rename to spec/formatters/field_multiline index cf03f5784..a7ffa3b92 100644 --- a/spec/formatters/record_field_multiline +++ b/spec/formatters/field_multiline @@ -1,4 +1,4 @@ -record Test { +type Test { a : String } @@ -8,7 +8,7 @@ module Test { } } -------------------------------------------------------------------------------- -record Test { +type Test { a : String } diff --git a/spec/formatters/record_field_with_comments b/spec/formatters/field_with_comments similarity index 92% rename from spec/formatters/record_field_with_comments rename to spec/formatters/field_with_comments index 0953aac20..12fc2b0f3 100644 --- a/spec/formatters/record_field_with_comments +++ b/spec/formatters/field_with_comments @@ -1,4 +1,4 @@ -record Test { +type Test { a : String, b : String } @@ -9,7 +9,7 @@ module Test { } } -------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : String } diff --git a/spec/formatters/html_fragment b/spec/formatters/html_fragment index e190dd14e..dccf00166 100644 --- a/spec/formatters/html_fragment +++ b/spec/formatters/html_fragment @@ -4,7 +4,6 @@ component Test { "Hello There" <> - < key="Hello"> <><{"AA"}> } @@ -16,7 +15,6 @@ component Test { "Hello There" <> - < key="Hello"> <><{ "AA" }> } diff --git a/spec/formatters/inline_function_multiline b/spec/formatters/inline_function_multiline index d80372e4e..ffcd19dc5 100644 --- a/spec/formatters/inline_function_multiline +++ b/spec/formatters/inline_function_multiline @@ -1,4 +1,4 @@ -record X { +type X { name : String, age : Number } @@ -14,7 +14,7 @@ module A { } } -------------------------------------------------------------------------------- -record X { +type X { name : String, age : Number } diff --git a/spec/formatters/member_access b/spec/formatters/member_access index d6c4d200c..7336f3aac 100644 --- a/spec/formatters/member_access +++ b/spec/formatters/member_access @@ -1,4 +1,4 @@ -record Test { +type Test { test : String } @@ -8,7 +8,7 @@ component Main { } } -------------------------------------------------------------------------------- -record Test { +type Test { test : String } diff --git a/spec/formatters/provider b/spec/formatters/provider index 2cd332a17..94c947e52 100644 --- a/spec/formatters/provider +++ b/spec/formatters/provider @@ -1,4 +1,4 @@ -record Subscription { +type Subscription { a : Bool } @@ -8,7 +8,7 @@ providerProvider:Subscription { } } -------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } diff --git a/spec/formatters/provider_with_comments b/spec/formatters/provider_with_comments index 526491e5a..0bef0de29 100644 --- a/spec/formatters/provider_with_comments +++ b/spec/formatters/provider_with_comments @@ -1,4 +1,4 @@ -record Subscription { +type Subscription { a : Bool } @@ -10,7 +10,7 @@ record Subscription { /*C*/ } -------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } diff --git a/spec/formatters/provider_with_items b/spec/formatters/provider_with_items index 4efc415f6..b3d8a0ad1 100644 --- a/spec/formatters/provider_with_items +++ b/spec/formatters/provider_with_items @@ -1,4 +1,4 @@ -record Subscription { +type Subscription { a : Bool } @@ -14,7 +14,7 @@ provider Provider:Subscription { } } -------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } diff --git a/spec/formatters/record_constructor b/spec/formatters/record_constructor deleted file mode 100644 index 1255c3148..000000000 --- a/spec/formatters/record_constructor +++ /dev/null @@ -1,27 +0,0 @@ -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = - Test("Joe",32) - - item.name - } -} --------------------------------------------------------------------------------- -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = - Test("Joe", 32) - - item.name - } -} diff --git a/spec/formatters/record_constructor_with_new_line b/spec/formatters/record_constructor_with_new_line deleted file mode 100644 index 1f88af57c..000000000 --- a/spec/formatters/record_constructor_with_new_line +++ /dev/null @@ -1,30 +0,0 @@ -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = - Test("Joe", - 32) - - item.name - } -} --------------------------------------------------------------------------------- -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = - Test( - "Joe", - 32) - - item.name - } -} diff --git a/spec/formatters/record_multiline b/spec/formatters/record_multiline index ae0b1aeed..f0209d020 100644 --- a/spec/formatters/record_multiline +++ b/spec/formatters/record_multiline @@ -1,4 +1,4 @@ -record A { +type A { a : String, b : Bool } @@ -9,7 +9,7 @@ module Test { } } -------------------------------------------------------------------------------- -record A { +type A { a : String, b : Bool } diff --git a/spec/formatters/record_singleline b/spec/formatters/record_singleline index 2ea951a88..a5cefa65d 100644 --- a/spec/formatters/record_singleline +++ b/spec/formatters/record_singleline @@ -1,4 +1,4 @@ -record A { +type A { a : String } @@ -10,7 +10,7 @@ a:"Hello" } } -------------------------------------------------------------------------------- -record A { +type A { a : String } diff --git a/spec/formatters/record_update_multiline b/spec/formatters/record_update_multiline index 30c208c7d..2ef19bbd5 100644 --- a/spec/formatters/record_update_multiline +++ b/spec/formatters/record_update_multiline @@ -1,4 +1,4 @@ -record A { +type A { a : String, b : Bool } @@ -12,7 +12,7 @@ module Test { } } -------------------------------------------------------------------------------- -record A { +type A { a : String, b : Bool } diff --git a/spec/formatters/record_update_singleline b/spec/formatters/record_update_singleline index a9cc35653..b366059ab 100644 --- a/spec/formatters/record_update_singleline +++ b/spec/formatters/record_update_singleline @@ -1,4 +1,4 @@ -record A { +type A { a : String } @@ -11,7 +11,7 @@ module Test { } } -------------------------------------------------------------------------------- -record A { +type A { a : String } diff --git a/spec/formatters/statement b/spec/formatters/statement index 627c14273..25948156a 100644 --- a/spec/formatters/statement +++ b/spec/formatters/statement @@ -1,6 +1,6 @@ module A { fun test : Bool { - letx="hello"lety=trueletz=false + letx="hello"lety=0letz=1 true } } @@ -11,10 +11,10 @@ module A { "hello" let y = - true + 0 let z = - false + 1 true } diff --git a/spec/formatters/tuple_destructuring b/spec/formatters/tuple_destructuring index 94e3c8e1e..ae1d27805 100644 --- a/spec/formatters/tuple_destructuring +++ b/spec/formatters/tuple_destructuring @@ -9,8 +9,8 @@ module Test { -------------------------------------------------------------------------------- module Test { fun test : String { - let {a, b} = - {"A", "B"} + let #(a, b) = + #("A", "B") a } diff --git a/spec/formatters/tuple_multiple b/spec/formatters/tuple_multiple index 0e581e3f9..5ec41068f 100644 --- a/spec/formatters/tuple_multiple +++ b/spec/formatters/tuple_multiple @@ -9,10 +9,10 @@ module Test { -------------------------------------------------------------------------------- module Test { fun test : Tuple(String, String, String) { - { + #( "Hello", "Blah", "Joe" - } + ) } } diff --git a/spec/formatters/tuple_single b/spec/formatters/tuple_single index 53599d94b..cb4b26616 100644 --- a/spec/formatters/tuple_single +++ b/spec/formatters/tuple_single @@ -8,6 +8,6 @@ module Test { -------------------------------------------------------------------------------- module Test { fun test : Tuple(String) { - {"Hello"} + #("Hello") } } diff --git a/spec/formatters/type b/spec/formatters/type index ac91f3a09..2a672c6eb 100644 --- a/spec/formatters/type +++ b/spec/formatters/type @@ -1,10 +1,10 @@ -record Test { +type Test { number : Result(Number,Array(String)), param : Error(Bool), string : String } -------------------------------------------------------------------------------- -record Test { +type Test { number : Result(Number, Array(String)), param : Error(Bool), string : String diff --git a/spec/formatters/record_definition b/spec/formatters/type_definition similarity index 72% rename from spec/formatters/record_definition rename to spec/formatters/type_definition index 83f9bbb81..005dc1a95 100644 --- a/spec/formatters/record_definition +++ b/spec/formatters/type_definition @@ -1,6 +1,6 @@ -recordTest{a:String,b:Blah} +typeTest{a:String,b:Blah} -------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : Blah } diff --git a/spec/formatters/record_definition_with_comments b/spec/formatters/type_definition_with_comments similarity index 65% rename from spec/formatters/record_definition_with_comments rename to spec/formatters/type_definition_with_comments index f430d672e..aea803004 100644 --- a/spec/formatters/record_definition_with_comments +++ b/spec/formatters/type_definition_with_comments @@ -1,10 +1,9 @@ -/*A*/recordTest{/*B*/a:String,/*C*/b:Blah,/*D*/} +/*A*/typeTest{/*B*/a:String,/*C*/b:Blah} -------------------------------------------------------------------------------- /* A */ -record Test { +type Test { /* B */ a : String, /* C */ b : Blah - /* D */ } diff --git a/spec/formatters/record_definition_with_from b/spec/formatters/type_definition_with_using similarity index 66% rename from spec/formatters/record_definition_with_from rename to spec/formatters/type_definition_with_using index d31dc4fae..820325d94 100644 --- a/spec/formatters/record_definition_with_from +++ b/spec/formatters/type_definition_with_using @@ -1,6 +1,6 @@ -recordTest{a:String using "blah",b:Blah using "what"} +typeTest{a:String using "blah",b:Blah using "what"} -------------------------------------------------------------------------------- -record Test { +type Test { a : String using "blah", b : Blah using "what" } diff --git a/spec/formatters/enum_record b/spec/formatters/type_record similarity index 78% rename from spec/formatters/enum_record rename to spec/formatters/type_record index 81a684e8b..89255c260 100644 --- a/spec/formatters/enum_record +++ b/spec/formatters/type_record @@ -12,16 +12,16 @@ component Main { } } -------------------------------------------------------------------------------- -enum A { +type A { B(name : String, color : String) C } component Main { fun render : String { - case A::B(name: "Joe", color: "Blue") { - A::B(name, color) => "" - A::C => "" + case A.B(name: "Joe", color: "Blue") { + A.B(name, color) => "" + A.C => "" } } } diff --git a/spec/formatters/enum_record_multiline b/spec/formatters/type_record_multiline similarity index 95% rename from spec/formatters/enum_record_multiline rename to spec/formatters/type_record_multiline index 9aca41a84..7388bd4c5 100644 --- a/spec/formatters/enum_record_multiline +++ b/spec/formatters/type_record_multiline @@ -15,14 +15,14 @@ component Main { } } -------------------------------------------------------------------------------- -enum A { +type A { B(name : String, color : String) C } component Main { const X = - A::B( + A.B( color: "Blue", name: "Joe") diff --git a/spec/formatters/type_with_parameters b/spec/formatters/type_with_parameters index d67f6f395..2185fd804 100644 --- a/spec/formatters/type_with_parameters +++ b/spec/formatters/type_with_parameters @@ -1,5 +1,5 @@ module Test { - fun a : Array(Result(String,String)) { [] } + fun a : Array(Result(String,String)) { [] } } -------------------------------------------------------------------------------- module Test { diff --git a/spec/formatters/use b/spec/formatters/use index a1322bc24..22cfb6708 100644 --- a/spec/formatters/use +++ b/spec/formatters/use @@ -1,4 +1,4 @@ -record Provider.Subscription { +type Provider.Subscription { a : String, b : String } @@ -17,7 +17,7 @@ component Test { } } -------------------------------------------------------------------------------- -record Provider.Subscription { +type Provider.Subscription { a : String, b : String } diff --git a/spec/formatting_spec.cr b/spec/formatting_spec.cr index f28bf85de..75b4d67b6 100644 --- a/spec/formatting_spec.cr +++ b/spec/formatting_spec.cr @@ -6,38 +6,46 @@ Dir .sort! .each do |file| it file do - # Read and separate sample from expected - sample, expected = File.read(file).split("-" * 80) - - # Parse sample - ast = Mint::Parser.parse(sample, file) - ast.class.should eq(Mint::Ast) - - # Type check - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - - formatter = Mint::Formatter.new - - # Format and compare the results - result = formatter.format(ast) - - begin - result.should eq(expected.lstrip) - rescue error - fail diff(expected, result) - end - - # Parse the result, format again and compare - ast = Mint::Parser.parse(result, file) - ast.class.should eq(Mint::Ast) - - result = formatter.format(ast) - begin - result.should eq(expected.lstrip) - rescue error - fail diff(expected, result) + # Read and separate sample from expected + sample, expected = File.read(file).split("-" * 80) + + # Parse sample + ast = Mint::Parser.parse(sample, file) + ast.class.should eq(Mint::Ast) + + begin + # Type check + type_checker = Mint::TypeChecker.new(ast) + type_checker.check + rescue error : Mint::Error + fail error.to_terminal.to_s + end + + formatter = Mint::Formatter.new + + # Format and compare the results + result = formatter.format(ast) + + begin + result.should eq(expected.lstrip) + rescue error + fail diff(expected, result) + end + + # Parse the result, format again and compare + ast = Mint::Parser.parse(result, file) + ast.class.should eq(Mint::Ast) + + result = formatter.format(ast) + + begin + result.should eq(expected.lstrip) + rescue error + fail diff(expected, result) + end + rescue error : Mint::Error + fail error.to_terminal.to_s end end end diff --git a/spec/html_snippet_spec.cr b/spec/html_snippet_spec.cr index 5e8dc91fc..bb7040e84 100644 --- a/spec/html_snippet_spec.cr +++ b/spec/html_snippet_spec.cr @@ -8,9 +8,9 @@ describe Mint::HtmlSnippet do node = Mint::Ast::Node.new( - input: Mint::Ast::Data.new( - input: "line1\r\nline2\r\nline2", - file: "FILE"), + file: Mint::Parser::File.new( + contents: "line1\r\nline2\r\nline2", + path: "FILE"), from: 0, to: 23) @@ -25,9 +25,9 @@ describe Mint::HtmlSnippet do node = Mint::Ast::Node.new( - input: Mint::Ast::Data.new( - input: "line1\nline2\nline2", - file: "FILE"), + file: Mint::Parser::File.new( + contents: "line1\nline2\nline2", + path: "FILE"), from: 0, to: 23) diff --git a/spec/installer/repository_spec.cr b/spec/installer/repository_spec.cr index 51c3b322e..15ffb151c 100644 --- a/spec/installer/repository_spec.cr +++ b/spec/installer/repository_spec.cr @@ -12,7 +12,7 @@ describe "Repository" do repository = Mint::Installer::Repository.new("name", "success") message = <<-MESSAGE - ░ INSTALL ERROR ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + ░ ERROR (REPOSITORY_INVALID_MINT_JSON) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ I could not parse the mint.json for the package: name (success) for the version or tag: master @@ -21,7 +21,7 @@ describe "Repository" do begin repository.json("master") fail "Should have raised!" - rescue error : Mint::Installer::RepositoryInvalidMintJson + rescue error : Mint::Error error.to_terminal.to_s.uncolorize.should eq(message) end end @@ -32,7 +32,7 @@ describe "Repository" do repository = Mint::Installer::Repository.new("name", "success") message = <<-MESSAGE - ░ INSTALL ERROR ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + ░ ERROR (REPOSITORY_NO_MINT_JSON) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ I could not find the mint.json for the package: name (success) for the version or tag: master @@ -41,7 +41,7 @@ describe "Repository" do begin repository.json("master") fail "Should have raised!" - rescue error : Mint::Installer::RepositoryNoMintJson + rescue error : Mint::Error error.to_terminal.to_s.uncolorize.should eq(message) end end @@ -51,7 +51,7 @@ describe "Repository" do repository = Mint::Installer::Repository.new("name", "error") message = <<-MESSAGE - ░ INSTALL ERROR ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + ░ ERROR (REPOSITORY_COULD_NOT_GET_VERSIONS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ I could not get the tags of the repository: error @@ -64,7 +64,7 @@ describe "Repository" do begin repository.versions fail "Should have raised!" - rescue error : Mint::Installer::RepositoryCouldNotGetVersions + rescue error : Mint::Error error.to_terminal.to_s.uncolorize.should eq(message) end end @@ -73,7 +73,7 @@ describe "Repository" do repository = Mint::Installer::Repository.new("name", "error") message = <<-MESSAGE - ░ INSTALL ERROR ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + ░ ERROR (REPOSITORY_COULD_NOT_CHECKOUT) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ I could not checkout the version or tag: master of the repository: error @@ -85,7 +85,7 @@ describe "Repository" do begin repository.checkout("master") fail "Should have raised!" - rescue error : Mint::Installer::RepositoryCouldNotCheckout + rescue error : Mint::Error error.to_terminal.to_s.uncolorize.should eq(message) end end @@ -94,7 +94,7 @@ describe "Repository" do FileUtils.rm_rf("#{tmp_dir}/error") message = <<-MESSAGE - ░ INSTALL ERROR ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + ░ ERROR (REPOSITORY_COULD_NOT_CLONE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ I could not clone the repository: error @@ -106,7 +106,7 @@ describe "Repository" do begin Mint::Installer::Repository.open("name", "error") fail "Should have raised!" - rescue error : Mint::Installer::RepositoryCouldNotClone + rescue error : Mint::Error error.to_terminal.to_s.uncolorize.should eq(message) end end @@ -115,7 +115,7 @@ describe "Repository" do FileUtils.mkdir_p("#{tmp_dir}/error") message = <<-MESSAGE - ░ INSTALL ERROR ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + ░ ERROR (REPOSITORY_COULD_NOT_UPDATE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ I could not update the repository: error @@ -127,7 +127,7 @@ describe "Repository" do begin Mint::Installer::Repository.open("name", "error") fail "Should have raised!" - rescue error : Mint::Installer::RepositoryCouldNotUpdate + rescue error : Mint::Error error.to_terminal.to_s.uncolorize.should eq(message) end end diff --git a/spec/language_server/definition/location/html_style b/spec/language_server/definition/location/html_style index 89ad1e9f1..32bdc007e 100644 --- a/spec/language_server/definition/location/html_style +++ b/spec/language_server/definition/location/html_style @@ -1,6 +1,6 @@ component Test { style test { - + color: red; } fun render : Html { diff --git a/spec/language_server/definition/location/enum_id_name b/spec/language_server/definition/location/type_definition similarity index 100% rename from spec/language_server/definition/location/enum_id_name rename to spec/language_server/definition/location/type_definition diff --git a/spec/language_server/definition/location/enum_destructuring_name b/spec/language_server/definition/location/type_destructuring_name similarity index 100% rename from spec/language_server/definition/location/enum_destructuring_name rename to spec/language_server/definition/location/type_destructuring_name diff --git a/spec/language_server/definition/location/enum_destructuring_option b/spec/language_server/definition/location/type_destructuring_option similarity index 100% rename from spec/language_server/definition/location/enum_destructuring_option rename to spec/language_server/definition/location/type_destructuring_option diff --git a/spec/language_server/definition/location/type_enum b/spec/language_server/definition/location/type_type similarity index 100% rename from spec/language_server/definition/location/type_enum rename to spec/language_server/definition/location/type_type diff --git a/spec/language_server/definition/location/enum_id_option b/spec/language_server/definition/location/type_variant similarity index 100% rename from spec/language_server/definition/location/enum_id_option rename to spec/language_server/definition/location/type_variant diff --git a/spec/language_server/definition/location/variable_casebranch_enumdestructuring b/spec/language_server/definition/location/variable_casebranch_typedestructuring similarity index 100% rename from spec/language_server/definition/location/variable_casebranch_enumdestructuring rename to spec/language_server/definition/location/variable_casebranch_typedestructuring diff --git a/spec/language_server/definition/location_link/connect_variable_get b/spec/language_server/definition/location_link/connect_variable_get index f292778ef..3ca995d2f 100644 --- a/spec/language_server/definition/location_link/connect_variable_get +++ b/spec/language_server/definition/location_link/connect_variable_get @@ -63,8 +63,8 @@ component Test { "character": 2 }, "end": { - "line": 5, - "character": 0 + "line": 4, + "character": 3 } }, "targetSelectionRange": { diff --git a/spec/language_server/definition/location_link/html_style b/spec/language_server/definition/location_link/html_style index 404cf20e1..b90f2e496 100644 --- a/spec/language_server/definition/location_link/html_style +++ b/spec/language_server/definition/location_link/html_style @@ -1,6 +1,6 @@ component Test { style test { - + color: red; } fun render : Html { diff --git a/spec/language_server/definition/location_link/module_access_component_gets b/spec/language_server/definition/location_link/module_access_component_gets index 3b827025b..ec5298369 100644 --- a/spec/language_server/definition/location_link/module_access_component_gets +++ b/spec/language_server/definition/location_link/module_access_component_gets @@ -66,8 +66,8 @@ component Test { "character": 2 }, "end": { - "line": 5, - "character": 2 + "line": 3, + "character": 3 } }, "targetSelectionRange": { diff --git a/spec/language_server/definition/location_link/module_access_store_gets b/spec/language_server/definition/location_link/module_access_store_gets index a1b18df36..37e3ce943 100644 --- a/spec/language_server/definition/location_link/module_access_store_gets +++ b/spec/language_server/definition/location_link/module_access_store_gets @@ -62,8 +62,8 @@ component Test { "character": 2 }, "end": { - "line": 4, - "character": 0 + "line": 3, + "character": 3 } }, "targetSelectionRange": { diff --git a/spec/language_server/definition/location_link/enum_destructuring_name b/spec/language_server/definition/location_link/type_destructuring_name similarity index 100% rename from spec/language_server/definition/location_link/enum_destructuring_name rename to spec/language_server/definition/location_link/type_destructuring_name diff --git a/spec/language_server/definition/location_link/enum_destructuring_option b/spec/language_server/definition/location_link/type_destructuring_option similarity index 100% rename from spec/language_server/definition/location_link/enum_destructuring_option rename to spec/language_server/definition/location_link/type_destructuring_option diff --git a/spec/language_server/definition/location_link/variable_casebranch_enumdestructuring b/spec/language_server/definition/location_link/variable_casebranch_typedestructuring similarity index 100% rename from spec/language_server/definition/location_link/variable_casebranch_enumdestructuring rename to spec/language_server/definition/location_link/variable_casebranch_typedestructuring diff --git a/spec/language_server/definition/location_link/variable_component_get b/spec/language_server/definition/location_link/variable_component_get index 2541d9838..dae7fc792 100644 --- a/spec/language_server/definition/location_link/variable_component_get +++ b/spec/language_server/definition/location_link/variable_component_get @@ -60,8 +60,8 @@ component Test { "character": 2 }, "end": { - "line": 5, - "character": 2 + "line": 3, + "character": 3 } }, "targetSelectionRange": { diff --git a/spec/language_server/definition/location_link/variable_store_get b/spec/language_server/definition/location_link/variable_store_get index 070091f95..413e85253 100644 --- a/spec/language_server/definition/location_link/variable_store_get +++ b/spec/language_server/definition/location_link/variable_store_get @@ -62,8 +62,8 @@ store Test { "character": 2 }, "end": { - "line": 5, - "character": 2 + "line": 3, + "character": 3 } }, "targetSelectionRange": { diff --git a/spec/language_server/hover/function_provider b/spec/language_server/hover/function_provider index 343ad7e85..e394d10c4 100644 --- a/spec/language_server/hover/function_provider +++ b/spec/language_server/hover/function_provider @@ -1,5 +1,5 @@ record Test.Subscription { - + test : Test } provider Test : Test.Subscription { diff --git a/spec/language_server/hover/module_access b/spec/language_server/hover/module_access index 1b2378a34..93df02d38 100644 --- a/spec/language_server/hover/module_access +++ b/spec/language_server/hover/module_access @@ -20,7 +20,7 @@ component Test { }, "position": { "line": 9, - "character": 10 + "character": 22 } } } diff --git a/spec/language_server/hover/enum b/spec/language_server/hover/type_definition similarity index 100% rename from spec/language_server/hover/enum rename to spec/language_server/hover/type_definition diff --git a/spec/language_server/hover/enum_destructuring b/spec/language_server/hover/type_destructuring similarity index 100% rename from spec/language_server/hover/enum_destructuring rename to spec/language_server/hover/type_destructuring diff --git a/spec/language_server/hover/type_record b/spec/language_server/hover/type_record index 0719c0948..7802a395b 100644 --- a/spec/language_server/hover/type_record +++ b/spec/language_server/hover/type_record @@ -32,7 +32,7 @@ module Test { "jsonrpc": "2.0", "result": { "contents": [ - "```\nArticle(id: Number, description: String, title: String)\n```" + "```\ntype Article {\n id : Number,\n description : String,\n title : String\n}\n```" ] }, "id": 0 diff --git a/spec/language_server/hover/type_enum b/spec/language_server/hover/type_type similarity index 90% rename from spec/language_server/hover/type_enum rename to spec/language_server/hover/type_type index 948cb6db4..329814118 100644 --- a/spec/language_server/hover/type_enum +++ b/spec/language_server/hover/type_type @@ -1,4 +1,4 @@ -/* Comment for Status enum. */ +/* Comment for Status type. */ enum Status { Error Ok @@ -29,7 +29,7 @@ module Test { "result": { "contents": [ "**Status**\n", - "Comment for Status enum.\n", + "Comment for Status type.\n", "**Error**", "**Ok**" ] diff --git a/spec/language_server/hover/enum_id b/spec/language_server/hover/type_variant similarity index 100% rename from spec/language_server/hover/enum_id rename to spec/language_server/hover/type_variant diff --git a/spec/language_server/hover/enum_option b/spec/language_server/hover/type_variant_2 similarity index 100% rename from spec/language_server/hover/enum_option rename to spec/language_server/hover/type_variant_2 diff --git a/spec/language_server/ls_spec.cr b/spec/language_server/ls_spec.cr index ef9b05518..be40db072 100644 --- a/spec/language_server/ls_spec.cr +++ b/spec/language_server/ls_spec.cr @@ -5,7 +5,7 @@ def clean_json(workspace : Workspace, path : String) end Dir - .glob("./spec/language_server/{definition,hover,semantic_tokens}/**/*") + .glob("./spec/language_server/{hover,semantic_tokens}/**/*") .select! { |file| File.file?(file) } .sort! .each do |file| diff --git a/spec/messages_spec.cr b/spec/messages_spec.cr deleted file mode 100644 index a5ebb2a13..000000000 --- a/spec/messages_spec.cr +++ /dev/null @@ -1,15 +0,0 @@ -require "./spec_helper" - -ERROR_MESSAGES.each do |error| - it "#{error} has a message file" do - File.exists?("./src/messages/#{error}.cr").should eq(true) - end -end - -Dir.glob("./src/messages/**/*").each do |file| - basename = File.basename(file)[0..-4] - - it "#{basename} has an associated error" do - ERROR_MESSAGES.includes?(basename).should eq(true) - end -end diff --git a/spec/parsers/access_spec.cr b/spec/parsers/access_spec.cr deleted file mode 100644 index 189178e34..000000000 --- a/spec/parsers/access_spec.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "../spec_helper" - -describe "Access" do - subject access(Mint::Ast::Record::UNIT) - - expect_error ".", Mint::Parser::AccessExpectedVariable - - expect_ok ".asd" -end diff --git a/spec/parsers/argument_spec.cr b/spec/parsers/argument_spec.cr deleted file mode 100644 index 6b9e789b9..000000000 --- a/spec/parsers/argument_spec.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "../spec_helper" - -describe "Argument" do - subject argument - - expect_ignore "?" - expect_ignore "." - - expect_error "asd", Mint::Parser::ArgumentExpectedColon - expect_error "asd ", Mint::Parser::ArgumentExpectedColon - expect_error "asd :", Mint::Parser::ArgumentExpectedTypeOrVariable - expect_error "asd : ", Mint::Parser::ArgumentExpectedTypeOrVariable - - expect_ok "asd : T" - expect_ok "asd : x" - expect_ok "asd:Z" -end diff --git a/spec/parsers/array_access_spec.cr b/spec/parsers/array_access_spec.cr deleted file mode 100644 index 61938e43d..000000000 --- a/spec/parsers/array_access_spec.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "../spec_helper" - -describe "Array access" do - subject array_access(Mint::Ast::Record::UNIT) - - expect_error "[", Mint::Parser::ArrayAccessExpectedIndex - expect_error "[1", Mint::Parser::ArrayAccessExpectedClosingBracket - expect_error "[]", Mint::Parser::ArrayAccessExpectedIndex - - expect_ok "[1]" - expect_ok "[1][ 1 ]" -end diff --git a/spec/parsers/array_destructuring.cr b/spec/parsers/array_destructuring.cr deleted file mode 100644 index fc6eddfef..000000000 --- a/spec/parsers/array_destructuring.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe "Array Destructuring" do - subject array_destructuring - - expect_ignore "." - expect_ignore ".." - expect_ignore "[" - - expect_error "[a", Mint::Parser::ArrayDestructuringExpectedClosingBracket - expect_error "[a,", Mint::Parser::ArrayDestructuringExpectedClosingBracket - expect_error "[a, b", Mint::Parser::ArrayDestructuringExpectedClosingBracket - - expect_ok "[a]" - expect_ok "[a,b]" - expect_ok "[...a,b]" - expect_ok "[a,b,...c]" -end diff --git a/spec/parsers/array_literal_spec.cr b/spec/parsers/array_literal_spec.cr deleted file mode 100644 index e6174d3bd..000000000 --- a/spec/parsers/array_literal_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Array" do - subject array - - expect_ignore " " - expect_ignore "." - expect_ignore "asd" - - expect_error "[", Mint::Parser::ArrayExpectedClosingBracket - expect_error "[a", Mint::Parser::ArrayExpectedClosingBracket - expect_error "[a] of", Mint::Parser::ArrayLiteralExpectedTypeOrVariable - - expect_ok "[a,b,c]" - expect_ok "[a,b,c] of String" -end diff --git a/spec/parsers/bool_literal_spec.cr b/spec/parsers/bool_literal_spec.cr deleted file mode 100644 index fbb4d4cfc..000000000 --- a/spec/parsers/bool_literal_spec.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "../spec_helper" - -describe "Bool Literal" do - subject bool_literal - - expect_ignore "a" - expect_ignore "." - expect_ignore "blah" - - expect_ok "true" - expect_ok "false" -end diff --git a/spec/parsers/call_spec.cr b/spec/parsers/call_spec.cr deleted file mode 100644 index 3f8c3286a..000000000 --- a/spec/parsers/call_spec.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "../spec_helper" - -describe "Call" do - subject call(Mint::Ast::Record::UNIT) - - expect_error "(", Mint::Parser::CallExpectedClosingParentheses - - expect_ok "(asd, asd)" -end diff --git a/spec/parsers/case_branch_spec.cr b/spec/parsers/case_branch_spec.cr deleted file mode 100644 index f241d847a..000000000 --- a/spec/parsers/case_branch_spec.cr +++ /dev/null @@ -1,14 +0,0 @@ -require "../spec_helper" - -describe "Case Branch" do - subject case_branch - - expect_ignore "" - expect_ignore "???" - expect_ignore "asd" - - expect_error "=>", Mint::Parser::CaseBranchExpectedExpression - expect_error "asd =>", Mint::Parser::CaseBranchExpectedExpression - - expect_ok "asd => asd" -end diff --git a/spec/parsers/case_spec.cr b/spec/parsers/case_spec.cr deleted file mode 100644 index 55443741b..000000000 --- a/spec/parsers/case_spec.cr +++ /dev/null @@ -1,24 +0,0 @@ -require "../spec_helper" - -describe "Case Expression" do - subject case_expression - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "case", Mint::Parser::CaseExpectedCondition - expect_error "case ", Mint::Parser::CaseExpectedCondition - expect_error "case (", Mint::Parser::CaseExpectedCondition - expect_error "case (a", Mint::Parser::CaseExpectedClosingParentheses - expect_error "case (a)", Mint::Parser::CaseExpectedOpeningBracket - expect_error "case (a) ", Mint::Parser::CaseExpectedOpeningBracket - expect_error "case (a) {", Mint::Parser::CaseExpectedBranches - expect_error "case (a) { ", Mint::Parser::CaseExpectedBranches - expect_error "case (a) { a => b", Mint::Parser::CaseExpectedClosingBracket - - expect_ok "case (a) { a => b }" - expect_ok "case (a) { a => b b => a }" - expect_ok "case (a) { a => T.blah()b => a }" - expect_ok "case (a) { [] => a [head, ...tail] => a }" -end diff --git a/spec/parsers/comment_spec.cr b/spec/parsers/comment_spec.cr deleted file mode 100644 index e4b95599c..000000000 --- a/spec/parsers/comment_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Block Comment" do - subject comment - - expect_ok "/*\n Block Comment\n */" - expect_ok "/*!\n * Block Comment\n */" - expect_ok "/* Block comment with EOF" -end - -describe "Inline Comment" do - subject comment - - expect_ok "//\n" - expect_ok "//A single inline comment" -end diff --git a/spec/parsers/component_spec.cr b/spec/parsers/component_spec.cr deleted file mode 100644 index c44656af4..000000000 --- a/spec/parsers/component_spec.cr +++ /dev/null @@ -1,27 +0,0 @@ -require "../spec_helper" - -describe "Component Definition" do - subject component - - expect_ignore "comp" - expect_ignore "asd" - - expect_error "component", Mint::Parser::ComponentExpectedName - expect_error "component{", Mint::Parser::ComponentExpectedName - expect_error "component ", Mint::Parser::ComponentExpectedName - expect_error "component a", Mint::Parser::ComponentExpectedName - expect_error "component T", Mint::Parser::ComponentExpectedOpeningBracket - expect_error "component T ", Mint::Parser::ComponentExpectedOpeningBracket - expect_error "component T {", Mint::Parser::ComponentExpectedBody - expect_error "component T { ", Mint::Parser::ComponentExpectedBody - expect_error "component T.", Mint::Parser::ComponentExpectedName - expect_error "component T.T { property a : T = a", Mint::Parser::ComponentExpectedClosingBracket - - expect_ok "component T { get a : T { a } }" - expect_ok "component T { property a : T = b }" - expect_ok "component T.T { property a : T = a }" - expect_ok "component T.T { property a : T = a}" - expect_ok "component T { style test { a: b; } }" - expect_ok "component T { connect B exposing { a } }" - expect_ok "component T { style test { a: b; }style a { a: b; } }" -end diff --git a/spec/parsers/connect_spec.cr b/spec/parsers/connect_spec.cr deleted file mode 100644 index 1101679c0..000000000 --- a/spec/parsers/connect_spec.cr +++ /dev/null @@ -1,21 +0,0 @@ -require "../spec_helper" - -describe "Connect" do - subject connect - - expect_ignore "asd" - expect_ignore "component" - expect_ignore ".*" - - expect_error "connect ", Mint::Parser::ConnectExpectedType - expect_error "connect X", Mint::Parser::ConnectExpectedExposing - expect_error "connect X ", Mint::Parser::ConnectExpectedExposing - expect_error "connect X exposing", Mint::Parser::ConnectExpectedOpeningBracket - expect_error "connect X exposing ", Mint::Parser::ConnectExpectedOpeningBracket - expect_error "connect X exposing {", Mint::Parser::ConnectExpectedKeys - expect_error "connect X exposing {a", Mint::Parser::ConnectExpectedClosingBracket - expect_error "connect X exposing {a ", Mint::Parser::ConnectExpectedClosingBracket - - expect_ok "connect X exposing { a }" - expect_ok "connect X exposing { a, b }" -end diff --git a/spec/parsers/connect_variable_spec.cr b/spec/parsers/connect_variable_spec.cr deleted file mode 100644 index a30d3b3b3..000000000 --- a/spec/parsers/connect_variable_spec.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "../spec_helper" - -describe "ConnectVariable" do - subject connect_variable - - expect_ignore ".*" - - expect_error "x as", Mint::Parser::ConnectVariableExpectedAs - - expect_ok "x" - expect_ok "x as y" -end diff --git a/spec/parsers/constant_spec.cr b/spec/parsers/constant_spec.cr deleted file mode 100644 index ff3a3cc61..000000000 --- a/spec/parsers/constant_spec.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Constant" do - subject constant - - expect_ignore "prop" - expect_ignore "asd" - - expect_error "const ", Mint::Parser::ConstantExpectedName - expect_error "const .", Mint::Parser::ConstantExpectedName - expect_error "const a", Mint::Parser::ConstantExpectedName - expect_error "const A", Mint::Parser::ConstantExpectedEqualSign - expect_error "const A ", Mint::Parser::ConstantExpectedEqualSign - expect_error "const A =", Mint::Parser::ConstantExpectedValue - expect_error "const A = ", Mint::Parser::ConstantExpectedValue - - expect_ok "const A = a" - expect_ok "const ASD_ASD = a" -end diff --git a/spec/parsers/css_definition_spec.cr b/spec/parsers/css_definition_spec.cr deleted file mode 100644 index e7266f646..000000000 --- a/spec/parsers/css_definition_spec.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "../spec_helper" - -describe "Css Definition" do - subject css_definition - - expect_ignore "." - expect_ignore "A" - expect_ignore ":" - - expect_error "a:", Mint::Parser::CssDefinitionExpectedSemicolon - expect_error "a: b", Mint::Parser::CssDefinitionExpectedSemicolon - expect_error "a: \#{", Mint::Parser::InterpolationExpectedExpression - expect_error "a: \#{a", Mint::Parser::InterpolationExpectedClosingBracket - - expect_ok "a: \#{a};" - expect_ok "a: x \#{a} v;" - expect_ok "a: x \#{a} v \#{a};" - expect_ok "a: x \#{a}\#{a};" - expect_ok "a: b;" - expect_ok "-WebKit-Box: 0 red;" - expect_ok "-webit-box-shadow: 0 0 20px black;" -end diff --git a/spec/parsers/css_interpolation_spec.cr b/spec/parsers/css_interpolation_spec.cr deleted file mode 100644 index 27e9c558e..000000000 --- a/spec/parsers/css_interpolation_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe "Interpolation" do - subject interpolation - - expect_ignore "" - expect_ignore "??" - expect_ignore "asd" - expect_ignore "{" - - expect_error "\#{", Mint::Parser::InterpolationExpectedExpression - expect_error "\#{ ", Mint::Parser::InterpolationExpectedExpression - expect_error "\#{a", Mint::Parser::InterpolationExpectedClosingBracket - expect_error "\#{a ", Mint::Parser::InterpolationExpectedClosingBracket - - expect_ok "\#{a}" - expect_ok "\#{ a }" -end diff --git a/spec/parsers/css_keyframes.cr b/spec/parsers/css_keyframes.cr deleted file mode 100644 index d23d351b8..000000000 --- a/spec/parsers/css_keyframes.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "../spec_helper" - -describe "Css Keyframes" do - subject css_keyframes - - expect_error "@keyframes", Mint::Parser::CssKeyframesExpectedName - expect_error "@kayframes test ", Mint::Parser::CssKeyframesExpectedOpeningBracket - expect_error "@keyframes test {", Mint::Parser::CssKeyframesExpectedClosingBracket - - expect_ok "@keyframes test { }" - expect_ok "@keyframes test { 0% { a: b; } }" -end diff --git a/spec/parsers/css_selector_spec.cr b/spec/parsers/css_selector_spec.cr deleted file mode 100644 index 04357a565..000000000 --- a/spec/parsers/css_selector_spec.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "../spec_helper" - -describe "Css Selectors" do - subject css_selector - - expect_error "v {", Mint::Parser::CssSelectorExpectedClosingBracket - expect_error "v { ", Mint::Parser::CssSelectorExpectedClosingBracket - expect_error "v { a: b;", Mint::Parser::CssSelectorExpectedClosingBracket - - expect_ok "valami { }" - expect_ok "valami { a: b; }" -end diff --git a/spec/parsers/decode.cr b/spec/parsers/decode.cr deleted file mode 100644 index 4df175bf1..000000000 --- a/spec/parsers/decode.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Decode Expression" do - subject decode - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "decode", Mint::Parser::DecodeExpectedExpression - expect_error "decode x", Mint::Parser::DecodeExpectedAs - expect_error "decode x x", Mint::Parser::DecodeExpectedAs - expect_error "decode x ?", Mint::Parser::DecodeExpectedAs - expect_error "decode x as", Mint::Parser::DecodeExpectedType - expect_error "decode x as x", Mint::Parser::DecodeExpectedType - - expect_ok "decode as T" - expect_ok "decode x as T" -end diff --git a/spec/parsers/directives/documentation.cr b/spec/parsers/directives/documentation.cr deleted file mode 100644 index e7dd0135f..000000000 --- a/spec/parsers/directives/documentation.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../../spec_helper" - -describe "Documentation Directive" do - subject documentation_directive - - expect_ignore "?" - expect_ignore "." - expect_ignore "@docu" - - expect_error "@documentation", Mint::Parser::DocumentationDirectiveExpectedOpeningParntheses - expect_error "@documentation(", Mint::Parser::DocumentationDirectiveExpectedEntity - expect_error "@documentation(A", Mint::Parser::DocumentationDirectiveExpectedClosingParntheses - - expect_ok "@documentation(a)" - expect_ok "@documentation( a )" -end diff --git a/spec/parsers/directives/format_spec.cr b/spec/parsers/directives/format_spec.cr deleted file mode 100644 index 27859b034..000000000 --- a/spec/parsers/directives/format_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../../spec_helper" - -describe "Format Directive" do - subject format_directive - - expect_ignore "?" - expect_ignore "." - expect_ignore "@form" - - expect_error "@format", Mint::Parser::FormatDirectiveExpectedOpeningBracket - expect_error "@format {", Mint::Parser::FormatDirectiveExpectedExpression - expect_error "@format {a", Mint::Parser::FormatDirectiveExpectedClosingBracket - - expect_ok "@format{a}" - expect_ok "@format { a }" -end diff --git a/spec/parsers/env_spec.cr b/spec/parsers/env_spec.cr deleted file mode 100644 index f794456a7..000000000 --- a/spec/parsers/env_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Env" do - subject env - - expect_ignore "a" - expect_ignore "." - expect_ignore "ge" - - expect_error "@", Mint::Parser::EnvExpectedName - expect_error "@a", Mint::Parser::EnvExpectedName - - expect_ok "@API_ENDPOINT" - expect_ok "@ENDPOINT" - expect_ok "@HOST" -end diff --git a/spec/parsers/for_spec.cr b/spec/parsers/for_spec.cr deleted file mode 100644 index f7f970ba0..000000000 --- a/spec/parsers/for_spec.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "../spec_helper" - -describe "For Expression" do - subject for_expression - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "for ", Mint::Parser::ForExpectedOf - expect_error "for (", Mint::Parser::ForExpectedOf - expect_error "for (a", Mint::Parser::ForExpectedOf - expect_error "for (a, b", Mint::Parser::ForExpectedOf - expect_error "for (a, b of", Mint::Parser::ForExpectedSubject - expect_error "for (a, b of a", Mint::Parser::ForExpectedClosingParentheses - expect_error "for (a, b of a)", Mint::Parser::ForExpectedOpeningBracket - expect_error "for (a, b of a) {", Mint::Parser::ForExpectedBody - expect_error "for (a, b of a) { x", Mint::Parser::ForExpectedClosingBracket - expect_error "for (a, b of a) { x } when", Mint::Parser::ForConditionExpectedOpeningBracket - expect_error "for (a, b of a) { x } when {", Mint::Parser::ForConditionExpectedBody - expect_error "for (a, b of a) { x } when { x", Mint::Parser::ForConditionExpectedClosingBracket - - expect_ok "for (a, b of a) { x }" - expect_ok "for (a, b of a) { x } when { x }" -end diff --git a/spec/parsers/function_spec.cr b/spec/parsers/function_spec.cr deleted file mode 100644 index 7b16fdd65..000000000 --- a/spec/parsers/function_spec.cr +++ /dev/null @@ -1,26 +0,0 @@ -require "../spec_helper" - -describe "Function Definition" do - subject function - - expect_ignore ":" - expect_ignore "a" - expect_ignore "fu" - - expect_error "fun", Mint::Parser::FunctionExpectedName - expect_error "fun ", Mint::Parser::FunctionExpectedName - expect_error "fun a", Mint::Parser::FunctionExpectedOpeningBracket - expect_error "fun a ", Mint::Parser::FunctionExpectedOpeningBracket - expect_error "fun a (", Mint::Parser::FunctionExpectedClosingParentheses - expect_error "fun a ( ", Mint::Parser::FunctionExpectedClosingParentheses - expect_error "fun a ()", Mint::Parser::FunctionExpectedOpeningBracket - expect_error "fun a () ", Mint::Parser::FunctionExpectedOpeningBracket - expect_error "fun a () :", Mint::Parser::FunctionExpectedTypeOrVariable - expect_error "fun a () : ", Mint::Parser::FunctionExpectedTypeOrVariable - - expect_ok "fun a { true } " - expect_ok "fun a : T { true } " - expect_ok "fun a : x { true } " - expect_ok "fun a () : T { false }" - expect_ok "fun a ( ) : T { balh }" -end diff --git a/spec/parsers/get_spec.cr b/spec/parsers/get_spec.cr deleted file mode 100644 index 81a0e89d1..000000000 --- a/spec/parsers/get_spec.cr +++ /dev/null @@ -1,24 +0,0 @@ -require "../spec_helper" - -describe "Component Get" do - subject get - - expect_ignore "a" - expect_ignore "." - expect_ignore "ge" - - expect_error "get ", Mint::Parser::GetExpectedName - expect_error "get a", Mint::Parser::GetExpectedOpeningBracket - expect_error "get a ", Mint::Parser::GetExpectedOpeningBracket - expect_error "get a :", Mint::Parser::GetExpectedType - expect_error "get a : ", Mint::Parser::GetExpectedType - expect_error "get a : T", Mint::Parser::GetExpectedOpeningBracket - expect_error "get a : T ", Mint::Parser::GetExpectedOpeningBracket - expect_error "get a : T {", Mint::Parser::GetExpectedExpression - expect_error "get a : T { ", Mint::Parser::GetExpectedExpression - expect_error "get a : T { a ", Mint::Parser::GetExpectedClosingBracket - - expect_ok "get a { a}" - expect_ok "get a : T { a}" - expect_ok "get a : T { a }" -end diff --git a/spec/parsers/html_attribute_spec.cr b/spec/parsers/html_attribute_spec.cr deleted file mode 100644 index 765636869..000000000 --- a/spec/parsers/html_attribute_spec.cr +++ /dev/null @@ -1,20 +0,0 @@ -require "../spec_helper" - -describe "Html Attribute" do - subject html_attribute - - expect_ignore " " - expect_ignore "." - expect_ignore "0" - expect_ignore "??" - - expect_error "name", Mint::Parser::HtmlAttributeExpectedEqualSign - expect_error "name=", Mint::Parser::HtmlAttributeExpectedOpeningBracket - expect_error "name={", Mint::Parser::HtmlAttributeExpectedExpression - expect_error "name={a", Mint::Parser::HtmlAttributeExpectedClosingBracket - - expect_ok %(test="asd") - expect_ok %(test={a}) - expect_ok %(test={ a }) - expect_ok %(data-text={a}) -end diff --git a/spec/parsers/html_component_spec.cr b/spec/parsers/html_component_spec.cr deleted file mode 100644 index a59cda0a8..000000000 --- a/spec/parsers/html_component_spec.cr +++ /dev/null @@ -1,20 +0,0 @@ -require "../spec_helper" - -describe "Html Component" do - subject html_component - - expect_error "", Mint::Parser::HtmlComponentExpectedClosingTag - expect_error "", Mint::Parser::HtmlAttributeExpectedEqualSign - expect_error "", Mint::Parser::HtmlComponentExpectedClosingTag - - expect_ok "" - expect_ok "" - expect_ok "" - expect_ok "" - expect_ok "" - expect_ok "" - expect_ok " " -end diff --git a/spec/parsers/html_element_spec.cr b/spec/parsers/html_element_spec.cr deleted file mode 100644 index d8b68e4d9..000000000 --- a/spec/parsers/html_element_spec.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "../spec_helper" - -describe "Html Element" do - subject html_element - - expect_ignore "asd" - expect_ignore "< " - - expect_error "" - expect_ok "" - expect_ok "" - expect_ok "" - expect_ok " " - expect_ok " " - expect_ok "" - expect_ok "" - expect_ok "" -end diff --git a/spec/parsers/html_expression_spec.cr b/spec/parsers/html_expression_spec.cr deleted file mode 100644 index 0f4b8386d..000000000 --- a/spec/parsers/html_expression_spec.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "../spec_helper" - -describe "Html Expression" do - subject html_expression - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - expect_ignore "<" - - expect_error "<{", Mint::Parser::HtmlExpressionExpectedClosingTag - expect_error "<{ ", Mint::Parser::HtmlExpressionExpectedClosingTag - expect_error "<{ a", Mint::Parser::HtmlExpressionExpectedClosingTag - expect_error "<{ a ", Mint::Parser::HtmlExpressionExpectedClosingTag - - expect_ok "<{ a }>" -end diff --git a/spec/parsers/html_fragment_spec.cr b/spec/parsers/html_fragment_spec.cr deleted file mode 100644 index 44c8bd057..000000000 --- a/spec/parsers/html_fragment_spec.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Html Fragment" do - subject html_fragment - - expect_ignore "asd" - - expect_error "< ", Mint::Parser::HtmlFragmentExpectedClosingBracket - expect_error "<>", Mint::Parser::HtmlFragmentExpectedClosingTag - expect_error "< a", Mint::Parser::HtmlFragmentExpectedClosingBracket - expect_error "< ??", Mint::Parser::HtmlFragmentExpectedClosingBracket - expect_error "< key=", Mint::Parser::HtmlAttributeExpectedOpeningBracket - expect_error "< key=\"\"", Mint::Parser::HtmlFragmentExpectedClosingBracket - - expect_ok "<>" - expect_ok "< >" - expect_ok "< key=\"a\">" - expect_ok "< key=\"a\" >" -end diff --git a/spec/parsers/if_spec.cr b/spec/parsers/if_spec.cr deleted file mode 100644 index 47201821f..000000000 --- a/spec/parsers/if_spec.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "../spec_helper" - -describe "If Expression" do - subject if_expression - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "if", Mint::Parser::IfExpectedCondition - expect_error "if ", Mint::Parser::IfExpectedCondition - expect_error "if (", Mint::Parser::IfExpectedCondition - expect_error "if (a", Mint::Parser::IfExpectedClosingParentheses - expect_error "if (a)", Mint::Parser::IfExpectedTruthyOpeningBracket - expect_error "if (a) ", Mint::Parser::IfExpectedTruthyOpeningBracket - expect_error "if (a) {", Mint::Parser::IfExpectedTruthyExpression - expect_error "if (a) { ", Mint::Parser::IfExpectedTruthyExpression - expect_error "if (a) { a", Mint::Parser::IfExpectedTruthyClosingBracket - expect_error "if (a) { a ", Mint::Parser::IfExpectedTruthyClosingBracket - expect_error "if (a) { a } else", Mint::Parser::IfExpectedFalsyOpeningBracket - expect_error "if (a) { a } else ", Mint::Parser::IfExpectedFalsyOpeningBracket - expect_error "if (a) { a } else {", Mint::Parser::IfExpectedFalsyExpression - expect_error "if (a) { a } else { ", Mint::Parser::IfExpectedFalsyExpression - expect_error "if (a) { a } else { a", Mint::Parser::IfExpectedFalsyClosingBracket - expect_error "if (a) { a } else { a ", Mint::Parser::IfExpectedFalsyClosingBracket - - expect_ok "if (a) { a }" - expect_ok "if (a) { a } " - expect_ok "if (a) { b } else { c }" - expect_ok "if ( a ) { b } else { c }" - expect_ok "if (a) { b } else if (x) { y } else { z }" -end diff --git a/spec/parsers/inline_function_spec.cr b/spec/parsers/inline_function_spec.cr deleted file mode 100644 index 405c24743..000000000 --- a/spec/parsers/inline_function_spec.cr +++ /dev/null @@ -1,20 +0,0 @@ -require "../spec_helper" - -describe "Inline Function" do - subject inline_function - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "(", Mint::Parser::InlineFunctionExpectedClosingParentheses - expect_error "(a : Event ", Mint::Parser::InlineFunctionExpectedClosingParentheses - expect_error "(a : Event)", Mint::Parser::InlineFunctionExpectedOpeningBracket - expect_error "(a : Event) :", Mint::Parser::InlineFunctionExpectedType - expect_error "(a : Event) : X", Mint::Parser::InlineFunctionExpectedOpeningBracket - expect_error "(a : Event) : X {", Mint::Parser::InlineFunctionExpectedExpression - expect_error "(a : Event) : X { b ", Mint::Parser::InlineFunctionExpectedClosingBracket - - expect_ok "(a : Event) { b }" - expect_ok "(a : Event) : X { b }" -end diff --git a/spec/parsers/js_spec.cr b/spec/parsers/js_spec.cr deleted file mode 100644 index 336ab2be5..000000000 --- a/spec/parsers/js_spec.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "../spec_helper" - -describe "Js" do - subject js - - expect_ignore "." - expect_ignore "asd" - expect_ignore "blah blah" - - expect_error %q(`asd"), Mint::Parser::JsExpectedClosingTick - expect_error %q(`sad #{), Mint::Parser::InterpolationExpectedExpression - expect_error %q(`asd #{x), Mint::Parser::InterpolationExpectedClosingBracket - expect_error %q(`asd` as), Mint::Parser::JsExpectedTypeOrVariable - - expect_ok %q(`hello`) - expect_ok %q(`hello` as String) - expect_ok %q(`\`Hello`) - expect_ok %q(`Hello ##something`) - expect_ok %q(`Hello #{blah()}`) - expect_ok %q(`Hello \`#{blah()}\``) - expect_ok %q(`Hello #{blah(`"WHAAT"`)}`) -end diff --git a/spec/parsers/locale_key_spec.cr b/spec/parsers/locale_key_spec.cr deleted file mode 100644 index b1c314824..000000000 --- a/spec/parsers/locale_key_spec.cr +++ /dev/null @@ -1,11 +0,0 @@ -require "../spec_helper" - -describe "Locale" do - subject locale_key - - expect_ignore "comp" - expect_ignore "asd" - expect_ignore ":" - - expect_ok ":ui.button.ok" -end diff --git a/spec/parsers/locale_spec.cr b/spec/parsers/locale_spec.cr deleted file mode 100644 index 4c7b0f667..000000000 --- a/spec/parsers/locale_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Locale" do - subject locale - - expect_ignore "comp" - expect_ignore "asd" - - expect_error "locale", Mint::Parser::LocaleExpectedLanguage - expect_error "locale{", Mint::Parser::LocaleExpectedLanguage - expect_error "locale ", Mint::Parser::LocaleExpectedLanguage - expect_error "locale en", Mint::Parser::LocaleExpectedOpeningBracket - expect_error "locale en {", Mint::Parser::LocaleExpectedClosingBracket - - expect_ok "locale en { a: \"\" }" -end diff --git a/spec/parsers/member_access_spec.cr b/spec/parsers/member_access_spec.cr deleted file mode 100644 index 10d0204ff..000000000 --- a/spec/parsers/member_access_spec.cr +++ /dev/null @@ -1,11 +0,0 @@ -require "../spec_helper" - -describe "MemberAccess" do - subject member_access - - expect_ignore "asd" - - expect_error ".", Mint::Parser::MemberAccessExpectedVariable - - expect_ok ".asd" -end diff --git a/spec/parsers/module_access_spec.cr b/spec/parsers/module_access_spec.cr deleted file mode 100644 index 28288f4eb..000000000 --- a/spec/parsers/module_access_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Module Call" do - subject module_access - - expect_ignore " " - expect_ignore "." - expect_ignore "a" - expect_ignore "???" - expect_ignore "Asd" - expect_ignore "Asd.Asd" - - expect_error "Asd.", Mint::Parser::ModuleAccessExpectedFunction - - expect_ok "Asd.asd" -end diff --git a/spec/parsers/module_spec.cr b/spec/parsers/module_spec.cr deleted file mode 100644 index d69080ff3..000000000 --- a/spec/parsers/module_spec.cr +++ /dev/null @@ -1,23 +0,0 @@ -require "../spec_helper" - -describe "Module" do - subject module_definition - - expect_ignore "." - expect_ignore "a" - expect_ignore "::" - expect_ignore "mod" - expect_ignore "modul" - - expect_error "module", Mint::Parser::ModuleExpectedName - expect_error "module ", Mint::Parser::ModuleExpectedName - expect_error "module ,", Mint::Parser::ModuleExpectedName - expect_error "module a", Mint::Parser::ModuleExpectedName - expect_error "module Test", Mint::Parser::ModuleExpectedOpeningBracket - expect_error "module Test ", Mint::Parser::ModuleExpectedOpeningBracket - expect_error "module Test {", Mint::Parser::ModuleExpectedClosingBracket - expect_error "module Test { ", Mint::Parser::ModuleExpectedClosingBracket - expect_error "module Test { fun a : Test { blah }", Mint::Parser::ModuleExpectedClosingBracket - - expect_ok "module Test { }" -end diff --git a/spec/parsers/negated_expression_spec.cr b/spec/parsers/negated_expression_spec.cr deleted file mode 100644 index bd55585b2..000000000 --- a/spec/parsers/negated_expression_spec.cr +++ /dev/null @@ -1,15 +0,0 @@ -require "../spec_helper" - -describe "Negated Expression" do - subject negated_expression - - expect_error "!", Mint::Parser::NegatedExpressionExpectedExpression - - expect_ok "!a" - expect_ok "!true" - expect_ok "!false" - expect_ok "!!true" - expect_ok "!!false" - expect_ok "!(a)" - expect_ok "!(!a)" -end diff --git a/spec/parsers/next_call_spec.cr b/spec/parsers/next_call_spec.cr deleted file mode 100644 index 88f312174..000000000 --- a/spec/parsers/next_call_spec.cr +++ /dev/null @@ -1,13 +0,0 @@ -require "../spec_helper" - -describe "Next Call" do - subject next_call - - expect_ignore "{" - expect_ignore "asd" - expect_ignore "next" - - expect_error "next ", Mint::Parser::NextCallExpectedRecord - - expect_ok "next {}" -end diff --git a/spec/parsers/number_literal_spec.cr b/spec/parsers/number_literal_spec.cr deleted file mode 100644 index b782f3cda..000000000 --- a/spec/parsers/number_literal_spec.cr +++ /dev/null @@ -1,15 +0,0 @@ -require "../spec_helper" - -describe "Number Literal" do - subject number_literal - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "0.", Mint::Parser::NumberLiteralExpectedDecimal - - expect_ok "0" - expect_ok "0.0" - expect_ok "-10.0" -end diff --git a/spec/parsers/operation_spec.cr b/spec/parsers/operation_spec.cr deleted file mode 100644 index ee50ed453..000000000 --- a/spec/parsers/operation_spec.cr +++ /dev/null @@ -1,41 +0,0 @@ -require "../spec_helper" - -describe "Operation" do - it "parses simple operation" do - operation = - Mint::Parser.new("a == b", "TestFile.mint") - .expression!(Mint::SyntaxError) - .as(Mint::Ast::Operation) - - operation.operator.should eq "==" - operation.left.should be_a(Mint::Ast::Variable) - operation.right.should be_a(Mint::Ast::Variable) - end - - it "honors precedence" do - operation = - Mint::Parser.new("a == b * c", "TestFile.mint") - .expression!(Mint::SyntaxError) - .as(Mint::Ast::Operation) - - operation.operator.should eq "==" - operation.left.should be_a(Mint::Ast::Variable) - operation.right.should be_a(Mint::Ast::Operation) - end - - it "honors precedence 2" do - operation = - Mint::Parser.new("a * b == c", "TestFile.mint") - .expression!(Mint::SyntaxError) - .as(Mint::Ast::Operation) - - operation.operator.should eq "==" - operation.left.should be_a(Mint::Ast::Operation) - operation.right.should be_a(Mint::Ast::Variable) - - left = operation.left.as(Mint::Ast::Operation) - left.operator.should eq "*" - left.left.should be_a(Mint::Ast::Variable) - left.right.should be_a(Mint::Ast::Variable) - end -end diff --git a/spec/parsers/parenthesized_expression_spec.cr b/spec/parsers/parenthesized_expression_spec.cr deleted file mode 100644 index 20aa52009..000000000 --- a/spec/parsers/parenthesized_expression_spec.cr +++ /dev/null @@ -1,15 +0,0 @@ -require "../spec_helper" - -describe "Parenthesized Expression" do - subject parenthesized_expression - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_ignore "(" - expect_ignore "(a" - - expect_ok "(a)" - expect_ok "( a )" -end diff --git a/spec/parsers/pipe_spec.cr b/spec/parsers/pipe_spec.cr deleted file mode 100644 index ac7e3b37f..000000000 --- a/spec/parsers/pipe_spec.cr +++ /dev/null @@ -1,11 +0,0 @@ -require "../spec_helper" - -describe "Pipe" do - it "rolls up a function call" do - call = - Mint::Parser.new("a |> b()", "TestFile.mint") - .expression!(Mint::SyntaxError) - - call.should be_a(Mint::Ast::Pipe) - end -end diff --git a/spec/parsers/property_spec.cr b/spec/parsers/property_spec.cr deleted file mode 100644 index 3c844653e..000000000 --- a/spec/parsers/property_spec.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Component Property" do - subject property - - expect_ignore "prop" - expect_ignore "asd" - - expect_error "property ", Mint::Parser::PropertyExpectedName - expect_error "property .", Mint::Parser::PropertyExpectedName - expect_error "property a :", Mint::Parser::PropertyExpectedType - expect_error "property a : ", Mint::Parser::PropertyExpectedType - expect_error "property a : T =", Mint::Parser::PropertyExpectedDefaultValue - expect_error "property a : T = ", Mint::Parser::PropertyExpectedDefaultValue - - expect_ok "property a : T" - expect_ok "property test = a" - expect_ok "property test : Type = a" -end diff --git a/spec/parsers/provider_spec.cr b/spec/parsers/provider_spec.cr deleted file mode 100644 index 37770b229..000000000 --- a/spec/parsers/provider_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe "Provider" do - subject provider - - expect_ignore "" - expect_ignore "." - expect_ignore "prov" - - expect_error "provider", Mint::Parser::ProviderExpectedName - expect_error "provider Test", Mint::Parser::ProviderExpectedColon - expect_error "provider Test: ", Mint::Parser::ProviderExpectedSubscription - expect_error "provider Test:TestSub", Mint::Parser::ProviderExpectedOpeningBracket - expect_error "provider Test:TestSub {", Mint::Parser::ProviderExpectedBody - expect_error "provider Test:TestSub { fun test : Void {void}", Mint::Parser::ProviderExpectedClosingBracket - - expect_ok "provider Test:TestSub { fun test : Void {void} }" -end diff --git a/spec/parsers/record_definition_field_spec.cr b/spec/parsers/record_definition_field_spec.cr deleted file mode 100644 index 5195dafc8..000000000 --- a/spec/parsers/record_definition_field_spec.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Record Definition Field" do - subject record_definition_field - - expect_ignore ":" - expect_ignore "-asd" - expect_ignore "???" - - expect_error "asd", Mint::Parser::RecordDefinitionFieldExpectedColon - expect_error "asd:", Mint::Parser::RecordDefinitionFieldExpectedType - expect_error "asd: ", Mint::Parser::RecordDefinitionFieldExpectedType - expect_error "asd: T using", Mint::Parser::RecordDefinitionFieldExpectedMapping - - expect_ok "asd: T" - expect_ok "asd : T" - expect_ok "asd: T(Number)" - expect_ok "asd: T(Number) using \"wtf\"" -end diff --git a/spec/parsers/record_definition_spec.cr b/spec/parsers/record_definition_spec.cr deleted file mode 100644 index 630c0a9ee..000000000 --- a/spec/parsers/record_definition_spec.cr +++ /dev/null @@ -1,20 +0,0 @@ -require "../spec_helper" - -describe "Record Definition" do - subject record_definition - - expect_ignore "." - expect_ignore "asd" - expect_ignore "::" - - expect_error "record", Mint::Parser::RecordDefinitionExpectedName - expect_error "record ", Mint::Parser::RecordDefinitionExpectedName - expect_error "record T.T", Mint::Parser::RecordDefinitionExpectedOpeningBracket - expect_error "record T.T ", Mint::Parser::RecordDefinitionExpectedOpeningBracket - expect_error "record T.T {", Mint::Parser::RecordDefinitionExpectedClosingBracket - expect_error "record T.T { ", Mint::Parser::RecordDefinitionExpectedClosingBracket - expect_error "record T.T { a: T", Mint::Parser::RecordDefinitionExpectedClosingBracket - - expect_ok "record T.T { a: T } " - expect_ok "record T.T { } " -end diff --git a/spec/parsers/record_field_spec.cr b/spec/parsers/record_field_spec.cr deleted file mode 100644 index e38e7b39c..000000000 --- a/spec/parsers/record_field_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Record Field" do - subject record_field - - expect_ignore "." - expect_ignore "-" - expect_ignore "{" - - expect_ignore "asd" - expect_ignore "asd " - expect_ignore "asd:" - expect_ignore "asd: " - - expect_ok "asd: asd" -end diff --git a/spec/parsers/record_spec.cr b/spec/parsers/record_spec.cr deleted file mode 100644 index 14f62f0b9..000000000 --- a/spec/parsers/record_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe "Record" do - subject record - - expect_ignore "," - expect_ignore "-lsa" - expect_ignore "asd" - - expect_ignore "{" - expect_ignore "{ " - expect_ignore "{ a: a" - expect_ignore "{ a: a " - - expect_ok "{}" - expect_ok "{ }" - expect_ok "{ a: a }" -end diff --git a/spec/parsers/record_update_spec.cr b/spec/parsers/record_update_spec.cr deleted file mode 100644 index 846a6750c..000000000 --- a/spec/parsers/record_update_spec.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Record Update" do - subject record_update - - expect_ignore "{" - expect_ignore "..." - expect_ignore "{ " - expect_ignore "a" - expect_ignore "{ asdasd" - - expect_error "{ request |", Mint::Parser::RecordUpdateExpectedFields - expect_error "{ request | }", Mint::Parser::RecordUpdateExpectedFields - expect_error "{ request | a: x", Mint::Parser::RecordUpdateExpectedClosingBracket - expect_error "{ request | a: x ", Mint::Parser::RecordUpdateExpectedClosingBracket - - expect_ok "{request|body:value}" - expect_ok "{ request | body: value }" -end diff --git a/spec/parsers/regexp_literal_spec.cr b/spec/parsers/regexp_literal_spec.cr deleted file mode 100644 index b13097987..000000000 --- a/spec/parsers/regexp_literal_spec.cr +++ /dev/null @@ -1,14 +0,0 @@ -require "../spec_helper" - -describe "Regexp Literal" do - subject regexp_literal - - expect_ignore "." - expect_ignore "a" - expect_ignore "blahblahblah" - - expect_error "/", Mint::Parser::RegexpLiteralExpectedClosingSlash - - expect_ok "/\\dsomething_other/" - expect_ok "/.*?/gm" -end diff --git a/spec/parsers/return_call_spec.cr b/spec/parsers/return_call_spec.cr deleted file mode 100644 index 1b055b94b..000000000 --- a/spec/parsers/return_call_spec.cr +++ /dev/null @@ -1,13 +0,0 @@ -require "../spec_helper" - -describe "Return Call" do - subject return_call - - expect_ignore "{" - expect_ignore "asd" - expect_ignore "return" - - expect_error "return ", Mint::Parser::ReturnCallExpectedExpression - - expect_ok "return a" -end diff --git a/spec/parsers/route_spec.cr b/spec/parsers/route_spec.cr deleted file mode 100644 index c5ce2f300..000000000 --- a/spec/parsers/route_spec.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "../spec_helper" - -describe "Route" do - subject route - - expect_ignore "" - expect_ignore ".." - expect_ignore "a" - expect_ignore "asdasd" - - expect_error "*asd", Mint::Parser::RouteExpectedOpeningBracket - expect_error "/test", Mint::Parser::RouteExpectedOpeningBracket - expect_error "/test (a:String", Mint::Parser::RouteExpectedClosingParentheses - expect_error "/test (a:String)", Mint::Parser::RouteExpectedOpeningBracket - expect_error "/test (a:String){", Mint::Parser::RouteExpectedExpression - expect_error "/test (a:String){ void ", Mint::Parser::RouteExpectedClosingBracket - - expect_ok "/ { void }" - expect_ok "* { void }" - expect_ok "/asd { void }" - expect_ok "/asd (a : String) { void }" -end diff --git a/spec/parsers/routes_spec.cr b/spec/parsers/routes_spec.cr deleted file mode 100644 index 084820ff4..000000000 --- a/spec/parsers/routes_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" - -describe "Route" do - subject routes - - expect_ignore "" - expect_ignore ".." - expect_ignore "a" - expect_ignore "asdasd" - - expect_error "routes", Mint::Parser::RoutesExpectedOpeningBracket - expect_error "routes{", Mint::Parser::RoutesExpectedRoute - expect_error "routes{ /test{void}", Mint::Parser::RoutesExpectedClosingBracket - - expect_ok "routes{ /test{void} }" -end diff --git a/spec/parsers/spread.cr b/spec/parsers/spread.cr deleted file mode 100644 index 2187cda60..000000000 --- a/spec/parsers/spread.cr +++ /dev/null @@ -1,13 +0,0 @@ -require "../spec_helper" - -describe "Spread" do - subject spread - - expect_ignore "." - expect_ignore ".." - expect_ignore "asd" - - expect_error "...", Mint::Parser::SpreadExpectedVariable - - expect_ok "...asd" -end diff --git a/spec/parsers/state_spec.cr b/spec/parsers/state_spec.cr deleted file mode 100644 index 7a04e9a20..000000000 --- a/spec/parsers/state_spec.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "../spec_helper" - -describe "State" do - subject state - - expect_ignore "." - expect_ignore "::" - expect_ignore "asd" - - expect_error "state ", Mint::Parser::StateExpectedName - expect_error "state .", Mint::Parser::StateExpectedName - expect_error "state a.", Mint::Parser::StateExpectedEqualSign - expect_error "state a .", Mint::Parser::StateExpectedEqualSign - expect_error "state a :", Mint::Parser::StateExpectedType - expect_error "state a : ", Mint::Parser::StateExpectedType - expect_error "state a : T", Mint::Parser::StateExpectedEqualSign - expect_error "state a : T ", Mint::Parser::StateExpectedEqualSign - expect_error "state a : T =", Mint::Parser::StateExpectedDefaultValue - expect_error "state a : T = ", Mint::Parser::StateExpectedDefaultValue - - expect_ok "state test : Type = a" -end diff --git a/spec/parsers/statement_spec.cr b/spec/parsers/statement_spec.cr deleted file mode 100644 index 0ecbbf2fa..000000000 --- a/spec/parsers/statement_spec.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "../spec_helper" - -describe "Statement" do - subject statement - - expect_ignore "" - expect_ignore "??" - expect_ignore "✔" - - expect_ok "let a = a" - expect_ok "let {a, b, c} = a" -end diff --git a/spec/parsers/store_spec.cr b/spec/parsers/store_spec.cr deleted file mode 100644 index b732425ee..000000000 --- a/spec/parsers/store_spec.cr +++ /dev/null @@ -1,21 +0,0 @@ -require "../spec_helper" - -describe "Store" do - subject store - - expect_ignore "." - expect_ignore "asd" - expect_ignore "blah" - - expect_error "store", Mint::Parser::StoreExpectedName - expect_error "store ", Mint::Parser::StoreExpectedName - expect_error "store T", Mint::Parser::StoreExpectedOpeningBracket - expect_error "store T ", Mint::Parser::StoreExpectedOpeningBracket - expect_error "store T {", Mint::Parser::StoreExpectedBody - expect_error "store T { ", Mint::Parser::StoreExpectedBody - expect_error "store T { state a : T = a", Mint::Parser::StoreExpectedClosingBracket - expect_error "store T { state a : T = a ", Mint::Parser::StoreExpectedClosingBracket - expect_error "store T { state a : T = 0state b : T = 1", Mint::Parser::StoreExpectedClosingBracket - - expect_ok "store T { state a : T = a }" -end diff --git a/spec/parsers/string_literal_spec.cr b/spec/parsers/string_literal_spec.cr deleted file mode 100644 index 6328913f3..000000000 --- a/spec/parsers/string_literal_spec.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "../spec_helper" - -describe "String Literal" do - subject string_literal - - expect_ignore "." - expect_ignore "a" - expect_ignore "blahblahblah" - - expect_error %("asd), Mint::Parser::StringExpectedEndQuote - expect_error %("asd" \\), Mint::Parser::StringExpectedOtherString - - expect_ok %("OK") - expect_ok %(""OK") - expect_ok %("OK"\\"OK") - expect_ok %("OK" \\ "OK") -end diff --git a/spec/parsers/style_spec.cr b/spec/parsers/style_spec.cr deleted file mode 100644 index c14ff578c..000000000 --- a/spec/parsers/style_spec.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "../spec_helper" - -describe "Component Style" do - subject style - - expect_ignore "asd" - expect_ignore "." - expect_ignore ":" - - expect_error "style", Mint::Parser::StyleExpectedName - expect_error "style ", Mint::Parser::StyleExpectedName - expect_error "style .", Mint::Parser::StyleExpectedName - expect_error "style T", Mint::Parser::StyleExpectedName - expect_error "style t", Mint::Parser::StyleExpectedOpeningBracket - expect_error "style t {", Mint::Parser::StyleExpectedClosingBracket - expect_error "style t { a: b;", Mint::Parser::StyleExpectedClosingBracket - expect_error "style t { a: b; ", Mint::Parser::StyleExpectedClosingBracket - expect_error "style t (name : String", Mint::Parser::StyleExpectedClosingParentheses - - expect_ok "style t { a: b; }" - expect_ok "style t (name : String) { a: name; }" -end diff --git a/spec/parsers/tuple_destructuring_spec.cr b/spec/parsers/tuple_destructuring_spec.cr deleted file mode 100644 index 99448a118..000000000 --- a/spec/parsers/tuple_destructuring_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe "Tuple Destructuring" do - subject tuple_destructuring - - expect_ignore "" - expect_ignore "??" - expect_ignore "✔" - expect_ignore "a" - expect_ignore "a " - - expect_ignore "{a " - expect_ignore "{a, {b}" - - expect_ok "{a, b, c}" - expect_ok "{a, b, c, d}" - expect_ok "{a, {b}, c, d}" -end diff --git a/spec/parsers/tuple_literal_spec.cr b/spec/parsers/tuple_literal_spec.cr deleted file mode 100644 index ccf3a5f14..000000000 --- a/spec/parsers/tuple_literal_spec.cr +++ /dev/null @@ -1,19 +0,0 @@ -require "../spec_helper" - -describe "Tuple" do - subject tuple_literal - - expect_ignore " " - expect_ignore "." - expect_ignore "asd" - - expect_ignore "{" - expect_ignore "{a" - expect_ignore "{a," - expect_ignore "{a,b" - expect_ignore "{a,{b}" - - expect_ok "{}" - expect_ok "{a,b,c}" - expect_ok "{a,{b},c}" -end diff --git a/spec/parsers/type_spec.cr b/spec/parsers/type_spec.cr deleted file mode 100644 index 8d3cd21a0..000000000 --- a/spec/parsers/type_spec.cr +++ /dev/null @@ -1,29 +0,0 @@ -require "../spec_helper" - -describe "Type" do - subject type - - expect_ignore ":" - expect_ignore "a" - - expect_error "T(a, T.)", Mint::Parser::TypeExpectedType - expect_error "T(", Mint::Parser::TypeExpectedTypeOrVariable - expect_error "T(T", Mint::Parser::TypeExpectedClosingParentheses - - expect_ok "T" - expect_ok "Type01Blank" - expect_ok "T()" - expect_ok "T(T)" - expect_ok "T(T,T)" - expect_ok "T(T, T, T)" - expect_ok "T(T, T, T(T))" - expect_ok "T(T, T, T(T, X(Y)))" -end - -describe "Type!" do - subject type!(Mint::SyntaxError) - - expect_error "a", Mint::SyntaxError - - expect_ok "T" -end diff --git a/spec/parsers/type_variable_spec.cr b/spec/parsers/type_variable_spec.cr deleted file mode 100644 index ce836f733..000000000 --- a/spec/parsers/type_variable_spec.cr +++ /dev/null @@ -1,14 +0,0 @@ -require "../spec_helper" - -describe "Variable" do - subject type_variable - - expect_ignore " " - expect_ignore "." - expect_ignore "???" - - expect_ok "a" - expect_ok "asd" - expect_ok "asdAsd" - expect_ok "asd_" -end diff --git a/spec/parsers/unary_minus_spec.cr b/spec/parsers/unary_minus_spec.cr deleted file mode 100644 index 1e5899117..000000000 --- a/spec/parsers/unary_minus_spec.cr +++ /dev/null @@ -1,13 +0,0 @@ -require "../spec_helper" - -describe "Unary Minus" do - subject unary_minus - - expect_ignore "." - expect_ignore "-" - expect_ignore "- " - - expect_ok "-0" - expect_ok "--20" - expect_ok "-a" -end diff --git a/spec/parsers/use_spec.cr b/spec/parsers/use_spec.cr deleted file mode 100644 index fea879139..000000000 --- a/spec/parsers/use_spec.cr +++ /dev/null @@ -1,23 +0,0 @@ -require "../spec_helper" - -describe "Component Use" do - subject use - - expect_ignore "." - expect_ignore "us" - - expect_error "use", Mint::Parser::UseExpectedProvider - expect_error "use ", Mint::Parser::UseExpectedProvider - expect_error "use Test", Mint::Parser::UseExpectedRecord - expect_error "use Test ", Mint::Parser::UseExpectedRecord - expect_error "use Test {}when", Mint::Parser::UseExpectedOpeningBracket - expect_error "use Test {} when", Mint::Parser::UseExpectedOpeningBracket - expect_error "use Test {} when ", Mint::Parser::UseExpectedOpeningBracket - expect_error "use Test {} when {", Mint::Parser::UseExpectedExpression - expect_error "use Test {} when { ", Mint::Parser::UseExpectedExpression - expect_error "use Test {} when { a", Mint::Parser::UseExpectedClosingBracket - expect_error "use Test {} when { a ", Mint::Parser::UseExpectedClosingBracket - - expect_ok "use Test {}" - expect_ok "use Test {} when { true }" -end diff --git a/spec/parsers/variable_spec.cr b/spec/parsers/variable_spec.cr deleted file mode 100644 index bcf4d0232..000000000 --- a/spec/parsers/variable_spec.cr +++ /dev/null @@ -1,76 +0,0 @@ -require "../spec_helper" - -describe "Variable" do - subject variable - - expect_ignore " " - expect_ignore "." - expect_ignore "???" - - expect_ok "a" - expect_ok "asd" - expect_ok "asdAsd" - expect_ok "asd_" -end - -describe "Variable!" do - subject variable!(Mint::SyntaxError) - - expect_error " ", Mint::SyntaxError - expect_error ".", Mint::SyntaxError - expect_error "???", Mint::SyntaxError -end - -describe "Variable With Dashes" do - subject variable_with_dashes - - expect_ignore " " - expect_ignore "." - expect_ignore "???" - - expect_ok "a" - expect_ok "asd-ada-sd---asd" - expect_ok "asd" - expect_ok "asdAsd" - expect_ok "asd_" -end - -describe "Variable Attribute Name" do - subject variable_attribute_name - - expect_ignore " " - expect_ignore "." - expect_ignore "???" - - expect_ok "a" - expect_ok "asd-ada-sd---asd" - expect_ok "asd" - expect_ok "asdAsd" - expect_ok "asd-::asd" -end - -describe "Variable With Dashes!" do - subject variable_with_dashes!(Mint::SyntaxError) - - expect_error " ", Mint::SyntaxError - expect_error ".", Mint::SyntaxError - expect_error "???", Mint::SyntaxError -end - -describe "Variable Constant!" do - subject variable_constant! - - expect_ok "A" - expect_ok "ASD" - expect_ok "ASD_ASD_ASD" - expect_ok "ASD_ASD__ASD" - expect_ok "ASD_ASD________ASD" - expect_ok "ASD_" - - expect_error " ", Mint::Parser::ConstantExpectedName - expect_error ".", Mint::Parser::ConstantExpectedName - expect_error "_", Mint::Parser::ConstantExpectedName - expect_error "???", Mint::Parser::ConstantExpectedName - expect_error "_ASD", Mint::Parser::ConstantExpectedName - expect_error "1ASD", Mint::Parser::ConstantExpectedName -end diff --git a/spec/parsers/void_spec.cr b/spec/parsers/void_spec.cr deleted file mode 100644 index dd08a654d..000000000 --- a/spec/parsers/void_spec.cr +++ /dev/null @@ -1,11 +0,0 @@ -require "../spec_helper" - -describe "Void" do - subject void - - expect_ignore "" - expect_ignore "asd" - expect_ignore "voi" - - expect_ok "void" -end diff --git a/spec/recursion_spec.cr b/spec/recursion_spec.cr deleted file mode 100644 index 65d4c4306..000000000 --- a/spec/recursion_spec.cr +++ /dev/null @@ -1,120 +0,0 @@ -require "./spec_helper" - -describe "variable" do - it "raises error" do - example = - <<-MINT - component Test { - state greeting : String = "" - - fun test : Promise(Void) { - let greeting = - if (greeting == "hello") { - "bye" - } else { - "hello" - } - - next { greeting: greeting } - } - - fun render : Html { - test() - -
- } - } - - component Main { - fun render : Html { - - } - } - MINT - - ast = Mint::Parser.parse(example, "test.mint") - ast.class.should eq(Mint::Ast) - - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - end -end - -describe "function" do - it "raises error" do - example = - <<-MINT - component Main { - state greeting : String = "" - - fun test : Void { - test() - } - - fun render : Html { - test() - -
- } - } - MINT - - ast = Mint::Parser.parse(example, "test.mint") - ast.class.should eq(Mint::Ast) - - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - end -end - -describe "state" do - it "raises error" do - example = - <<-MINT - component Main { - state greeting : String = greeting - - fun render : Html { -
- } - } - MINT - - ast = Mint::Parser.parse(example, "test.mint") - ast.class.should eq(Mint::Ast) - - expect_raises(Mint::TypeChecker::Recursion) do - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - end - end -end - -describe "property" do - it "raises error" do - example = - <<-MINT - component Test { - property greeting : String = greeting - - fun render : Html { -
- } - } - - component Main { - fun render : Html { - - } - } - MINT - - ast = Mint::Parser.parse(example, "test.mint") - ast.class.should eq(Mint::Ast) - - expect_raises(Mint::TypeChecker::Recursion) do - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - end - end -end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 9ff4578a7..4eaf40d13 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,17 +1,6 @@ require "spec" MINT_ENV["TEST"] = "TRUE" -ERROR_MESSAGES = %w[] - -class Mint::Error < Exception - macro inherited - name = {{@type.name.stringify.split("::").last.underscore}} - - unless name.in?("type_error", "install_error", "syntax_error", "json_error") - ERROR_MESSAGES << name - end - end -end def diff(a, b) file1 = File.tempfile do |f| diff --git a/spec/type_checking/access b/spec/type_checking/access deleted file mode 100644 index 4d32f95eb..000000000 --- a/spec/type_checking/access +++ /dev/null @@ -1,50 +0,0 @@ -record Blah1 { - blah : String -} - -record Blah { - blah : Blah1 -} - -component Main { - fun render : String { - let blah = - { blah: { blah: "Helllo" } } - - blah.blah.blah - } -} ------------------------------------------------------------------AccessNotRecord -component Main { - fun render : Bool { - let blah = "" - - blah.blah.blah - } -} ------------------------------------------------------------------AccessNotRecord -record Blah { - blah : String -} - -component Main { - fun render : Bool { - let blah = - { blah: "Blah" } - - blah.blah.blah - } -} --------------------------------------------------------------AccessFieldNotFound -record Blah { - blah : String -} - -component Main { - fun render : Bool { - let blah = - { blah: "Hello" } - - blah.blaha - } -} diff --git a/spec/type_checking/argument b/spec/type_checking/argument deleted file mode 100644 index 71c7eeb38..000000000 --- a/spec/type_checking/argument +++ /dev/null @@ -1,19 +0,0 @@ -component Main { - fun test (a : String) : String { - a - } - - fun render : String { - test("") - } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test (a : String) : Number { - a - } - - fun render : String { - test("") - } -} diff --git a/spec/type_checking/argument_with_default_value b/spec/type_checking/argument_with_default_value deleted file mode 100644 index e989342dd..000000000 --- a/spec/type_checking/argument_with_default_value +++ /dev/null @@ -1,19 +0,0 @@ -component Main { - fun test (a : String = "Hello") : String { - a - } - - fun render : String { - test() - } -} --------------------------------------------FunctionArgumentMustHaveADefaultValue -component Main { - fun test (a : String = "Hello", b : String) : Number { - a - } - - fun render : String { - test() - } -} diff --git a/spec/type_checking/argument_with_default_value_inline_function b/spec/type_checking/argument_with_default_value_inline_function deleted file mode 100644 index 2b972173a..000000000 --- a/spec/type_checking/argument_with_default_value_inline_function +++ /dev/null @@ -1,21 +0,0 @@ -component Main { - fun render : String { - let test = - (a : String = "Hello") : String { - a - } - - test() - } -} --------------------------------------------FunctionArgumentMustHaveADefaultValue -component Main { - fun render : String { - let test = - (a : String = "Hello", b : String) : Number { - a - } - - test() - } -} diff --git a/spec/type_checking/bool_literal_false b/spec/type_checking/bool_literal_false deleted file mode 100644 index 9f27d775c..000000000 --- a/spec/type_checking/bool_literal_false +++ /dev/null @@ -1,23 +0,0 @@ -component Main { - fun test : Bool { - false - } - - fun render : Html { - test() - -
- } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test : String { - false - } - - fun render : Html { - test() - -
- } -} diff --git a/spec/type_checking/bool_literal_true b/spec/type_checking/bool_literal_true deleted file mode 100644 index 9aae5b127..000000000 --- a/spec/type_checking/bool_literal_true +++ /dev/null @@ -1,23 +0,0 @@ -component Main { - fun test : Bool { - true - } - - fun render : Html { - test() - -
- } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test : String { - true - } - - fun render : Html { - test() - -
- } -} diff --git a/spec/type_checking/case b/spec/type_checking/case deleted file mode 100644 index 523a26bed..000000000 --- a/spec/type_checking/case +++ /dev/null @@ -1,57 +0,0 @@ -component Main { - fun render : String { - case ("x") { - "a" => "a" - "b" => "b" - => "c" - } - } -} -------------------------------------------------------------CaseBranchNotMatches -component Main { - fun render : String { - case ("x") { - "a" => "a" - "b" => true - => "c" - } - } -} ---------------------------------------------------------------CaseUnnecessaryAll -enum A { - B - C -} - -component Main { - fun render : String { - case (A::B) { - A::B => "a" - A::C => "c" - => "x" - } - } -} -------------------------------------------------------------------CaseNotCovered -component Main { - fun render : String { - case ("a") { - "a" => "a" - } - } -} ---------------------------------------------------------------CaseEnumNotCovered -enum A { - B - C - D -} - -component Main { - fun render : String { - case (A::B) { - A::B => "a" - A::C => "c" - } - } -} diff --git a/spec/type_checking/case_branch b/spec/type_checking/case_branch deleted file mode 100644 index 6f3bde2a9..000000000 --- a/spec/type_checking/case_branch +++ /dev/null @@ -1,67 +0,0 @@ -component Main { - fun render : String { - case ("x") { - "a" => "a" - "b" => "b" - => "c" - } - } -} -------------------------------------------------------DestructuringTypeMismatch -component Main { - fun render : String { - case ("x") { - true => "a" - "b" => "b" - => "c" - } - } -} ----------------------------------------------------DestructuringMultipleSpreads -component Main { - fun render : String { - case ([]) { - [...a,...b] => "a" - } - } -} -------------------------------------------------------DestructuringTypeMismatch -component Main { - fun render : String { - case ("") { - [...a,...b] => "a" - } - } -} ------------------------------------------------------DestructuringTupleMismatch -component Main { - fun render : String { - case ({"a", "b"}) { - {a, b, c} => "a" - } - } -} -------------------------------------------------------DestructuringTypeMismatch -component Main { - fun render : String { - case ("") { - {a, b} => "a" - } - } -} -------------------------------------------------------DestructuringTypeMismatch -component Main { - fun render : String { - case ({"a", "b"}) { - {"a", {"b"}} => "a" - } - } -} -------------------------------------------------------DestructuringTypeMismatch -component Main { - fun render : String { - case ({"a", "b"}) { - {{a}, b} => "a" - } - } -} diff --git a/spec/type_checking/case_type_unification b/spec/type_checking/case_type_unification deleted file mode 100644 index ec52cc781..000000000 --- a/spec/type_checking/case_type_unification +++ /dev/null @@ -1,39 +0,0 @@ -enum Maybe(value) { - Just(value) - Nothing -} - -component Main { - fun testCase : Maybe(Number) { - case (-1) { - -1 => Maybe::Nothing - => Maybe::Just(2) - } - } - - fun render : String { - testCase() - - "" - } -} -------------------------------------------------------------FunctionTypeMismatch -enum Maybe(value) { - Just(value) - Nothing -} - -component Main { - fun testCase : Maybe(String) { - case (-1) { - -1 => Maybe::Nothing - => Maybe::Just(2) - } - } - - fun render : String { - testCase() - - "" - } -} diff --git a/spec/type_checking/component b/spec/type_checking/component deleted file mode 100644 index fc4c29b6e..000000000 --- a/spec/type_checking/component +++ /dev/null @@ -1,43 +0,0 @@ -component Main { - fun render : Html { -
- } -} ------------------------------------------------------ComponentRenderTypeMismatch -component Main { - fun render : Bool { - true - } -} ----------------------------------------------------------ComponentNotFoundRender -component Main { - fun a : String { - "" - } -} ------------------------------------------------------ComponentEntityNameConflict -component Main { - property render : String = "" - - fun render : Bool { - true - } -} ---------------------------------------------------ComponentReferenceNameConflict -component Main { - fun render : Html { -
-
-
- } -} -----------------------------------------------------ComponentFunctionTypeMismatch -component Main { - fun componentDidUpdate (a : String) : String { - "" - } - - fun render : Html { -
- } -} diff --git a/spec/type_checking/connect b/spec/type_checking/connect deleted file mode 100644 index 488cc47f6..000000000 --- a/spec/type_checking/connect +++ /dev/null @@ -1,83 +0,0 @@ -store Test { - state x : String = "" - - fun y : String { - `hello` - } -} - -component Main { - connect Test exposing { x, y } - - fun render : Html { -
- } -} ------------------------------------------------------------ConnectNotFoundMember -store Test { - state x : String = "" -} - -component Main { - connect Test exposing { x, y } - - fun render : Html { -
- } -} -------------------------------------------------------------ConnectNotFoundStore -component Main { - connect Test exposing { x, y } - - fun render : Html { -
- } -} -----------------------------------------------------ComponentExposedNameConflict -store Test { - state x : String = "" -} - -component A { - connect Test exposing { x } - - get x : String { - "" - } - - fun render : Html { -
- } -} -----------------------------------------------------ComponentExposedNameConflict -store Test { - state x : String = "" -} - -component A { - connect Test exposing { x as y } - - get y : String { - "" - } - - fun render : Html { -
- } -} --------------------------------------------------------------------------------- -store Test { - state x : String = "" -} - -component A { - connect Test exposing { x as y } - - get x : String { - "" - } - - fun render : Html { -
- } -} diff --git a/spec/type_checking/css_font_face b/spec/type_checking/css_font_face deleted file mode 100644 index 8833f738b..000000000 --- a/spec/type_checking/css_font_face +++ /dev/null @@ -1,31 +0,0 @@ -component Main { - style test { - @font-face { - src: url(sansation_light.woff); - font-family: myFirstFont; - } - - @font-face { - src: url(sansation_light2.woff); - font-family: myFirstFont; - font-weight: bold; - } - } - - fun render : Html { - - } -} ---------------------------------------------------------CssFontFaceInterpolation -component Main { - style test { - @font-face { - src: url(sansation_light.woff); - font-family: #{"myFirstFont"}; - } - } - - fun render : Html { - - } -} diff --git a/spec/type_checking/css_selector b/spec/type_checking/css_selector deleted file mode 100644 index 5aabdc850..000000000 --- a/spec/type_checking/css_selector +++ /dev/null @@ -1,38 +0,0 @@ -component Main { - style test { - & div { - color: #{color}; - } - - &:focus { - color: red; - } - } - - get color : String { - "blue" - } - - fun render : Html { - - } -} --------------------------------------------------------CssDefinitionTypeMismatch -component Main { - style test { - & div { - color: #{color}; - } - &:focus { - color: red; - } - } - - get color : Bool { - true - } - - fun render : Html { - - } -} diff --git a/spec/type_checking/css_string b/spec/type_checking/css_string deleted file mode 100644 index f654522f1..000000000 --- a/spec/type_checking/css_string +++ /dev/null @@ -1,15 +0,0 @@ -component Main { - state name : String = "Joe" - - style unicode { - span::after { - content: "Here is some content; Thanks #{name}"; - } - } - - fun render { - - -
- } -} diff --git a/spec/type_checking/css_with_arguments b/spec/type_checking/css_with_arguments deleted file mode 100644 index 6cf93a4e0..000000000 --- a/spec/type_checking/css_with_arguments +++ /dev/null @@ -1,19 +0,0 @@ -component Main { - style test(name : String) { - color: #{name}; - } - - fun render : Html { - - } -} ------------------------------------------------------------------VariableMissing -component Main { - style test(name : String) { - color: #{name2}; - } - - fun render : Html { - - } -} diff --git a/spec/type_checking/decode b/spec/type_checking/decode deleted file mode 100644 index f1526211e..000000000 --- a/spec/type_checking/decode +++ /dev/null @@ -1,47 +0,0 @@ -record X { - name : String -} - -component Main { - fun render : Html { - decode (`{}`) as X - -
- } -} -------------------------------------------------------------DecodeExpectedObject -record X { - name : String -} - -component Main { - fun render : Html { - decode "" as X - -
- } -} ----------------------------------------------------------------DecodeComplexType -record X { - name : Blah -} - -component Main { - fun render : Html { - decode (`{}`) as X - -
- } -} ----------------------------------------------------------------DecodeComplexType -record X { - name : Maybe(Blah) -} - -component Main { - fun render : Html { - decode (`{}`) as X - -
- } -} diff --git a/spec/type_checking/directives/documentation b/spec/type_checking/directives/documentation deleted file mode 100644 index b8e8262cf..000000000 --- a/spec/type_checking/directives/documentation +++ /dev/null @@ -1,15 +0,0 @@ -component Main { - fun render : String { - @documentation(Main) - - "Hello There" - } -} ---------------------------------------------DocumentationDirectiveEntityNotFound -component Main { - fun render : String { - @documentation(X) - - "Hello There" - } -} diff --git a/spec/type_checking/directives/format b/spec/type_checking/directives/format deleted file mode 100644 index 6e06670ad..000000000 --- a/spec/type_checking/directives/format +++ /dev/null @@ -1,10 +0,0 @@ -component Main { - fun render : String { - let {result, formatted} = - @format { - "Hello" - } - - result + formatted - } -} diff --git a/spec/type_checking/directives/svg b/spec/type_checking/directives/svg deleted file mode 100644 index b640fd62f..000000000 --- a/spec/type_checking/directives/svg +++ /dev/null @@ -1,29 +0,0 @@ -component Main { - fun render : Html { - @svg(../../fixtures/icon.svg) - } -} ---------------------------------------------------------SvgDirectiveExpectedFile -component Main { - fun render : Html { - @svg(../../fixtures/icon-missing) - } -} ----------------------------------------------------------SvgDirectiveExpectedSvg -component Main { - fun render : Html { - @svg(../../fixtures/icon-not-svg) - } -} -------------------------------------------------------SvgDirectiveExpectedSvgTag -component Main { - fun render : Html { - @svg(../../fixtures/icon-no-svg-tag) - } -} ---------------------------------------------------SvgDirectiveExpectedDimensions -component Main { - fun render : Html { - @svg(../../fixtures/icon-no-dimensions) - } -} diff --git a/spec/type_checking/enum b/spec/type_checking/enum deleted file mode 100644 index 11b151cea..000000000 --- a/spec/type_checking/enum +++ /dev/null @@ -1,17 +0,0 @@ -enum Result(error, value) { - Error(error) - Ok(value) -} --------------------------------------------------------------EnumUnusedParameter -enum A(a, b, c) { - B - C -} ----------------------------------------------------------EnumNotDefinedParameter -enum A { - B(a) -} ----------------------------------------------------------EnumNotDefinedParameter -enum A { - B(Maybe(a)) -} diff --git a/spec/type_checking/enum_id b/spec/type_checking/enum_id deleted file mode 100644 index 8e33a27a5..000000000 --- a/spec/type_checking/enum_id +++ /dev/null @@ -1,46 +0,0 @@ -enum A { - B - C -} - -component Main { - fun render : String { - case (A::B) { - => "" - } - } -} ---------------------------------------------------------------EnumIdTypeMismatch -enum A { - B(String) - C -} - -component Main { - fun render : String { - case (A::B(0)) { - => "" - } - } -} ----------------------------------------------------------------EnumIdEnumMissing -enum A { - B(String) - C -} - -component Main { - fun render : String { - case (A::D(0)) { - => "" - } - } -} ----------------------------------------------------------------EnumIdTypeMissing -component Main { - fun render : String { - case (C::D(0)) { - => "" - } - } -} diff --git a/spec/type_checking/enum_record b/spec/type_checking/enum_record deleted file mode 100644 index 110e19946..000000000 --- a/spec/type_checking/enum_record +++ /dev/null @@ -1,13 +0,0 @@ -enum A { - B(name : String, color : String) - C -} - -component Main { - fun render : String { - case (A::B(name: "Joe", color: "Blue")) { - A::B(name, color) => "" - A::C => "" - } - } -} diff --git a/spec/type_checking/env b/spec/type_checking/env deleted file mode 100644 index 4ec041b9e..000000000 --- a/spec/type_checking/env +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : String { - @TEST - } -} --------------------------------------------------------------EnvNotFoundVariable -component Main { - fun render : String { - @XXX - } -} diff --git a/spec/type_checking/function b/spec/type_checking/function deleted file mode 100644 index cdf761dcd..000000000 --- a/spec/type_checking/function +++ /dev/null @@ -1,35 +0,0 @@ -component Main { - fun test : Bool { - true - } - - fun render : String { - test() - - "" - } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test : Bool { - "hello" - } - - fun render : String { - test() - - "" - } -} ---------------------------------------------------------FunctionArgumentConflict -component Main { - fun test (a : String, a : String) : Bool { - "hello" - } - - fun render : String { - test() - - "" - } -} diff --git a/spec/type_checking/function_call b/spec/type_checking/function_call deleted file mode 100644 index 356683d24..000000000 --- a/spec/type_checking/function_call +++ /dev/null @@ -1,71 +0,0 @@ -component Main { - fun a : String { - "Hello" - } - - fun b : String { - a() - } - - fun render : Html { -
- } -} ------------------------------------------------------------------VariableMissing -component Main { - fun b : String { - x() - } - - fun render : Html { - b() - -
- } -} -----------------------------------------------------------------CallNotAFunction -component Main { - state x : String = "" - - fun b : String { - x() - } - - fun render : Html { - b() - -
- } -} ---------------------------------------------------------CallArgumentTypeMismatch -component Main { - fun a (input : String) : String { - input - } - - fun b : String { - a(0) - } - - fun render : Html { - b() - -
- } -} ---------------------------------------------------------CallArgumentSizeMismatch -component Main { - fun a (input : String) : String { - input - } - - fun b : String { - a("Hello", "There") - } - - fun render : Html { - b() - -
- } -} diff --git a/spec/type_checking/function_call_labelled b/spec/type_checking/function_call_labelled deleted file mode 100644 index ada9281d0..000000000 --- a/spec/type_checking/function_call_labelled +++ /dev/null @@ -1,39 +0,0 @@ -component Main { - fun test (argument1 : String, argument2: Number) : Html { -
- } - - fun render : Html { - test(argument2: 0, argument1: "") - } -} ----------------------------------------------------------CallWithMixedArguments -component Main { - fun test (argument1 : String, argument2: Number) : Html { -
- } - - fun render : Html { - test(0, argument1: "") - } -} ----------------------------------------------------------CallWithMixedArguments -component Main { - fun test (argument1 : String, argument2: Number) : Html { -
- } - - fun render : Html { - test(argument2: 0, "") - } -} ------------------------------------------------------------CallNotFoundArgument -component Main { - fun test (argument1 : String, argument2: Number) : Html { -
- } - - fun render : Html { - test(argument3: 0, argument1: "") - } -} diff --git a/spec/type_checking/function_returning_argument b/spec/type_checking/function_returning_argument deleted file mode 100644 index 859449ad4..000000000 --- a/spec/type_checking/function_returning_argument +++ /dev/null @@ -1,19 +0,0 @@ -component Main { - fun test (a : Bool) : Bool { - a - } - - fun render : String { - "" - } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test (a : String) : Bool { - a - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/function_returning_variable_argument b/spec/type_checking/function_returning_variable_argument deleted file mode 100644 index b85d4a48f..000000000 --- a/spec/type_checking/function_returning_variable_argument +++ /dev/null @@ -1,9 +0,0 @@ -component Main { - fun test (a : a) : a { - a - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/get b/spec/type_checking/get deleted file mode 100644 index 496a7df8a..000000000 --- a/spec/type_checking/get +++ /dev/null @@ -1,23 +0,0 @@ -component Main { - get test : Number { - 0 - } - - fun render : Html { - test - -
- } -} ------------------------------------------------------------------GetTypeMismatch -component Main { - get test : Number { - "asd" - } - - fun render : Html { - test() - -
- } -} diff --git a/spec/type_checking/global_component_inside_call b/spec/type_checking/global_component_inside_call deleted file mode 100644 index f533a932f..000000000 --- a/spec/type_checking/global_component_inside_call +++ /dev/null @@ -1,19 +0,0 @@ -global component Test { - fun c : String { - "" - } - - fun b : String { - c() - } - - fun render : Html { -
- } -} - -component Main { - fun render : String { - Test.b() - } -} diff --git a/spec/type_checking/html_attribute b/spec/type_checking/html_attribute deleted file mode 100644 index 8b06ce106..000000000 --- a/spec/type_checking/html_attribute +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : Html { -
- } -} ----------------------------------------HtmlAttributeElementAttributeTypeMismatch -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/html_attribute_array b/spec/type_checking/html_attribute_array deleted file mode 100644 index 070f14e80..000000000 --- a/spec/type_checking/html_attribute_array +++ /dev/null @@ -1,33 +0,0 @@ -component Test { - property things : Array(String) = [] - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} ---------------------------------------HtmlAttributeComponentPropertyTypeMismatch -component Test { - property things : Array(String) = [] - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} ----------------------------------------HtmlAttributeElementAttributeTypeMismatch -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/html_attribute_disabled b/spec/type_checking/html_attribute_disabled deleted file mode 100644 index 15f572a5b..000000000 --- a/spec/type_checking/html_attribute_disabled +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : Html { -
- } -} ----------------------------------------HtmlAttributeElementAttributeTypeMismatch -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/html_attribute_event b/spec/type_checking/html_attribute_event deleted file mode 100644 index f824809d4..000000000 --- a/spec/type_checking/html_attribute_event +++ /dev/null @@ -1,17 +0,0 @@ -component Main { - fun render : Html { -
- } -} --------------------------------------------------------------------------------- -component Test { - fun render : Html { -
- } -} ----------------------------------------HtmlAttributeElementAttributeTypeMismatch -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/html_attribute_key b/spec/type_checking/html_attribute_key deleted file mode 100644 index f132fd4a8..000000000 --- a/spec/type_checking/html_attribute_key +++ /dev/null @@ -1,23 +0,0 @@ -component X { - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} --------------------------------------------HtmlAttributeComponentKeyTypeMismatch -component X { - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} diff --git a/spec/type_checking/html_attribute_not_found b/spec/type_checking/html_attribute_not_found deleted file mode 100644 index 459b340f8..000000000 --- a/spec/type_checking/html_attribute_not_found +++ /dev/null @@ -1,27 +0,0 @@ -component X { - property test : String = "" - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} -------------------------------------------HtmlAttributeNotFoundComponentProperty -component X { - property test : String = "" - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} diff --git a/spec/type_checking/html_attribute_readonly b/spec/type_checking/html_attribute_readonly deleted file mode 100644 index 8e6d31858..000000000 --- a/spec/type_checking/html_attribute_readonly +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : Html { -
- } -} ----------------------------------------HtmlAttributeElementAttributeTypeMismatch -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/html_attribute_ref b/spec/type_checking/html_attribute_ref deleted file mode 100644 index f9f85f3e1..000000000 --- a/spec/type_checking/html_attribute_ref +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : Html { -
- } -} ----------------------------------------------------------HtmlElementRefForbidden -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/html_attribute_type_mismatch b/spec/type_checking/html_attribute_type_mismatch deleted file mode 100644 index 23b2c2574..000000000 --- a/spec/type_checking/html_attribute_type_mismatch +++ /dev/null @@ -1,27 +0,0 @@ -component X { - property test : String = "" - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} ---------------------------------------HtmlAttributeComponentPropertyTypeMismatch -component X { - property test : String = "" - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} diff --git a/spec/type_checking/html_component b/spec/type_checking/html_component deleted file mode 100644 index adca73239..000000000 --- a/spec/type_checking/html_component +++ /dev/null @@ -1,43 +0,0 @@ -component Test { - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} ---------------------------------------------------HtmlComponentNotFoundComponent -component Main { - fun render : Html { - - } -} -----------------------------------------------------HtmlComponentGlobalComponent -global component X { - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} ---------------------------------------------------HtmlComponentAttributeRequired -component Test { - property name : String - - fun render : Html { -
- } -} - -component Main { - fun render : Html { - - } -} diff --git a/spec/type_checking/html_element_not_in_component b/spec/type_checking/html_element_not_in_component deleted file mode 100644 index c8c745566..000000000 --- a/spec/type_checking/html_element_not_in_component +++ /dev/null @@ -1,52 +0,0 @@ -component Main { - style base { - color: red; - } - - fun render : Html { - -
- } -} -----------------------------------------------HtmlElementStyleOutsideOfComponent -module X { - fun render : Html { - - } -} - -component Main { - fun render : Html { - X.render() - } -} -------------------------------------------HtmlElementReferenceOutsideOfComponent -module X { - fun render : Html { -
- } -} - -component Main { - fun render : Html { - X.render() - } -} -----------------------------------------HtmlComponentReferenceOutsideOfComponent -module X { - fun render : Html { - - } -} - -component Test { - fun render : Html { -
- } -} - -component Main { - fun render : Html { - X.render() - } -} diff --git a/spec/type_checking/html_element_style b/spec/type_checking/html_element_style deleted file mode 100644 index ece1768f2..000000000 --- a/spec/type_checking/html_element_style +++ /dev/null @@ -1,16 +0,0 @@ -component Main { - style base { - color: red; - } - - fun render : Html { - -
- } -} ----------------------------------------------------------------HtmlStyleNotFound -component Main { - fun render : Html { - - } -} diff --git a/spec/type_checking/html_expression b/spec/type_checking/html_expression deleted file mode 100644 index c8d930582..000000000 --- a/spec/type_checking/html_expression +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : Html { -
<{ "Hello" }>
- } -} ----------------------------------------------------------HtmlContentTypeMismatch -component Main { - fun render : Html { -
<{ 0 }>
- } -} diff --git a/spec/type_checking/html_style b/spec/type_checking/html_style deleted file mode 100644 index 56578e702..000000000 --- a/spec/type_checking/html_style +++ /dev/null @@ -1,39 +0,0 @@ -component Main { - style base (name : String, active : Bool) { - color: red; - } - - fun render : Html { - - } -} ----------------------------------------------------HtmlStyleArgumentSizeMismatch -component Main { - style base (name : String, active : Bool) { - color: red; - } - - fun render : Html { - - } -} ----------------------------------------------------HtmlStyleArgumentSizeMismatch -component Main { - style base (name : String, active : Bool) { - color: red; - } - - fun render : Html { - - } -} ----------------------------------------------------HtmlStyleArgumentTypeMismatch -component Main { - style base (name : String, active : Bool) { - color: red; - } - - fun render : Html { - - } -} diff --git a/spec/type_checking/if b/spec/type_checking/if deleted file mode 100644 index b5a303bcb..000000000 --- a/spec/type_checking/if +++ /dev/null @@ -1,29 +0,0 @@ -component Main { - fun render : String { - if ("a" == "b") { - "x" - } else { - "y" - } - } -} ----------------------------------------------------------IfConditionTypeMismatch -component Main { - fun render : String { - if ("a") { - "x" - } else { - "y" - } - } -} ---------------------------------------------------------------IfElseTypeMismatch -component Main { - fun render : String { - if ("a" == "b") { - "x" - } else { - 10 - } - } -} diff --git a/spec/type_checking/if_in_html b/spec/type_checking/if_in_html deleted file mode 100644 index b152c9d9f..000000000 --- a/spec/type_checking/if_in_html +++ /dev/null @@ -1,21 +0,0 @@ -component Main { - fun render : Html { -
- if ("a" == "b") { - "x" - } -
- } -} --------------------------------------------------------------------------------- -component Main { - fun render : Html { -
- if ("a" == "b") { - "x" - } else { - "x" - } -
- } -} diff --git a/spec/type_checking/if_let b/spec/type_checking/if_let deleted file mode 100644 index f21c89b93..000000000 --- a/spec/type_checking/if_let +++ /dev/null @@ -1,59 +0,0 @@ -enum T { - A(String) - B -} - -component Main { - fun render : String { - if (let T::A(a) = T::A("")) { - a - } else { - "b" - } - } -} -------------------------------------------------------------------------------- -enum T { - A(String) - B -} - -component Main { - fun render : String { - if (let T::A(a) = T::B) { - a - } else { - "b" - } - } -} -------------------------------------------------------DestructuringTypeMismatch -enum T { - A(String) - B -} - -component Main { - fun render : String { - if (let T::A(a) = "") { - a - } else { - "b" - } - } -} --------------------------------------------------------------IfElseTypeMismatch -enum T { - A(String) - B(Number) -} - -component Main { - fun render : String { - if (let T::B(a) = T::B(0)) { - a - } else { - "b" - } - } -} diff --git a/spec/type_checking/inline_function b/spec/type_checking/inline_function deleted file mode 100644 index e5c485219..000000000 --- a/spec/type_checking/inline_function +++ /dev/null @@ -1,38 +0,0 @@ -component Main { - fun test : String { - let a = - () : String { "Hello" } - - a() - } - - fun render : String { - "" - } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test : String { - let a = - () : Bool { true } - - a() - } - - fun render : String { - "" - } -} -------------------------------------------------------InlineFunctionTypeMismatch -component Main { - fun test : String { - let a = - () : String { true } - - a() - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/locale_key b/spec/type_checking/locale_key deleted file mode 100644 index 08b2eb7cf..000000000 --- a/spec/type_checking/locale_key +++ /dev/null @@ -1,43 +0,0 @@ -locale en { - test: "" -} - -component Main { - fun render : String { - :test - } -} --------------------------------------------------------------TranslationMissing -component Main { - fun render : String { - :test - } -} --------------------------------------------------------TranslationNotTranslated -locale en { - test: "" -} - -locale hu { - -} - -component Main { - fun render : String { - :test - } -} -------------------------------------------------------------TranslationMismatch -locale en { - test: "" -} - -locale hu { - test: 0 -} - -component Main { - fun render : String { - :test - } -} diff --git a/spec/type_checking/member_access b/spec/type_checking/member_access deleted file mode 100644 index 323070c7b..000000000 --- a/spec/type_checking/member_access +++ /dev/null @@ -1,19 +0,0 @@ -record Test { - test : String -} - -component Main { - fun render : String { - .test({test: "Hello"}) - } -} ---------------------------------------------------------CallArgumentTypeMismatch -record Test { - test : String -} - -component Main { - fun render : String { - .asd({test: "Hello"}) - } -} diff --git a/spec/type_checking/module b/spec/type_checking/module deleted file mode 100644 index 23c5ade30..000000000 --- a/spec/type_checking/module +++ /dev/null @@ -1,11 +0,0 @@ -module A { - fun test : String { - "Hello" - } -} - -component Main { - fun render : String { - A.test() - } -} diff --git a/spec/type_checking/module_access b/spec/type_checking/module_access deleted file mode 100644 index 8733b1777..000000000 --- a/spec/type_checking/module_access +++ /dev/null @@ -1,42 +0,0 @@ -module Test { - fun a : String { - "Hello" - } - - fun b : Function(String) { - Test.a - } -} - -component Main { - fun render : String { - let x = - Test.b() - - x() - } -} -----------------------------------------------------ModuleAccessNotFoundFunction -module Test { - fun b : Function(String) { - Test.a - } -} - -component Main { - fun render : String { - Test.b() - } -} -------------------------------------------------------ModuleAccessNotFoundModule -module Test { - fun b : Function(String) { - XTest.a - } -} - -component Main { - fun render : String { - Test.b() - } -} diff --git a/spec/type_checking/module_access_get b/spec/type_checking/module_access_get deleted file mode 100644 index 3e5152e0c..000000000 --- a/spec/type_checking/module_access_get +++ /dev/null @@ -1,9 +0,0 @@ -store Test { - get a : String { - "Hello" - } - - fun b : String { - Test.a - } -} diff --git a/spec/type_checking/module_access_provider b/spec/type_checking/module_access_provider deleted file mode 100644 index 144978769..000000000 --- a/spec/type_checking/module_access_provider +++ /dev/null @@ -1,19 +0,0 @@ -record Test { - test : String -} - -provider Test : Test { - fun print (a : String) : String { - a - } -} - -component Main { - use Test { - test: "" - } - - fun render : String { - Test.print("x") - } -} diff --git a/spec/type_checking/module_access_subscriptions b/spec/type_checking/module_access_subscriptions deleted file mode 100644 index a0291e59d..000000000 --- a/spec/type_checking/module_access_subscriptions +++ /dev/null @@ -1,19 +0,0 @@ -record Test { - test : String -} -provider Test : Test { - fun print (a : String) : String { - a - } -} - -component Main { - use Test { - test: "" - } - - fun render : String { - Test.subscriptions - Test.print("a") - } -} diff --git a/spec/type_checking/module_call b/spec/type_checking/module_call deleted file mode 100644 index 27fdb2f65..000000000 --- a/spec/type_checking/module_call +++ /dev/null @@ -1,88 +0,0 @@ -module Test { - fun a (x : Bool, value : String) : String { - value - } - - fun b : String { - true - |> Test.a("test") - } -} - -component Main { - fun render : String { - Test.b() - } -} --------------------------------------------------------------------------------- -global component Test { - fun b : String { - "" - } - - fun render : Html { -
- } -} - -component Main { - fun render : String { - Test.b() - } -} -------------------------------------------------------ModuleAccessNotFoundModule -module Test { - fun b : String { - X.x() - } -} - -component Main { - fun render : String { - Test.b() - } -} -----------------------------------------------------ModuleAccessNotFoundFunction -module Test { - fun b : String { - Test.a("test") - } -} - -component Main { - fun render : String { - Test.b() - } -} ---------------------------------------------------------CallArgumentTypeMismatch -module Test { - fun a (value : String, x : Bool) : String { - value - } - - fun b : String { - Test.a("test", "z") - } -} - -component Main { - fun render : String { - Test.b() - } -} ---------------------------------------------------------CallArgumentTypeMismatch -module Test { - fun a (value : a, x : a) : String { - value - } - - fun b : String { - Test.a("test", 0) - } -} - -component Main { - fun render : String { - Test.b() - } -} diff --git a/spec/type_checking/negated_bool b/spec/type_checking/negated_bool deleted file mode 100644 index 87c880bd0..000000000 --- a/spec/type_checking/negated_bool +++ /dev/null @@ -1,5 +0,0 @@ -module A { - fun test : Bool { - !true && !false - } -} diff --git a/spec/type_checking/negated_expression b/spec/type_checking/negated_expression deleted file mode 100644 index d12ed913e..000000000 --- a/spec/type_checking/negated_expression +++ /dev/null @@ -1,31 +0,0 @@ -module Test { - fun test : Bool { - !false - } -} - -component Main { - fun render : String { - if (Test.test()) { - "Hello" - } else { - "Hello" - } - } -} ---------------------------------------------------------NegatedExpressionNotBool -module Test { - fun test : Bool { - !"asd" - } -} - -component Main { - fun render : String { - if (Test.test()) { - "Hello" - } else { - "Hello" - } - } -} diff --git a/spec/type_checking/next_call b/spec/type_checking/next_call deleted file mode 100644 index 67fcbd19a..000000000 --- a/spec/type_checking/next_call +++ /dev/null @@ -1,50 +0,0 @@ -component Main { - state name : String = "Joe" - state age : Number = 24 - - fun test : Promise(Void) { - next { - name: "Hello", - age: 30 - } - } - - fun render : Html { -
- } -} --------------------------------------------------------NextCallInvalidInvocation -module Test { - fun test : Promise(Void) { - next { age: 30 } - } -} - -component Main { - fun render : Html { - let test = - Test.test() - -
- } -} --------------------------------------------------------NextCallStateTypeMismatch -component Main { - state name : String = "Joe" - - fun render : Html { - next { name: 30 } - -
- } -} ------------------------------------------------------------NextCallStateNotFound -component Main { - state name : String = "Joe" - - fun render : Html { - next { age: 30 } - -
- } -} diff --git a/spec/type_checking/number_literal b/spec/type_checking/number_literal deleted file mode 100644 index 965033cf1..000000000 --- a/spec/type_checking/number_literal +++ /dev/null @@ -1,9 +0,0 @@ -component Main { - fun test : Number { - 0 - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/open_module b/spec/type_checking/open_module deleted file mode 100644 index 22191597e..000000000 --- a/spec/type_checking/open_module +++ /dev/null @@ -1,39 +0,0 @@ -module Test { - const FIRST = "" - - fun hello : String { - "Hello" - } -} - -module Test { - const SECOND = "" - - fun greet : String { - "#{hello()} Bello" - } -} - -component Main { - fun render : String { - Test.greet() + Test:FIRST + Test:SECOND - } -} ---------------------------------------------------------ModuleEntityNameConflict -module Test { - fun hello : String { - "Hello" - } -} - -module Test { - fun hello : String { - "Overridden...." - } -} - -component Main { - fun render : String { - Test.hello() - } -} diff --git a/spec/type_checking/operation_bool b/spec/type_checking/operation_bool deleted file mode 100644 index 867d2871a..000000000 --- a/spec/type_checking/operation_bool +++ /dev/null @@ -1,19 +0,0 @@ -component Main { - fun test : Bool { - "Hello" == "There" - } - - fun render : String { - "" - } -} -------------------------------------------------------------FunctionTypeMismatch -component Main { - fun test : String { - "Hello" == "There" - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/operation_numeric b/spec/type_checking/operation_numeric deleted file mode 100644 index a5981bd77..000000000 --- a/spec/type_checking/operation_numeric +++ /dev/null @@ -1,39 +0,0 @@ -component Main { - fun test : Number { - 0 * 10 - } - - fun render : String { - "" - } -} -----------------------------------------------------OperationNumericTypeMismatch -component Main { - fun test : Number { - "Hello" * 0 - } - - fun render : String { - "" - } -} -----------------------------------------------------OperationNumericTypeMismatch -component Main { - fun test : Number { - 0 * "Hello" - } - - fun render : String { - "" - } -} -----------------------------------------------------OperationNumericTypeMismatch -component Main { - fun test : Number { - "Blah" * "Hello" - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/operation_or b/spec/type_checking/operation_or deleted file mode 100644 index 94aba21ca..000000000 --- a/spec/type_checking/operation_or +++ /dev/null @@ -1,32 +0,0 @@ -enum Maybe(a) { - Nothing - Just(a) -} - -component Main { - fun render : String { - Maybe::Nothing or "Hello" - } -} ----------------------------------------------------------OperationOrTypeMismatch -enum Maybe(a) { - Nothing - Just(a) -} - -component Main { - fun render : String { - Maybe::Just(0) or "Hello" - } -} ------------------------------------------------------OperationOrNotMaybeOrResult -enum Maybe(a) { - Nothing - Just(a) -} - -component Main { - fun render : String { - 0 or "Hello" - } -} diff --git a/spec/type_checking/operation_plus b/spec/type_checking/operation_plus deleted file mode 100644 index 87ab99e6e..000000000 --- a/spec/type_checking/operation_plus +++ /dev/null @@ -1,23 +0,0 @@ -component Main { - fun render : String { - "Hello" + "There" - } -} --------------------------------------------------------OperationPlusTypeMismatch -component Main { - fun render : String { - "Hello" + void - } -} --------------------------------------------------------OperationPlusTypeMismatch -component Main { - fun render : String { - "Hello" + true - } -} --------------------------------------------------------OperationPlusTypeMismatch -component Main { - fun render : String { - true + "Hello" - } -} diff --git a/spec/type_checking/operation_with_pipe b/spec/type_checking/operation_with_pipe deleted file mode 100644 index dc2e46762..000000000 --- a/spec/type_checking/operation_with_pipe +++ /dev/null @@ -1,15 +0,0 @@ -component Main { - fun render : String { - "Hello" + "There" - } -} -----------------------------------------------------------OperationPipeAmbiguous -component Main { - fun toString(value : Number) : String { - "" - } - - fun render : String { - "" + 0 |> toString + "" + 0 |> toString - } -} diff --git a/spec/type_checking/parenthesized_expression b/spec/type_checking/parenthesized_expression deleted file mode 100644 index 33d1d2a11..000000000 --- a/spec/type_checking/parenthesized_expression +++ /dev/null @@ -1,9 +0,0 @@ -component Main { - fun test : Bool { - (true) - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/provider_const b/spec/type_checking/provider_const deleted file mode 100644 index 8ea67f70b..000000000 --- a/spec/type_checking/provider_const +++ /dev/null @@ -1,24 +0,0 @@ -record Subscription { - a : Bool -} - -provider Provider : Subscription { - const ONE_PLUS_ONE = 1 + 1 - const TWO = 2 - - fun test : Bool { - ONE_PLUS_ONE == TWO - } -} ------------------------------------------------------------------VariableMissing -record Subscription { - a : Bool -} - -provider Provider : Subscription { - const TWO = 2 - - fun test : Bool { - 1 + TWO == THREE - } -} diff --git a/spec/type_checking/record b/spec/type_checking/record deleted file mode 100644 index b0541e832..000000000 --- a/spec/type_checking/record +++ /dev/null @@ -1,50 +0,0 @@ -record Test { - a : String, - b : Number -} - -component Main { - fun test : Test { - { - a: "Hello", - b: 0 - } - } - - fun render : String { - "" - } -} ------------------------------------------------------------------RecordWithHoles -record Test { - a : Array(a), - b : Number -} --------------------------------------------------------------------------------- -component Main { - fun test : Object { - encode { - a: "Hello", - b: "Blah" - } - } - - fun render : String { - "" - } -} --------------------------------------------------------------------------------- -component Main { - fun test : Object { - encode { - a: "Hello", - b: { - c: "Blah" - } - } - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/record_constructor b/spec/type_checking/record_constructor deleted file mode 100644 index 1e10d31e4..000000000 --- a/spec/type_checking/record_constructor +++ /dev/null @@ -1,67 +0,0 @@ -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = Test("Joe", 32) - - item.name - } -} ------------------------------------------------------------------VariableMissing -component Main { - fun render : String { - let item = Test("Joe") - - item.name - } -} --------------------------------------------RecordConstructorArgumentTypeMismatch -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = Test(32, "Joe") - - item.name - } -} --------------------------------------------RecordConstructorArgumentSizeMismatch -record Test { - name : String, - age : Number -} - -component Main { - fun render : String { - let item = Test(32, "Joe", "Third") - - item.name - } -} --------------------------------------------------------------------------------- -record User { - name : String, - age : Number, - active : Bool, -} - -component Main { - fun render : String { - let partial = - User("John Doe", 32) - - partial(true) == { - name: "John Doe", - active: true, - age: 32 - } - - "" - } -} diff --git a/spec/type_checking/record_definition_not_found b/spec/type_checking/record_definition_not_found deleted file mode 100644 index ff539fb0f..000000000 --- a/spec/type_checking/record_definition_not_found +++ /dev/null @@ -1,39 +0,0 @@ -record A { - name : String -} - -component Main { - state data = { name: "" } - - fun render : Html { -
- <{ data.name }> -
- } -} -----------------------------------------------------RecordNotFoundMatchingRecordDefinition -component Main { - state data = { name: "" } - - fun render : Html { -
- <{ data.name }> -
- } -} -----------------------------------------------------RecordNotFoundMatchingRecordDefinition -component Test { - property data = { name: "" } - - fun render : Html { -
- <{ data.name }> -
- } -} - -component Main { - fun render : Html { - - } -} diff --git a/spec/type_checking/record_field b/spec/type_checking/record_field deleted file mode 100644 index ad2940ce2..000000000 --- a/spec/type_checking/record_field +++ /dev/null @@ -1,17 +0,0 @@ -record Test { - a : String, - b : Number -} - -component Main { - fun test : Test { - { - a: "Hello", - b: 0 - } - } - - fun render : String { - "" - } -} diff --git a/spec/type_checking/record_same b/spec/type_checking/record_same deleted file mode 100644 index afe8d9c3d..000000000 --- a/spec/type_checking/record_same +++ /dev/null @@ -1,44 +0,0 @@ -record Test { - a : String, - b : Number -} - -record Test2 { - a : String, - b : Number -} - -component Main { - fun test : Test { - { - a: "Hello", - b: 0 - } - } - - fun render : String { - test().a - } -} --------------------------------------------------------------------------------- -record Test { - a : String, - b : Number -} - -record Test2 { - a : String, - b : Number -} - -component Main { - state test : Test = - { - a: "Hello", - b: 0 - } - - fun render : String { - test.a - } -} diff --git a/spec/type_checking/route b/spec/type_checking/route deleted file mode 100644 index dfe536f20..000000000 --- a/spec/type_checking/route +++ /dev/null @@ -1,11 +0,0 @@ -routes { - /:name (name : String) { - void - } -} ----------------------------------------------------------------RouteParamInvalid -routes { - /:name (name : Array(String)) { - void - } -} diff --git a/spec/type_checking/routes b/spec/type_checking/routes deleted file mode 100644 index 0c09493a7..000000000 --- a/spec/type_checking/routes +++ /dev/null @@ -1,9 +0,0 @@ -routes { - /test { - void - } - - * { - void - } -} diff --git a/spec/type_checking/state b/spec/type_checking/state deleted file mode 100644 index dbf89bc4a..000000000 --- a/spec/type_checking/state +++ /dev/null @@ -1,28 +0,0 @@ -component Main { - state b : String = "Hello" - state a : Number = 0 - - fun render : Html { -
- } -} ----------------------------------------------------------------StateTypeMismatch -component Main { - state b : String = 0 - - fun render : Html { -
- } -} ----------------------------------------------------------------StateTypeMismatch -record A { - a : String -} - -component Main { - state name : Test = { a: "Hello" } - - fun render : Html { -
- } -} diff --git a/spec/type_checking/statement b/spec/type_checking/statement deleted file mode 100644 index d27a0195c..000000000 --- a/spec/type_checking/statement +++ /dev/null @@ -1,20 +0,0 @@ -component Main { - fun render : String { - let x = "hello" - "" - } -} -------------------------------------------------------DestructuringTypeMismatch -component Main { - fun render : String { - let {x, y, z} = "hello" - "" - } -} ------------------------------------------------------DestructuringTupleMismatch -component Main { - fun render : String { - let {x, y, z} = {"hello", "a"} - "" - } -} diff --git a/spec/type_checking/store b/spec/type_checking/store deleted file mode 100644 index 991f3bee2..000000000 --- a/spec/type_checking/store +++ /dev/null @@ -1,41 +0,0 @@ -store Test { - state a : String = "" - - fun b : Promise(Void) { - next { a: "Blah" } - } -} - -component Main { - connect Test exposing { a, b } - - fun render : String { - "" - } -} ------------------------------------------------------------NextCallStateNotFound -store Test { - state a : String = "" - - fun b : Promise(Never, Void) { - next { b: "Blah" } - } -} - -component Main { - connect Test exposing { a, b } -} ----------------------------------------------------------StoreEntityNameConflict -store Test { - fun a : String { - "" - } - - fun a : String { - "" - } -} - -component Main { - connect Test exposing { a } -} diff --git a/spec/type_checking/store_call_with_next b/spec/type_checking/store_call_with_next deleted file mode 100644 index e9b92f56c..000000000 --- a/spec/type_checking/store_call_with_next +++ /dev/null @@ -1,18 +0,0 @@ -store Test { - fun set : Promise(Void) { - next {} - } -} - -component Main { - fun render : Html { - Test.set() -
- } -} - -routes { - / { - Test.set() - } -} diff --git a/spec/type_checking/string_literal b/spec/type_checking/string_literal deleted file mode 100644 index 18c7ee75e..000000000 --- a/spec/type_checking/string_literal +++ /dev/null @@ -1,21 +0,0 @@ -component Main { - fun render : String { - "Hello There" - } -} --------------------------------------------------------------------------------- -component Main { - fun render : String { - let name = 0 - - "Hello There #{name}!" - } -} -------------------------------------------StringLiteralInterpolationTypeMismatch -component Main { - fun render : String { - let name = {} - - "Hello There #{name}!" - } -} diff --git a/spec/type_checking/suite_const b/spec/type_checking/suite_const deleted file mode 100644 index b02e0674a..000000000 --- a/spec/type_checking/suite_const +++ /dev/null @@ -1,30 +0,0 @@ -suite "Suite" { - test "Test" { - 1 + 1 == TWO - } - - const ONE_PLUS_ONE = 1 + 1 - const TWO = 2 - - test "Test 2" { - ONE_PLUS_ONE == TWO - } -} ------------------------------------------------------------------VariableMissing -suite "Suite" { - const TWO = 2 - - test "Test" { - 1 + 1 == THREE - } -} ------------------------------------------------------------------VariableMissing -suite "Suite" { - const TWO = 2 -} - -suite "Suite 2" { - test "Test" { - 1 + 1 == TWO - } -} diff --git a/spec/type_checking/tuple_with_pipe b/spec/type_checking/tuple_with_pipe deleted file mode 100644 index 236fa4663..000000000 --- a/spec/type_checking/tuple_with_pipe +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun pipe (value : String) : String { - value - } - - fun render : String { - let x = "" - - { x |> pipe }[0] - } -} diff --git a/spec/type_checking/type_normalize b/spec/type_checking/type_normalize deleted file mode 100644 index 052453797..000000000 --- a/spec/type_checking/type_normalize +++ /dev/null @@ -1,33 +0,0 @@ -module Test { - fun test1 : a { - "I'm a String" - } - - fun test2 : a { - "I'm a string too!" - } - - fun test4 : String { - test1() + test2() - } -} -----------------------------------------------------OperationNumericTypeMismatch -module Test { - fun test1 : a { - "I'm a String" - } - - fun test2 : a { - 123 - } - - fun test3 : a { - [4, 5, 6, 7] - } - - fun test4 : String { - test1() * test2() * test3() - - "" - } -} diff --git a/spec/type_checking/unary_minus b/spec/type_checking/unary_minus deleted file mode 100644 index 5d2535cef..000000000 --- a/spec/type_checking/unary_minus +++ /dev/null @@ -1,15 +0,0 @@ -component Main { - fun render : String { - -(10) - - "" - } -} --------------------------------------------------------------UnaryMinusNotNumber -component Main { - fun render : String { - -"ASD" - - "" - } -} diff --git a/spec/type_checking/uncapitalized_type b/spec/type_checking/uncapitalized_type deleted file mode 100644 index ba9668651..000000000 --- a/spec/type_checking/uncapitalized_type +++ /dev/null @@ -1,11 +0,0 @@ -component Main { - fun render : Html { -
- } -} -----------------------------------------------------------------TypeExpectedType -component Main { - fun render : Html { -
- } -} diff --git a/spec/type_checking/variable b/spec/type_checking/variable deleted file mode 100644 index 959205d72..000000000 --- a/spec/type_checking/variable +++ /dev/null @@ -1,37 +0,0 @@ -component Main { - get a : String { - "Hello" - } - - fun b : String { - a - } - - fun render : String { - b() - } -} ------------------------------------------------------------------VariableMissing -component Main { - get a : String { - "Hello" - } - - fun b : String { - c - } - - fun render : Html { - b() - } -} -----------------------------------------------------------------VariableReserved -component Main { - fun b(default : String) : String { - default - } - - fun render : Html { - b("") - } -} diff --git a/spec/type_checking_spec.cr b/spec/type_checking_spec.cr deleted file mode 100644 index d7e4db26d..000000000 --- a/spec/type_checking_spec.cr +++ /dev/null @@ -1,59 +0,0 @@ -require "./spec_helper" - -Dir - .glob("./spec/type_checking/**/*") - .select! { |file| File.file?(file) } - .sort! - .each do |file| - # Read samples - samples = [] of Tuple(String, String?) - contents = File.read(file) - name = File.basename(file) - position = 0 - error = nil - - contents.scan(/^\-+(\w+)?/m) do |match| - samples << {contents[position, match.begin - position], error} - position = match.end - error = match[1]? - end - - samples << {contents[position, contents.size - position], error} - - samples.each_with_index do |sample, index| - it "#{name} ##{index}" do - source, error = sample - - ast = Mint::Ast.new - - # Parse source - if error - begin - ast = Mint::Parser.parse(source, file) - ast.class.should eq(Mint::Ast) - - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - - type_checker.cache.size.should_not eq(0) - rescue item : Mint::Error - item.class.name.split("::").last.should eq(error) - end - - item.should be_a(Mint::Error) - - # Check if they are rendered correctly. - item.try(&.to_terminal) - item.try(&.to_html) - else - ast = Mint::Parser.parse(source, file) - ast.class.should eq(Mint::Ast) - - type_checker = Mint::TypeChecker.new(ast) - type_checker.check - - type_checker.cache.size.should_not eq(0) - end - end - end - end diff --git a/src/all.cr b/src/all.cr index c9f6e48d1..7e99791ce 100644 --- a/src/all.cr +++ b/src/all.cr @@ -14,13 +14,12 @@ MINT_ENV = {} of String => String require "./version" require "./ext/**" +require "./errorable" -require "./errors/error" -require "./errors/**" require "./constants" -require "./macros" require "./assets" require "./skippable" +require "./helpers" require "./js" require "./core" require "./env" @@ -28,14 +27,12 @@ require "./env" require "./render/**" require "./utils/**" -require "./message" -require "./messages/**" - require "./ast/node" require "./ast/**" require "./ast" require "./style_builder" +require "./scope" require "./type_checkers/**" require "./type_checker/**" @@ -51,6 +48,7 @@ require "./installer/**" require "./installer" require "./parsers/**" +require "./parser/*" require "./parser" require "./documentation_generator/**" diff --git a/src/ast.cr b/src/ast.cr index 9b1b591bc..9ccaf28ea 100644 --- a/src/ast.cr +++ b/src/ast.cr @@ -1,43 +1,13 @@ module Mint class Ast - alias TypeOrVariable = Type | TypeVariable - - alias Expression = ParenthesizedExpression | - NegatedExpression | - InlineFunction | - StringLiteral | - NumberLiteral | - HtmlComponent | - HtmlFragment | - RecordUpdate | - ModuleAccess | - ArrayLiteral | - ArrayAccess | - BoolLiteral | - HtmlElement | - Operation | - NextCall | - Variable | - Routes | - Encode | - EnumId | - Decode | - Record | - Access | - Route | - Void | - Case | - If | - Js - - getter components, modules, records, stores, routes, providers, operators - getter suites, enums, comments, nodes, keywords, locales + getter components, modules, stores, routes, providers, operators + getter suites, comments, nodes, keywords, locales, type_definitions getter unified_modules, unified_locales - def initialize(@operators = [] of Tuple(Int32, Int32), - @keywords = [] of Tuple(Int32, Int32), - @records = [] of RecordDefinition, + def initialize(@type_definitions = [] of TypeDefinition, + @operators = [] of Tuple(Int64, Int64), + @keywords = [] of Tuple(Int64, Int64), @unified_modules = [] of Module, @unified_locales = [] of Locale, @components = [] of Component, @@ -48,7 +18,6 @@ module Mint @routes = [] of Routes, @suites = [] of Suite, @stores = [] of Store, - @enums = [] of Enum, @nodes = [] of Node) end @@ -57,11 +26,11 @@ module Mint end def self.space_separated?(node1, node2) - node1.input.input[node1.from, node2.from - node1.from].includes?("\n\n") + node1.file.contents[node1.from, node2.from - node1.from].includes?("\n\n") end def self.new_line?(node1, node2) - node1.input.input[node1.from, node2.from - node1.from].includes?('\n') + node1.file.contents[node1.from, node2.from - node1.from].includes?('\n') end def new_line?(node1, node2) @@ -71,20 +40,19 @@ module Mint count = node2.to - node1.from - node1.input.input[start_position, count].includes?('\n') + node1.file.contents[start_position, count].includes?('\n') end def merge(ast) : self + @type_definitions.concat ast.type_definitions @components.concat ast.components @providers.concat ast.providers @comments.concat ast.comments @modules.concat ast.modules - @records.concat ast.records @locales.concat ast.locales @stores.concat ast.stores @routes.concat ast.routes @suites.concat ast.suites - @enums.concat ast.enums @nodes.concat ast.nodes self @@ -94,9 +62,19 @@ module Mint self.class.new.merge(self) end + def includes?(node : Ast::Node, other : Ast::Node) + node.input == other.input && + node.from <= other.from && + node.to >= other.to + end + # Normalizes the ast: # - merges multiple modules with the same name def normalize + nodes.select(Ast::HtmlComponent).each do |item| + item.component_node = components.find(&.name.value.==(item.component.value)) + end + @unified_modules = @modules .group_by(&.name.value) @@ -104,7 +82,7 @@ module Mint Module.new( functions: modules.flat_map(&.functions), constants: modules.flat_map(&.constants), - input: Data.new(input: "", file: ""), + file: Parser::File.new(contents: "", path: ""), # TODO: We may need to store each modules name node for # future features, but for now we just store the first name: modules.first.name, @@ -120,7 +98,7 @@ module Mint .group_by(&.language) .map do |_, locales| Locale.new( - input: Data.new(input: "", file: ""), + file: Parser::File.new(contents: "", path: ""), fields: locales.flat_map(&.fields), language: locales.first.language, comment: nil, diff --git a/src/ast/access.cr b/src/ast/access.cr index e1960143f..89b1257e9 100644 --- a/src/ast/access.cr +++ b/src/ast/access.cr @@ -1,13 +1,21 @@ module Mint class Ast class Access < Node - getter field, lhs + getter field, expression, type - def initialize(@field : Variable, - @lhs : Expression, - @input : Data, - @from : Int32, - @to : Int32) + # TODO: Remove in 0.21.0 when deprecation ends. + enum Type + DoubleColon + Colon + Dot + end + + def initialize(@file : Parser::File, + @expression : Node, + @field : Variable, + @from : Int64, + @type : Type, + @to : Int64) end end end diff --git a/src/ast/argument.cr b/src/ast/argument.cr index 2f34626b2..3a7a1b6f3 100644 --- a/src/ast/argument.cr +++ b/src/ast/argument.cr @@ -3,12 +3,12 @@ module Mint class Argument < Node getter type, name, default - def initialize(@type : TypeOrVariable, - @name : Variable, + def initialize(@file : Parser::File, @default : Node?, - @input : Data, - @from : Int32, - @to : Int32) + @name : Variable, + @from : Int64, + @type : Node, + @to : Int64) end end end diff --git a/src/ast/array_access.cr b/src/ast/array_access.cr index acffb7264..ff171c66f 100644 --- a/src/ast/array_access.cr +++ b/src/ast/array_access.cr @@ -1,13 +1,13 @@ module Mint class Ast class ArrayAccess < Node - getter index, lhs + getter index, expression - def initialize(@index : Int64 | Expression, - @lhs : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @expression : Node, + @index : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/array_destructuring.cr b/src/ast/array_destructuring.cr index 73e97ac4c..00e3d2ffa 100644 --- a/src/ast/array_destructuring.cr +++ b/src/ast/array_destructuring.cr @@ -3,36 +3,10 @@ module Mint class ArrayDestructuring < Node getter items - def initialize(@items : Array(Node), - @input : Data, - @from : Int32, - @to : Int32) - end - - # Returns true if the destructuring covers - # arrays with the given length. - # - # [x, ...rest] => 1+ - # [x] => 1 - # [...rest] => 0+ - # [] => 0 - def covers?(length) - if spread? - length >= (items.size - 1) - else - length == items.size - end - end - - def spread? - items.any?(Ast::Spread) - end - - def exhaustive? - items.all? do |item| - item.is_a?(Ast::Variable) || - item.is_a?(Ast::Spread) - end && items.any?(Ast::Spread) + def initialize(@file : Parser::File, + @items : Array(Node), + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/array_literal.cr b/src/ast/array_literal.cr index b271de8c4..f78c6c98b 100644 --- a/src/ast/array_literal.cr +++ b/src/ast/array_literal.cr @@ -3,22 +3,11 @@ module Mint class ArrayLiteral < Node getter items, type - def initialize(@items : Array(Expression), - @input : Data, - @from : Int32, + def initialize(@file : Parser::File, + @items : Array(Node), + @from : Int64, @type : Node?, - @to : Int32) - end - - def static? - items.all?(&.static?) - end - - def static_value - values = - items.join(',', &.static_value) - - "[#{values}]" + @to : Int64) end end end diff --git a/src/ast/block.cr b/src/ast/block.cr index 251895573..07f9cd9c2 100644 --- a/src/ast/block.cr +++ b/src/ast/block.cr @@ -1,20 +1,13 @@ module Mint class Ast class Block < Node - getter statements + getter expressions, returns - def initialize(@statements : Array(Node), - @input : Data, - @from : Int32, - @to : Int32) - end - - def async? - statements.select(Ast::Statement).any?(&.await) - end - - def static? - statements.all?(&.static?) + def initialize(@returns : Array(ReturnCall), + @expressions : Array(Node), + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/bool_literal.cr b/src/ast/bool_literal.cr index 15262b5e1..7147eda79 100644 --- a/src/ast/bool_literal.cr +++ b/src/ast/bool_literal.cr @@ -3,18 +3,10 @@ module Mint class BoolLiteral < Node getter value - def initialize(@value : Bool, - @input : Data, - @from : Int32, - @to : Int32) - end - - def static? - true - end - - def static_value - value.to_s + def initialize(@file : Parser::File, + @value : Bool, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/call.cr b/src/ast/call.cr index a59b84582..9743f5984 100644 --- a/src/ast/call.cr +++ b/src/ast/call.cr @@ -3,11 +3,11 @@ module Mint class Call < Node getter arguments, expression - def initialize(@arguments : Array(CallExpression), - @expression : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@arguments : Array(Field), + @file : Parser::File, + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/call_expression.cr b/src/ast/call_expression.cr deleted file mode 100644 index c4f314f3b..000000000 --- a/src/ast/call_expression.cr +++ /dev/null @@ -1,14 +0,0 @@ -module Mint - class Ast - class CallExpression < Node - getter name, expression - - def initialize(@expression : Expression, - @name : Variable?, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/case.cr b/src/ast/case.cr index 9948fa850..54839b601 100644 --- a/src/ast/case.cr +++ b/src/ast/case.cr @@ -1,15 +1,16 @@ module Mint class Ast + # TODO: Change condition to a statment like with if. class Case < Node getter branches, condition, comments, await def initialize(@branches : Array(CaseBranch), @comments : Array(Comment), - @condition : Expression, + @file : Parser::File, + @condition : Node, @await : Bool, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/case_branch.cr b/src/ast/case_branch.cr index 77cd8385b..81e53ba44 100644 --- a/src/ast/case_branch.cr +++ b/src/ast/case_branch.cr @@ -1,13 +1,13 @@ module Mint class Ast class CaseBranch < Node - getter match, expression + getter pattern, expression def initialize(@expression : Node | Array(CssDefinition), - @match : Node?, - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @pattern : Node?, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/comment.cr b/src/ast/comment.cr index 3e8801804..1ac4f3cdd 100644 --- a/src/ast/comment.cr +++ b/src/ast/comment.cr @@ -1,22 +1,23 @@ module Mint class Ast + # TODO: Allow multiple comments in this node instead of a single one. class Comment < Node enum Type Inline Block end - getter value, type + getter content, type - def initialize(@value : String, + def initialize(@file : Parser::File, + @content : String, + @from : Int64, @type : Type, - @input : Data, - @from : Int32, - @to : Int32) + @to : Int64) end def to_html - Markd.to_html(value) + Markd.to_html(content) end end end diff --git a/src/ast/component.cr b/src/ast/component.cr index 5351d5c45..d89d172b3 100644 --- a/src/ast/component.cr +++ b/src/ast/component.cr @@ -1,8 +1,8 @@ module Mint class Ast class Component < Node - getter properties, connects, styles, states, comments getter functions, gets, uses, name, comment, refs, constants + getter properties, connects, styles, states, comments getter? global, locales @@ -14,19 +14,15 @@ module Mint @connects : Array(Connect), @states : Array(State), @styles : Array(Style), + @file : Parser::File, @comment : Comment?, @gets : Array(Get), @uses : Array(Use), @locales : Bool, @global : Bool, - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) - end - - def owns?(node) - {functions, constants, states, gets, properties}.any? &.includes?(node) + @from : Int64, + @to : Int64, + @name : Id) end end end diff --git a/src/ast/connect.cr b/src/ast/connect.cr index f01aff65c..f09a480e4 100644 --- a/src/ast/connect.cr +++ b/src/ast/connect.cr @@ -4,10 +4,10 @@ module Mint getter keys, store def initialize(@keys : Array(ConnectVariable), - @store : TypeId, - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @from : Int64, + @to : Int64, + @store : Id) end end end diff --git a/src/ast/connect_variable.cr b/src/ast/connect_variable.cr index 7ea688d20..ac2d64fce 100644 --- a/src/ast/connect_variable.cr +++ b/src/ast/connect_variable.cr @@ -1,13 +1,13 @@ module Mint class Ast class ConnectVariable < Node - getter variable, name + getter target, name - def initialize(@variable : Variable, - @name : Variable?, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @target : Variable?, + @name : Variable, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/constant.cr b/src/ast/constant.cr index 7c3e0edfa..b903b8643 100644 --- a/src/ast/constant.cr +++ b/src/ast/constant.cr @@ -1,14 +1,14 @@ module Mint class Ast class Constant < Node - getter name, value, comment + getter name, expression, comment - def initialize(@value : Expression, + def initialize(@file : Parser::File, @comment : Comment?, + @expression : Node, @name : Variable, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/css_definition.cr b/src/ast/css_definition.cr index d4c875631..cb492f457 100644 --- a/src/ast/css_definition.cr +++ b/src/ast/css_definition.cr @@ -4,10 +4,10 @@ module Mint getter name, value def initialize(@value : Array(String | Node), + @file : Parser::File, @name : String, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/css_font_face.cr b/src/ast/css_font_face.cr index 2b2f6c7e4..991ba36eb 100644 --- a/src/ast/css_font_face.cr +++ b/src/ast/css_font_face.cr @@ -4,9 +4,9 @@ module Mint getter definitions def initialize(@definitions : Array(Node), - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/css_keyframes.cr b/src/ast/css_keyframes.cr index dbda4c963..2cfad8d76 100644 --- a/src/ast/css_keyframes.cr +++ b/src/ast/css_keyframes.cr @@ -4,10 +4,10 @@ module Mint getter selectors, name def initialize(@selectors : Array(Node), + @file : Parser::File, @name : String, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/css_nested_at.cr b/src/ast/css_nested_at.cr index f083aad5a..95047cc22 100644 --- a/src/ast/css_nested_at.cr +++ b/src/ast/css_nested_at.cr @@ -3,12 +3,12 @@ module Mint class CssNestedAt < Node getter content, body, name - def initialize(@body : Array(Node), + def initialize(@file : Parser::File, + @body : Array(Node), @content : String, @name : String, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/css_selector.cr b/src/ast/css_selector.cr index af7033434..dc375b831 100644 --- a/src/ast/css_selector.cr +++ b/src/ast/css_selector.cr @@ -4,10 +4,10 @@ module Mint getter selectors, body def initialize(@selectors : Array(String), + @file : Parser::File, @body : Array(Node), - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/data.cr b/src/ast/data.cr deleted file mode 100644 index a14e7b1c1..000000000 --- a/src/ast/data.cr +++ /dev/null @@ -1,14 +0,0 @@ -module Mint - class Ast - class Data - getter input, file - - def initialize(@input : String, @file : String) - end - - def to_s(io : IO) - io << '<' << file << ' ' << input[0, 10] << "...>" - end - end - end -end diff --git a/src/ast/decode.cr b/src/ast/decode.cr index fa09f65df..6c605772a 100644 --- a/src/ast/decode.cr +++ b/src/ast/decode.cr @@ -3,11 +3,11 @@ module Mint class Decode < Node getter expression, type - def initialize(@expression : Expression?, - @input : Data, - @from : Int32, + def initialize(@file : Parser::File, + @expression : Node?, + @from : Int64, @type : Type, - @to : Int32) + @to : Int64) end end end diff --git a/src/ast/directives/asset.cr b/src/ast/directives/asset.cr deleted file mode 100644 index 3ed2786c5..000000000 --- a/src/ast/directives/asset.cr +++ /dev/null @@ -1,40 +0,0 @@ -module Mint - class Ast - module Directives - class Asset < Node - getter real_path : Path - getter path - - def initialize(@path : String, - @input : Data, - @from : Int32, - @to : Int32) - @real_path = Path[input.file].sibling(path).expand - end - - def filename(build) : String? - return unless exists? - - hash_base = - build ? file_contents : real_path.to_s - - hash = - Digest::MD5.new - .update(hash_base) - .final - .hexstring - - "#{real_path.stem}_#{hash}#{real_path.extension}" - end - - def exists? - File.exists?(real_path) - end - - def file_contents : String - File.read(real_path) - end - end - end - end -end diff --git a/src/ast/directives/documentation.cr b/src/ast/directives/documentation.cr index e58cc0878..93a0b6039 100644 --- a/src/ast/directives/documentation.cr +++ b/src/ast/directives/documentation.cr @@ -4,10 +4,10 @@ module Mint class Documentation < Node getter entity - def initialize(@entity : TypeId, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @from : Int64, + @entity : Id, + @to : Int64) end end end diff --git a/src/ast/directives/file_based.cr b/src/ast/directives/file_based.cr new file mode 100644 index 000000000..f3dc67e2b --- /dev/null +++ b/src/ast/directives/file_based.cr @@ -0,0 +1,54 @@ +module Mint + class Ast + module Directives + class FileBased < Node + getter real_path : Path + getter path : String + + def initialize(@file : Parser::File, + @path : String, + @from : Int64, + @to : Int64) + @real_path = Path[file.path].sibling(path).expand + end + + # Returns the hashed filename of the target. For the build version it + # uses the the file contents of the file as the hash value to make sure + # that the file will not be cached. + def filename(*, build : Bool) : String? + return unless exists? + + hash_base = + build ? file_contents : real_path.to_s + + hash = + Digest::MD5.new + .update(hash_base) + .final + .hexstring + + "#{real_path.stem}_#{hash}#{real_path.extension}" + end + + # Returns whether the file exists. + def exists? + File.exists?(real_path) + end + + # Returns the files contents. + def file_contents : String + File.read(real_path) + end + end + + class Asset < FileBased + end + + class Inline < FileBased + end + + class Svg < FileBased + end + end + end +end diff --git a/src/ast/directives/format.cr b/src/ast/directives/format.cr index baef2df00..b5a870032 100644 --- a/src/ast/directives/format.cr +++ b/src/ast/directives/format.cr @@ -4,10 +4,10 @@ module Mint class Format < Node getter content - def initialize(@content : Block, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @content : Block, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/directives/highlight.cr b/src/ast/directives/highlight.cr index 3f4ac2ba0..b44cd67e9 100644 --- a/src/ast/directives/highlight.cr +++ b/src/ast/directives/highlight.cr @@ -4,10 +4,10 @@ module Mint class Highlight < Node getter content - def initialize(@content : Block, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @content : Block, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/directives/inline.cr b/src/ast/directives/inline.cr deleted file mode 100644 index 21af57e6e..000000000 --- a/src/ast/directives/inline.cr +++ /dev/null @@ -1,25 +0,0 @@ -module Mint - class Ast - module Directives - class Inline < Node - getter real_path : Path - getter path - - def initialize(@path : String, - @input : Data, - @from : Int32, - @to : Int32) - @real_path = Path[input.file].sibling(path).expand - end - - def exists? - File.exists?(real_path) - end - - def file_contents : String - File.read(real_path) - end - end - end - end -end diff --git a/src/ast/directives/svg.cr b/src/ast/directives/svg.cr deleted file mode 100644 index 22f114526..000000000 --- a/src/ast/directives/svg.cr +++ /dev/null @@ -1,25 +0,0 @@ -module Mint - class Ast - module Directives - class Svg < Node - getter real_path : Path - getter path - - def initialize(@path : String, - @input : Data, - @from : Int32, - @to : Int32) - @real_path = Path[input.file].sibling(path).expand - end - - def exists? - File.exists?(real_path) - end - - def file_contents : String - File.read(real_path) - end - end - end - end -end diff --git a/src/ast/encode.cr b/src/ast/encode.cr index 9418ce9dd..ffd865587 100644 --- a/src/ast/encode.cr +++ b/src/ast/encode.cr @@ -3,10 +3,10 @@ module Mint class Encode < Node getter expression - def initialize(@expression : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/enum.cr b/src/ast/enum.cr deleted file mode 100644 index c20049ecc..000000000 --- a/src/ast/enum.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Mint - class Ast - class Enum < Node - getter options, name, comments, comment, parameters - - def initialize(@parameters : Array(TypeVariable), - @options : Array(EnumOption), - @comments : Array(Comment), - @comment : Comment?, - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/enum_destructuring.cr b/src/ast/enum_destructuring.cr deleted file mode 100644 index 9ecd99491..000000000 --- a/src/ast/enum_destructuring.cr +++ /dev/null @@ -1,27 +0,0 @@ -module Mint - class Ast - class EnumDestructuring < Node - getter name, option, parameters - - def initialize(@parameters : Array(Node), - @option : TypeId, - @name : TypeId?, - @input : Data, - @from : Int32, - @to : Int32) - end - - # TODO: Probably this will need to go into the type checker - # if we want to support cases like this: - # - # enum Test { - # Branch(String) - # } - # - # let Test::Branch(value) = Test::Branch("Hello") - def exhaustive? - false - end - end - end -end diff --git a/src/ast/enum_id.cr b/src/ast/enum_id.cr deleted file mode 100644 index bcc38c4b1..000000000 --- a/src/ast/enum_id.cr +++ /dev/null @@ -1,15 +0,0 @@ -module Mint - class Ast - class EnumId < Node - getter option, name, expressions - - def initialize(@expressions : Array(Expression), - @option : TypeId, - @name : TypeId?, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/enum_option.cr b/src/ast/enum_option.cr deleted file mode 100644 index 37a32848d..000000000 --- a/src/ast/enum_option.cr +++ /dev/null @@ -1,15 +0,0 @@ -module Mint - class Ast - class EnumOption < Node - getter value, comment, parameters - - def initialize(@parameters : Array(Node), - @comment : Comment?, - @value : TypeId, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/enum_record.cr b/src/ast/enum_record.cr deleted file mode 100644 index 900124ddc..000000000 --- a/src/ast/enum_record.cr +++ /dev/null @@ -1,8 +0,0 @@ -require "./record" - -module Mint - class Ast - class EnumRecord < Record - end - end -end diff --git a/src/ast/enum_record_definition.cr b/src/ast/enum_record_definition.cr deleted file mode 100644 index 456237193..000000000 --- a/src/ast/enum_record_definition.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class Ast - class EnumRecordDefinition < Node - getter fields - - def initialize(@fields : Array(RecordDefinitionField), - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/env.cr b/src/ast/env.cr index 22e95152d..51daa81a2 100644 --- a/src/ast/env.cr +++ b/src/ast/env.cr @@ -3,10 +3,10 @@ module Mint class Env < Node getter name - def initialize(@name : String, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @name : String, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/field.cr b/src/ast/field.cr new file mode 100644 index 000000000..ff2d12d7d --- /dev/null +++ b/src/ast/field.cr @@ -0,0 +1,15 @@ +module Mint + class Ast + class Field < Node + getter key, value, comment + + def initialize(@file : Parser::File, + @comment : Comment?, + @key : Variable?, + @value : Node, + @from : Int64, + @to : Int64) + end + end + end +end diff --git a/src/ast/for.cr b/src/ast/for.cr index ed1b2b627..a3f1b0359 100644 --- a/src/ast/for.cr +++ b/src/ast/for.cr @@ -3,13 +3,13 @@ module Mint class For < Node getter subject, body, arguments, condition - def initialize(@condition : ForCondition?, - @arguments : Array(Variable), - @subject : Expression, + def initialize(@arguments : Array(Variable), + @file : Parser::File, + @condition : Block?, + @subject : Node, @body : Block, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/for_condition.cr b/src/ast/for_condition.cr deleted file mode 100644 index a14530059..000000000 --- a/src/ast/for_condition.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class Ast - class ForCondition < Node - getter condition - - def initialize(@condition : Block, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/function.cr b/src/ast/function.cr index cf1f5f433..b8a80a330 100644 --- a/src/ast/function.cr +++ b/src/ast/function.cr @@ -7,13 +7,13 @@ module Mint property? keep_name = false def initialize(@arguments : Array(Argument), - @type : TypeOrVariable?, + @file : Parser::File, @comment : Comment?, @name : Variable, + @type : Node?, @body : Block, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/get.cr b/src/ast/get.cr index 259851e48..f2a6ec7a4 100644 --- a/src/ast/get.cr +++ b/src/ast/get.cr @@ -3,13 +3,13 @@ module Mint class Get < Node getter name, body, type, comment - def initialize(@type : TypeOrVariable?, + def initialize(@file : Parser::File, @comment : Comment?, @name : Variable, @body : Block, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @type : Node?, + @to : Int64) end end end diff --git a/src/ast/here_doc.cr b/src/ast/here_doc.cr deleted file mode 100644 index 2fdec10fd..000000000 --- a/src/ast/here_doc.cr +++ /dev/null @@ -1,29 +0,0 @@ -module Mint - class Ast - class HereDoc < Node - getter value, token, modifier - - def initialize(@value : Array(String | Interpolation), - @modifier : Char, - @token : String, - @input : Data, - @from : Int32, - @to : Int32) - end - - def string_value - value - .select(String) - .join - end - - def static? - value.all?(String) - end - - def static_value - string_value - end - end - end -end diff --git a/src/ast/here_document.cr b/src/ast/here_document.cr new file mode 100644 index 000000000..b7a7772cf --- /dev/null +++ b/src/ast/here_document.cr @@ -0,0 +1,15 @@ +module Mint + class Ast + class HereDocument < Node + getter value, token, modifier + + def initialize(@value : Array(String | Interpolation), + @file : Parser::File, + @modifier : Char, + @token : String, + @from : Int64, + @to : Int64) + end + end + end +end diff --git a/src/ast/html_attribute.cr b/src/ast/html_attribute.cr index 97818a690..e7e42a3c9 100644 --- a/src/ast/html_attribute.cr +++ b/src/ast/html_attribute.cr @@ -1,19 +1,13 @@ module Mint class Ast class HtmlAttribute < Node - getter value, name + getter name, value - delegate static?, to: @value - - def initialize(@value : Expression, + def initialize(@file : Parser::File, @name : Variable, - @input : Data, - @from : Int32, - @to : Int32) - end - - def static_value : String - "#{name.value}=#{value.static_value}" + @value : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/html_component.cr b/src/ast/html_component.cr index f999db33b..6307e867e 100644 --- a/src/ast/html_component.cr +++ b/src/ast/html_component.cr @@ -1,31 +1,21 @@ module Mint class Ast class HtmlComponent < Node - getter attributes, children, component, comments, ref, closing_tag_position + getter attributes, children, component, comments, ref + getter closing_tag_position + + property component_node : Ast::Component? = nil + property? in_component : Bool = false def initialize(@attributes : Array(HtmlAttribute), - @closing_tag_position : Int32?, + @closing_tag_position : Int64?, @comments : Array(Comment), @children : Array(Node), - @component : TypeId, + @file : Parser::File, @ref : Variable?, - @input : Data, - @from : Int32, - @to : Int32) - end - - def static? - children.all?(&.static?) && ref.nil? && attributes.all?(&.static?) - end - - def static_value - static_hash - end - - def static_hash - component.value + - attributes.join(&.static_value) + - children.join(&.static_value) + @component : Id, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/html_element.cr b/src/ast/html_element.cr index d587353c6..35a54e1e2 100644 --- a/src/ast/html_element.cr +++ b/src/ast/html_element.cr @@ -4,29 +4,18 @@ module Mint getter attributes, children, styles, tag, comments, ref getter closing_tag_position + property? in_component : Bool = false + def initialize(@attributes : Array(HtmlAttribute), - @closing_tag_position : Int32?, + @closing_tag_position : Int64?, @comments : Array(Comment), @styles : Array(HtmlStyle), @children : Array(Node), + @file : Parser::File, @ref : Variable?, @tag : Variable, - @input : Data, - @from : Int32, - @to : Int32) - end - - def static? - children.all?(&.static?) && - ref.nil? && - attributes.all?(&.static?) && - styles.empty? - end - - def static_value - tag.value + - attributes.join(&.static_value) + - children.join(&.static_value) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/html_expression.cr b/src/ast/html_expression.cr index 3d18c85b6..3937bb9be 100644 --- a/src/ast/html_expression.cr +++ b/src/ast/html_expression.cr @@ -4,17 +4,9 @@ module Mint getter expressions def initialize(@expressions : Array(Node), - @input : Data, - @from : Int32, - @to : Int32) - end - - def static? - expressions.all?(&.static?) - end - - def static_value - expressions.join(&.static_value) + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/html_fragment.cr b/src/ast/html_fragment.cr index fd1490883..cb2ca352f 100644 --- a/src/ast/html_fragment.cr +++ b/src/ast/html_fragment.cr @@ -1,14 +1,13 @@ module Mint class Ast class HtmlFragment < Node - getter key, children, tag, comments + getter children, tag, comments def initialize(@comments : Array(Comment), @children : Array(Node), - @key : HtmlAttribute?, - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/html_style.cr b/src/ast/html_style.cr index 114d6c78a..6bc9a5489 100644 --- a/src/ast/html_style.cr +++ b/src/ast/html_style.cr @@ -3,11 +3,13 @@ module Mint class HtmlStyle < Node getter name, arguments - def initialize(@arguments : Array(Expression), + property style_node : Ast::Style? = nil + + def initialize(@arguments : Array(Node), + @file : Parser::File, @name : Variable, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/id.cr b/src/ast/id.cr new file mode 100644 index 000000000..fcd058a2a --- /dev/null +++ b/src/ast/id.cr @@ -0,0 +1,13 @@ +module Mint + class Ast + class Id < Node + getter value + + def initialize(@file : Parser::File, + @value : String, + @from : Int64, + @to : Int64) + end + end + end +end diff --git a/src/ast/if.cr b/src/ast/if.cr index 4bf809738..d17c3f814 100644 --- a/src/ast/if.cr +++ b/src/ast/if.cr @@ -3,16 +3,15 @@ module Mint class If < Node getter condition, branches - alias Branches = Tuple(Array(CssDefinition), Array(CssDefinition)) | - Tuple(Array(CssDefinition), Nil) | - Tuple(Array(CssDefinition), If) | - Tuple(Block, Block) + alias Branches = Tuple(Block, Block) | + Tuple(Block, Nil) | + Tuple(Block, If) def initialize(@branches : Branches, + @file : Parser::File, @condition : Node, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/inline_function.cr b/src/ast/inline_function.cr index 4846a36f4..b681e5132 100644 --- a/src/ast/inline_function.cr +++ b/src/ast/inline_function.cr @@ -4,11 +4,11 @@ module Mint getter body, arguments, type def initialize(@arguments : Array(Argument), - @type : TypeOrVariable?, + @file : Parser::File, @body : Block, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @type : Node?, + @to : Int64) end end end diff --git a/src/ast/interpolation.cr b/src/ast/interpolation.cr index 8e1c191e2..843d0daa4 100644 --- a/src/ast/interpolation.cr +++ b/src/ast/interpolation.cr @@ -3,10 +3,10 @@ module Mint class Interpolation < Node getter expression - def initialize(@expression : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/js.cr b/src/ast/js.cr index 18b807188..17865f43b 100644 --- a/src/ast/js.cr +++ b/src/ast/js.cr @@ -4,10 +4,10 @@ module Mint getter value, type def initialize(@value : Array(String | Interpolation), - @input : Data, - @from : Int32, + @file : Parser::File, + @from : Int64, @type : Node?, - @to : Int32) + @to : Int64) end end end diff --git a/src/ast/locale.cr b/src/ast/locale.cr index 027c2c210..d33f9603d 100644 --- a/src/ast/locale.cr +++ b/src/ast/locale.cr @@ -3,12 +3,12 @@ module Mint class Locale < Node getter fields, comment, language - def initialize(@fields : Array(RecordField), + def initialize(@fields : Array(Field), + @file : Parser::File, @comment : Comment?, @language : String, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/locale_key.cr b/src/ast/locale_key.cr index 742aa0bfc..c9171df1e 100644 --- a/src/ast/locale_key.cr +++ b/src/ast/locale_key.cr @@ -3,10 +3,10 @@ module Mint class LocaleKey < Node getter value - def initialize(@value : String, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @value : String, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/member_access.cr b/src/ast/member_access.cr index 3556e2029..da863cf54 100644 --- a/src/ast/member_access.cr +++ b/src/ast/member_access.cr @@ -3,10 +3,10 @@ module Mint class MemberAccess < Node getter name - def initialize(@name : Variable, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @name : Variable, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/module.cr b/src/ast/module.cr index f788f6df7..2e08fadeb 100644 --- a/src/ast/module.cr +++ b/src/ast/module.cr @@ -6,11 +6,11 @@ module Mint def initialize(@functions : Array(Function), @constants : Array(Constant), @comments : Array(Comment), + @file : Parser::File, @comment : Comment?, - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64, + @name : Id) end end end diff --git a/src/ast/module_access.cr b/src/ast/module_access.cr deleted file mode 100644 index 6bb669d49..000000000 --- a/src/ast/module_access.cr +++ /dev/null @@ -1,16 +0,0 @@ -module Mint - class Ast - class ModuleAccess < Node - getter variable, name - getter? constant - - def initialize(@variable : Variable, - @name : TypeId, - @from : Int32, - @input : Data, - @to : Int32, - @constant : Bool = false) - end - end - end -end diff --git a/src/ast/negated_expression.cr b/src/ast/negated_expression.cr index 29bb4a92a..8b81916e6 100644 --- a/src/ast/negated_expression.cr +++ b/src/ast/negated_expression.cr @@ -3,11 +3,11 @@ module Mint class NegatedExpression < Node getter expression, negations - def initialize(@expression : Expression, + def initialize(@file : Parser::File, @negations : String, - @input : Data, - @from : Int32, - @to : Int32) + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/next_call.cr b/src/ast/next_call.cr index b40023637..1666548a6 100644 --- a/src/ast/next_call.cr +++ b/src/ast/next_call.cr @@ -3,10 +3,12 @@ module Mint class NextCall < Node getter data - def initialize(@data : Record, - @input : Data, - @from : Int32, - @to : Int32) + property entity : Ast::Node? = nil + + def initialize(@file : Parser::File, + @data : Record, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/node.cr b/src/ast/node.cr index 9a1565fa6..58c8945ce 100644 --- a/src/ast/node.cr +++ b/src/ast/node.cr @@ -2,7 +2,7 @@ module Mint class Ast class Node # Line and column number pair. - alias Position = {Int32, Int32} + alias Position = {Int64, Int64} struct Location include JSON::Serializable @@ -22,11 +22,11 @@ module Mint def initialize(@filename, @start, @end) end - def contains?(line : Int) + def contains?(line : Int64) start[0] <= line <= end[0] end - def contains?(line : Int, column : Int) + def contains?(line : Int64, column : Int64) case when line == start[0] == end[0] # If on the only line start[1] <= column < end[1] @@ -40,31 +40,20 @@ module Mint end end - property from : Int32 - getter input : Data - getter to : Int32 + getter file : Parser::File - def initialize(@input, @from, @to) - end - - def to_tuple - {input: input, from: from, to: to} - end + property from : Int64 + getter to : Int64 - def owns?(node) - false + def initialize(@file, @from, @to) end - def static? - false - end - - def static_value - "" + def to_tuple + {file: file, from: from, to: to} end def source - input.input[from, to - from] + file.contents[from, to - from] end def new_line? @@ -73,8 +62,8 @@ module Mint def self.compute_position(lines, needle) : Position line_start_pos, line = begin - left, right = 0, lines.size - 1 - index = pos = 0 + left, right = 0_i64, lines.size - 1_i64 + index = pos = 0_i64 found = false while left <= right @@ -82,9 +71,9 @@ module Mint case pos = lines[middle] when .< needle - left = middle + 1 + left = middle + 1_i64 when .> needle - right = middle - 1 + right = middle - 1_i64 else index = middle found = true @@ -93,7 +82,7 @@ module Mint end unless found - index = left - 1 + index = left - 1_i64 pos = lines[index] end @@ -101,28 +90,28 @@ module Mint end # NOTE: for the line numbers use 1-based indexing - line += 1 + line += 1_i64 column = needle - line_start_pos {line, column} end - def self.compute_location(input : Data, from, to) + def self.compute_location(file : Parser::File, from, to) # TODO: avoid creating this array for every (initial) call to `Node#location` lines = [0] - input.input.each_char_with_index do |ch, i| + file.contents.each_char_with_index do |ch, i| lines << i + 1 if ch == '\n' end Location.new( - filename: input.file, + filename: file.path, start: compute_position(lines, from), end: compute_position(lines, to), ) end getter location : Location do - Node.compute_location(input, from, to) + Node.compute_location(file, from, to) end end end diff --git a/src/ast/number_literal.cr b/src/ast/number_literal.cr index 7e9bcf0a7..cee7dbfc8 100644 --- a/src/ast/number_literal.cr +++ b/src/ast/number_literal.cr @@ -1,22 +1,14 @@ module Mint class Ast class NumberLiteral < Node - getter value getter? float + getter value - def initialize(@value : String, - @input : Data, + def initialize(@file : Parser::File, + @value : String, @float : Bool, - @from : Int32, - @to : Int32) - end - - def static? - true - end - - def static_value - value + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/operation.cr b/src/ast/operation.cr index 3b4e2a71b..99190c197 100644 --- a/src/ast/operation.cr +++ b/src/ast/operation.cr @@ -3,12 +3,12 @@ module Mint class Operation < Node getter left, right, operator - def initialize(@right : Expression, - @left : Expression, + def initialize(@file : Parser::File, @operator : String, - @input : Data, - @from : Int32, - @to : Int32) + @right : Node, + @from : Int64, + @left : Node, + @to : Int64) end end end diff --git a/src/ast/option.cr b/src/ast/option.cr deleted file mode 100644 index 3cb3cfb3e..000000000 --- a/src/ast/option.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class Ast - class Option < Node - getter name - - def initialize(@name : String, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/parenthesized_expression.cr b/src/ast/parenthesized_expression.cr index 72dbfbcfb..9bb94652d 100644 --- a/src/ast/parenthesized_expression.cr +++ b/src/ast/parenthesized_expression.cr @@ -3,10 +3,10 @@ module Mint class ParenthesizedExpression < Node getter expression - def initialize(@expression : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/pipe.cr b/src/ast/pipe.cr index 39ff89003..9e8a5ed12 100644 --- a/src/ast/pipe.cr +++ b/src/ast/pipe.cr @@ -3,21 +3,22 @@ module Mint class Pipe < Node getter expression, argument - def initialize(@expression : Expression, - @argument : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @expression : Node, + @argument : Node, + @from : Int64, + @to : Int64) end def call arg = - Ast::CallExpression.new( - expression: argument, - input: argument.input, + Ast::Field.new( + file: argument.file, from: argument.from, to: argument.to, - name: nil) + value: argument, + comment: nil, + key: nil) @call ||= case item = expression @@ -25,14 +26,14 @@ module Mint Ast::Call.new( arguments: [arg] + item.arguments, expression: item.expression, - input: item.input, + file: item.file, from: item.from, to: item.to) else Ast::Call.new( expression: expression, arguments: [arg], - input: input, + file: file, from: from, to: to) end diff --git a/src/ast/property.cr b/src/ast/property.cr index 73bd5e08e..76b23923f 100644 --- a/src/ast/property.cr +++ b/src/ast/property.cr @@ -3,13 +3,13 @@ module Mint class Property < Node getter name, default, type, comment - def initialize(@default : Expression?, + def initialize(@file : Parser::File, @comment : Comment?, + @default : Node?, @name : Variable, - @input : Data, - @from : Int32, + @from : Int64, @type : Type?, - @to : Int32) + @to : Int64) end end end diff --git a/src/ast/provider.cr b/src/ast/provider.cr index 1ac733229..e1eb900dc 100644 --- a/src/ast/provider.cr +++ b/src/ast/provider.cr @@ -8,13 +8,13 @@ module Mint @constants : Array(Constant), @comments : Array(Comment), @states : Array(State), - @subscription : TypeId, + @subscription : Id, + @file : Parser::File, @comment : Comment?, @gets : Array(Get), - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) + @name : Id, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/record.cr b/src/ast/record.cr index c49106d13..1d29b5805 100644 --- a/src/ast/record.cr +++ b/src/ast/record.cr @@ -4,15 +4,15 @@ module Mint getter fields UNIT = new( - fields: [] of RecordField, - input: Data.new("", ""), + file: Parser::File.new("", ""), + fields: [] of Field, from: 0, to: 2) - def initialize(@fields : Array(RecordField), - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@fields : Array(Field), + @file : Parser::File, + @from : Int64, + @to : Int64) end def self.empty diff --git a/src/ast/record_definition.cr b/src/ast/record_definition.cr deleted file mode 100644 index 1a49ec2c9..000000000 --- a/src/ast/record_definition.cr +++ /dev/null @@ -1,16 +0,0 @@ -module Mint - class Ast - class RecordDefinition < Node - getter fields, name, comment, block_comment - - def initialize(@fields : Array(RecordDefinitionField), - @block_comment : Comment?, - @comment : Comment?, - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/record_field.cr b/src/ast/record_field.cr deleted file mode 100644 index 3af978228..000000000 --- a/src/ast/record_field.cr +++ /dev/null @@ -1,15 +0,0 @@ -module Mint - class Ast - class RecordField < Node - getter key, value, comment - - def initialize(@value : Expression, - @comment : Comment?, - @key : Variable, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/record_update.cr b/src/ast/record_update.cr index 77fbe9321..bbfcbca01 100644 --- a/src/ast/record_update.cr +++ b/src/ast/record_update.cr @@ -3,11 +3,11 @@ module Mint class RecordUpdate < Node getter fields, expression - def initialize(@fields : Array(RecordField), - @expression : Ast::Node, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@expression : Ast::Node, + @fields : Array(Field), + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/regexp_literal.cr b/src/ast/regexp_literal.cr index fcafc6a4e..17cf7a212 100644 --- a/src/ast/regexp_literal.cr +++ b/src/ast/regexp_literal.cr @@ -3,23 +3,11 @@ module Mint class RegexpLiteral < Node getter value, flags - def initialize(@value : String, + def initialize(@file : Parser::File, + @value : String, @flags : String, - @input : Data, - @from : Int32, - @to : Int32) - end - - def static? - true - end - - def uniq_flags - flags.split.uniq!.join - end - - def static_value - "/#{value}/#{uniq_flags}" + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/return_call.cr b/src/ast/return_call.cr index 28b422c4c..144d1d1b3 100644 --- a/src/ast/return_call.cr +++ b/src/ast/return_call.cr @@ -1,14 +1,14 @@ module Mint class Ast class ReturnCall < Node - getter expression - property statement : Ast::Statement? = nil - def initialize(@expression : Expression, - @input : Data, - @from : Int32, - @to : Int32) + getter expression + + def initialize(@file : Parser::File, + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/route.cr b/src/ast/route.cr index 141a10fc7..169151da4 100644 --- a/src/ast/route.cr +++ b/src/ast/route.cr @@ -4,11 +4,11 @@ module Mint getter url, expression, arguments def initialize(@arguments : Array(Argument), + @file : Parser::File, @expression : Block, - @input : Data, - @from : Int32, + @from : Int64, @url : String, - @to : Int32) + @to : Int64) end end end diff --git a/src/ast/routes.cr b/src/ast/routes.cr index 75f50caf3..6b04226ce 100644 --- a/src/ast/routes.cr +++ b/src/ast/routes.cr @@ -5,9 +5,9 @@ module Mint def initialize(@comments : Array(Comment), @routes : Array(Route), - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/spread.cr b/src/ast/spread.cr index b68498746..e0867bfc7 100644 --- a/src/ast/spread.cr +++ b/src/ast/spread.cr @@ -4,9 +4,9 @@ module Mint getter variable def initialize(@variable : Variable, - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/state.cr b/src/ast/state.cr index b0157e90c..f95ab4c60 100644 --- a/src/ast/state.cr +++ b/src/ast/state.cr @@ -3,13 +3,13 @@ module Mint class State < Node getter default, type, name, comment - def initialize(@default : Expression, + def initialize(@file : Parser::File, @comment : Comment?, @name : Variable, - @input : Data, - @from : Int32, + @default : Node, + @from : Int64, @type : Type?, - @to : Int32) + @to : Int64) end end end diff --git a/src/ast/statement.cr b/src/ast/statement.cr index c2e657b9c..7bb8384fc 100644 --- a/src/ast/statement.cr +++ b/src/ast/statement.cr @@ -1,17 +1,16 @@ module Mint class Ast class Statement < Node - getter target, expression, await property if_node : Ast::If? = nil - delegate static?, to: @expression + getter target, expression, await - def initialize(@expression : Expression, + def initialize(@file : Parser::File, + @expression : Node, @target : Node?, @await : Bool, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/store.cr b/src/ast/store.cr index e095c5e78..2f87c6fca 100644 --- a/src/ast/store.cr +++ b/src/ast/store.cr @@ -7,16 +7,12 @@ module Mint @constants : Array(Constant), @comments : Array(Comment), @states : Array(State), + @file : Parser::File, @comment : Comment?, @gets : Array(Get), - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) - end - - def owns?(node) - {functions, constants, states, gets}.any? &.includes?(node) + @from : Int64, + @to : Int64, + @name : Id) end end end diff --git a/src/ast/string_literal.cr b/src/ast/string_literal.cr index b24b68d94..68378111e 100644 --- a/src/ast/string_literal.cr +++ b/src/ast/string_literal.cr @@ -1,28 +1,14 @@ module Mint class Ast class StringLiteral < Node - getter value getter? broken + getter value def initialize(@value : Array(String | Interpolation), + @file : Parser::File, @broken : Bool, - @input : Data, - @from : Int32, - @to : Int32) - end - - def string_value - value - .select(String) - .join - end - - def static? - value.all?(String) - end - - def static_value - string_value + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/style.cr b/src/ast/style.cr index 6044a2f35..83f3fb0b8 100644 --- a/src/ast/style.cr +++ b/src/ast/style.cr @@ -4,11 +4,11 @@ module Mint getter name, body, arguments def initialize(@arguments : Array(Argument), + @file : Parser::File, @body : Array(Node), @name : Variable, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/suite.cr b/src/ast/suite.cr index b24f8cf1d..36f07602a 100644 --- a/src/ast/suite.cr +++ b/src/ast/suite.cr @@ -3,13 +3,13 @@ module Mint class Suite < Node getter tests, name, comments, constants - def initialize(@comments : Array(Comment), - @constants : Array(Constant), + def initialize(@constants : Array(Constant), + @comments : Array(Comment), @name : StringLiteral, @tests : Array(Test), - @input : Data, - @from : Int32, - @to : Int32) + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/test.cr b/src/ast/test.cr index ad0a89f6e..ab7f40100 100644 --- a/src/ast/test.cr +++ b/src/ast/test.cr @@ -4,10 +4,10 @@ module Mint getter name, expression def initialize(@name : StringLiteral, + @file : Parser::File, @expression : Block, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/tuple_destructuring.cr b/src/ast/tuple_destructuring.cr index a32739ea2..3a4baa2c7 100644 --- a/src/ast/tuple_destructuring.cr +++ b/src/ast/tuple_destructuring.cr @@ -1,16 +1,12 @@ module Mint class Ast class TupleDestructuring < Node - getter parameters + getter items - def initialize(@parameters : Array(Node), - @input : Data, - @from : Int32, - @to : Int32) - end - - def exhaustive? - parameters.all?(Ast::Variable) + def initialize(@items : Array(Node), + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/tuple_literal.cr b/src/ast/tuple_literal.cr index 143a879dc..4dfb0f668 100644 --- a/src/ast/tuple_literal.cr +++ b/src/ast/tuple_literal.cr @@ -3,21 +3,10 @@ module Mint class TupleLiteral < Node getter items - def initialize(@items : Array(Expression), - @input : Data, - @from : Int32, - @to : Int32) - end - - def static? - items.all?(&.static?) - end - - def static_value - values = - items.join(',', &.static_value) - - "[#{values}]" + def initialize(@items : Array(Node), + @file : Parser::File, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/type.cr b/src/ast/type.cr index 6ebfc4ba5..741b483d5 100644 --- a/src/ast/type.cr +++ b/src/ast/type.cr @@ -3,11 +3,11 @@ module Mint class Type < Node getter name, parameters - def initialize(@parameters : Array(TypeOrVariable), - @name : TypeId, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@parameters : Array(Node), + @file : Parser::File, + @from : Int64, + @to : Int64, + @name : Id) end end end diff --git a/src/ast/type_definition.cr b/src/ast/type_definition.cr new file mode 100644 index 000000000..98aace20d --- /dev/null +++ b/src/ast/type_definition.cr @@ -0,0 +1,16 @@ +module Mint + class Ast + class TypeDefinition < Node + getter name, fields, parameters, comment + + def initialize(@fields : Array(TypeDefinitionField) | Array(Ast::TypeVariant), + @parameters : Array(TypeVariable), + @file : Parser::File, + @comment : Comment?, + @from : Int64, + @to : Int64, + @name : Id) + end + end + end +end diff --git a/src/ast/record_definition_field.cr b/src/ast/type_definition_field.cr similarity index 54% rename from src/ast/record_definition_field.cr rename to src/ast/type_definition_field.cr index b94097e20..a85753282 100644 --- a/src/ast/record_definition_field.cr +++ b/src/ast/type_definition_field.cr @@ -1,15 +1,15 @@ module Mint class Ast - class RecordDefinitionField < Node + class TypeDefinitionField < Node getter key, type, mapping, comment def initialize(@mapping : StringLiteral?, + @file : Parser::File, @comment : Comment?, @key : Variable, - @input : Data, - @from : Int32, - @type : Type, - @to : Int32) + @from : Int64, + @type : Node, + @to : Int64) end end end diff --git a/src/ast/type_destructuring.cr b/src/ast/type_destructuring.cr new file mode 100644 index 000000000..093b4b7f2 --- /dev/null +++ b/src/ast/type_destructuring.cr @@ -0,0 +1,15 @@ +module Mint + class Ast + class TypeDestructuring < Node + getter name, variant, items + + def initialize(@items : Array(Node), + @file : Parser::File, + @from : Int64, + @variant : Id, + @to : Int64, + @name : Id?) + end + end + end +end diff --git a/src/ast/type_id.cr b/src/ast/type_id.cr deleted file mode 100644 index a28f4f57a..000000000 --- a/src/ast/type_id.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class Ast - class TypeId < Node - getter value - - def initialize(@value : String, - @input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/ast/type_variable.cr b/src/ast/type_variable.cr index bad545581..ae536cdf2 100644 --- a/src/ast/type_variable.cr +++ b/src/ast/type_variable.cr @@ -3,10 +3,10 @@ module Mint class TypeVariable < Node getter value - def initialize(@value : String, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @value : String, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/type_variant.cr b/src/ast/type_variant.cr new file mode 100644 index 000000000..1de912313 --- /dev/null +++ b/src/ast/type_variant.cr @@ -0,0 +1,21 @@ +module Mint + class Ast + class TypeVariant < Node + getter value, comment, parameters + + def initialize(@parameters : Array(Node) | Array(TypeDefinitionField), + @file : Parser::File, + @comment : Comment?, + @from : Int64, + @to : Int64, + @value : Id) + end + + def fields : Array(TypeDefinitionField)? + if @parameters.all?(Ast::TypeDefinitionField) + parameters.select(Ast::TypeDefinitionField) + end + end + end + end +end diff --git a/src/ast/unary_minus.cr b/src/ast/unary_minus.cr index 6d59cd4d3..d6e951834 100644 --- a/src/ast/unary_minus.cr +++ b/src/ast/unary_minus.cr @@ -3,10 +3,10 @@ module Mint class UnaryMinus < Node getter expression, negations - def initialize(@expression : Expression, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @expression : Node, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/use.cr b/src/ast/use.cr index af14e4dd8..5860244d6 100644 --- a/src/ast/use.cr +++ b/src/ast/use.cr @@ -3,12 +3,12 @@ module Mint class Use < Node getter data, provider, condition - def initialize(@condition : Expression?, - @provider : TypeId, + def initialize(@file : Parser::File, + @condition : Node?, + @provider : Id, @data : Record, - @input : Data, - @from : Int32, - @to : Int32) + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/variable.cr b/src/ast/variable.cr index 06e4734ce..52338e82a 100644 --- a/src/ast/variable.cr +++ b/src/ast/variable.cr @@ -3,10 +3,10 @@ module Mint class Variable < Node getter value - def initialize(@value : String, - @input : Data, - @from : Int32, - @to : Int32) + def initialize(@file : Parser::File, + @value : String, + @from : Int64, + @to : Int64) end end end diff --git a/src/ast/void.cr b/src/ast/void.cr deleted file mode 100644 index 692e08cab..000000000 --- a/src/ast/void.cr +++ /dev/null @@ -1,10 +0,0 @@ -module Mint - class Ast - class Void < Node - def initialize(@input : Data, - @from : Int32, - @to : Int32) - end - end - end -end diff --git a/src/builder.cr b/src/builder.cr index 06a6e00a0..ae2492968 100644 --- a/src/builder.cr +++ b/src/builder.cr @@ -134,9 +134,7 @@ module Mint def index(css_prefix, relative, optimize, runtime_path, web_components) runtime = if runtime_path - raise RuntimeFileNotFound, { - "path" => runtime_path, - } unless File.exists?(runtime_path) + Cli.runtime_file_not_found(runtime_path) unless File.exists?(runtime_path) File.read(runtime_path) else Assets.read("runtime.js") diff --git a/src/cli.cr b/src/cli.cr index dad26230e..327a75f52 100644 --- a/src/cli.cr +++ b/src/cli.cr @@ -3,9 +3,6 @@ require "./commands/command" require "./commands/**" module Mint - command_error EnvFileNotFound - command_error RuntimeFileNotFound - class CliException < Exception end @@ -30,6 +27,16 @@ module Mint register_sub_command loc, type: Loc register_sub_command ls, type: Ls + def self.runtime_file_not_found(path : String) + Errorable.error :runtime_file_not_found do + block do + text "The specified runtime file" + code path + text "could not be found" + end + end + end + def run execute "Help" do terminal.puts help diff --git a/src/commands/compile.cr b/src/commands/compile.cr index a9eb1421f..1cdca52cc 100644 --- a/src/commands/compile.cr +++ b/src/commands/compile.cr @@ -32,9 +32,7 @@ module Mint runtime = if runtime_path - raise RuntimeFileNotFound, { - "path" => runtime_path, - } unless File.exists?(runtime_path) + Cli.runtime_file_not_found(runtime_path) unless File.exists?(runtime_path) File.read(runtime_path) else Assets.read("runtime.js") diff --git a/src/compiler.cr b/src/compiler.cr index 0f28f4544..b8b13008e 100644 --- a/src/compiler.cr +++ b/src/compiler.cr @@ -1,9 +1,10 @@ module Mint class Compiler + include Helpers include Skippable delegate lookups, checked, cache, component_records, to: @artifacts - delegate ast, types, variables, resolve_order, to: @artifacts + delegate ast, variables, resolve_order, to: @artifacts delegate record_field_lookup, locales, argument_order, to: @artifacts getter js, style_builder, static_components, static_components_pool diff --git a/src/compilers/access.cr b/src/compilers/access.cr index a6f702e77..ac9c56ee4 100644 --- a/src/compilers/access.cr +++ b/src/compilers/access.cr @@ -1,17 +1,54 @@ module Mint class Compiler def _compile(node : Ast::Access) : String - first = - compile node.lhs + if items = variables[node]? + case items[0] + when Ast::TypeVariant + name = + js.class_of(items[0]) - field = - if record_field_lookup[node.field]? - node.field.value + type = + cache[node]? + + case type + when nil + "" + else + if type.name == "Function" + "_n(#{name})" + else + "new #{name}()" + end + end else - js.variable_of(lookups[node.field]) + name = + js.class_of(items[1].as(Ast::Node)) + + case items[1] + when Ast::Provider + if node.field.value == "subscriptions" + return "#{name}._subscriptions" + end + end + + variable = + js.variable_of(items[0].as(Ast::Node)) + + "#{name}.#{variable}" end + else + first = + compile node.expression + + field = + if record_field_lookup[node.field]? + node.field.value + else + js.variable_of(lookups[node.field][0]) + end - "#{first}.#{field}" + "#{first}.#{field}" + end end end end diff --git a/src/compilers/array_access.cr b/src/compilers/array_access.cr index 4d33a2e48..deccf0763 100644 --- a/src/compilers/array_access.cr +++ b/src/compilers/array_access.cr @@ -2,23 +2,23 @@ module Mint class Compiler def _compile(node : Ast::ArrayAccess) : String type = - cache[node.lhs] + cache[node.expression] - lhs = - compile node.lhs + expression = + compile node.expression index = - case node.index - when Int64 - node.index + case item = node.index + when Ast::NumberLiteral + item.value.to_i when Ast::Node compile node.index.as(Ast::Node) end - if type.name == "Tuple" && node.index.is_a?(Int64) - "#{lhs}[#{index}]" + if type.name == "Tuple" && node.index.is_a?(Ast::NumberLiteral) + "#{expression}[#{index}]" else - "_at(#{lhs}, #{index})" + "_at(#{expression}, #{index})" end end end diff --git a/src/compilers/block.cr b/src/compilers/block.cr index 1b1f13fc0..81329dff6 100644 --- a/src/compilers/block.cr +++ b/src/compilers/block.cr @@ -5,31 +5,31 @@ module Mint end def _compile(node : Ast::Block, for_function = false) : String - statements = + expressions = node - .statements + .expressions .select(Ast::Statement) .sort_by! { |item| resolve_order.index(item) || -1 } .flat_map { |item| _compile2 item } last = - statements.pop + expressions.pop - if statements.empty? && !node.async? + if expressions.empty? && !async?(node) if for_function js.return(last) else last end elsif for_function - js.statements(statements + [js.return(last)]) - elsif node.async? + js.statements(expressions + [js.return(last)]) + elsif async?(node) js.asynciif do - js.statements(statements + [js.return(last)]) + js.statements(expressions + [js.return(last)]) end else js.iif do - js.statements(statements + [js.return(last)]) + js.statements(expressions + [js.return(last)]) end end end diff --git a/src/compilers/call_expression.cr b/src/compilers/call_expression.cr deleted file mode 100644 index 111e7998a..000000000 --- a/src/compilers/call_expression.cr +++ /dev/null @@ -1,7 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::CallExpression) - compile node.expression - end - end -end diff --git a/src/compilers/case.cr b/src/compilers/case.cr index 23c301660..d6d858353 100644 --- a/src/compilers/case.cr +++ b/src/compilers/case.cr @@ -10,7 +10,7 @@ module Mint branches = node .branches - .sort_by(&.match.nil?.to_s) + .sort_by(&.pattern.nil?.to_s) .map do |branch| _compile branch, block end diff --git a/src/compilers/case_branch.cr b/src/compilers/case_branch.cr index 7c28799dc..7e472ab32 100644 --- a/src/compilers/case_branch.cr +++ b/src/compilers/case_branch.cr @@ -15,12 +15,12 @@ module Mint "" end - if match = node.match + if pattern = node.pattern variables = [] of String matcher = - destructuring(match, variables) + destructuring(pattern, variables) js.array([matcher, js.arrow_function(variables, js.return(expression))]) else diff --git a/src/compilers/component.cr b/src/compilers/component.cr index 78363634e..3381e10fc 100644 --- a/src/compilers/component.cr +++ b/src/compilers/component.cr @@ -116,9 +116,9 @@ module Mint item.keys.map do |key| store_name = js.class_of(store) - original = key.variable.value + original = key.name.value - id = js.variable_of(lookups[key]) + id = js.variable_of(lookups[key][0]) name = js.variable_of(key) case @@ -168,7 +168,7 @@ module Mint condition ||= "true" name = - js.class_of(lookups[use]) + js.class_of(lookups[use][0]) data = compile use.data @@ -203,8 +203,6 @@ module Mint function = node.functions.find(&.name.value.==(key)) - function.keep_name = true if function - # If the user defined the same function the code goes after it. if function && !value.empty? compile function, js.statements(value) diff --git a/src/compilers/constant.cr b/src/compilers/constant.cr index 857ea0247..bbaafd108 100644 --- a/src/compilers/constant.cr +++ b/src/compilers/constant.cr @@ -6,7 +6,7 @@ module Mint .sort_by! { |item| resolve_order.index(item) || -1 } .each_with_object({} of String => String) do |node, memo| memo[js.variable_of(node)] = - js.arrow_function(%w[], js.return(compile(node.value))) + js.arrow_function(%w[], js.return(compile(node.expression))) end end end diff --git a/src/compilers/decode.cr b/src/compilers/decode.cr index 99c40db6d..030e50ba2 100644 --- a/src/compilers/decode.cr +++ b/src/compilers/decode.cr @@ -1,8 +1,21 @@ module Mint class Compiler def _compile(node : Ast::Decode) : String + type = + cache[node] + + object = + case type.name + when "Result" + type.parameters.last + when "Function" + type.parameters.last.parameters.last + else + raise "SHOULD NOT HAPPEN" + end + code = - @serializer.decoder types[node] + @serializer.decoder object if item = node.expression expression = diff --git a/src/compilers/destructuring.cr b/src/compilers/destructuring.cr index 49efb9fb3..7e613a138 100644 --- a/src/compilers/destructuring.cr +++ b/src/compilers/destructuring.cr @@ -56,14 +56,13 @@ module Mint end def destructuring(node : Ast::TupleDestructuring, variables : Array(String)) - js.array(node.parameters.map { |item| destructuring(item, variables) }) + js.array(node.items.map { |item| destructuring(item, variables) }) end - def destructuring(node : Ast::EnumDestructuring, variables : Array(String)) + def destructuring(node : Ast::TypeDestructuring, variables : Array(String)) items = - case lookups[node].as(Ast::EnumOption).parameters.first? - when Ast::EnumRecordDefinition - params = node.parameters.select(Ast::Variable) + if lookups[node][0].as(Ast::TypeVariant).fields + params = node.items.select(Ast::Variable) if !params.empty? fields = @@ -74,13 +73,13 @@ module Mint ]) end - [js.call("_PR", [js.array(fields)])] + js.call("_PR", [js.array(fields)]) end - end || node.parameters.map do |param| + end || js.array(node.items.map do |param| destructuring(param, variables) - end + end) - js.call("_PE", [js.class_of(lookups[node]), js.array(items)]) + js.call("_PE", [js.class_of(lookups[node][0]), items]) end end end diff --git a/src/compilers/directives/documentation.cr b/src/compilers/directives/documentation.cr index 945e4e358..553ddfd9f 100644 --- a/src/compilers/directives/documentation.cr +++ b/src/compilers/directives/documentation.cr @@ -2,7 +2,7 @@ module Mint class Compiler def _compile(node : Ast::Directives::Documentation) : String entity = - lookups[node] + lookups[node][0] JSON.build do |json| DocumentationGenerator.new.generate(entity, json) diff --git a/src/compilers/directives/highlight.cr b/src/compilers/directives/highlight.cr index 8690696a9..3a007045f 100644 --- a/src/compilers/directives/highlight.cr +++ b/src/compilers/directives/highlight.cr @@ -8,7 +8,7 @@ module Mint Formatter.new.format(node.content, Formatter::BlockFormat::Naked) parser = Parser.new(formatted, "source.mint") - parser.code_block_naked + parser.many { parser.comment || parser.statement } parts = SemanticTokenizer.tokenize(parser.ast) diff --git a/src/compilers/enum.cr b/src/compilers/enum.cr deleted file mode 100644 index a7c647524..000000000 --- a/src/compilers/enum.cr +++ /dev/null @@ -1,31 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::Enum) : String - enum_ids = - node.options.map do |option| - name = - js.class_of(option) - - ids = - (1..option.parameters.size) - .map { |index| "_#{index - 1}" } - - assignments = - ids.map { |item| "this.#{item} = #{item}" } - - js.class( - name, - extends: "_E", - body: [js.function("constructor", ids) do - js.statements([ - js.call("super", %w[]), - assignments, - "this.length = #{option.parameters.size}", - ].flatten) - end]) - end - - js.statements(enum_ids) - end - end -end diff --git a/src/compilers/enum_id.cr b/src/compilers/enum_id.cr deleted file mode 100644 index 56df3278d..000000000 --- a/src/compilers/enum_id.cr +++ /dev/null @@ -1,60 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::EnumId) : String - case parent = lookups[node]? - when Ast::Variable - compile(parent) - when nil - type = - types[node]? - - case type - when TypeChecker::Record - name = - js.class_of(type.name) - - args = %w[] - - fields = - type - .fields - .each_with_index - .reduce({} of String => String) do |memo, value| - field, index = value - key, _ = field - - memo[key] = - if item = node.expressions[index]? - compile(item) - else - arg = "_#{args.size}" - args << arg - arg - end - - memo - end - - body = - "new #{name}(#{js.object(fields)})" - - if args.empty? - body - else - js.arrow_function(args, js.return(body)) - end - else - "" - end - else - name = - js.class_of(parent) - - expressions = - compile node.expressions, "," - - "new #{name}(#{expressions})" - end - end - end -end diff --git a/src/compilers/field.cr b/src/compilers/field.cr new file mode 100644 index 000000000..b36279bd7 --- /dev/null +++ b/src/compilers/field.cr @@ -0,0 +1,19 @@ +module Mint + class Compiler + def _compile(node : Ast::Field) + compile node.value + end + + def resolve(node : Ast::Field) : Hash(String, String) + return {} of String => String unless key = node.key + + value = + compile node.value + + name = + key.value + + {name => value} + end + end +end diff --git a/src/compilers/for_expression.cr b/src/compilers/for_expression.cr index 329b1ef26..9135290e1 100644 --- a/src/compilers/for_expression.cr +++ b/src/compilers/for_expression.cr @@ -33,7 +33,7 @@ module Mint condition = node.condition.try do |item| <<-JS - const _2 = #{compile(item.condition)} + const _2 = #{compile(item)} if (!_2) { continue } JS end diff --git a/src/compilers/function.cr b/src/compilers/function.cr index 5c83e969f..daf6fab3e 100644 --- a/src/compilers/function.cr +++ b/src/compilers/function.cr @@ -20,7 +20,7 @@ module Mint body = js.statements(items) - if node.body.async? + if async?(node.body) js.async_function(name, arguments, body) else js.function(name, arguments, body) diff --git a/src/compilers/here_doc.cr b/src/compilers/here_doc.cr index 5d39a894d..b954c0b74 100644 --- a/src/compilers/here_doc.cr +++ b/src/compilers/here_doc.cr @@ -1,6 +1,6 @@ module Mint class Compiler - def _compile(node : Ast::HereDoc) : String + def _compile(node : Ast::HereDocument) : String if node.modifier == '#' interpolations = [] of Tuple(String, String) diff --git a/src/compilers/html_attribute.cr b/src/compilers/html_attribute.cr index 734d44f61..609547c7c 100644 --- a/src/compilers/html_attribute.cr +++ b/src/compilers/html_attribute.cr @@ -18,8 +18,8 @@ module Mint if downcase_name == "readonly" && is_element {"readOnly" => value} - elsif lookups[node]? - {js.variable_of(lookups[node]) => value} + elsif lookups[node]?.try(&.first?) + {js.variable_of(lookups[node][0]) => value} else { %("#{node.name.value}") => value } end diff --git a/src/compilers/html_component.cr b/src/compilers/html_component.cr index 36f9cef04..b00e0ab9d 100644 --- a/src/compilers/html_component.cr +++ b/src/compilers/html_component.cr @@ -1,9 +1,9 @@ module Mint class Compiler def _compile(node : Ast::HtmlComponent) : String - if node.static? + if hash = static_value(node) name = - static_components_pool.of(node.static_hash, nil) + static_components_pool.of(hash, nil) static_components[name] ||= compile_html_component(node) @@ -15,7 +15,7 @@ module Mint def compile_html_component(node : Ast::HtmlComponent) : String name = - js.class_of(lookups[node]) + js.class_of(lookups[node][0]) children = if node.children.empty? diff --git a/src/compilers/html_element.cr b/src/compilers/html_element.cr index 10edcd350..cf27909db 100644 --- a/src/compilers/html_element.cr +++ b/src/compilers/html_element.cr @@ -46,7 +46,7 @@ module Mint .reduce({} of String => String) { |memo, item| memo.merge(item) } style_nodes = - node.styles.map { |item| lookups[item].as(Ast::Style) } + node.styles.map { |item| lookups[item][0].as(Ast::Style) } class_name = unless style_nodes.empty? @@ -83,13 +83,13 @@ module Mint styles = %w[] node.styles.each do |item| - next unless style_builder.any?(lookups[item]) + next unless style_builder.any?(lookups[item][0]) arguments = compile item.arguments style_name = - style_builder.style_pool.of(lookups[item].as(Ast::Style), nil) + style_builder.style_pool.of(lookups[item][0].as(Ast::Style), nil) styles << js.call("this.$#{style_name}", arguments) end diff --git a/src/compilers/html_fragment.cr b/src/compilers/html_fragment.cr index 26180be0e..166d025eb 100644 --- a/src/compilers/html_fragment.cr +++ b/src/compilers/html_fragment.cr @@ -1,20 +1,13 @@ module Mint class Compiler def _compile(node : Ast::HtmlFragment) : String - attributes = - if key = node.key - js.object({"key" => compile key.value}) - else - "{}" - end - - if node.children.empty? && !node.key + if node.children.empty? "null" else items = compile node.children - "_h(React.Fragment, #{attributes}, #{js.array(items)})" + "_h(React.Fragment, {}, #{js.array(items)})" end end end diff --git a/src/compilers/if.cr b/src/compilers/if.cr index 07c861f75..7a30ef52e 100644 --- a/src/compilers/if.cr +++ b/src/compilers/if.cr @@ -28,23 +28,24 @@ module Mint node.branches truthy = - case item = truthy_item - when Array(Ast::CssDefinition) - _compile item, block: block + if truthy_item.expressions.all?(Ast::CssDefinition) + _compile truthy_item.expressions.select(Ast::CssDefinition), block: block else - compile item + compile truthy_item end falsy = case item = falsy_item - when Array(Ast::CssDefinition) - _compile item, block: block when Ast::If compile item, block: block - when Ast::Node - compile item + when Ast::Block + if item.expressions.all?(Ast::CssDefinition) + _compile item.expressions.select(Ast::CssDefinition), block: block + else + compile item + end else - if truthy_item.is_a?(Ast::Node) + if truthy_item type = cache[truthy_item] case type.name diff --git a/src/compilers/inline_function.cr b/src/compilers/inline_function.cr index 19be3c9f2..7fc854b6f 100644 --- a/src/compilers/inline_function.cr +++ b/src/compilers/inline_function.cr @@ -12,7 +12,7 @@ module Mint arguments = compile node.arguments - if node.body.async? + if async?(node.body) js.async_arrow_function(arguments, body) else js.arrow_function(arguments, body) diff --git a/src/compilers/module_access.cr b/src/compilers/module_access.cr deleted file mode 100644 index 5f51c7a85..000000000 --- a/src/compilers/module_access.cr +++ /dev/null @@ -1,20 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::ModuleAccess) : String - name = - js.class_of(lookups[node]) - - case lookups[node] - when Ast::Provider - if node.variable.value == "subscriptions" - return "#{name}._subscriptions" - end - end - - variable = - js.variable_of(lookups[node.variable]) - - "#{name}.#{variable}" - end - end -end diff --git a/src/compilers/next_call.cr b/src/compilers/next_call.cr index 0053b11bb..f608fbe4b 100644 --- a/src/compilers/next_call.cr +++ b/src/compilers/next_call.cr @@ -2,23 +2,25 @@ module Mint class Compiler def _compile(node : Ast::NextCall) : String entity = - lookups[node]? + lookups[node]?.try(&.first?) if node.data.fields.empty? "null" else state = node.data.fields.each_with_object({} of String => String) do |item, memo| + next memo unless key = item.key + field = case entity when Ast::Provider entity .states - .find(&.name.value.==(item.key.value)) + .find(&.name.value.==(key.value)) when Ast::Component, Ast::Store entity .states - .find(&.name.value.==(item.key.value)) + .find(&.name.value.==(key.value)) end if field diff --git a/src/compilers/number_literal.cr b/src/compilers/number_literal.cr index c405529ce..45a2b669b 100644 --- a/src/compilers/number_literal.cr +++ b/src/compilers/number_literal.cr @@ -1,7 +1,7 @@ module Mint class Compiler def _compile(node : Ast::NumberLiteral) : String - node.static_value + static_value(node).to_s end end end diff --git a/src/compilers/record.cr b/src/compilers/record.cr index bb2cda5e9..1afdc2cc2 100644 --- a/src/compilers/record.cr +++ b/src/compilers/record.cr @@ -6,10 +6,7 @@ module Mint .map { |item| resolve(item) } .reduce({} of String => String) { |memo, item| memo.merge(item) } - type = - types[node]? - - if type + if type = cache[node]? name = js.class_of(type.name) diff --git a/src/compilers/record_constructor.cr b/src/compilers/record_constructor.cr deleted file mode 100644 index 8d1855ae4..000000000 --- a/src/compilers/record_constructor.cr +++ /dev/null @@ -1,47 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::RecordConstructor) : String - type = - types[node]? - - case type - when TypeChecker::Record - name = - js.class_of(type.name) - - args = %w[] - - fields = - type - .fields - .each_with_index - .reduce({} of String => String) do |memo, value| - field, index = value - key, _ = field - - memo[key] = - if item = node.arguments[index]? - compile(item) - else - arg = "_#{args.size}" - args << arg - arg - end - - memo - end - - body = - "new #{name}(#{js.object(fields)})" - - if args.empty? - body - else - js.arrow_function(args, js.return(body)) - end - else - "" - end - end - end -end diff --git a/src/compilers/record_definition.cr b/src/compilers/record_definition.cr deleted file mode 100644 index 79b0474d5..000000000 --- a/src/compilers/record_definition.cr +++ /dev/null @@ -1,24 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::RecordDefinition) : String - type = types[node] - - name = - js.class_of(type.name) - - case type - when TypeChecker::Record - mappings = - begin - @serializer.generate_mappings type - rescue - "{}" - end - - "const #{name} = _R(#{mappings})" - else - "" - end - end - end -end diff --git a/src/compilers/record_field.cr b/src/compilers/record_field.cr deleted file mode 100644 index 1aeb22028..000000000 --- a/src/compilers/record_field.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class Compiler - def resolve(node : Ast::RecordField) : Hash(String, String) - value = - compile node.value - - name = - node.key.value - - {name => value} - end - end -end diff --git a/src/compilers/regexp_literal.cr b/src/compilers/regexp_literal.cr index 83d137850..1b17812c4 100644 --- a/src/compilers/regexp_literal.cr +++ b/src/compilers/regexp_literal.cr @@ -1,7 +1,7 @@ module Mint class Compiler def _compile(node : Ast::RegexpLiteral) : String - node.static_value + static_value(node).to_s end end end diff --git a/src/compilers/route.cr b/src/compilers/route.cr index 39d5a8d9b..9d1f94ece 100644 --- a/src/compilers/route.cr +++ b/src/compilers/route.cr @@ -18,7 +18,7 @@ module Mint .map { |argument| @serializer.decoder(cache[argument]) } handler = - if node.expression.async? + if async?(node.expression) js.async_arrow_function(arguments, expression) else js.arrow_function(arguments, expression) diff --git a/src/compilers/statement.cr b/src/compilers/statement.cr index 37db25227..ba5a59722 100644 --- a/src/compilers/statement.cr +++ b/src/compilers/statement.cr @@ -19,7 +19,7 @@ module Mint case target when Ast::Variable [js.const(js.variable_of(target), right)] - when Ast::TupleDestructuring, Ast::EnumDestructuring, Ast::ArrayDestructuring + when Ast::TupleDestructuring, Ast::TypeDestructuring, Ast::ArrayDestructuring variables = [] of String pattern = @@ -27,7 +27,7 @@ module Mint case target when Ast::TupleDestructuring - if target.parameters.all?(Ast::Variable) + if target.items.all?(Ast::Variable) ["const [#{variables.join(",")}] = #{right}"] end end || begin diff --git a/src/compilers/top_level.cr b/src/compilers/top_level.cr index c4cfe6416..0b727f73a 100644 --- a/src/compilers/top_level.cr +++ b/src/compilers/top_level.cr @@ -98,8 +98,8 @@ module Mint # Compiles the application def compile(include_tests : Bool = false) : String - records = - compile ast.records + type_definitions = + compile ast.type_definitions providers = compile ast.providers @@ -116,9 +116,6 @@ module Mint routes = compile ast.routes - enums = - compile ast.enums - all_css = style_builder.compile @@ -138,7 +135,7 @@ module Mint end elements = - (%w[] &+ enums &+ records &+ modules &+ providers &+ routes &+ components &+ static &+ stores &+ footer &+ suites &+ compiled_web_components) + (%w[] &+ type_definitions &+ modules &+ providers &+ routes &+ components &+ static &+ stores &+ footer &+ suites &+ compiled_web_components) .reject!(&.empty?) replace_skipped(js.statements(elements)) @@ -147,19 +144,29 @@ module Mint # -------------------------------------------------------------------------- def maybe - ast.enums.find!(&.name.value.==("Maybe")) + ast.type_definitions.find!(&.name.value.==("Maybe")) end def just node = - maybe.options.find!(&.value.value.==("Just")) + case fields = maybe.fields + when Array(Ast::TypeVariant) + fields.find!(&.value.value.==("Just")) + else + raise "SHOULD NOT HAPPEN" + end js.class_of(node) end def nothing node = - maybe.options.find!(&.value.value.==("Nothing")) + case fields = maybe.fields + when Array(Ast::TypeVariant) + fields.find!(&.value.value.==("Nothing")) + else + raise "SHOULD NOT HAPPEN" + end js.class_of(node) end @@ -167,19 +174,29 @@ module Mint # -------------------------------------------------------------------------- def result - ast.enums.find!(&.name.value.==("Result")) + ast.type_definitions.find!(&.name.value.==("Result")) end def ok node = - result.options.find!(&.value.value.==("Ok")) + case fields = result.fields + when Array(Ast::TypeVariant) + fields.find!(&.value.value.==("Ok")) + else + raise "SHOULD NOT HAPPEN" + end js.class_of(node) end def err node = - result.options.find!(&.value.value.==("Err")) + case fields = result.fields + when Array(Ast::TypeVariant) + fields.find!(&.value.value.==("Err")) + else + raise "SHOULD NOT HAPPEN" + end js.class_of(node) end @@ -383,19 +400,25 @@ module Mint } } else if (pattern instanceof Pattern) { if (value instanceof pattern.x) { - for (let index in pattern.pattern) { - if (!__match(value[`_${index}`], pattern.pattern[index], values)) { + if (pattern.pattern instanceof RecordPattern) { + if (!__match(value, pattern.pattern, values)) { return false } + } else { + for (let index in pattern.pattern) { + if (!__match(value[`_${index}`], pattern.pattern[index], values)) { + return false + } + } } } else { return false } - } else if (pattern instanceof RecordPattern && value instanceof Record) { + } else if (pattern instanceof RecordPattern) { for (let index in pattern.patterns) { const item = pattern.patterns[index]; - if (!__match(value[item[0]], item[1], values)) { + if (!__match(value[value._mapping[item[0]]], item[1], values)) { return false } } @@ -449,6 +472,10 @@ module Mint } } + const _n = (item) => { + return (...args) => new item(...args) + } + class DoError extends Error {} #{body} diff --git a/src/compilers/type_definition.cr b/src/compilers/type_definition.cr new file mode 100644 index 000000000..358214742 --- /dev/null +++ b/src/compilers/type_definition.cr @@ -0,0 +1,62 @@ +module Mint + class Compiler + def _compile(node : Ast::TypeDefinition) : String + case type = cache[node]? + when TypeChecker::Record + name = + js.class_of(type.name) + + mappings = + begin + @serializer.generate_mappings type + rescue + "{}" + end + + "const #{name} = _R(#{mappings})" + else + variants = + case fields = node.fields + when Array(Ast::TypeVariant) + fields.map do |option| + name = + js.class_of(option) + + mapping = + {} of String => String + + ids = + if fields = option.fields + fields.map_with_index do |field, index| + mapping[field.key.value] = "\"_#{index}\"" + + "_#{index}" + end + else + (1..option.parameters.size).map { |index| "_#{index - 1}" } + end + + assignments = + ids.map { |id| "this.#{id} = #{id}" } + + js.class( + name, + extends: "_E", + body: [js.function("constructor", ids) do + js.statements([ + js.call("super", %w[]), + assignments, + "this.length = #{ids.size}", + mapping.empty? ? nil : "this._mapping = #{js.object(mapping)}", + ].compact.flatten) + end]) + end + else + [] of String + end + + js.statements(variants) + end + end + end +end diff --git a/src/compilers/variable.cr b/src/compilers/variable.cr index d9b182759..77070367b 100644 --- a/src/compilers/variable.cr +++ b/src/compilers/variable.cr @@ -1,46 +1,27 @@ module Mint class Compiler def _compile(node : Ast::Variable) : String - entity, parent = variables[node] - - # Subscriptions for providers are handled here - if node.value == "subscriptions" && parent.is_a?(Ast::Provider) - return "this._subscriptions" - end - - connected = nil - - case parent - when Ast::Component - parent.connects.each do |connect| - store = ast.stores.find(&.name.value.==(connect.store.value)) - - name = - case entity - when Ast::Function, Ast::State, Ast::Get, Ast::Constant - entity.name.value - end + if node.value == "void" + "null" + else + entity, parent = variables[node] - if store - connect.keys.each do |key| - if (store.functions.includes?(entity) || - store.constants.includes?(entity) || - store.states.includes?(entity) || - store.gets.includes?(entity)) && - key.variable.value == name - connected = key - end - end - end + # Subscriptions for providers are handled here + if node.value == "subscriptions" && parent.is_a?(Ast::Provider) + return "this._subscriptions" end - end - case parent - when Tuple(String, TypeChecker::Checkable, Ast::Node) - js.variable_of(parent[2]) - else - case entity - when Ast::Component, Ast::HtmlElement + # puts({entity.class, parent.class}) + + case {entity, parent} + when {Ast::Variable, Ast::Block}, + {Ast::Variable, Ast::Statement}, + {Ast::Variable, Ast::For}, + {Ast::Variable, Ast::CaseBranch}, + {Ast::Spread, Ast::CaseBranch} + js.variable_of(entity) + when {Ast::Component, Ast::Component}, + {Ast::HtmlElement, Ast::Component} case parent when Ast::Component ref = @@ -53,42 +34,39 @@ module Mint else raise "SHOULD NOT HAPPEN" end - when Ast::Function - function = - if connected - js.variable_of(connected) - else + when {Ast::ConnectVariable, _} + "this.#{js.variable_of(entity)}" + else + case entity + when Ast::Function + function = js.variable_of(entity.as(Ast::Node)) - end - case parent - when Ast::Module, Ast::Store - name = - js.class_of(parent.as(Ast::Node)) + case parent + when Ast::Module, Ast::Store + name = + js.class_of(parent.as(Ast::Node)) - "#{name}.#{function}" - else - "this.#{function}" - end - when Ast::Property, Ast::Get, Ast::State, Ast::Constant - name = - if connected - js.variable_of(connected) + "#{name}.#{function}" else - js.variable_of(entity.as(Ast::Node)) + "this.#{function}" end + when Ast::Property, Ast::Get, Ast::State, Ast::Constant + name = + js.variable_of(entity.as(Ast::Node)) - case parent - when Ast::Suite - # The variable is a constant in a test suite - "constants.#{name}()" + case parent + when Ast::Suite + # The variable is a constant in a test suite + "constants.#{name}()" + else + "this.#{name}" + end + when Ast::Argument + js.variable_of(entity) else - "this.#{name}" + "this.#{node.value}" end - when Ast::Argument - js.variable_of(entity) - else - "this.#{node.value}" end end end diff --git a/src/compilers/void.cr b/src/compilers/void.cr deleted file mode 100644 index 517cdf09d..000000000 --- a/src/compilers/void.cr +++ /dev/null @@ -1,7 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::Void) : String - "null" - end - end -end diff --git a/src/documentation_generator.cr b/src/documentation_generator.cr index 93ed738a5..5d65620d0 100644 --- a/src/documentation_generator.cr +++ b/src/documentation_generator.cr @@ -1,5 +1,7 @@ module Mint class DocumentationGenerator + include Helpers + @formatter = Formatter.new def generate(asts : Hash(MintJson, Ast)) @@ -58,11 +60,7 @@ module Mint end json.field "records" do - generate ast.records.sort_by(&.name.value), json - end - - json.field "enums" do - generate ast.enums.sort_by(&.name.value), json + generate ast.type_definitions.sort_by(&.name.value), json end end end diff --git a/src/documentation_generator/connect.cr b/src/documentation_generator/connect.cr index fa78dde28..e949bbc57 100644 --- a/src/documentation_generator/connect.cr +++ b/src/documentation_generator/connect.cr @@ -2,7 +2,7 @@ module Mint class DocumentationGenerator def generate(node : Ast::Connect, json : JSON::Builder) json.object do - json.field "keys", node.keys.map(&.variable.value) + json.field "keys", node.keys.map(&.name.value) json.field "store" do generate node.store, json end diff --git a/src/documentation_generator/enum.cr b/src/documentation_generator/enum.cr deleted file mode 100644 index efb9e23e4..000000000 --- a/src/documentation_generator/enum.cr +++ /dev/null @@ -1,20 +0,0 @@ -module Mint - class DocumentationGenerator - def generate(node : Ast::Enum, json : JSON::Builder) - json.object do - json.field "description", node.comment.try(&.to_html) - json.field "name" do - generate node.name, json - end - - json.field "parameters" do - generate node.parameters, json - end - - json.field "options" do - generate node.options, json - end - end - end - end -end diff --git a/src/documentation_generator/type_id.cr b/src/documentation_generator/id.cr similarity index 55% rename from src/documentation_generator/type_id.cr rename to src/documentation_generator/id.cr index b4c9efbb9..6f89f9405 100644 --- a/src/documentation_generator/type_id.cr +++ b/src/documentation_generator/id.cr @@ -1,10 +1,10 @@ module Mint class DocumentationGenerator - def stringify(node : Ast::TypeId) + def stringify(node : Ast::Id) node.value end - def generate(node : Ast::TypeId, json : JSON::Builder) + def generate(node : Ast::Id, json : JSON::Builder) json.string stringify(node) end end diff --git a/src/documentation_generator/record_definition.cr b/src/documentation_generator/type_definition.cr similarity index 81% rename from src/documentation_generator/record_definition.cr rename to src/documentation_generator/type_definition.cr index 0ceda1af9..585704538 100644 --- a/src/documentation_generator/record_definition.cr +++ b/src/documentation_generator/type_definition.cr @@ -1,6 +1,6 @@ module Mint class DocumentationGenerator - def generate(node : Ast::RecordDefinition, json : JSON::Builder) + def generate(node : Ast::TypeDefinition, json : JSON::Builder) json.object do json.field "description", node.comment.try(&.to_html) json.field "name" do diff --git a/src/documentation_generator/record_definition_field.cr b/src/documentation_generator/type_definition_field.cr similarity index 56% rename from src/documentation_generator/record_definition_field.cr rename to src/documentation_generator/type_definition_field.cr index c5ad8c402..a7daa1bb7 100644 --- a/src/documentation_generator/record_definition_field.cr +++ b/src/documentation_generator/type_definition_field.cr @@ -1,10 +1,10 @@ module Mint class DocumentationGenerator - def generate(node : Ast::RecordDefinitionField, json : JSON::Builder) + def generate(node : Ast::TypeDefinitionField, json : JSON::Builder) json.object do json.field "key", node.key.value json.field "type", stringify(node.type) - json.field "mapping", node.mapping.try(&.string_value) + json.field "mapping", static_value(node.mapping) end end end diff --git a/src/documentation_generator/enum_option.cr b/src/documentation_generator/type_variant.cr similarity index 83% rename from src/documentation_generator/enum_option.cr rename to src/documentation_generator/type_variant.cr index 80f242bf4..eb40c1317 100644 --- a/src/documentation_generator/enum_option.cr +++ b/src/documentation_generator/type_variant.cr @@ -1,6 +1,6 @@ module Mint class DocumentationGenerator - def generate(node : Ast::EnumOption, json : JSON::Builder) + def generate(node : Ast::TypeVariant, json : JSON::Builder) json.object do json.field "description", node.comment.try(&.to_html) json.field "name" do diff --git a/src/env.cr b/src/env.cr index 9e46eb5e1..5760bb203 100644 --- a/src/env.cr +++ b/src/env.cr @@ -23,9 +23,13 @@ module Mint end if env - raise EnvFileNotFound, { - "name" => env, - } unless File.exists?(env) + Errorable.error :env_file_not_found do + block do + text "The specified environment file" + code env + text "does not exists" + end + end unless File.exists?(env) @@env = env load { yield env } diff --git a/src/errorable.cr b/src/errorable.cr new file mode 100644 index 000000000..d2d6966cb --- /dev/null +++ b/src/errorable.cr @@ -0,0 +1,190 @@ +module Mint + # This module is used in all of the stages of the compiler which can error + # out (parser, type checker, scope builder, etc...). + # + # It defines an interface (method) for creating descriptive errors and it can + # either gather them or raise them depending on the raise errors flag, which + # the including entity must define (unusally in the initialize method). + module Errorable + # The errors found during parsing. + getter errors : Array(Error) = [] of Error + + def self.error(name : Symbol, &) + raise Error.new(name).tap { |error| with error yield } + end + + def error!(name : Symbol, &) + raise Error.new(name).tap { |error| with error yield } + end + + def error(name : Symbol, &) + errors << Error.new(name).tap { |error| with error yield } + nil + end + end + + # Represents a raisable rich and descriptive error. + class Error < Exception + alias Element = Text | Bold | Code + + record Snippet, value : Ast::Node | String | TypeChecker::Checkable + record Code, value : String + record Bold, value : String + record Text, value : String + + getter blocks = [] of Array(Element) | Snippet + getter name : Symbol + + def initialize(@name : Symbol) + @current = [] of Element + end + + def build(&) + with self yield + end + + def block(&) + with self yield + @blocks << @current + @current = [] of Element + end + + def block(contents : String) + block { text(contents) } + end + + def code(value : String) + @current << Code.new(value) + end + + def text(value : String) + @current << Text.new(value) + end + + def bold(value : String) + @current << Bold.new(value) + end + + def snippet(value : String, node : Ast::Node | TypeChecker::Checkable | String) + block value + snippet node + end + + def snippet(value : Parser) + from = + value.position + + to = + value.position + value.word.to_s.size + + snippet(Ast::Node.new(file: value.file, from: from, to: to)) + end + + def snippet(value : String | Ast::Node | TypeChecker::Checkable) + @blocks << Snippet.new(value) + end + + def expected(subject : TypeChecker::Checkable | String, got : TypeChecker::Checkable) + snippet "I was expecting:", subject + snippet "Instead it is:", got + end + + def expected(subject : String, got : String) + block do + text "I was expecting #{subject} but I found" + code got + text "instead:" + end + end + + def to_html + renderer = Render::Html.new + renderer.title "ERROR (#{name})" + + blocks.each do |element| + case element + # when TypeList + # renderer.type_list element.value + # when StringList + # renderer.list element.value + # when Pre + # renderer.pre element.value + # when Type + # renderer.type element.value + # when Title + # renderer.title element.value + when Error::Snippet + case node = element.value + when TypeChecker::Checkable + renderer.pre node.to_pretty + when Ast::Node + renderer.snippet node + end + when Array(Error::Element) + renderer.block do + element.each do |item| + case item + when Error::Text + text item.value + when Error::Bold + bold item.value + when Error::Code + code item.value + end + end + end + end + end + + # ameba:disable Lint/UselessAssign + contents = + renderer.io.to_s + + ECR.render("#{__DIR__}/message.ecr") + end + + def to_terminal + renderer = Render::Terminal.new + renderer.title "ERROR (#{name})" + + blocks.each do |element| + case element + # when TypeList + # renderer.type_list element.value + # when StringList + # renderer.list element.value + # when Pre + # renderer.pre element.value + # when Type + # renderer.type element.value + # when Title + # renderer.title element.value + when Error::Snippet + case node = element.value + when TypeChecker::Checkable + renderer.snippet node + when Ast::Node + renderer.snippet node + when String + renderer.snippet node + end + when Array(Error::Element) + renderer.block do + element.each do |item| + case item + when Error::Text + text item.value + when Error::Bold + bold item.value + when Error::Code + code item.value + end + end + end + end + end + + renderer.io + end + end +end diff --git a/src/errors/error.cr b/src/errors/error.cr deleted file mode 100644 index c13f929c1..000000000 --- a/src/errors/error.cr +++ /dev/null @@ -1,29 +0,0 @@ -module Mint - # This is the base class of an error, it uses a Message - # to render to both to the Terminal and to an HTML format. - class Error < Exception - alias Value = String | Ast::Node | TypeChecker::Checkable | - Array(TypeChecker::Checkable) | Tuple(Ast::Node, Int32 | Array(Int32)) | - Array(String) - - alias Locals = Hash(String, Value) - - getter locals : Locals - getter instance : Message { Message.new(locals) } - - def initialize(@locals = Locals.new) - end - - def to_html - instance.to_html - end - - def to_terminal - instance.to_terminal(80) - end - - def message - to_terminal.to_s - end - end -end diff --git a/src/errors/install_error.cr b/src/errors/install_error.cr deleted file mode 100644 index f1df502df..000000000 --- a/src/errors/install_error.cr +++ /dev/null @@ -1,4 +0,0 @@ -module Mint - class InstallError < Error - end -end diff --git a/src/errors/json_error.cr b/src/errors/json_error.cr deleted file mode 100644 index 1ba442a11..000000000 --- a/src/errors/json_error.cr +++ /dev/null @@ -1,4 +0,0 @@ -module Mint - class JsonError < Error - end -end diff --git a/src/errors/syntax_error.cr b/src/errors/syntax_error.cr deleted file mode 100644 index d702146a7..000000000 --- a/src/errors/syntax_error.cr +++ /dev/null @@ -1,4 +0,0 @@ -module Mint - class SyntaxError < Error - end -end diff --git a/src/errors/top_level.cr b/src/errors/top_level.cr deleted file mode 100644 index 997a3e9da..000000000 --- a/src/errors/top_level.cr +++ /dev/null @@ -1,16 +0,0 @@ -# Top level methods to raise a Mint::Error with data -def raise(error : Mint::Error.class) - raise error, {} of String => Mint::Error::Value -end - -def raise(error : Mint::Error.class, raw : Hash(String, T)) forall T - locals = {} of String => Mint::Error::Value - - raw.map do |key, value| - if value - locals[key] = value - end - end - - raise error.new(locals) -end diff --git a/src/errors/type_error.cr b/src/errors/type_error.cr deleted file mode 100644 index 4be601f6b..000000000 --- a/src/errors/type_error.cr +++ /dev/null @@ -1,4 +0,0 @@ -module Mint - class TypeError < Error - end -end diff --git a/src/formatter.cr b/src/formatter.cr index 9772d59a4..845e72c65 100644 --- a/src/formatter.cr +++ b/src/formatter.cr @@ -1,5 +1,6 @@ module Mint class Formatter + include Helpers include Skippable class Config diff --git a/src/formatters/access.cr b/src/formatters/access.cr index 47c06387d..ff616d1bb 100644 --- a/src/formatters/access.cr +++ b/src/formatters/access.cr @@ -1,10 +1,10 @@ module Mint class Formatter def format(node : Ast::Access) : String - lhs = - format node.lhs + expression = + format node.expression - "#{lhs}.#{node.field.value}" + "#{expression}.#{node.field.value}" end end end diff --git a/src/formatters/array_access.cr b/src/formatters/array_access.cr index 611acd2fe..dd237a1b0 100644 --- a/src/formatters/array_access.cr +++ b/src/formatters/array_access.cr @@ -2,17 +2,12 @@ module Mint class Formatter def format(node : Ast::ArrayAccess) : String index = - case node.index - when Int64 - node.index - else - format node.index.as(Ast::Expression) - end + format node.index - lhs = - format node.lhs + expression = + format node.expression - "#{lhs}[#{index}]" + "#{expression}[#{index}]" end end end diff --git a/src/formatters/block.cr b/src/formatters/block.cr index 3b30d438d..8cbc2ef44 100644 --- a/src/formatters/block.cr +++ b/src/formatters/block.cr @@ -9,7 +9,7 @@ module Mint def format(node : Ast::Block, format = BlockFormat::Block) : String body = - list node.statements + list node.expressions if format == BlockFormat::Naked body diff --git a/src/formatters/call_expression.cr b/src/formatters/call_expression.cr deleted file mode 100644 index ec50baa49..000000000 --- a/src/formatters/call_expression.cr +++ /dev/null @@ -1,14 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::CallExpression) - expression = - format node.expression - - if name = node.name - "#{name.value}: #{expression}" - else - expression - end - end - end -end diff --git a/src/formatters/case_branch.cr b/src/formatters/case_branch.cr index acda00e8f..b0901d4bf 100644 --- a/src/formatters/case_branch.cr +++ b/src/formatters/case_branch.cr @@ -11,12 +11,12 @@ module Mint "" end - match = - format node.match + pattern = + format node.pattern head = - if match - "#{match} =>" + if pattern + "#{pattern} =>" else "=>" end diff --git a/src/formatters/comment.cr b/src/formatters/comment.cr index 7c68eee7e..d9722305f 100644 --- a/src/formatters/comment.cr +++ b/src/formatters/comment.cr @@ -3,7 +3,7 @@ module Mint def format(node : Ast::Comment) : String value = node - .value + .content .remove_leading_whitespace .rstrip diff --git a/src/formatters/connect_variable.cr b/src/formatters/connect_variable.cr index 7ceebb309..9d11c75bb 100644 --- a/src/formatters/connect_variable.cr +++ b/src/formatters/connect_variable.cr @@ -1,16 +1,16 @@ module Mint class Formatter def format(node : Ast::ConnectVariable) : String - variable = - format node.variable - name = - node.name.try { |item| format item } + format node.name + + target = + node.target.try { |item| format item } - if name - "#{variable} as #{name}" + if target + "#{name} as #{target}" else - variable + name end end end diff --git a/src/formatters/constant.cr b/src/formatters/constant.cr index d1522f2bd..b00c2af79 100644 --- a/src/formatters/constant.cr +++ b/src/formatters/constant.cr @@ -1,8 +1,8 @@ module Mint class Formatter def format(node : Ast::Constant) : String - value = - format node.value + expression = + format node.expression name = format node.name @@ -10,10 +10,10 @@ module Mint comment = node.comment.try { |item| "#{format item}\n" } - if node.value.new_line? - "#{comment}const #{name} =\n#{indent(value)}" + if node.expression.new_line? + "#{comment}const #{name} =\n#{indent(expression)}" else - "#{comment}const #{name} = #{value}" + "#{comment}const #{name} = #{expression}" end end end diff --git a/src/formatters/enum.cr b/src/formatters/enum.cr deleted file mode 100644 index 7f385e11d..000000000 --- a/src/formatters/enum.cr +++ /dev/null @@ -1,22 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::Enum) - name = - format node.name - - items = - node.options + node.comments - - body = - list items - - comment = - node.comment.try { |item| "#{format item}\n" } - - parameters = - format_parameters(node.parameters) - - "#{comment}enum #{name}#{parameters} {\n#{indent(body)}\n}" - end - end -end diff --git a/src/formatters/enum_destructuring.cr b/src/formatters/enum_destructuring.cr deleted file mode 100644 index 3223b9368..000000000 --- a/src/formatters/enum_destructuring.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::EnumDestructuring) - parameters = - format node.parameters, ", " - - name = - "#{format node.name}::" if node.name - - if parameters.empty? - "#{name}#{format node.option}" - else - "#{name}#{format node.option}(#{parameters})" - end - end - end -end diff --git a/src/formatters/enum_id.cr b/src/formatters/enum_id.cr deleted file mode 100644 index 7cff25a09..000000000 --- a/src/formatters/enum_id.cr +++ /dev/null @@ -1,21 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::EnumId) - expressions = - case - when node.expressions.empty? - "" - when node.new_line? - "(\n#{indent(format(node.expressions, ",\n"))})" - else - "(#{format(node.expressions, ", ")})" - end - - if node.name - "#{format node.name}::#{format node.option}#{expressions}" - else - "#{format node.option}#{expressions}" - end - end - end -end diff --git a/src/formatters/enum_option.cr b/src/formatters/enum_option.cr deleted file mode 100644 index 9af5f8caf..000000000 --- a/src/formatters/enum_option.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::EnumOption) - comment = - node.comment.try { |item| "#{format item}\n" } - - parameters = - format_parameters(node.parameters) - - "#{comment}#{format node.value}#{parameters}" - end - end -end diff --git a/src/formatters/enum_record_definition.cr b/src/formatters/enum_record_definition.cr deleted file mode 100644 index 4d0da5ee6..000000000 --- a/src/formatters/enum_record_definition.cr +++ /dev/null @@ -1,14 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::EnumRecordDefinition) - if node.new_line? - fields = - format node.fields, ",\n" - - "\n#{indent(fields)}" - else - format node.fields, ", " - end - end - end -end diff --git a/src/formatters/field.cr b/src/formatters/field.cr new file mode 100644 index 000000000..9322c2bcc --- /dev/null +++ b/src/formatters/field.cr @@ -0,0 +1,24 @@ +module Mint + class Formatter + def format(node : Ast::Field) : String + value = + format node.value + + key = + format node.key + + comment = + node.comment.try { |item| "#{format(item)}\n" } + + if key + if replace_skipped(value).includes?('\n') + "#{comment}#{key}:\n#{indent(value)}" + else + "#{comment}#{key}: #{value}" + end + else + "#{comment}#{value}" + end + end + end +end diff --git a/src/formatters/for.cr b/src/formatters/for.cr index ce8a6b96a..f53964e92 100644 --- a/src/formatters/for.cr +++ b/src/formatters/for.cr @@ -1,12 +1,5 @@ module Mint class Formatter - def format(node : Ast::ForCondition) : String - body = - format node.condition - - " when #{body}" - end - def format(node : Ast::For) : String body = format node.body @@ -18,7 +11,9 @@ module Mint format node.arguments, ", " condition = - format node.condition + if item = node.condition + " when #{format(item)}" + end "for #{arguments} of #{subject} #{body}#{condition}" end diff --git a/src/formatters/here_doc.cr b/src/formatters/here_doc.cr index 3e4c607f6..c71072ce2 100644 --- a/src/formatters/here_doc.cr +++ b/src/formatters/here_doc.cr @@ -1,6 +1,6 @@ module Mint class Formatter - def format(node : Ast::HereDoc) : String + def format(node : Ast::HereDocument) : String value = node.value.reduce("") do |memo, item| case item diff --git a/src/formatters/html_fragment.cr b/src/formatters/html_fragment.cr index ee4480944..c96a475f1 100644 --- a/src/formatters/html_fragment.cr +++ b/src/formatters/html_fragment.cr @@ -4,13 +4,10 @@ module Mint children = list(node.children + node.comments) - key = - node.key.try { |item| " #{format(item)}" } - if node.new_line? - "<#{key}>\n#{indent(children)}\n" + "<>\n#{indent(children)}\n" else - "<#{key}>#{children}" + "<>#{children}" end end end diff --git a/src/formatters/type_id.cr b/src/formatters/id.cr similarity index 59% rename from src/formatters/type_id.cr rename to src/formatters/id.cr index 663f07341..82204a153 100644 --- a/src/formatters/type_id.cr +++ b/src/formatters/id.cr @@ -1,6 +1,6 @@ module Mint class Formatter - def format(node : Ast::TypeId) : String + def format(node : Ast::Id) : String node.value end end diff --git a/src/formatters/module_access.cr b/src/formatters/module_access.cr deleted file mode 100644 index 00885677a..000000000 --- a/src/formatters/module_access.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::ModuleAccess) : String - variable = - format node.variable - - separator = - if node.constant? - ":" - else - "." - end - - "#{format node.name}#{separator}#{variable}" - end - end -end diff --git a/src/formatters/property.cr b/src/formatters/property.cr index 0b37988ac..6b965c49c 100644 --- a/src/formatters/property.cr +++ b/src/formatters/property.cr @@ -1,9 +1,6 @@ module Mint class Formatter def format(node : Ast::Property) : String - default = - format node.default - name = format node.name @@ -18,11 +15,14 @@ module Mint head = "#{comment}property #{name}#{type}" - if default - if node.new_line? - "#{head} =\n#{indent(default)}" + if default = node.default + formatted = + format default + + if default.new_line? || Ast.new_line?(node.name, default) + "#{head} =\n#{indent(formatted)}" else - "#{head} = #{default}" + "#{head} = #{formatted}" end else head diff --git a/src/formatters/record.cr b/src/formatters/record.cr index 463ed7ff0..ce65d4f31 100644 --- a/src/formatters/record.cr +++ b/src/formatters/record.cr @@ -1,32 +1,18 @@ module Mint class Formatter def format(node : Ast::Record, multiline = false) : String - case node - when Ast::EnumRecord - body = - format node.fields + body = + format node.fields - if node.new_line? - body.join(",\n") - else - body.join(", ") - end - when Ast::Record + if node.fields.size >= 2 || multiline || body.any? do |string| + replace_skipped(string).includes?('\n') + end + "{\n#{indent(body.join(",\n"))}\n}" + else body = - format node.fields + body.join(", ").presence.try { |v| " #{v} " } || " " - if node.fields.size >= 2 || multiline || body.any? do |string| - replace_skipped(string).includes?('\n') - end - "{\n#{indent(body.join(",\n"))}\n}" - else - body = - body.join(", ").presence.try { |v| " #{v} " } || " " - - "{#{body}}" - end - else - "" + "{#{body}}" end end end diff --git a/src/formatters/record_definition.cr b/src/formatters/record_definition.cr deleted file mode 100644 index aeaf750d8..000000000 --- a/src/formatters/record_definition.cr +++ /dev/null @@ -1,19 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::RecordDefinition) : String - name = - format node.name - - fields = - format node.fields, ",\n" - - comment = - node.comment.try { |item| "#{format(item)}\n" }.to_s - - block_comment = - node.block_comment.try { |item| "\n#{format(item)}" }.to_s - - "#{comment}record #{name} {\n#{indent(fields + block_comment)}\n}" - end - end -end diff --git a/src/formatters/record_field.cr b/src/formatters/record_field.cr deleted file mode 100644 index cebc0f313..000000000 --- a/src/formatters/record_field.cr +++ /dev/null @@ -1,20 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::RecordField) : String - value = - format node.value - - key = - format node.key - - comment = - node.comment.try { |item| "#{format(item)}\n" } - - if replace_skipped(value).includes?('\n') - "#{comment}#{key}:\n#{indent(value)}" - else - "#{comment}#{key}: #{value}" - end - end - end -end diff --git a/src/formatters/regexp_literal.cr b/src/formatters/regexp_literal.cr index 9322610ae..ddd2f3739 100644 --- a/src/formatters/regexp_literal.cr +++ b/src/formatters/regexp_literal.cr @@ -1,7 +1,7 @@ module Mint class Formatter def format(node : Ast::RegexpLiteral) : String - node.static_value + static_value(node).to_s end end end diff --git a/src/formatters/top_level.cr b/src/formatters/top_level.cr index 557ffb186..d4834d180 100644 --- a/src/formatters/top_level.cr +++ b/src/formatters/top_level.cr @@ -7,14 +7,13 @@ module Mint def format(ast : Ast) : String body = ( - ast.records + + ast.type_definitions + ast.providers + ast.components + ast.modules + ast.routes + ast.stores + ast.suites + - ast.enums + ast.comments + ast.locales ) diff --git a/src/formatters/tuple_destructuring.cr b/src/formatters/tuple_destructuring.cr index 610b9b59d..97f45c4f4 100644 --- a/src/formatters/tuple_destructuring.cr +++ b/src/formatters/tuple_destructuring.cr @@ -1,7 +1,7 @@ module Mint class Formatter def format(node : Ast::TupleDestructuring) - "{#{format(node.parameters, ", ")}}" + "#(#{format(node.items, ", ")})" end end end diff --git a/src/formatters/tuple_literal.cr b/src/formatters/tuple_literal.cr index 7426ed62c..ba26cfc81 100644 --- a/src/formatters/tuple_literal.cr +++ b/src/formatters/tuple_literal.cr @@ -12,9 +12,9 @@ module Mint format node.items, mutliline ? ",\n" : ", " if mutliline || replace_skipped(items).includes?('\n') - "{\n#{indent(items)}\n}" + "#(\n#{indent(items)}\n)" else - "{#{items}}" + "#(#{items})" end end end diff --git a/src/formatters/type_definition.cr b/src/formatters/type_definition.cr new file mode 100644 index 000000000..584f77a3f --- /dev/null +++ b/src/formatters/type_definition.cr @@ -0,0 +1,24 @@ +module Mint + class Formatter + def format(node : Ast::TypeDefinition) : String + name = + format node.name + + fields = + case node.fields + when Array(Ast::TypeVariant) + list node.fields + else + format node.fields, ",\n" + end + + comment = + node.comment.try { |item| "#{format(item)}\n" }.to_s + + parameters = + format_parameters(node.parameters) + + "#{comment}type #{name}#{parameters} {\n#{indent(fields)}\n}" + end + end +end diff --git a/src/formatters/record_definition_field.cr b/src/formatters/type_definition_field.cr similarity index 86% rename from src/formatters/record_definition_field.cr rename to src/formatters/type_definition_field.cr index 3691bd845..88aaa68e1 100644 --- a/src/formatters/record_definition_field.cr +++ b/src/formatters/type_definition_field.cr @@ -1,6 +1,6 @@ module Mint class Formatter - def format(node : Ast::RecordDefinitionField) : String + def format(node : Ast::TypeDefinitionField) : String key = format node.key diff --git a/src/formatters/type_destructuring.cr b/src/formatters/type_destructuring.cr new file mode 100644 index 000000000..021a89517 --- /dev/null +++ b/src/formatters/type_destructuring.cr @@ -0,0 +1,17 @@ +module Mint + class Formatter + def format(node : Ast::TypeDestructuring) + items = + format node.items, ", " + + name = + "#{format node.name}." if node.name + + if items.empty? + "#{name}#{format node.variant}" + else + "#{name}#{format node.variant}(#{items})" + end + end + end +end diff --git a/src/formatters/type_variant.cr b/src/formatters/type_variant.cr new file mode 100644 index 000000000..9007dfca9 --- /dev/null +++ b/src/formatters/type_variant.cr @@ -0,0 +1,20 @@ +module Mint + class Formatter + def format(node : Ast::TypeVariant) + comment = + node.comment.try { |item| "#{format item}\n" } + + parameters = + if (fields = node.fields) && fields.size > 0 && node.new_line? + items = + format fields, ",\n" + + "(\n#{indent(items)})" + else + format_parameters(node.parameters) + end + + "#{comment}#{format node.value}#{parameters}" + end + end +end diff --git a/src/formatters/void.cr b/src/formatters/void.cr deleted file mode 100644 index 2f03056ca..000000000 --- a/src/formatters/void.cr +++ /dev/null @@ -1,7 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::Void) : String - "void" - end - end -end diff --git a/src/helpers.cr b/src/helpers.cr new file mode 100644 index 000000000..673385693 --- /dev/null +++ b/src/helpers.cr @@ -0,0 +1,148 @@ +module Mint + # This module contains helper functions which are used in many parts of the + # process (parser, compiler, type checker, ect...). + module Helpers + # Returns true if the destructuring covers + # arrays with the given length. + # + # [x, ...rest] => 1+ + # [x] => 1 + # [...rest] => 0+ + # [] => 0 + def covers?(node : Ast::ArrayDestructuring, length : Int32) : Bool + if spread?(node) + length >= (node.items.size - 1) + else + length == node.items.size + end + end + + # Returns whether there are any spreads in the items. + def spread?(node : Ast::ArrayDestructuring) : Bool + node.items.any?(Ast::Spread) + end + + # Returns whether the destructuring is exhaustive. + # + # TODO: We want to support cases like this: + # + # type Test { + # Branch(String) + # } + # + # let Test::Branch(value) = Test::Branch("Hello") + def exhaustive?(node : Ast::Node) : Bool + case node + when Ast::TupleDestructuring + node.items.all?(Ast::Variable) + when Ast::ArrayDestructuring + node.items.all? do |item| + item.is_a?(Ast::Variable) || + item.is_a?(Ast::Spread) + end && node.items.any?(Ast::Spread) + else + false + end + end + + def owns?(node : Ast::Node, parent : Ast::Node) : Bool + case parent + when Ast::Store + { + parent.functions, + parent.constants, + parent.states, + parent.gets, + }.any? &.includes?(node) + when Ast::Component + { + parent.properties, + parent.functions, + parent.constants, + parent.states, + parent.gets, + }.any? &.includes?(node) + else + false + end + end + + def async?(node : Ast::Node) : Bool + node.expressions.select(Ast::Statement).any?(&.await) + end + + def static?(nodes : Array(Ast::Node)) : Bool + nodes.all? { |node| static?(node) } + end + + def static?(node : Ast::Node?) : Bool + case node + when Ast::StringLiteral, + Ast::HereDocument + node.value.all?(String) + when Ast::HtmlAttribute + static?(node.value) + when Ast::HtmlExpression, + Ast::Block + static?(node.expressions) + when Ast::Statement + static?(node.expression) + when Ast::HtmlComponent + node.ref.nil? && + static?(node.children) && + static?(node.attributes) + when Ast::HtmlElement + node.ref.nil? && + node.styles.empty? && + static?(node.children) && + static?(node.attributes) + when Ast::RegexpLiteral, + Ast::NumberLiteral, + Ast::BoolLiteral + true + when Ast::TupleLiteral, + Ast::ArrayLiteral + static?(node.items) + else + false + end + end + + def static_value(nodes : Array(Ast::Node), separator : Char? = nil) : String + nodes.compact_map { |node| static_value(node) }.join(separator) + end + + def static_value(node : Ast::Node?) : String? + return unless static?(node) + + case node + when Ast::StringLiteral, + Ast::HereDocument + node.value.select(String).join + when Ast::HtmlAttribute + "#{node.name.value}=#{static_value(node.value)}" + when Ast::HtmlExpression, + Ast::Block + static_value(node.expressions) + when Ast::Statement + static_value(node.expression) + when Ast::RegexpLiteral + "/#{node.value}/#{node.flags.split.uniq.join}" + when Ast::TupleLiteral, + Ast::ArrayLiteral + "[#{static_value(node.items, ',')}]" + when Ast::NumberLiteral, + Ast::BoolLiteral + node.value.to_s + when Ast::HtmlElement + node.tag.value + + static_value(node.attributes) + + static_value(node.children) + when Ast::HtmlComponent + node.component.value + + static_value(node.attributes) + + static_value(node.children) + end + end + end +end diff --git a/src/installer.cr b/src/installer.cr index 9a6e0535d..46e2aca0d 100644 --- a/src/installer.cr +++ b/src/installer.cr @@ -1,6 +1,6 @@ module Mint class Installer - install_error InstallerFailedToInstall + include Errorable alias Package = NamedTuple(name: String, version: String) alias Constraint = FixedConstraint | SimpleConstraint @@ -123,7 +123,7 @@ module Mint begin repository.json(version) - rescue error : RepositoryInvalidMintJson | RepositoryNoMintJson + rescue error : Error # If the mint.json is invalid or missing then this version # is eliminated. @eliminated << {package, base, constraint} @@ -156,12 +156,33 @@ module Mint "#{item[0][:version]} by #{item[2]} from #{item[1][:name]}:#{item[1][:version]}" end - raise InstallerFailedToInstall, { - "package" => "#{base[:name]}:#{base[:version]}", - "constraint" => constraint.to_s, - "eliminated" => eliminated, - "name" => dependency, - } + error! :installer_failed_to_install do + block "Failed to satisfy the following constraint:" + + block do + bold "#{dependency} #{constraint}" + text "from" + bold "#{base[:name]}:#{base[:version]}" + end + + case eliminated + when Array(String) + unless eliminated.empty? + block do + text "All versions of" + bold name.to_s + text "were eliminated:" + end + + snippet eliminated.join("\n") + + block do + text "There are no version available for:" + bold name.to_s + end + end + end + end end end rescue error : Retry @@ -217,7 +238,7 @@ module Mint resolve_dependencies( json.dependencies, {name: dependency.name, version: version.to_s}) - rescue RepositoryInvalidMintJson | RepositoryNoMintJson + rescue Error # Since we don't have a valid json we don't resolve the dependencies end end diff --git a/src/installer/repository.cr b/src/installer/repository.cr index 8e311bb4c..f0df013a2 100644 --- a/src/installer/repository.cr +++ b/src/installer/repository.cr @@ -1,17 +1,12 @@ module Mint class Installer - install_error RepositoryCouldNotGetVersions - install_error RepositoryCouldNotCheckout - install_error RepositoryInvalidMintJson - install_error RepositoryCouldNotUpdate - install_error RepositoryCouldNotClone - install_error RepositoryNoMintJson - # This class is for handling git repositories of packages. # # Repositories are cloned into a temp directory (/tmp/mint-packages) if # not exists and updated when they exists. class Repository + include Errorable + getter name : String getter url : String getter version : Semver? @@ -55,10 +50,18 @@ module Mint status, output, error = run "git tag --list" - raise RepositoryCouldNotGetVersions, { - "result" => error, - "url" => url, - } unless status.success? + error! :repository_could_not_get_versions do + block do + text "I could not get the tags of the repository:" + bold url + end + + block "The error I got from the git command is this:" + + block do + bold error.to_s.strip + end + end unless status.success? output .split @@ -88,19 +91,29 @@ module Mint checkout target MintJson.new(File.read(path), directory, path) - rescue error : JsonError - raise RepositoryInvalidMintJson, { - "id" => id.uncolorize, - "target" => target.to_s, - } rescue error : Error - # Propagate RepositoryCouldNotCheckout - raise error + if error.name.to_s.starts_with?("mint_json") + error! :repository_invalid_mint_json do + block do + text "I could not parse the mint.json for the package:" + bold id.uncolorize + text "for the version or tag:" + bold target.to_s + end + end + else + # Propagate RepositoryCouldNotCheckout + raise error + end rescue error - raise RepositoryNoMintJson, { - "id" => id.uncolorize, - "target" => target.to_s, - } + error! :repository_no_mint_json do + block do + text "I could not find the mint.json for the package:" + bold id.uncolorize + text "for the version or tag:" + bold target.to_s + end + end end # Returns true if the repository is cloned yet. @@ -112,10 +125,18 @@ module Mint def update status, _, error = run "git fetch --tags --force" - raise RepositoryCouldNotUpdate, { - "result" => error, - "url" => url, - } unless status.success? + error! :repository_could_not_update do + block do + text "I could not update the repository:" + bold url + end + + block "The error I got from the git command is this:" + + block do + bold error.to_s.strip + end + end unless status.success? terminal.puts " #{CHECKMARK} Updated #{id}" end @@ -124,10 +145,18 @@ module Mint def clone status, _, error = run "git clone #{url} #{directory}", Dir.current - raise RepositoryCouldNotClone, { - "result" => error, - "url" => url, - } unless status.success? + error! :repository_could_not_clone do + block do + text "I could not clone the repository:" + bold url + end + + block "The error I got from the git command is this:" + + block do + bold error.to_s.strip + end + end unless status.success? terminal.puts " #{CHECKMARK} Cloned #{id}" end @@ -139,11 +168,20 @@ module Mint status, _, error = run "git checkout #{target} -f" - raise RepositoryCouldNotCheckout, { - "target" => target.to_s, - "result" => error, - "url" => url, - } unless status.success? + error! :repository_could_not_checkout do + block do + text "I could not checkout the version or tag:" + bold target.to_s + text "of the repository:" + bold url + end + + block "The error I got from the git command is this:" + + block do + bold error.to_s.strip + end + end unless status.success? end # The directory of the repository diff --git a/src/ls/completion.cr b/src/ls/completion.cr index 061f7aef8..c162dcb84 100644 --- a/src/ls/completion.cr +++ b/src/ls/completion.cr @@ -51,16 +51,16 @@ module Mint .components .map { |node| completion_item(node) } - enum_completions = + type_completions = workspace .ast - .enums + .type_definitions .flat_map { |node| completions(node) } (global_completions + component_completions + scope_completions + - enum_completions + + type_completions + HTML_TAG_COMPLETIONS) .compact .sort_by!(&.label) diff --git a/src/ls/completion_item/constant.cr b/src/ls/completion_item/constant.cr index f175ec0db..c7907ff4b 100644 --- a/src/ls/completion_item/constant.cr +++ b/src/ls/completion_item/constant.cr @@ -1,7 +1,7 @@ module Mint module LS class Completion < LSP::RequestMessage - def completion_item(node : Ast::Constant, parent_name : Ast::TypeId? = nil) : LSP::CompletionItem + def completion_item(node : Ast::Constant, parent_name : Ast::Id? = nil) : LSP::CompletionItem name = if parent_name "#{parent_name.value}:#{node.name.value}" diff --git a/src/ls/completion_item/function.cr b/src/ls/completion_item/function.cr index f4725bc9d..760af5028 100644 --- a/src/ls/completion_item/function.cr +++ b/src/ls/completion_item/function.cr @@ -1,7 +1,7 @@ module Mint module LS class Completion < LSP::RequestMessage - def completion_item(node : Ast::Function, parent_name : Ast::TypeId? = nil) : LSP::CompletionItem + def completion_item(node : Ast::Function, parent_name : Ast::Id? = nil) : LSP::CompletionItem name = if parent_name "#{parent_name.value}.#{node.name.value}" @@ -22,7 +22,7 @@ module Mint MINT LSP::CompletionItem.new( - documentation: node.comment.try(&.value).to_s, + documentation: node.comment.try(&.content).to_s, kind: LSP::CompletionItemKind::Function, insert_text: snippet, detail: "Function", diff --git a/src/ls/completion_item/get.cr b/src/ls/completion_item/get.cr index ec48e186e..c69aeaf7f 100644 --- a/src/ls/completion_item/get.cr +++ b/src/ls/completion_item/get.cr @@ -1,7 +1,7 @@ module Mint module LS class Completion < LSP::RequestMessage - def completion_item(node : Ast::Get, parent_name : Ast::TypeId? = nil) : LSP::CompletionItem + def completion_item(node : Ast::Get, parent_name : Ast::Id? = nil) : LSP::CompletionItem name = if parent_name "#{parent_name.value}.#{node.name.value}" diff --git a/src/ls/completions/enum.cr b/src/ls/completions/enum.cr deleted file mode 100644 index ee73753f0..000000000 --- a/src/ls/completions/enum.cr +++ /dev/null @@ -1,42 +0,0 @@ -module Mint - module LS - class Completion < LSP::RequestMessage - def completions(node : Ast::Enum) : Array(LSP::CompletionItem) - node.options.map do |option| - name = - "#{node.name.value}::#{option.value.value}" - - snippet = - if option.parameters.empty? - name - else - parameters = - option - .parameters - .map_with_index do |variable, index| - case variable - when Ast::TypeVariable - %(${#{index + 1}:#{variable.value}}) - else - %(${#{index + 1}) - end - end - - <<-MINT - #{name}(#{parameters.join(", ")}) - MINT - end - - LSP::CompletionItem.new( - documentation: option.comment.try(&.value).to_s, - kind: LSP::CompletionItemKind::EnumMember, - detail: "Enum Option", - insert_text: snippet, - filter_text: name, - sort_text: name, - label: name) - end - end - end - end -end diff --git a/src/ls/completions/type_definition.cr b/src/ls/completions/type_definition.cr new file mode 100644 index 000000000..407abe392 --- /dev/null +++ b/src/ls/completions/type_definition.cr @@ -0,0 +1,47 @@ +module Mint + module LS + class Completion < LSP::RequestMessage + def completions(node : Ast::TypeDefinition) : Array(LSP::CompletionItem) + case fields = node.fields + when Array(Ast::TypeVariant) + fields.map do |option| + name = + "#{node.name.value}::#{option.value.value}" + + snippet = + if option.parameters.empty? + name + else + parameters = + option + .parameters + .map_with_index do |variable, index| + case variable + when Ast::TypeVariable + %(${#{index + 1}:#{variable.value}}) + else + %(${#{index + 1}) + end + end + + <<-MINT + #{name}(#{parameters.join(", ")}) + MINT + end + + LSP::CompletionItem.new( + documentation: option.comment.try(&.content).to_s, + kind: LSP::CompletionItemKind::EnumMember, + detail: "Type Option", + insert_text: snippet, + filter_text: name, + sort_text: name, + label: name) + end + else + [] of LSP::CompletionItem + end + end + end + end +end diff --git a/src/ls/definition.cr b/src/ls/definition.cr index 301977b34..ce1ba3312 100644 --- a/src/ls/definition.cr +++ b/src/ls/definition.cr @@ -17,6 +17,15 @@ module Mint return unless node = stack[0]? + # stack.each do |item| + # print item.class.name.sub("Mint::Ast::", "") + # case item + # when Ast::Id, Ast::Variable + # print "(#{item.value})" + # end + # puts item.location.start + # end + has_link_support = server .params diff --git a/src/ls/definition/access.cr b/src/ls/definition/access.cr index a38e04092..8d94d752d 100644 --- a/src/ls/definition/access.cr +++ b/src/ls/definition/access.cr @@ -1,26 +1,18 @@ module Mint module LS class Definition < LSP::RequestMessage - def definition(node : Ast::Access, workspace : Workspace, stack : Array(Ast::Node)) - lhs = workspace - .type_checker - .cache[node.lhs]? + def definition(node : Ast::Access, server : Server, workspace : Workspace, stack : Array(Ast::Node)) + lookup = workspace.type_checker.variables[node]?.try(&.first) - case lhs - when TypeChecker::Record - return unless record = - workspace - .ast - .records - .find(&.name.value.==(lhs.name)) - - return if Core.ast.records.includes?(record) - - return unless record_definition_field = record - .fields - .find(&.key.value.==(node.field.value)) - - location_link node.field, record_definition_field.key, record_definition_field + if lookup + case lookup + when Ast::Property, + Ast::Constant, + Ast::Function, + Ast::State, + Ast::Get + location_link node.field, lookup.name, lookup + end end end end diff --git a/src/ls/definition/connect_variable.cr b/src/ls/definition/connect_variable.cr index db055da69..7b4a1b2f9 100644 --- a/src/ls/definition/connect_variable.cr +++ b/src/ls/definition/connect_variable.cr @@ -2,21 +2,21 @@ module Mint module LS class Definition < LSP::RequestMessage def definition(node : Ast::ConnectVariable, workspace : Workspace, stack : Array(Ast::Node)) - return unless cursor_intersects?(node.variable) + return unless cursor_intersects?(node.name) return unless connect = stack[1]?.as?(Ast::Connect) return unless store = workspace.ast.stores.find(&.name.value.==(connect.store.value)) - return unless target = store.functions.find(&.name.value.==(node.variable.value)) || - store.constants.find(&.name.value.==(node.variable.value)) || - store.states.find(&.name.value.==(node.variable.value)) || - store.gets.find(&.name.value.==(node.variable.value)) + return unless target = store.functions.find(&.name.value.==(node.name.value)) || + store.constants.find(&.name.value.==(node.name.value)) || + store.states.find(&.name.value.==(node.name.value)) || + store.gets.find(&.name.value.==(node.name.value)) case target when Ast::Function, Ast::State, Ast::Get, Ast::Constant - location_link node.variable, target.name, target + location_link node.name, target.name, target end end end diff --git a/src/ls/definition/enum_destructuring.cr b/src/ls/definition/enum_destructuring.cr deleted file mode 100644 index 2ec266064..000000000 --- a/src/ls/definition/enum_destructuring.cr +++ /dev/null @@ -1,23 +0,0 @@ -module Mint - module LS - class Definition < LSP::RequestMessage - def definition(node : Ast::EnumDestructuring, workspace : Workspace, stack : Array(Ast::Node)) - return unless name = node.name - return unless enum_node = - workspace.ast.enums.find(&.name.value.==(name.value)) - - return if Core.ast.enums.includes?(enum_node) - - case - when cursor_intersects?(name) - location_link name, enum_node.name, enum_node - when cursor_intersects?(node.option) - return unless option = - enum_node.try &.options.find(&.value.value.==(node.option.value)) - - location_link node.option, option.value, option - end - end - end - end -end diff --git a/src/ls/definition/enum_id.cr b/src/ls/definition/enum_id.cr deleted file mode 100644 index 7396c2caa..000000000 --- a/src/ls/definition/enum_id.cr +++ /dev/null @@ -1,42 +0,0 @@ -module Mint - module LS - class Definition < LSP::RequestMessage - def definition(node : Ast::EnumId, workspace : Workspace, stack : Array(Ast::Node)) - name = node.name - - # When `.name` is nil the node is used as a CONSTANT - if name.nil? - stack.each do |parent| - case parent - when Ast::Component, - Ast::Store, - Ast::Suite, - Ast::Module, - Ast::Provider - parent.constants.each do |constant| - if node.option.value == constant.name.value - return location_link node.option, constant.name, constant - end - end - end - end - else - return unless enum_node = - workspace.ast.enums.find(&.name.value.==(name.value)) - - return if Core.ast.enums.includes?(enum_node) - - case - when cursor_intersects?(name) - location_link name, enum_node.name, enum_node - when cursor_intersects?(node.option) - return unless option = - enum_node.try &.options.find(&.value.value.==(node.option.value)) - - location_link node.option, option.value, option - end - end - end - end - end -end diff --git a/src/ls/definition/id.cr b/src/ls/definition/id.cr new file mode 100644 index 000000000..3e066472a --- /dev/null +++ b/src/ls/definition/id.cr @@ -0,0 +1,23 @@ +module Mint + module LS + class Definition < LSP::RequestMessage + def definition(node : Ast::Id, workspace : Workspace, stack : Array(Ast::Node)) + found = + workspace.ast.type_definitions.find(&.name.value.==(node.value)) || + workspace.ast.stores.find(&.name.value.==(node.value)) || + find_component(workspace, node.value) + + if found.nil? && (next_node = stack[1]) + return definition(next_node, workspace, stack) + end + + return if Core.ast.nodes.includes?(found) + + case found + when Ast::Store, Ast::Component, Ast::TypeDefinition + location_link node, found.name, found + end + end + end + end +end diff --git a/src/ls/definition/module_access.cr b/src/ls/definition/module_access.cr deleted file mode 100644 index e4314ccdd..000000000 --- a/src/ls/definition/module_access.cr +++ /dev/null @@ -1,20 +0,0 @@ -module Mint - module LS - class Definition < LSP::RequestMessage - def definition(node : Ast::ModuleAccess, workspace : Workspace, stack : Array(Ast::Node)) - lookup = workspace.type_checker.lookups[node.variable]? - - if lookup - case lookup - when Ast::Property, - Ast::Constant, - Ast::Function, - Ast::State, - Ast::Get - location_link node.variable, lookup.name, lookup - end - end - end - end - end -end diff --git a/src/ls/definition/type.cr b/src/ls/definition/type.cr index 321c95d3f..ee12b2af1 100644 --- a/src/ls/definition/type.cr +++ b/src/ls/definition/type.cr @@ -4,21 +4,12 @@ module Mint def definition(node : Ast::Type, workspace : Workspace, stack : Array(Ast::Node)) return unless cursor_intersects?(node.name) - enum_node = - workspace.ast.enums.find(&.name.value.==(node.name.value)) + return unless record = + workspace.ast.type_definitions.find(&.name.value.==(node.name.value)) - if enum_node - return if Core.ast.enums.includes?(enum_node) + return if Core.ast.type_definitions.includes?(record) - location_link node.name, enum_node.name, enum_node - else - return unless record = - workspace.ast.records.find(&.name.value.==(node.name.value)) - - return if Core.ast.records.includes?(record) - - location_link node.name, record.name, record - end + location_link node.name, record.name, record end end end diff --git a/src/ls/definition/type_destructuring.cr b/src/ls/definition/type_destructuring.cr new file mode 100644 index 000000000..a821d496b --- /dev/null +++ b/src/ls/definition/type_destructuring.cr @@ -0,0 +1,8 @@ +module Mint + module LS + class Definition < LSP::RequestMessage + def definition(node : Ast::TypeDestructuring, server : Server, workspace : Workspace, stack : Array(Ast::Node)) + end + end + end +end diff --git a/src/ls/definition/type_id.cr b/src/ls/definition/type_id.cr deleted file mode 100644 index 2398df353..000000000 --- a/src/ls/definition/type_id.cr +++ /dev/null @@ -1,37 +0,0 @@ -module Mint - module LS - class Definition < LSP::RequestMessage - def definition(node : Ast::TypeId, workspace : Workspace, stack : Array(Ast::Node)) - case stack[1]? - when Ast::ModuleAccess - links = workspace.ast.modules - .select(&.name.value.==(node.value)) - .reject(&.in?(Core.ast.nodes)) - .sort_by!(&.input.file) - .map do |mod| - location_link node, mod.name, mod - end - - return links unless links.empty? - end - - found = - workspace.ast.enums.find(&.name.value.==(node.value)) || - workspace.ast.records.find(&.name.value.==(node.value)) || - workspace.ast.stores.find(&.name.value.==(node.value)) || - find_component(workspace, node.value) - - if found.nil? && (next_node = stack[1]) - return definition(next_node, workspace, stack) - end - - return if Core.ast.nodes.includes?(found) - - case found - when Ast::Store, Ast::Enum, Ast::Component, Ast::RecordDefinition - location_link node, found.name, found - end - end - end - end -end diff --git a/src/ls/definition/variable.cr b/src/ls/definition/variable.cr index d2fe55243..d10916654 100644 --- a/src/ls/definition/variable.cr +++ b/src/ls/definition/variable.cr @@ -5,48 +5,55 @@ module Mint lookup = workspace.type_checker.variables[node]? if lookup - variable_lookup_parent(node, lookup[1], workspace) || - variable_connect(node, lookup[2]) || - variable_lookup(node, lookup[0]) - else - variable_record_key(node, workspace, stack) || - variable_next_key(node, workspace, stack) - end - end + entity, parent = lookup + + case {entity, parent} + when {Ast::Component, _}, + {Ast::Store, _} + location_link node, entity.name, entity + when {Ast::Module, _} + links = workspace.ast.modules + .select(&.name.value.==(node.value)) + .reject(&.in?(Core.ast.nodes)) + .sort_by!(&.file.path) + .map do |mod| + location_link node, mod.name, mod + end - def variable_connect(node : Ast::Variable, parents : Array(TypeChecker::Scope::Node)) - # Check to see if this variable is defined as an Ast::ConnectVariable - # as the `.variables` cache links directly to the stores state/function etc - return unless component = parents.select(Ast::Component).first? + return links.first if links.size == 1 + return links unless links.empty? + when {Ast::Variable, _} + variable_lookup_parent(node, entity, workspace) + when {Ast::ConnectVariable, Ast::Node} + connect = + workspace.ast.nodes + .select(Ast::Connect) + .find!(&.keys.find(&.==(entity))) - component.connects.each do |connect| - connect.keys.each do |key| - variable = key.name || key.variable + key = + lookup[0].as(Ast::ConnectVariable) - if variable.value == node.value - return location_link node, variable, connect - end + location_link node, key.target || key.name, connect + else + variable_lookup(node, entity) end + else + variable_record_key(node, workspace, stack) || + variable_next_key(node, workspace, stack) end end - def variable_lookup_parent(node : Ast::Variable, target : TypeChecker::Scope::Node, workspace : Workspace) - case target - when Tuple(String, TypeChecker::Checkable, Ast::Node) - case variable = target[2] - when Ast::Variable - # For some variables in the .variables` cache, we only have access to the - # target Ast::Variable and not its containing node, so we must search for it - return unless parent = workspace - .ast - .nodes - .select { |other| other.is_a?(Ast::EnumDestructuring) || other.is_a?(Ast::Statement) || other.is_a?(Ast::For) } - .select(&.input.file.==(variable.input.file)) - .find { |other| other.from < variable.from && other.to > variable.to } + def variable_lookup_parent(node : Ast::Variable, variable : Ast::Variable, workspace : Workspace) + # For some variables in the .variables` cache, we only have access to the + # target Ast::Variable and not its containing node, so we must search for it + return unless parent = workspace + .ast + .nodes + .select { |other| other.is_a?(Ast::TypeDestructuring) || other.is_a?(Ast::Statement) || other.is_a?(Ast::For) } + .select(&.file.path.==(variable.file.path)) + .find { |other| other.from < variable.from && other.to > variable.to } - location_link node, variable, parent - end - end + location_link node, variable, parent end def variable_lookup(node : Ast::Variable, target : Ast::Node | TypeChecker::Checkable) @@ -70,14 +77,19 @@ module Mint def variable_record_key(node : Ast::Variable, workspace : Workspace, stack : Array(Ast::Node)) case field = stack[1]? - when Ast::RecordField + when Ast::Field return unless record_name = workspace.type_checker.record_field_lookup[field]? return unless record_definition_field = workspace .ast - .records + .type_definitions .find(&.name.value.==(record_name)) - .try(&.fields.find(&.key.value.==(node.value))) + .try do |item| + case fields = item.fields + when Array(Ast::TypeDefinitionField) + fields.find(&.key.value.==(node.value)) + end + end location_link node, record_definition_field.key, record_definition_field end diff --git a/src/ls/folding_range.cr b/src/ls/folding_range.cr index 1d1e5bcd4..5b314863f 100644 --- a/src/ls/folding_range.cr +++ b/src/ls/folding_range.cr @@ -9,11 +9,6 @@ module Mint range(node, node.comment) end - def range(node : Ast::Enum) - range(node.comment) - range(node, node.comment) - end - def range(node : Ast::Module) range(node.comment) range(node, node.comment) diff --git a/src/ls/hover.cr b/src/ls/hover.cr index 3d015b3d1..027fb4b9f 100644 --- a/src/ls/hover.cr +++ b/src/ls/hover.cr @@ -54,13 +54,22 @@ module Mint stack = server.nodes_at_cursor(params) + # stack.each do |item| + # print item.class.name.sub("Mint::Ast::", "") + # case item + # when Ast::Id, Ast::Variable + # print "(#{item.value})" + # end + # puts item.location.start + # end + node = stack[0]? parent = stack[1]? case node - when Ast::Variable, Ast::TypeId + when Ast::Variable, Ast::Id # If the first node under the cursor is a `Ast::Variable` - # or `Ast::TypeId`, then get the associated nodes + # or `Ast::Id`, then get the associated nodes # information and hover that otherwise get the hover # information of the parent. lookup = diff --git a/src/ls/hover/access.cr b/src/ls/hover/access.cr new file mode 100644 index 000000000..26b06f437 --- /dev/null +++ b/src/ls/hover/access.cr @@ -0,0 +1,14 @@ +module Mint + module LS + class Hover < LSP::RequestMessage + def hover(node : Ast::Access, workspace) : Array(String) + if item = workspace.type_checker.variables[node]? + case item[1] + when Ast::TypeDefinition + hover(item[1], workspace) + end + end || [] of String + end + end + end +end diff --git a/src/ls/hover/enum.cr b/src/ls/hover/enum.cr deleted file mode 100644 index 09d363375..000000000 --- a/src/ls/hover/enum.cr +++ /dev/null @@ -1,26 +0,0 @@ -module Mint - module LS - class Hover < LSP::RequestMessage - def hover(node : Ast::Enum, workspace) : Array(String) - parameters = - workspace.formatter.format_parameters(node.parameters) - - options = - node.options.map do |option| - comment = - option.comment.try { |value| " - #{value.value.strip}" } - - params = - workspace.formatter.format_parameters(option.parameters) - - "**#{option.value.value}#{params}**#{comment}" - end - - ([ - "**#{node.name.value}#{parameters}**\n", - node.comment.try(&.value.strip.+("\n")), - ] + options).compact - end - end - end -end diff --git a/src/ls/hover/enum_id.cr b/src/ls/hover/enum_id.cr deleted file mode 100644 index ccfdd0f82..000000000 --- a/src/ls/hover/enum_id.cr +++ /dev/null @@ -1,12 +0,0 @@ -module Mint - module LS - class Hover < LSP::RequestMessage - def hover(node : Ast::EnumId, workspace) : Array(String) - item = - workspace.ast.enums.find(&.name.value.==(node.name.try(&.value))) - - hover(item, workspace) - end - end - end -end diff --git a/src/ls/hover/enum_option.cr b/src/ls/hover/enum_option.cr deleted file mode 100644 index 9e72de640..000000000 --- a/src/ls/hover/enum_option.cr +++ /dev/null @@ -1,12 +0,0 @@ -module Mint - module LS - class Hover < LSP::RequestMessage - def hover(node : Ast::EnumOption, workspace) : Array(String) - item = - workspace.ast.enums.find(&.options.includes?(node)) - - hover(item, workspace) - end - end - end -end diff --git a/src/ls/hover/function.cr b/src/ls/hover/function.cr index 5113cdf2a..be70bd7c3 100644 --- a/src/ls/hover/function.cr +++ b/src/ls/hover/function.cr @@ -24,7 +24,7 @@ module Mint [ "**#{name}.#{node.name.value}#{arguments}#{type}**\n", - node.comment.try(&.value.strip), + node.comment.try(&.content.strip), ].compact end end diff --git a/src/ls/hover/get.cr b/src/ls/hover/get.cr index 213f5bdce..70149286b 100644 --- a/src/ls/hover/get.cr +++ b/src/ls/hover/get.cr @@ -19,7 +19,7 @@ module Mint [ "**#{name}.#{node.name.value}#{type}**\n", - node.comment.try(&.value.strip), + node.comment.try(&.content.strip), ].compact end end diff --git a/src/ls/hover/html_component.cr b/src/ls/hover/html_component.cr index 7cc043159..fba9fcd39 100644 --- a/src/ls/hover/html_component.cr +++ b/src/ls/hover/html_component.cr @@ -12,7 +12,7 @@ module Mint ([ "**#{node.name.value}**\n", - node.comment.try(&.value.strip), + node.comment.try(&.content.strip), properties_title, ] + properties).compact end @@ -23,7 +23,7 @@ module Mint component = workspace .type_checker - .lookups[node]? + .lookups[node]?.try(&.first?) hover(component, workspace) end diff --git a/src/ls/hover/module_access.cr b/src/ls/hover/module_access.cr deleted file mode 100644 index bdb2f8815..000000000 --- a/src/ls/hover/module_access.cr +++ /dev/null @@ -1,12 +0,0 @@ -module Mint - module LS - class Hover < LSP::RequestMessage - def hover(node : Ast::ModuleAccess, workspace) : Array(String) - item = - workspace.type_checker.lookups[node.variable]? - - hover(item, workspace) - end - end - end -end diff --git a/src/ls/hover/property.cr b/src/ls/hover/property.cr index 04acac967..8a2f7f63f 100644 --- a/src/ls/hover/property.cr +++ b/src/ls/hover/property.cr @@ -14,7 +14,7 @@ module Mint [ "**#{node.name.value}#{type}#{default}**\n", - node.comment.try(&.value.strip), + node.comment.try(&.content.strip), ].compact end end diff --git a/src/ls/hover/state.cr b/src/ls/hover/state.cr index 4ad7119ce..7d21b4497 100644 --- a/src/ls/hover/state.cr +++ b/src/ls/hover/state.cr @@ -12,7 +12,7 @@ module Mint [ "**#{node.name.value}#{type}#{default}**\n", - node.comment.try(&.value.strip), + node.comment.try(&.content.strip), ].compact end end diff --git a/src/ls/hover/type.cr b/src/ls/hover/type.cr index f37ca3c77..3b05a67c5 100644 --- a/src/ls/hover/type.cr +++ b/src/ls/hover/type.cr @@ -2,26 +2,19 @@ module Mint module LS class Hover < LSP::RequestMessage def hover(node : Ast::Type, workspace) : Array(String) - enum_node = + definition = workspace .ast - .enums + .type_definitions .find(&.name.value.==(node.name.value)) - if enum_node - hover(enum_node, workspace) + if definition + hover(definition, workspace) else - record = - workspace - .type_checker - .records - .find(&.name.==(node.name.value)) - .try(&.to_pretty) - type = workspace.formatter.format(node) - ["```\n#{record || type}\n```"] + ["```\n#{type}\n```"] end end end diff --git a/src/ls/hover/type_definition.cr b/src/ls/hover/type_definition.cr new file mode 100644 index 000000000..e9e16ace6 --- /dev/null +++ b/src/ls/hover/type_definition.cr @@ -0,0 +1,33 @@ +module Mint + module LS + class Hover < LSP::RequestMessage + def hover(node : Ast::TypeDefinition, workspace) : Array(String) + parameters = + workspace.formatter.format_parameters(node.parameters) + + case items = node.fields + when Array(Ast::TypeVariant) + fields = items.map do |option| + comment = + option.comment.try { |item| " - #{item.content.strip}" } + + params = + workspace.formatter.format_parameters(option.parameters) + + "**#{option.value.value}#{params}**#{comment}" + end + + ([ + "**#{node.name.value}#{parameters}**\n", + node.comment.try(&.content.strip.+("\n")), + ] + fields).compact + else + type = + workspace.formatter.format(node) + + ["```\n#{type}\n```"] + end + end + end + end +end diff --git a/src/ls/hover/enum_destructuring.cr b/src/ls/hover/type_destructuring.cr similarity index 54% rename from src/ls/hover/enum_destructuring.cr rename to src/ls/hover/type_destructuring.cr index f919b73ea..51fd89426 100644 --- a/src/ls/hover/enum_destructuring.cr +++ b/src/ls/hover/type_destructuring.cr @@ -1,9 +1,9 @@ module Mint module LS class Hover < LSP::RequestMessage - def hover(node : Ast::EnumDestructuring, workspace) : Array(String) + def hover(node : Ast::TypeDestructuring, workspace) : Array(String) item = - workspace.type_checker.lookups[node]? + workspace.type_checker.lookups[node].try(&.first?) hover(item, workspace) end diff --git a/src/ls/hover/type_variant.cr b/src/ls/hover/type_variant.cr new file mode 100644 index 000000000..53171af04 --- /dev/null +++ b/src/ls/hover/type_variant.cr @@ -0,0 +1,20 @@ +module Mint + module LS + class Hover < LSP::RequestMessage + def hover(node : Ast::TypeVariant, workspace) : Array(String) + item = + workspace + .ast + .type_definitions + .find do |definition| + case fields = definition.fields + when Array(Ast::TypeVariant) + fields.includes?(node) + end + end + + hover(item, workspace) + end + end + end +end diff --git a/src/ls/semantic_tokens.cr b/src/ls/semantic_tokens.cr index aeb24a56d..d71ca8bba 100644 --- a/src/ls/semantic_tokens.cr +++ b/src/ls/semantic_tokens.cr @@ -12,8 +12,8 @@ module Mint Workspace[uri.path.to_s][uri.path.to_s] # This is used later on to convert the line/column of each token - input = - ast.nodes.first.input + file = + ast.nodes.first.file tokenizer = SemanticTokenizer.new tokenizer.tokenize(ast) @@ -21,7 +21,7 @@ module Mint data = tokenizer.tokens.sort_by(&.from).compact_map do |token| location = - Ast::Node.compute_location(input, token.from, token.to) + Ast::Node.compute_location(file, token.from, token.to) type = token.type.to_s.underscore @@ -31,13 +31,13 @@ module Mint location.start[0] - 1, location.start[1], token.to - token.from, - index, - 0, + index.to_i64, + 0_i64, ] end end - result = [] of Array(Int32) + result = [] of Array(Int64) data.each_with_index do |item, index| current = @@ -50,7 +50,7 @@ module Mint current[0] = current[0] - last[0] - current[1] = current[1] - last[1] if current[0] == 0 + current[1] = current[1] - last[1] if current[0] == 0_i64 end result << current diff --git a/src/ls/server.cr b/src/ls/server.cr index 9166feae6..4c17c023d 100644 --- a/src/ls/server.cr +++ b/src/ls/server.cr @@ -50,7 +50,7 @@ module Mint Mint::Workspace[path] .ast .nodes - .select(&.input.file.==(path)) + .select(&.file.path.==(path)) end end end diff --git a/src/lsp/protocol/folding_range.cr b/src/lsp/protocol/folding_range.cr index 367edae73..8ddad03fe 100644 --- a/src/lsp/protocol/folding_range.cr +++ b/src/lsp/protocol/folding_range.cr @@ -9,23 +9,23 @@ module LSP # after the line's last character. To be valid, the end must be zero or # larger and smaller than the number of lines in the document. @[JSON::Field(key: "startLine")] - property start_line : Int32 + property start_line : Int64 # The zero-based character offset from where the folded range starts. If # not defined, defaults to the length of the start line. @[JSON::Field(key: "startCharacter")] - property start_character : Int32? + property start_character : Int64? # The zero-based end line of the range to fold. The folded area ends with # the line's last character. To be valid, the end must be zero or larger # and smaller than the number of lines in the document. @[JSON::Field(key: "endLine")] - property end_line : Int32 + property end_line : Int64 # The zero-based character offset before the folded range ends. If not # defined, defaults to the length of the end line. @[JSON::Field(key: "endCharacter")] - property end_character : Int32? + property end_character : Int64? # Describes the kind of the folding range such as `comment` or `region`. # The kind is used to categorize folding ranges and used by commands like diff --git a/src/lsp/protocol/position.cr b/src/lsp/protocol/position.cr index d4f4537d4..7ab4fd630 100644 --- a/src/lsp/protocol/position.cr +++ b/src/lsp/protocol/position.cr @@ -3,7 +3,7 @@ module LSP include JSON::Serializable # Line position in a document (zero-based). - property line : Int32 + property line : Int64 # Character offset on a line in a document (zero-based). Assuming that # the line is represented as a string, the `character` value represents @@ -11,7 +11,7 @@ module LSP # # If the character value is greater than the line length it defaults back # to the line length. - property character : Int32 + property character : Int64 def initialize(@line, @character) end diff --git a/src/macros.cr b/src/macros.cr deleted file mode 100644 index 9527b4b46..000000000 --- a/src/macros.cr +++ /dev/null @@ -1,83 +0,0 @@ -module Mint - macro command_error(name) - class {{name}} < Error - def instance - Messages::{{name.names.last}}.new(locals) - end - end - end - - class Installer - macro install_error(name) - class {{name}} < InstallError - def instance - Messages::{{name.names.last}}.new(locals) - end - end - end - end - - class MintJson - macro json_error(name) - class {{name}} < JsonError - def instance - Messages::{{name.names.last}}.new(locals) - end - end - end - end - - class TestRunner - macro error(name) - class {{name}} < JsonError - def instance - Messages::{{name.names.last}}.new(locals) - end - end - end - end - - class Parser - macro syntax_error(name) - class {{name}} < SyntaxError - def instance - Messages::{{name.names.last}}.new(locals) - end - end - end - - macro consume_while(condition) - while {{condition}} - step - end - end - end - - class TypeChecker - macro type_error(name) - class {{name}} < TypeError - def instance - Messages::{{name.names.last}}.new(locals) - end - end - end - end - - MESSAGES = {} of String => Mint::Message.class -end - -macro message(name, &block) - module Mint - class Messages - class {{name}} < Mint::Message - def build - Builder.build do - {{block.body}} - end - end - end - - Mint::MESSAGES["{{name}}"] = {{name}} - end - end -end diff --git a/src/message.cr b/src/message.cr deleted file mode 100644 index 2e73eba72..000000000 --- a/src/message.cr +++ /dev/null @@ -1,235 +0,0 @@ -module Mint - class Message - class BlockBuilder - getter block = Block.new - - def text(value) - case value - when String - @block << Text.new(value: value) - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def code(value) - @block << Code.new(value: value.to_s) - end - - def bold(value) - @block << Bold.new(value: value.to_s) - end - end - - class Builder - getter elements = [] of Element - - def self.build(&) - builder = new - with builder yield - builder.elements - end - - def snippet(value, message : String? = "Here is the relevant code snippet:") - case value - when Tuple(Ast::Node, Int32) - snippet value[0], message - when TypeChecker::Checkable - type_with_text value, message.to_s - when Ast::Node - block { text message } if message - @elements << Snippet.new(value: value) - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def type(value) - case value - when TypeChecker::Checkable - @elements << Type.new(value: value) - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def pre(value) - case value - when String - @elements << Pre.new(value: value) - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def list(value, message : String) - case value - when Array(String) - unless value.empty? - block do - text message - end - @elements << StringList.new(value: value) - end - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def list(value) - case value - when Array(String) - unless value.empty? - @elements << StringList.new(value: value) - end - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def type_list(value) - case value - when Array(TypeChecker::Checkable) - @elements << TypeList.new(value: value) - else - raise ArgumentError.new "Invalid value type: #{value.class}" - end - end - - def title(value) - @elements << Title.new(value: value) - end - - def block(&) - builder = BlockBuilder.new - with builder yield - @elements << builder.block - end - - # Pre defined blocks - def type_with_text(item, text : String) - block do - text text - end - - type item - end - - def was_expecting_type(expected, got) - type_with_text expected, "I was expecting:" - type_with_text got, "Instead it is:" - end - - def was_looking_for(what, got, code = nil) - block do - text "I was looking for the" - bold what - - code code if code - - text "but found" - code got - text "instead." - end - end - - def closing_bracket(expression, got) - block do - text "The" - text "body of a" - bold expression - text "must end with" - bold "a closing bracket." - end - - was_looking_for "bracket", got, "}" - end - - def opening_bracket(expression, got) - block do - text "The" - text "body of a" - bold expression - text "must start with" - bold "an opening bracket." - end - - was_looking_for "bracket", got, "{" - end - end - - record TypeList, value : Array(TypeChecker::Checkable) - record StringList, value : Array(String) - record Type, value : TypeChecker::Checkable - record Snippet, value : Ast::Node - record Title, value : String - record Code, value : String - record Bold, value : String - record Text, value : String - record Pre, value : String - - alias Block = Array(Code | Bold | Text) - alias Element = Title | Snippet | Block | Type | Pre | TypeList | StringList - - @data : Error::Locals - - def initialize(@data = Error::Locals.new) - end - - macro method_missing(call) - @data[{{ call.name.id.stringify }}]? - end - - def to_html - # ameba:disable Lint/UselessAssign - contents = - render Render::Html.new - - ECR.render("#{__DIR__}/message.ecr") - end - - def to_terminal(width) - render Render::Terminal.new(width: width) - end - - def build - Builder.build do - snippet node - end - end - - def render(renderer) - build.each do |element| - case element - when TypeList - renderer.type_list element.value - when StringList - renderer.list element.value - when Pre - renderer.pre element.value - when Type - renderer.type element.value - when Title - renderer.title element.value - when Snippet - renderer.snippet element.value - when Block - renderer.block do - element.each do |item| - case item - when Text - text item.value - when Bold - bold item.value - when Code - code item.value - end - end - end - end - end - - renderer.io - end - end -end diff --git a/src/messages/access_expected_variable.cr b/src/messages/access_expected_variable.cr deleted file mode 100644 index 42de7be84..000000000 --- a/src/messages/access_expected_variable.cr +++ /dev/null @@ -1,11 +0,0 @@ -message AccessExpectedVariable do - title "Syntax Error" - - block do - text "I was looking for the name of the field of a record but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/access_field_not_found.cr b/src/messages/access_field_not_found.cr deleted file mode 100644 index 16366115d..000000000 --- a/src/messages/access_field_not_found.cr +++ /dev/null @@ -1,13 +0,0 @@ -message AccessFieldNotFound do - title "Type Error" - - block do - text "The field" - code field - text "does not exists on the record:" - end - - type target - - snippet node -end diff --git a/src/messages/access_not_record.cr b/src/messages/access_not_record.cr deleted file mode 100644 index cbd4a333a..000000000 --- a/src/messages/access_not_record.cr +++ /dev/null @@ -1,11 +0,0 @@ -message AccessNotRecord do - title "Type Error" - - block do - text "You are trying to access a field on an object which is not a record:" - end - - type object - - snippet node -end diff --git a/src/messages/argument_expected_colon.cr b/src/messages/argument_expected_colon.cr deleted file mode 100644 index 0c8bd1f0b..000000000 --- a/src/messages/argument_expected_colon.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ArgumentExpectedColon do - title "Syntax Error" - - block do - text "A colon must separate the arguments name from its type." - end - - was_looking_for "colon", got, ":" - - snippet node -end diff --git a/src/messages/argument_expected_default_value.cr b/src/messages/argument_expected_default_value.cr deleted file mode 100644 index 625cffb79..000000000 --- a/src/messages/argument_expected_default_value.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ArgumentExpectedDefaultValue do - title "Syntax Error" - - block do - text "The" - bold "default value" - text "of an argument must be defined after the equal sign." - end - - was_looking_for "default value", got - - snippet node -end diff --git a/src/messages/argument_expected_type_or_variable.cr b/src/messages/argument_expected_type_or_variable.cr deleted file mode 100644 index 7d9de998e..000000000 --- a/src/messages/argument_expected_type_or_variable.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ArgumentExpectedTypeOrVariable do - title "Syntax Error" - - block do - text "An argument must have its type defined." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/array_access_expected_closing_bracket.cr b/src/messages/array_access_expected_closing_bracket.cr deleted file mode 100644 index d2de8617f..000000000 --- a/src/messages/array_access_expected_closing_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ArrayAccessExpectedClosingBracket do - title "Syntax Error" - - block do - text "I was looking for the closing bracket" - code "]" - text "after the array index, but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/array_access_expected_index.cr b/src/messages/array_access_expected_index.cr deleted file mode 100644 index 822544404..000000000 --- a/src/messages/array_access_expected_index.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ArrayAccessExpectedIndex do - title "Syntax Error" - - block do - text "I was looking for an index into the array, but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/array_access_index_not_number.cr b/src/messages/array_access_index_not_number.cr deleted file mode 100644 index d943f964b..000000000 --- a/src/messages/array_access_index_not_number.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ArrayAccessIndexNotNumber do - title "Type Error" - - block do - text "The index of an array access is not a number." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/array_access_invalid_tuple.cr b/src/messages/array_access_invalid_tuple.cr deleted file mode 100644 index 29dc66e9c..000000000 --- a/src/messages/array_access_invalid_tuple.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ArrayAccessInvalidTuple do - title "Type Error" - - block do - text "The tuple only has" - bold size - text "members, but you wanted to access the" - bold index - text "." - end - - type_with_text got, "The exact type of the tuple is:" - - snippet node -end diff --git a/src/messages/array_access_not_an_array.cr b/src/messages/array_access_not_an_array.cr deleted file mode 100644 index 78c7b9b63..000000000 --- a/src/messages/array_access_not_an_array.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ArrayAccessNotAnArray do - title "Type Error" - - block do - text "The object you are trying to access an item of is not an array." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/array_destructuring_expected_closing_bracket.cr b/src/messages/array_destructuring_expected_closing_bracket.cr deleted file mode 100644 index 014c3e568..000000000 --- a/src/messages/array_destructuring_expected_closing_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ArrayDestructuringExpectedClosingBracket do - title "Syntax Error" - - block do - text "I was looking for the closing bracket" - code "]" - text "after items of the array destructuring, but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/array_expected_closing_bracket.cr b/src/messages/array_expected_closing_bracket.cr deleted file mode 100644 index dab0f11d2..000000000 --- a/src/messages/array_expected_closing_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ArrayExpectedClosingBracket do - title "Syntax Error" - - block do - text "I was looking for the closing bracket" - code "]" - text "of the array but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/array_literal_expected_type_or_variable.cr b/src/messages/array_literal_expected_type_or_variable.cr deleted file mode 100644 index 21e5e0056..000000000 --- a/src/messages/array_literal_expected_type_or_variable.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ArrayLiteralExpectedTypeOrVariable do - title "Syntax Error" - - block do - text "The type of an" - bold "array literal" - text "must be defined after the" - bold "of" - text "keyword." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/array_not_matches.cr b/src/messages/array_not_matches.cr deleted file mode 100644 index f6cef00b4..000000000 --- a/src/messages/array_not_matches.cr +++ /dev/null @@ -1,23 +0,0 @@ -message ArrayNotMatches do - title "Type Error" - - block do - text "The" - bold "#{index}. item" - text "of an array does not match the type of the first item." - end - - block do - text "I was expecting the same type as of the first item:" - end - - type expected - - block do - text "Instead it is:" - end - - type got - - snippet node -end diff --git a/src/messages/array_not_matches_defined_type.cr b/src/messages/array_not_matches_defined_type.cr deleted file mode 100644 index a95cac3b8..000000000 --- a/src/messages/array_not_matches_defined_type.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ArrayNotMatchesDefinedType do - title "Type Error" - - block do - text "The" - bold "defined type" - text "of an array does not match the type of its items." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/asset_directive_expected_closing_parentheses.cr b/src/messages/asset_directive_expected_closing_parentheses.cr deleted file mode 100644 index eb7845e48..000000000 --- a/src/messages/asset_directive_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message AssetDirectiveExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "path" - text "of an" - bold "asset directive" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/asset_directive_expected_file.cr b/src/messages/asset_directive_expected_file.cr deleted file mode 100644 index a9bf4be06..000000000 --- a/src/messages/asset_directive_expected_file.cr +++ /dev/null @@ -1,14 +0,0 @@ -message AssetDirectiveExpectedFile do - title "Syntax Error" - - block do - text "The path specified for an asset directive does not exists." - end - - block do - text "The file should be here: " - bold path - end - - snippet node -end diff --git a/src/messages/asset_directive_expected_opening_parentheses.cr b/src/messages/asset_directive_expected_opening_parentheses.cr deleted file mode 100644 index b173bcf25..000000000 --- a/src/messages/asset_directive_expected_opening_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message AssetDirectiveExpectedOpeningParentheses do - title "Syntax Error" - - block do - text "I was looking for the " - bold "opening parenthesis " - code "(" - text "of an" - bold "asset directive " - text "but found " - code got - text " instead." - end - - snippet node -end diff --git a/src/messages/asset_directive_expected_path.cr b/src/messages/asset_directive_expected_path.cr deleted file mode 100644 index 587a0e12a..000000000 --- a/src/messages/asset_directive_expected_path.cr +++ /dev/null @@ -1,11 +0,0 @@ -message AssetDirectiveExpectedPath do - title "Syntax Error" - - block do - text "An asset directive must specify the path to the file (relative to the current file)." - end - - was_looking_for "path", got - - snippet node -end diff --git a/src/messages/browser_not_found.cr b/src/messages/browser_not_found.cr deleted file mode 100644 index d5785c13b..000000000 --- a/src/messages/browser_not_found.cr +++ /dev/null @@ -1,12 +0,0 @@ -message BrowserNotFound do - title "Test Runner Error" - - block do - text "I cannot find the executable of browser:" - bold browser - end - - block do - text "Are you sure it's installed properly?" - end -end diff --git a/src/messages/call_argument_size_mismatch.cr b/src/messages/call_argument_size_mismatch.cr deleted file mode 100644 index 1b1e26570..000000000 --- a/src/messages/call_argument_size_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message CallArgumentSizeMismatch do - title "Type Error" - - block do - text "The function you called takes" - bold size - text "arguments, while you tried to call it with" - bold call_size - end - - snippet node, "You tried to call it here:" -end diff --git a/src/messages/call_argument_type_mismatch.cr b/src/messages/call_argument_type_mismatch.cr deleted file mode 100644 index 1b45ae095..000000000 --- a/src/messages/call_argument_type_mismatch.cr +++ /dev/null @@ -1,15 +0,0 @@ -message CallArgumentTypeMismatch do - title "Type Error" - - block do - text "The" - bold "#{index} argument" - text "to a function is causing a mismatch." - end - - type_with_text expected, "The function is expecting the #{index} argument to be:" - type_with_text got, "Instead it is:" - type_with_text function, "The type of the function is:" - - snippet node, "You tried to call it here:" -end diff --git a/src/messages/call_expected_closing_parentheses.cr b/src/messages/call_expected_closing_parentheses.cr deleted file mode 100644 index 6356c1f76..000000000 --- a/src/messages/call_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message CallExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "arguments" - text "of a" - bold "call" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/call_not_a_function.cr b/src/messages/call_not_a_function.cr deleted file mode 100644 index 80552acf0..000000000 --- a/src/messages/call_not_a_function.cr +++ /dev/null @@ -1,10 +0,0 @@ -message CallNotAFunction do - title "Type Error" - - block do - text "You tried to call something" - text "as a function which is not." - end - - snippet node, "You tried to call it here:" -end diff --git a/src/messages/call_not_found_argument.cr b/src/messages/call_not_found_argument.cr deleted file mode 100644 index 97f01aaae..000000000 --- a/src/messages/call_not_found_argument.cr +++ /dev/null @@ -1,13 +0,0 @@ -message CallNotFoundArgument do - title "Type Error" - - block do - text "I was looking for the argument:" - bold name - text "but it's not there." - end - - type_with_text function_type, "The type of the function is:" - - snippet node, "The call is here:" -end diff --git a/src/messages/call_type_mismatch.cr b/src/messages/call_type_mismatch.cr deleted file mode 100644 index 6b6472c01..000000000 --- a/src/messages/call_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message CallTypeMismatch do - title "Type Error" - - block do - text "The type signature of the call does not match the signature" - text "of the function." - end - - type_with_text expected, "The type signature of the function is:" - type_with_text got, "You tried to call it as:" - - snippet node, "You tried to call it here:" -end diff --git a/src/messages/call_with_mixed_arguments.cr b/src/messages/call_with_mixed_arguments.cr deleted file mode 100644 index e463b9618..000000000 --- a/src/messages/call_with_mixed_arguments.cr +++ /dev/null @@ -1,9 +0,0 @@ -message CallWithMixedArguments do - title "Type Error" - - block do - text "A call cannot have named and unamed arguments at the same time." - end - - snippet node, "It is here:" -end diff --git a/src/messages/case_branch_expected_expression.cr b/src/messages/case_branch_expected_expression.cr deleted file mode 100644 index de4381c57..000000000 --- a/src/messages/case_branch_expected_expression.cr +++ /dev/null @@ -1,11 +0,0 @@ -message CaseBranchExpectedExpression do - title "Syntax Error" - - block do - text "A case branch must have an expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/case_branch_not_matches.cr b/src/messages/case_branch_not_matches.cr deleted file mode 100644 index b2dc49876..000000000 --- a/src/messages/case_branch_not_matches.cr +++ /dev/null @@ -1,23 +0,0 @@ -message CaseBranchNotMatches do - title "Type Error" - - block do - text "The return type of the" - bold "#{index}. branch" - text "of a case expression does not match the type of the first branch." - end - - block do - text "I was expecting:" - end - - type expected - - block do - text "Instead it is:" - end - - type got - - snippet node -end diff --git a/src/messages/case_enum_not_covered.cr b/src/messages/case_enum_not_covered.cr deleted file mode 100644 index 20b176d55..000000000 --- a/src/messages/case_enum_not_covered.cr +++ /dev/null @@ -1,15 +0,0 @@ -message CaseEnumNotCovered do - title "Type Error" - - block do - text "Not all possibilities of a case expression are covered." - end - - block do - text "To cover all remaining possibilities create branches for the following options:" - end - - list options - - snippet node -end diff --git a/src/messages/case_expected_branches.cr b/src/messages/case_expected_branches.cr deleted file mode 100644 index 41fb95610..000000000 --- a/src/messages/case_expected_branches.cr +++ /dev/null @@ -1,15 +0,0 @@ -message CaseExpectedBranches do - title "Syntax Error" - - block do - text "I was looking for" - bold "a branch" - text "of a" - bold "case expression" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/case_expected_closing_bracket.cr b/src/messages/case_expected_closing_bracket.cr deleted file mode 100644 index 3ec9f25ec..000000000 --- a/src/messages/case_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CaseExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "case expression", got - - snippet node -end diff --git a/src/messages/case_expected_closing_parentheses.cr b/src/messages/case_expected_closing_parentheses.cr deleted file mode 100644 index f87c1d1ef..000000000 --- a/src/messages/case_expected_closing_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message CaseExpectedClosingParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing parenthesis" - code ")" - text "of a" - bold "case expression" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/case_expected_condition.cr b/src/messages/case_expected_condition.cr deleted file mode 100644 index 5b00fab34..000000000 --- a/src/messages/case_expected_condition.cr +++ /dev/null @@ -1,15 +0,0 @@ -message CaseExpectedCondition do - title "Syntax Error" - - block do - text "I was looking for the " - bold "condition " - text "of a " - bold "case expression " - text "but found " - code got - text " instead." - end - - snippet node -end diff --git a/src/messages/case_expected_opening_bracket.cr b/src/messages/case_expected_opening_bracket.cr deleted file mode 100644 index b875b339e..000000000 --- a/src/messages/case_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CaseExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "case expression", got - - snippet node -end diff --git a/src/messages/case_not_covered.cr b/src/messages/case_not_covered.cr deleted file mode 100644 index 1ccba457d..000000000 --- a/src/messages/case_not_covered.cr +++ /dev/null @@ -1,15 +0,0 @@ -message CaseNotCovered do - title "Type Error" - - block do - text "Not all possibilities of a case expression are covered." - end - - block do - text "To cover all remaining possibilities add an empty case branch:" - end - - pre "=> return value" - - snippet node -end diff --git a/src/messages/case_unnecessary_all.cr b/src/messages/case_unnecessary_all.cr deleted file mode 100644 index c1196587c..000000000 --- a/src/messages/case_unnecessary_all.cr +++ /dev/null @@ -1,9 +0,0 @@ -message CaseUnnecessaryAll do - title "Type Error" - - block do - text "All possibilities of the case expression are covered." - end - - snippet node, "This branch is not needed and can be safely removed." -end diff --git a/src/messages/component_entity_name_conflict.cr b/src/messages/component_entity_name_conflict.cr deleted file mode 100644 index f3eda5570..000000000 --- a/src/messages/component_entity_name_conflict.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ComponentEntityNameConflict do - title "Type Error" - - block do - text "There is already a" - bold what - text "with the name" - bold name - text "in this component." - end - - snippet node, "You are trying to define something with the same name here:" - snippet other, "The #{what} is defined here:" -end diff --git a/src/messages/component_expected_body.cr b/src/messages/component_expected_body.cr deleted file mode 100644 index 31ed50b19..000000000 --- a/src/messages/component_expected_body.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ComponentExpectedBody do - title "Syntax Error" - - block do - text "I was looking for the" - bold "body of a component" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/component_expected_closing_bracket.cr b/src/messages/component_expected_closing_bracket.cr deleted file mode 100644 index bb56bc94e..000000000 --- a/src/messages/component_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ComponentExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "component", got - - snippet node -end diff --git a/src/messages/component_expected_name.cr b/src/messages/component_expected_name.cr deleted file mode 100644 index 7c7321809..000000000 --- a/src/messages/component_expected_name.cr +++ /dev/null @@ -1,18 +0,0 @@ -message ComponentExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name of a component" - text "but found" - code got - text "instead." - end - - block do - text "The name of a component must start with an uppercase letter and only" - text "contain lowercase, uppercase letters and numbers." - end - - snippet node -end diff --git a/src/messages/component_expected_opening_bracket.cr b/src/messages/component_expected_opening_bracket.cr deleted file mode 100644 index 88ca6bbca..000000000 --- a/src/messages/component_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ComponentExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "component", got - - snippet node -end diff --git a/src/messages/component_exposed_name_conflict.cr b/src/messages/component_exposed_name_conflict.cr deleted file mode 100644 index 6b867d52c..000000000 --- a/src/messages/component_exposed_name_conflict.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ComponentExposedNameConflict do - title "Type Error" - - block do - text "You cannot expose" - bold name - text "from the store because the name is already taken." - end - - snippet other, message: "The entity with the same name is here:" - - snippet node -end diff --git a/src/messages/component_function_type_mismatch.cr b/src/messages/component_function_type_mismatch.cr deleted file mode 100644 index 2407d1507..000000000 --- a/src/messages/component_function_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ComponentFunctionTypeMismatch do - title "Type Error" - - block do - text "The type of the function" - bold name - text "of a component must be:" - end - - type expected - - type_with_text got, "Instead it is:" -end diff --git a/src/messages/component_main_property.cr b/src/messages/component_main_property.cr deleted file mode 100644 index e4c141964..000000000 --- a/src/messages/component_main_property.cr +++ /dev/null @@ -1,12 +0,0 @@ -message ComponentMainProperty do - title "Type Error" - - block do - text "The" - bold "Main" - text "component cannot have properties." - end - - snippet property_node, "A property is defined here:" - snippet node, "The component is here:" -end diff --git a/src/messages/component_multiple_connects.cr b/src/messages/component_multiple_connects.cr deleted file mode 100644 index ee64306e6..000000000 --- a/src/messages/component_multiple_connects.cr +++ /dev/null @@ -1,12 +0,0 @@ -message ComponentMultipleConnects do - title "Type Error" - - block do - text "The component is connected to the store" - bold name - text "multiple times." - end - - snippet other, "It is connected here:" - snippet node, "It is also connected here:" -end diff --git a/src/messages/component_multiple_exposed.cr b/src/messages/component_multiple_exposed.cr deleted file mode 100644 index 9bdea04c9..000000000 --- a/src/messages/component_multiple_exposed.cr +++ /dev/null @@ -1,12 +0,0 @@ -message ComponentMultipleExposed do - title "Type Error" - - block do - text "The function or property" - bold name - text "from a store is exposed multiple times." - end - - snippet other, "It is exposed here:" - snippet node, "It is also exposed here:" -end diff --git a/src/messages/component_multiple_uses.cr b/src/messages/component_multiple_uses.cr deleted file mode 100644 index 8312d2f7d..000000000 --- a/src/messages/component_multiple_uses.cr +++ /dev/null @@ -1,12 +0,0 @@ -message ComponentMultipleUses do - title "Type Error" - - block do - text "You are subscribing to the provider" - bold name - text "multiple times." - end - - snippet other, "A subscription is here:" - snippet node, "An other subscription is here:" -end diff --git a/src/messages/component_not_found_render.cr b/src/messages/component_not_found_render.cr deleted file mode 100644 index 6c4910bef..000000000 --- a/src/messages/component_not_found_render.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ComponentNotFoundRender do - title "Type Error" - - block do - text "A component must have a" - bold "render" - text "function." - end - - snippet node, "This component does not have one:" -end diff --git a/src/messages/component_reference_name_conflict.cr b/src/messages/component_reference_name_conflict.cr deleted file mode 100644 index 3423bc854..000000000 --- a/src/messages/component_reference_name_conflict.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ComponentReferenceNameConflict do - title "Type Error" - - block do - text "There are multiple references with the name:" - bold "#{name}." - end - - snippet node, "One reference is here:" - snippet other, "An other reference is here:" -end diff --git a/src/messages/component_render_type_mismatch.cr b/src/messages/component_render_type_mismatch.cr deleted file mode 100644 index c0e8742a0..000000000 --- a/src/messages/component_render_type_mismatch.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ComponentRenderTypeMismatch do - title "Type Error" - - block do - text "I was expecting the return value of the" - bold "render" - text "function to match one of these types:" - end - - pre "Html, String, Array(String), Array(Html)" - - type_with_text got, "Instead it is:" - - snippet node, "The render function in question:" -end diff --git a/src/messages/component_state_name_conflict.cr b/src/messages/component_state_name_conflict.cr deleted file mode 100644 index 4d14f2cbe..000000000 --- a/src/messages/component_state_name_conflict.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ComponentStateNameConflict do - title "Type Error" - - block do - text "There is already a" - bold what - text "with the name" - bold name - text "in this component." - end - - snippet node, "You are trying to define something with the same name here:" - snippet other, "The #{what} is defined here:" -end diff --git a/src/messages/component_style_name_conflict.cr b/src/messages/component_style_name_conflict.cr deleted file mode 100644 index 09aff7c15..000000000 --- a/src/messages/component_style_name_conflict.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ComponentStyleNameConflict do - title "Type Error" - - block do - text "There are multiple style definitions with the name:" - bold "#{name}." - end - - snippet node, "One definition is here:" - snippet other, "An other definition is here:" -end diff --git a/src/messages/connect_expected_closing_bracket.cr b/src/messages/connect_expected_closing_bracket.cr deleted file mode 100644 index 639b43716..000000000 --- a/src/messages/connect_expected_closing_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ConnectExpectedClosingBracket do - title "Syntax Error" - - block do - text "The" - bold "list of functions and properties to expose" - text "from a store must be enclosed by brackets" - end - - was_looking_for "closing bracket", got, "}" - - snippet node -end diff --git a/src/messages/connect_expected_exposing.cr b/src/messages/connect_expected_exposing.cr deleted file mode 100644 index 18e35714f..000000000 --- a/src/messages/connect_expected_exposing.cr +++ /dev/null @@ -1,17 +0,0 @@ -message ConnectExpectedExposing do - title "Syntax Error" - - block do - text "The" - bold "list of functions and properties to expose" - text "from a store and the" - bold "name of the store" - text "must be separated with an" - code "exposing" - text "keyword." - end - - was_looking_for "keyword", got, "exposing" - - snippet node -end diff --git a/src/messages/connect_expected_keys.cr b/src/messages/connect_expected_keys.cr deleted file mode 100644 index fdf8c24dd..000000000 --- a/src/messages/connect_expected_keys.cr +++ /dev/null @@ -1,19 +0,0 @@ -message ConnectExpectedKeys do - title "Syntax Error" - - block do - text "The" - bold "list of functions and properties to expose" - text "from a store must not be empty." - end - - block do - text "I was looking for" - bold "something to expose" - text "but found" - code got - text "instead" - end - - snippet node -end diff --git a/src/messages/connect_expected_opening_bracket.cr b/src/messages/connect_expected_opening_bracket.cr deleted file mode 100644 index bf5cc54af..000000000 --- a/src/messages/connect_expected_opening_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ConnectExpectedOpeningBracket do - title "Syntax Error" - - block do - text "The" - bold "list of functions and properties to expose" - text "from a store must be enclosed by brackets" - end - - was_looking_for "opening bracket", got, "{" - - snippet node -end diff --git a/src/messages/connect_expected_type.cr b/src/messages/connect_expected_type.cr deleted file mode 100644 index 7d76b2f3b..000000000 --- a/src/messages/connect_expected_type.cr +++ /dev/null @@ -1,23 +0,0 @@ -message ConnectExpectedType do - title "Syntax Error" - - block do - text "A" - bold "connect statement" - text "must specify the" - bold "name of the store" - text "after the" - code "connect" - text "keyword." - end - - block do - text "I was looking for" - bold "name of the store" - text "but found" - code got - text "instead" - end - - snippet node -end diff --git a/src/messages/connect_not_found_member.cr b/src/messages/connect_not_found_member.cr deleted file mode 100644 index bae97d2f9..000000000 --- a/src/messages/connect_not_found_member.cr +++ /dev/null @@ -1,12 +0,0 @@ -message ConnectNotFoundMember do - title "Type Error" - - block do - text "The" - bold key - text "function, property or computed property does not exists for the store:" - bold store - end - - snippet node -end diff --git a/src/messages/connect_not_found_store.cr b/src/messages/connect_not_found_store.cr deleted file mode 100644 index db915588a..000000000 --- a/src/messages/connect_not_found_store.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ConnectNotFoundStore do - title "Type Error" - - block do - text "I was looking for the store" - bold store - text "but could not find it." - end - - snippet node -end diff --git a/src/messages/connect_variable_expected_as.cr b/src/messages/connect_variable_expected_as.cr deleted file mode 100644 index 29ff78311..000000000 --- a/src/messages/connect_variable_expected_as.cr +++ /dev/null @@ -1,20 +0,0 @@ -message ConnectVariableExpectedAs do - title "Syntax Error" - - block do - text "The" - bold "exposed name" - text "of a state, function or computed property" - bold "must be specified." - end - - block do - text "I was looking for" - bold "the exposed name" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/constant_expected_equal_sign.cr b/src/messages/constant_expected_equal_sign.cr deleted file mode 100644 index 431abb76d..000000000 --- a/src/messages/constant_expected_equal_sign.cr +++ /dev/null @@ -1,16 +0,0 @@ -message ConstantExpectedEqualSign do - title "Syntax Error" - - block do - text "The" - bold "name" - text "of a constant and its" - bold "value" - text "must be separated by an" - bold "equal sign" - end - - was_looking_for "equal sign", got, "=" - - snippet node -end diff --git a/src/messages/constant_expected_name.cr b/src/messages/constant_expected_name.cr deleted file mode 100644 index 887cfa358..000000000 --- a/src/messages/constant_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ConstantExpectedName do - title "Syntax Error" - - was_looking_for "name of a constant", got - - snippet node -end diff --git a/src/messages/constant_expected_value.cr b/src/messages/constant_expected_value.cr deleted file mode 100644 index a31c7a715..000000000 --- a/src/messages/constant_expected_value.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ConstantExpectedValue do - title "Syntax Error" - - block do - text "The" - bold "value" - text "of a constant must be defined after the equal sign." - end - - was_looking_for "value", got - - snippet node -end diff --git a/src/messages/css_definition_expected_semicolon.cr b/src/messages/css_definition_expected_semicolon.cr deleted file mode 100644 index b7ed502e3..000000000 --- a/src/messages/css_definition_expected_semicolon.cr +++ /dev/null @@ -1,11 +0,0 @@ -message CssDefinitionExpectedSemicolon do - title "Syntax Error" - - block do - text "All CSS definitions must end in a semicolon." - end - - was_looking_for "semicolon", got, ";" - - snippet node -end diff --git a/src/messages/css_definition_type_mismatch.cr b/src/messages/css_definition_type_mismatch.cr deleted file mode 100644 index 7c08a7ff7..000000000 --- a/src/messages/css_definition_type_mismatch.cr +++ /dev/null @@ -1,19 +0,0 @@ -message CssDefinitionTypeMismatch do - title "Type Error" - - block do - text "The type of the value for the CSS property" - bold name - text "is invalid." - end - - block do - text "I was expecting one of these types:" - end - - pre "String, Number" - - type_with_text got, "Instead it is:" - - snippet node -end diff --git a/src/messages/css_font_face_expected_closing_bracket.cr b/src/messages/css_font_face_expected_closing_bracket.cr deleted file mode 100644 index d0e9a7b62..000000000 --- a/src/messages/css_font_face_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssFontFaceExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "font-face", got - - snippet node -end diff --git a/src/messages/css_font_face_expected_opening_bracket.cr b/src/messages/css_font_face_expected_opening_bracket.cr deleted file mode 100644 index 6d07aa8d1..000000000 --- a/src/messages/css_font_face_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssFontFaceExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "font-face", got - - snippet node -end diff --git a/src/messages/css_font_face_interpolation.cr b/src/messages/css_font_face_interpolation.cr deleted file mode 100644 index 8d1c85d3f..000000000 --- a/src/messages/css_font_face_interpolation.cr +++ /dev/null @@ -1,9 +0,0 @@ -message CssFontFaceInterpolation do - title "Type Error" - - block do - text "Interpolations are not allowed inside a font-face rule." - end - - snippet node -end diff --git a/src/messages/css_keyframes_expected_closing_bracket.cr b/src/messages/css_keyframes_expected_closing_bracket.cr deleted file mode 100644 index 86c63bfea..000000000 --- a/src/messages/css_keyframes_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssKeyframesExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "keyframes", got - - snippet node -end diff --git a/src/messages/css_keyframes_expected_name.cr b/src/messages/css_keyframes_expected_name.cr deleted file mode 100644 index 16171dafb..000000000 --- a/src/messages/css_keyframes_expected_name.cr +++ /dev/null @@ -1,11 +0,0 @@ -message CssKeyframesExpectedName do - title "Syntax Error" - - block do - text "An name of a keyframes must be defined." - end - - was_looking_for "name", got - - snippet node -end diff --git a/src/messages/css_keyframes_expected_opening_bracket.cr b/src/messages/css_keyframes_expected_opening_bracket.cr deleted file mode 100644 index b44889b94..000000000 --- a/src/messages/css_keyframes_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssKeyframesExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "keyframes", got - - snippet node -end diff --git a/src/messages/css_nested_at_expected_closing_bracket.cr b/src/messages/css_nested_at_expected_closing_bracket.cr deleted file mode 100644 index 287b840c4..000000000 --- a/src/messages/css_nested_at_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssNestedAtExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "at rule", got - - snippet node -end diff --git a/src/messages/css_nested_at_expected_condition.cr b/src/messages/css_nested_at_expected_condition.cr deleted file mode 100644 index 511dd78cc..000000000 --- a/src/messages/css_nested_at_expected_condition.cr +++ /dev/null @@ -1,11 +0,0 @@ -message CssNestedAtExpectedCondition do - title "Syntax Error" - - block do - text "An at rule must define at least one condition." - end - - was_looking_for "condition", got - - snippet node -end diff --git a/src/messages/css_nested_at_expected_opening_bracket.cr b/src/messages/css_nested_at_expected_opening_bracket.cr deleted file mode 100644 index f1667c69c..000000000 --- a/src/messages/css_nested_at_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssNestedAtExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "at rule", got - - snippet node -end diff --git a/src/messages/css_nested_at_expected_space_after_keyword.cr b/src/messages/css_nested_at_expected_space_after_keyword.cr deleted file mode 100644 index 6411d9dd6..000000000 --- a/src/messages/css_nested_at_expected_space_after_keyword.cr +++ /dev/null @@ -1,14 +0,0 @@ -message CssNestedAtExpectedSpaceAfterKeyword do - title "Syntax Error" - - block do - text "There must be a space between the" - bold "at rule" - text "and any" - bold "conditions." - end - - was_looking_for "space", got - - snippet node -end diff --git a/src/messages/css_no_property.cr b/src/messages/css_no_property.cr deleted file mode 100644 index 2b31b7c9a..000000000 --- a/src/messages/css_no_property.cr +++ /dev/null @@ -1,10 +0,0 @@ -message CssNoProperty do - title "Type Error" - - block do - text "There is no CSS property with the name:" - code name - end - - snippet node -end diff --git a/src/messages/css_selector_expected_closing_bracket.cr b/src/messages/css_selector_expected_closing_bracket.cr deleted file mode 100644 index 6dc1d547d..000000000 --- a/src/messages/css_selector_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssSelectorExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "sub selector", got - - snippet node -end diff --git a/src/messages/css_selector_expected_opening_bracket.cr b/src/messages/css_selector_expected_opening_bracket.cr deleted file mode 100644 index c2bb9a684..000000000 --- a/src/messages/css_selector_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message CssSelectorExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "sub selector", got - - snippet node -end diff --git a/src/messages/decode_complex_type.cr b/src/messages/decode_complex_type.cr deleted file mode 100644 index ab645102e..000000000 --- a/src/messages/decode_complex_type.cr +++ /dev/null @@ -1,27 +0,0 @@ -message DecodeComplexType do - title "Type Error" - - block do - text "This type cannot be automatically decoded:" - end - - type got - - block do - text "Only these types and records containing them can" - text "be automatically decoded:" - end - - type_list [ - TypeChecker::Type.new("Array", [TypeChecker::Variable.new("a")] of TypeChecker::Checkable), - TypeChecker::Type.new("Maybe", [TypeChecker::Variable.new("a")] of TypeChecker::Checkable), - TypeChecker::Type.new("Map", [TypeChecker::STRING, TypeChecker::Variable.new("a")] of TypeChecker::Checkable), - TypeChecker::STRING, - TypeChecker::NUMBER, - TypeChecker::TIME, - TypeChecker::BOOL, - TypeChecker::OBJECT, - ] of TypeChecker::Checkable - - snippet node -end diff --git a/src/messages/decode_expected_as.cr b/src/messages/decode_expected_as.cr deleted file mode 100644 index 7cf93ec30..000000000 --- a/src/messages/decode_expected_as.cr +++ /dev/null @@ -1,17 +0,0 @@ -message DecodeExpectedAs do - title "Syntax Error" - - block do - text "The" - bold "object to be decoded" - text "and the" - bold "type" - text "must be separated by an" - bold "as" - text "keyword." - end - - was_looking_for "as keyword", got - - snippet node -end diff --git a/src/messages/decode_expected_expression.cr b/src/messages/decode_expected_expression.cr deleted file mode 100644 index 93b3817c6..000000000 --- a/src/messages/decode_expected_expression.cr +++ /dev/null @@ -1,14 +0,0 @@ -message DecodeExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "object to be decoded" - text "must come from an" - bold "expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/decode_expected_object.cr b/src/messages/decode_expected_object.cr deleted file mode 100644 index eee203530..000000000 --- a/src/messages/decode_expected_object.cr +++ /dev/null @@ -1,13 +0,0 @@ -message DecodeExpectedObject do - title "Type Error" - - block do - text "Only" - code "Object" - text "types can be decoded!" - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/decode_expected_type.cr b/src/messages/decode_expected_type.cr deleted file mode 100644 index 3c5317ad2..000000000 --- a/src/messages/decode_expected_type.cr +++ /dev/null @@ -1,15 +0,0 @@ -message DecodeExpectedType do - title "Syntax Error" - - block do - text "The" - bold "type" - text "of which to decode to must follow the" - bold "as" - text "key." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/destructuring_multiple_spreads.cr b/src/messages/destructuring_multiple_spreads.cr deleted file mode 100644 index 5493c406b..000000000 --- a/src/messages/destructuring_multiple_spreads.cr +++ /dev/null @@ -1,15 +0,0 @@ -message DestructuringMultipleSpreads do - title "Type Error" - - block do - text "This array destructuring contains" - code count - text "spread notations." - end - - block do - text "An array destructuring can only contain one spread notation." - end - - snippet node -end diff --git a/src/messages/destructuring_no_parameter.cr b/src/messages/destructuring_no_parameter.cr deleted file mode 100644 index 3b313c455..000000000 --- a/src/messages/destructuring_no_parameter.cr +++ /dev/null @@ -1,19 +0,0 @@ -message DestructuringNoParameter do - title "Type Error" - - block do - text "You are trying to destructure the" - bold index - text "parameter from the enum option:" - bold name - end - - block do - text "The option only has" - bold size - text "parameters." - end - - snippet node, "You are trying to destructure it here:" - snippet option, "The option is defined here:" -end diff --git a/src/messages/destructuring_tuple_mismatch.cr b/src/messages/destructuring_tuple_mismatch.cr deleted file mode 100644 index 658140675..000000000 --- a/src/messages/destructuring_tuple_mismatch.cr +++ /dev/null @@ -1,21 +0,0 @@ -message DestructuringTupleMismatch do - title "Type Error" - - block do - text "This destructuring of a tuple does not match the given tuple." - end - - block do - text "I was expecting a tuple with" - bold size - text "parameters." - end - - block do - text "Instead it is this:" - end - - type got - - snippet node -end diff --git a/src/messages/destructuring_type_mismatch.cr b/src/messages/destructuring_type_mismatch.cr deleted file mode 100644 index defe12658..000000000 --- a/src/messages/destructuring_type_mismatch.cr +++ /dev/null @@ -1,21 +0,0 @@ -message DestructuringTypeMismatch do - title "Type Error" - - block do - text "A value does not match its supposed type." - end - - block do - text "I was expecting:" - end - - type expected - - block do - text "Instead it is:" - end - - type got - - snippet node -end diff --git a/src/messages/documentation_directive_entity_not_found.cr b/src/messages/documentation_directive_entity_not_found.cr deleted file mode 100644 index 728167dcb..000000000 --- a/src/messages/documentation_directive_entity_not_found.cr +++ /dev/null @@ -1,11 +0,0 @@ -message DocumentationDirectiveEntityNotFound do - title "Environment Error" - - block do - text "The entity for the documentation directive:" - code name - text "does not exists." - end - - snippet node -end diff --git a/src/messages/documentation_directive_expected_closing_parentheses.cr b/src/messages/documentation_directive_expected_closing_parentheses.cr deleted file mode 100644 index 8dc72bec7..000000000 --- a/src/messages/documentation_directive_expected_closing_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message DocumentationDirectiveExpectedClosingParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing parenthesis" - code ")" - text "of a" - bold "documentation directive" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/documentation_directive_expected_entity.cr b/src/messages/documentation_directive_expected_entity.cr deleted file mode 100644 index 58066f7de..000000000 --- a/src/messages/documentation_directive_expected_entity.cr +++ /dev/null @@ -1,15 +0,0 @@ -message DocumentationDirectiveExpectedEntity do - title "Syntax Error" - - block do - text "I was looking for the" - bold "entity" - text "of a" - bold "documentation directive" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/documentation_directive_expected_opening_parentheses.cr b/src/messages/documentation_directive_expected_opening_parentheses.cr deleted file mode 100644 index 9ec2a34f9..000000000 --- a/src/messages/documentation_directive_expected_opening_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message DocumentationDirectiveExpectedOpeningParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "opening parenthesis" - code "(" - text "of a" - bold "documentation directive" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/encode_complex_type.cr b/src/messages/encode_complex_type.cr deleted file mode 100644 index 24b8a30cb..000000000 --- a/src/messages/encode_complex_type.cr +++ /dev/null @@ -1,25 +0,0 @@ -message EncodeComplexType do - title "Type Error" - - block do - text "This type cannot be automatically encoded:" - end - - type got - - block do - text "Only these types and records containing them can" - text "be automatically decoded:" - end - - type_list [ - TypeChecker::Type.new("Array", [TypeChecker::Variable.new("a")] of TypeChecker::Checkable), - TypeChecker::Type.new("Maybe", [TypeChecker::Variable.new("a")] of TypeChecker::Checkable), - TypeChecker::STRING, - TypeChecker::NUMBER, - TypeChecker::TIME, - TypeChecker::BOOL, - ] of TypeChecker::Checkable - - snippet node -end diff --git a/src/messages/encode_expected_expression.cr b/src/messages/encode_expected_expression.cr deleted file mode 100644 index 3a36a4115..000000000 --- a/src/messages/encode_expected_expression.cr +++ /dev/null @@ -1,14 +0,0 @@ -message EncodeExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "object to be encoded" - text "must come from an" - bold "expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/enum_destructuring_expected_closing_parentheses.cr b/src/messages/enum_destructuring_expected_closing_parentheses.cr deleted file mode 100644 index 912088459..000000000 --- a/src/messages/enum_destructuring_expected_closing_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message EnumDestructuringExpectedClosingParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing parenthesis" - code ")" - text "of the destructuring of an" - bold "enum" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/enum_destructuring_expected_double_colon.cr b/src/messages/enum_destructuring_expected_double_colon.cr deleted file mode 100644 index 5afba7f17..000000000 --- a/src/messages/enum_destructuring_expected_double_colon.cr +++ /dev/null @@ -1,19 +0,0 @@ -message EnumDestructuringExpectedDoubleColon do - title "Syntax Error" - - block do - text "The" - bold "name" - text "of an" - bold "enum" - text "and its" - bold "option" - text "must be separated by a" - bold "double colon" - code "::" - end - - was_looking_for "double colon", got, "::" - - snippet node -end diff --git a/src/messages/enum_destructuring_expected_option.cr b/src/messages/enum_destructuring_expected_option.cr deleted file mode 100644 index ffb8366ea..000000000 --- a/src/messages/enum_destructuring_expected_option.cr +++ /dev/null @@ -1,13 +0,0 @@ -message EnumDestructuringExpectedOption do - title "Syntax Error" - - block do - text "I was looing for the" - bold "option" - text "of an" - bold "enum" - text "but found" - code got - text "instead." - end -end diff --git a/src/messages/enum_expected_closing_bracket.cr b/src/messages/enum_expected_closing_bracket.cr deleted file mode 100644 index 5cf20b346..000000000 --- a/src/messages/enum_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message EnumExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "enum", got - - snippet node -end diff --git a/src/messages/enum_expected_closing_parentheses.cr b/src/messages/enum_expected_closing_parentheses.cr deleted file mode 100644 index e21468aba..000000000 --- a/src/messages/enum_expected_closing_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message EnumExpectedClosingParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing parenthesis" - code ")" - text "of the definition of an" - bold "enum" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/enum_expected_name.cr b/src/messages/enum_expected_name.cr deleted file mode 100644 index ee0583954..000000000 --- a/src/messages/enum_expected_name.cr +++ /dev/null @@ -1,18 +0,0 @@ -message EnumExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name of an enum" - text "but found" - code got - text "instead." - end - - block do - text "The name of an enum must start with an uppercase letter and only" - text "contain lowercase, uppercase letters and numbers." - end - - snippet node -end diff --git a/src/messages/enum_expected_opening_bracket.cr b/src/messages/enum_expected_opening_bracket.cr deleted file mode 100644 index b60e4c44c..000000000 --- a/src/messages/enum_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message EnumExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "enum", got - - snippet node -end diff --git a/src/messages/enum_id_enum_missing.cr b/src/messages/enum_id_enum_missing.cr deleted file mode 100644 index 34d9cf006..000000000 --- a/src/messages/enum_id_enum_missing.cr +++ /dev/null @@ -1,13 +0,0 @@ -message EnumIdEnumMissing do - title "Type Error" - - block do - text "I could not find the option" - bold name - text "of enum" - bold parent_name - end - - snippet node, "You tried to reference it here:" - snippet parent, "The enum is defined here:" -end diff --git a/src/messages/enum_id_expected_closing_parentheses.cr b/src/messages/enum_id_expected_closing_parentheses.cr deleted file mode 100644 index e42dc0b02..000000000 --- a/src/messages/enum_id_expected_closing_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message EnumIdExpectedClosingParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing parenthesis" - code ")" - text "of an" - bold "enum option" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/enum_id_expected_double_colon.cr b/src/messages/enum_id_expected_double_colon.cr deleted file mode 100644 index 26d4cb485..000000000 --- a/src/messages/enum_id_expected_double_colon.cr +++ /dev/null @@ -1,19 +0,0 @@ -message EnumIdExpectedDoubleColon do - title "Syntax Error" - - block do - text "The" - bold "name" - text "of an" - bold "enum" - text "and its" - bold "option" - text "must be separated by a" - bold "double colon" - code "::" - end - - was_looking_for "double colon", got, "::" - - snippet node -end diff --git a/src/messages/enum_id_expected_option.cr b/src/messages/enum_id_expected_option.cr deleted file mode 100644 index 524e2f0c4..000000000 --- a/src/messages/enum_id_expected_option.cr +++ /dev/null @@ -1,15 +0,0 @@ -message EnumIdExpectedOption do - title "Syntax Error" - - block do - text "I was looking for an" - bold "option" - text "of an" - bold "enum" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/enum_id_type_mismatch.cr b/src/messages/enum_id_type_mismatch.cr deleted file mode 100644 index 55ccf95aa..000000000 --- a/src/messages/enum_id_type_mismatch.cr +++ /dev/null @@ -1,15 +0,0 @@ -message EnumIdTypeMismatch do - title "Type Error" - - block do - text "The" - bold "type of an enum" - text "does not match its definition" - end - - was_expecting_type expected, got - - snippet node, "The enum is here:" - - snippet option, "The definition is here:" -end diff --git a/src/messages/enum_id_type_missing.cr b/src/messages/enum_id_type_missing.cr deleted file mode 100644 index 3fd115be1..000000000 --- a/src/messages/enum_id_type_missing.cr +++ /dev/null @@ -1,10 +0,0 @@ -message EnumIdTypeMissing do - title "Type Error" - - block do - text "I could not find the enum:" - bold name - end - - snippet node -end diff --git a/src/messages/enum_not_defined_parameter.cr b/src/messages/enum_not_defined_parameter.cr deleted file mode 100644 index b88a108b7..000000000 --- a/src/messages/enum_not_defined_parameter.cr +++ /dev/null @@ -1,15 +0,0 @@ -message EnumNotDefinedParameter do - title "Type Error" - - block do - text "The parameter" - bold name - text "was not defined in the type of the enum." - end - - block do - text "Parameters used by options must be defined in the type of the enum." - end - - snippet node -end diff --git a/src/messages/enum_option_expected_closing_parentheses.cr b/src/messages/enum_option_expected_closing_parentheses.cr deleted file mode 100644 index c3ca6ce6d..000000000 --- a/src/messages/enum_option_expected_closing_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message EnumOptionExpectedClosingParentheses do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing parenthesis" - code ")" - text "of the definition of an" - bold "enum" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/enum_unused_parameter.cr b/src/messages/enum_unused_parameter.cr deleted file mode 100644 index 373ecdaeb..000000000 --- a/src/messages/enum_unused_parameter.cr +++ /dev/null @@ -1,15 +0,0 @@ -message EnumUnusedParameter do - title "Type Error" - - block do - text "The parameter" - bold name - text "was not used by any of the options." - end - - block do - text "Parameters must be used by at least one of the option." - end - - snippet node -end diff --git a/src/messages/env_expected_name.cr b/src/messages/env_expected_name.cr deleted file mode 100644 index 74730dd93..000000000 --- a/src/messages/env_expected_name.cr +++ /dev/null @@ -1,19 +0,0 @@ -message EnvExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name" - text "of an" - bold "environment variable" - text "but found" - code got - text "instead." - end - - block do - text "The name of an environment variable must be uppercase" - end - - snippet node -end diff --git a/src/messages/env_file_not_found.cr b/src/messages/env_file_not_found.cr deleted file mode 100644 index 27256ff82..000000000 --- a/src/messages/env_file_not_found.cr +++ /dev/null @@ -1,9 +0,0 @@ -message EnvFileNotFound do - title "Environment Error" - - block do - text "The specified environment file" - code name - text "does not exists" - end -end diff --git a/src/messages/env_not_found_variable.cr b/src/messages/env_not_found_variable.cr deleted file mode 100644 index 01ae40ce9..000000000 --- a/src/messages/env_not_found_variable.cr +++ /dev/null @@ -1,10 +0,0 @@ -message EnvNotFoundVariable do - title "Type Error" - - block do - text "I cannot find the environment variable with the name" - bold name - end - - snippet node -end diff --git a/src/messages/expected_end_of_file.cr b/src/messages/expected_end_of_file.cr deleted file mode 100644 index de72a4289..000000000 --- a/src/messages/expected_end_of_file.cr +++ /dev/null @@ -1,26 +0,0 @@ -message ExpectedEndOfFile do - title "Syntax Error" - - block do - text "I was expecting any of the top level constructs:" - end - - list [ - "Component", - "Module", - "Record", - "Enum", - "Provider", - "Routes", - "Store", - "Suite", - "Locale", - ] - - block do - text "Instead I found" - code got - end - - snippet node -end diff --git a/src/messages/for_array_or_set_arguments_mismatch.cr b/src/messages/for_array_or_set_arguments_mismatch.cr deleted file mode 100644 index 05700cf00..000000000 --- a/src/messages/for_array_or_set_arguments_mismatch.cr +++ /dev/null @@ -1,10 +0,0 @@ -message ForArrayOrSetArgumentsMismatch do - title "Type Error" - - block do - text "If the iterable object of a for expression is a set or an array." - text "Then it needs to the have only one argument." - end - - snippet node -end diff --git a/src/messages/for_condition_expected_body.cr b/src/messages/for_condition_expected_body.cr deleted file mode 100644 index 1b1878a87..000000000 --- a/src/messages/for_condition_expected_body.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ForConditionExpectedBody do - title "Syntax Error" - - block do - text "A" - bold "when" - text "must have exactly" - bold "one expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/for_condition_expected_closing_bracket.cr b/src/messages/for_condition_expected_closing_bracket.cr deleted file mode 100644 index e4a22a777..000000000 --- a/src/messages/for_condition_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ForConditionExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "when", got - - snippet node -end diff --git a/src/messages/for_condition_expected_opening_bracket.cr b/src/messages/for_condition_expected_opening_bracket.cr deleted file mode 100644 index c9a02c064..000000000 --- a/src/messages/for_condition_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ForConditionExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "when", got - - snippet node -end diff --git a/src/messages/for_condition_type_mismatch.cr b/src/messages/for_condition_type_mismatch.cr deleted file mode 100644 index d1c02f16f..000000000 --- a/src/messages/for_condition_type_mismatch.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ForConditionTypeMismatch do - title "Type Error" - - block do - text "The condition of a for expression has an invalid type." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/for_expected_body.cr b/src/messages/for_expected_body.cr deleted file mode 100644 index b57698980..000000000 --- a/src/messages/for_expected_body.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ForExpectedBody do - title "Syntax Error" - - block do - text "A" - bold "for expression" - text "must have exactly" - bold "one expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/for_expected_closing_bracket.cr b/src/messages/for_expected_closing_bracket.cr deleted file mode 100644 index 8ee569adb..000000000 --- a/src/messages/for_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ForExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "for expression", got - - snippet node -end diff --git a/src/messages/for_expected_closing_parentheses.cr b/src/messages/for_expected_closing_parentheses.cr deleted file mode 100644 index b0ff4945c..000000000 --- a/src/messages/for_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ForExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "condition" - text "of a" - bold "for expression" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/for_expected_of.cr b/src/messages/for_expected_of.cr deleted file mode 100644 index 501fa1b27..000000000 --- a/src/messages/for_expected_of.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ForExpectedOf do - title "Syntax Error" - - block do - text "The arguments of a " - bold "for expression" - text "and its subject must be separated with" - bold "of keyword." - end - - was_looking_for "the of keyword", got - - snippet node -end diff --git a/src/messages/for_expected_opening_bracket.cr b/src/messages/for_expected_opening_bracket.cr deleted file mode 100644 index a97ee905b..000000000 --- a/src/messages/for_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ForExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "for expression", got - - snippet node -end diff --git a/src/messages/for_expected_subject.cr b/src/messages/for_expected_subject.cr deleted file mode 100644 index 2cb1a62b7..000000000 --- a/src/messages/for_expected_subject.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ForExpectedSubject do - title "Syntax Error" - - block do - text "I was looking for the" - bold "subject" - text "of a for expression" - - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/for_map_arguments_mismatch.cr b/src/messages/for_map_arguments_mismatch.cr deleted file mode 100644 index ada42a99a..000000000 --- a/src/messages/for_map_arguments_mismatch.cr +++ /dev/null @@ -1,10 +0,0 @@ -message ForMapArgumentsMismatch do - title "Type Error" - - block do - text "If the iterable object of a for expression is a map." - text "Then it needs to the have two arguments." - end - - snippet node -end diff --git a/src/messages/for_type_mismatch.cr b/src/messages/for_type_mismatch.cr deleted file mode 100644 index cb1508594..000000000 --- a/src/messages/for_type_mismatch.cr +++ /dev/null @@ -1,17 +0,0 @@ -message ForTypeMismatch do - title "Type Error" - - block do - text "The iterable object of a for expression has an invalid type." - end - - block do - text "I was expecting one of the following types:" - end - - pre "Array(a), Set(a), Map(a, b)" - - type_with_text got, "Instead it is:" - - snippet node -end diff --git a/src/messages/format_directive_expected_closing_bracket.cr b/src/messages/format_directive_expected_closing_bracket.cr deleted file mode 100644 index 977daff55..000000000 --- a/src/messages/format_directive_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message FormatDirectiveExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "format directive", got - - snippet node -end diff --git a/src/messages/format_directive_expected_expression.cr b/src/messages/format_directive_expected_expression.cr deleted file mode 100644 index 551ba2abb..000000000 --- a/src/messages/format_directive_expected_expression.cr +++ /dev/null @@ -1,12 +0,0 @@ -message FormatDirectiveExpectedExpression do - title "Syntax Error" - - block do - text "A format directive must have exactly" - bold "one expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/format_directive_expected_opening_bracket.cr b/src/messages/format_directive_expected_opening_bracket.cr deleted file mode 100644 index 18a7e3d82..000000000 --- a/src/messages/format_directive_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message FormatDirectiveExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "format directive", got - - snippet node -end diff --git a/src/messages/function_argument_conflict.cr b/src/messages/function_argument_conflict.cr deleted file mode 100644 index dc9c134ed..000000000 --- a/src/messages/function_argument_conflict.cr +++ /dev/null @@ -1,12 +0,0 @@ -message FunctionArgumentConflict do - title "Type Error" - - block do - text "The argument" - bold name - text "is declared multiple times." - end - - snippet other, "It is declared here:" - snippet node, "It is also declared here:" -end diff --git a/src/messages/function_argument_must_have_a_default_value.cr b/src/messages/function_argument_must_have_a_default_value.cr deleted file mode 100644 index 53c225958..000000000 --- a/src/messages/function_argument_must_have_a_default_value.cr +++ /dev/null @@ -1,15 +0,0 @@ -message FunctionArgumentMustHaveADefaultValue do - title "Type Error" - - block do - text "The argument" - bold name - text "is declared after one that had a default value." - end - - block do - text "Arguments that come after ones that have a default value must also have a default value." - end - - snippet node -end diff --git a/src/messages/function_expected_closing_bracket.cr b/src/messages/function_expected_closing_bracket.cr deleted file mode 100644 index 53b486751..000000000 --- a/src/messages/function_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message FunctionExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "function", got - - snippet node -end diff --git a/src/messages/function_expected_closing_parentheses.cr b/src/messages/function_expected_closing_parentheses.cr deleted file mode 100644 index 171d2ccbf..000000000 --- a/src/messages/function_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message FunctionExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "arguments" - text "of a" - bold "function" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/function_expected_expression.cr b/src/messages/function_expected_expression.cr deleted file mode 100644 index 4c1623b2e..000000000 --- a/src/messages/function_expected_expression.cr +++ /dev/null @@ -1,15 +0,0 @@ -message FunctionExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "body" - text "of a" - bold "function" - text "must be a single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/function_expected_name.cr b/src/messages/function_expected_name.cr deleted file mode 100644 index 4768095a9..000000000 --- a/src/messages/function_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message FunctionExpectedName do - title "Syntax Error" - - was_looking_for "name of a function", got - - snippet node -end diff --git a/src/messages/function_expected_opening_bracket.cr b/src/messages/function_expected_opening_bracket.cr deleted file mode 100644 index b4adbf966..000000000 --- a/src/messages/function_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message FunctionExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "function", got - - snippet node -end diff --git a/src/messages/function_expected_type_or_variable.cr b/src/messages/function_expected_type_or_variable.cr deleted file mode 100644 index 3344fdf05..000000000 --- a/src/messages/function_expected_type_or_variable.cr +++ /dev/null @@ -1,13 +0,0 @@ -message FunctionExpectedTypeOrVariable do - title "Syntax Error" - - block do - text "The return type of a" - bold "function" - text "must be defined." - end - - was_looking_for "return type", got - - snippet node -end diff --git a/src/messages/function_type_mismatch.cr b/src/messages/function_type_mismatch.cr deleted file mode 100644 index 577f73791..000000000 --- a/src/messages/function_type_mismatch.cr +++ /dev/null @@ -1,11 +0,0 @@ -message FunctionTypeMismatch do - title "Type Error" - - block do - text "The return type of a function does not match its type definition." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/function_type_needed.cr b/src/messages/function_type_needed.cr deleted file mode 100644 index 2e853e690..000000000 --- a/src/messages/function_type_needed.cr +++ /dev/null @@ -1,13 +0,0 @@ -message FunctionTypeNeeded do - title "Type Error" - - block do - text "Type" - bold "return type" - text "of a" - bold "function" - text "needs to be defined if the function is called recursively." - end - - snippet node, "The function in question is:" -end diff --git a/src/messages/get_expected_closing_bracket.cr b/src/messages/get_expected_closing_bracket.cr deleted file mode 100644 index b743c0145..000000000 --- a/src/messages/get_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message GetExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "get", got - - snippet node -end diff --git a/src/messages/get_expected_colon.cr b/src/messages/get_expected_colon.cr deleted file mode 100644 index 4a39dd40f..000000000 --- a/src/messages/get_expected_colon.cr +++ /dev/null @@ -1,17 +0,0 @@ -message GetExpectedColon do - title "Syntax Error" - - block do - text "The" - bold "body" - text "of a" - bold "get" - text "and its" - bold "return type" - text "must be separated by a colon." - end - - was_looking_for "colon", got, ":" - - snippet node -end diff --git a/src/messages/get_expected_expression.cr b/src/messages/get_expected_expression.cr deleted file mode 100644 index 7511e1d01..000000000 --- a/src/messages/get_expected_expression.cr +++ /dev/null @@ -1,15 +0,0 @@ -message GetExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "body" - text "of a" - bold "get" - text "must be a single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/get_expected_name.cr b/src/messages/get_expected_name.cr deleted file mode 100644 index 9949fbc9a..000000000 --- a/src/messages/get_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message GetExpectedName do - title "Syntax Error" - - was_looking_for "name of a get", got - - snippet node -end diff --git a/src/messages/get_expected_opening_bracket.cr b/src/messages/get_expected_opening_bracket.cr deleted file mode 100644 index 3b325bcdf..000000000 --- a/src/messages/get_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message GetExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "get", got - - snippet node -end diff --git a/src/messages/get_expected_type.cr b/src/messages/get_expected_type.cr deleted file mode 100644 index 7f40fde65..000000000 --- a/src/messages/get_expected_type.cr +++ /dev/null @@ -1,13 +0,0 @@ -message GetExpectedType do - title "Syntax Error" - - block do - text "The return type of a" - bold "get" - text "must be defined." - end - - was_looking_for "return type", got - - snippet node -end diff --git a/src/messages/get_type_mismatch.cr b/src/messages/get_type_mismatch.cr deleted file mode 100644 index 9be3e966f..000000000 --- a/src/messages/get_type_mismatch.cr +++ /dev/null @@ -1,11 +0,0 @@ -message GetTypeMismatch do - title "Type Error" - - block do - text "The return type of a get does not match its type definition." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/global_name_conflict.cr b/src/messages/global_name_conflict.cr deleted file mode 100644 index ffe5b0ff2..000000000 --- a/src/messages/global_name_conflict.cr +++ /dev/null @@ -1,13 +0,0 @@ -message GlobalNameConflict do - title "Type Error" - - block do - text "There is already a" - bold what - text "with the name:" - bold name - end - - snippet node, "You are trying to define something with the same name here:" - snippet other, "The #{what} is defined here:" -end diff --git a/src/messages/here_doc_expected_end.cr b/src/messages/here_doc_expected_end.cr deleted file mode 100644 index 8dc48b717..000000000 --- a/src/messages/here_doc_expected_end.cr +++ /dev/null @@ -1,7 +0,0 @@ -message HereDocExpectedEnd do - title "Syntax Error" - - was_looking_for "end token of a here doc", got - - snippet node -end diff --git a/src/messages/here_doc_expected_start.cr b/src/messages/here_doc_expected_start.cr deleted file mode 100644 index 805995812..000000000 --- a/src/messages/here_doc_expected_start.cr +++ /dev/null @@ -1,7 +0,0 @@ -message HereDocExpectedStart do - title "Syntax Error" - - was_looking_for "start token of a here doc", got - - snippet node -end diff --git a/src/messages/here_doc_interpolation_type_mismatch.cr b/src/messages/here_doc_interpolation_type_mismatch.cr deleted file mode 100644 index 305d7c10d..000000000 --- a/src/messages/here_doc_interpolation_type_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message HereDocInterpolationTypeMismatch do - title "Type Error" - - block do - text "An interpolation in here document is causing a mismatch." - end - - type_with_text expected, "The expected type is:" - type_with_text got, "Instead it got:" - - snippet node, "It is here:" -end diff --git a/src/messages/html_attribute_component_key_type_mismatch.cr b/src/messages/html_attribute_component_key_type_mismatch.cr deleted file mode 100644 index 1e0aa89a3..000000000 --- a/src/messages/html_attribute_component_key_type_mismatch.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlAttributeComponentKeyTypeMismatch do - title "Type Error" - - block do - text "The" - bold "key" - text "attribute of a component has an invalid type. It can only be:" - code "String" - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/html_attribute_component_property_type_mismatch.cr b/src/messages/html_attribute_component_property_type_mismatch.cr deleted file mode 100644 index 1e0076170..000000000 --- a/src/messages/html_attribute_component_property_type_mismatch.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlAttributeComponentPropertyTypeMismatch do - title "Type Error" - - block do - text "The type of the value for the property" - bold name - text "of the component" - bold component - text "does not match its definition." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/html_attribute_element_attribute_type_mismatch.cr b/src/messages/html_attribute_element_attribute_type_mismatch.cr deleted file mode 100644 index 7c8841c77..000000000 --- a/src/messages/html_attribute_element_attribute_type_mismatch.cr +++ /dev/null @@ -1,21 +0,0 @@ -message HtmlAttributeElementAttributeTypeMismatch do - title "Type Error" - - block do - text "The type of the value for the property" - bold name - text "of element" - bold "tag" - text "does not match its type." - end - - block do - text "I was expecting one of the following types:" - end - - pre expected - - type_with_text got, "Instead it is:" - - snippet node -end diff --git a/src/messages/html_attribute_expected_closing_bracket.cr b/src/messages/html_attribute_expected_closing_bracket.cr deleted file mode 100644 index cae58d4b1..000000000 --- a/src/messages/html_attribute_expected_closing_bracket.cr +++ /dev/null @@ -1,22 +0,0 @@ -message HtmlAttributeExpectedClosingBracket do - title "Syntax Error" - - block do - text "The" - bold "value of an attribute" - text "must be either a string literal or an expression" - text "enclosed by brackets." - end - - block do - text "I was looking for the" - bold "closing bracket" - code "}" - - text "for the expression but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/html_attribute_expected_equal_sign.cr b/src/messages/html_attribute_expected_equal_sign.cr deleted file mode 100644 index ef4eedb99..000000000 --- a/src/messages/html_attribute_expected_equal_sign.cr +++ /dev/null @@ -1,17 +0,0 @@ -message HtmlAttributeExpectedEqualSign do - title "Syntax Error" - - block do - text "The" - bold "name of an attribute" - text "and its" - bold "value" - text "must be separated by an" - bold "equal sign" - code "=" - end - - was_looking_for "equal sign", got, "=" - - snippet node -end diff --git a/src/messages/html_attribute_expected_expression.cr b/src/messages/html_attribute_expected_expression.cr deleted file mode 100644 index c106c9051..000000000 --- a/src/messages/html_attribute_expected_expression.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlAttributeExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "value of an attribute" - text "must be either a string literal or an expression" - text "enclosed by brackets." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/html_attribute_expected_opening_bracket.cr b/src/messages/html_attribute_expected_opening_bracket.cr deleted file mode 100644 index cfda4d3af..000000000 --- a/src/messages/html_attribute_expected_opening_bracket.cr +++ /dev/null @@ -1,22 +0,0 @@ -message HtmlAttributeExpectedOpeningBracket do - title "Syntax Error" - - block do - text "The" - bold "value of an attribute" - text "must be either a string literal or an expression" - text "enclosed by brackets." - end - - block do - text "I was looking for the" - bold "opening bracket" - code "{" - - text "for the expression but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/html_attribute_fragment_key_type_mismatch.cr b/src/messages/html_attribute_fragment_key_type_mismatch.cr deleted file mode 100644 index 8328bea55..000000000 --- a/src/messages/html_attribute_fragment_key_type_mismatch.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlAttributeFragmentKeyTypeMismatch do - title "Type Error" - - block do - text "The" - bold "key" - text "attribute of a fragment has an invalid type. It can only be:" - code "String" - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/html_attribute_not_found_component_property.cr b/src/messages/html_attribute_not_found_component_property.cr deleted file mode 100644 index 54893d5b8..000000000 --- a/src/messages/html_attribute_not_found_component_property.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlAttributeNotFoundComponentProperty do - title "Type Error" - - block do - text "I was looking for the property" - bold name - text "on the" - bold component - text "component but could not find it." - end - - list properties, "Maybe you want one of its properties:" - - snippet node -end diff --git a/src/messages/html_component_attribute_required.cr b/src/messages/html_component_attribute_required.cr deleted file mode 100644 index 7637b2784..000000000 --- a/src/messages/html_component_attribute_required.cr +++ /dev/null @@ -1,10 +0,0 @@ -message HtmlComponentAttributeRequired do - title "Type Error" - - block do - text "One of the required properties were not specified for a component." - end - - snippet property_node, "The property in question is:" - snippet node, "The component was referenced here:" -end diff --git a/src/messages/html_component_expected_closing_bracket.cr b/src/messages/html_component_expected_closing_bracket.cr deleted file mode 100644 index 1663d0d50..000000000 --- a/src/messages/html_component_expected_closing_bracket.cr +++ /dev/null @@ -1,23 +0,0 @@ -message HtmlComponentExpectedClosingBracket do - title "Syntax Error" - - block do - text "I could not parse further. I was looking for one of the following:" - end - - list [ - %(an attribute for the component), - %(a reference to the component "as component"), - %("/>" for self closing components), - %(">" for non self closing components), - ] - - block do - text "but found" - code got - text "instead." - text "You can read more about components here: https://www.mint-lang.com/guide/reference/components" - end - - snippet node -end diff --git a/src/messages/html_component_expected_closing_tag.cr b/src/messages/html_component_expected_closing_tag.cr deleted file mode 100644 index e56c1037b..000000000 --- a/src/messages/html_component_expected_closing_tag.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlComponentExpectedClosingTag do - title "Syntax Error" - - block do - text "A none self closing component tag must have a" - bold "closing tag." - end - - snippet opening_tag, "I am looking for the closing tag of:" - - was_looking_for "closing tag", got - - snippet node -end diff --git a/src/messages/html_component_expected_reference.cr b/src/messages/html_component_expected_reference.cr deleted file mode 100644 index 578111a8c..000000000 --- a/src/messages/html_component_expected_reference.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlComponentExpectedReference do - title "Syntax Error" - - block do - text "I was looking for the" - bold "identifier" - text "of the component after the" - code "as" - text "keyword but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/html_component_expected_type.cr b/src/messages/html_component_expected_type.cr deleted file mode 100644 index 35433b7ef..000000000 --- a/src/messages/html_component_expected_type.cr +++ /dev/null @@ -1,18 +0,0 @@ -message HtmlComponentExpectedType do - title "Syntax Error" - - block do - text "I was looking for the" - bold "component identifier" - text "of a component tag but found" - code got - text "instead." - end - - block do - text "A component identifier must start with an uppercase letter" - text "and only contain numbers, upper- and lowercase characters." - end - - snippet node -end diff --git a/src/messages/html_component_global_component.cr b/src/messages/html_component_global_component.cr deleted file mode 100644 index 3a1d43a9e..000000000 --- a/src/messages/html_component_global_component.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlComponentGlobalComponent do - title "Type Error" - - block do - text "The component named" - bold name - text "is global and cannot be used." - end - - block do - text "Global components are added to the body and always rendered." - end - - snippet node -end diff --git a/src/messages/html_component_not_found_component.cr b/src/messages/html_component_not_found_component.cr deleted file mode 100644 index 34b65df36..000000000 --- a/src/messages/html_component_not_found_component.cr +++ /dev/null @@ -1,11 +0,0 @@ -message HtmlComponentNotFoundComponent do - title "Type Error" - - block do - text "I was looking for a component named" - bold name - text "but I could not find it." - end - - snippet node -end diff --git a/src/messages/html_component_reference_outside_of_component.cr b/src/messages/html_component_reference_outside_of_component.cr deleted file mode 100644 index 558bdcccb..000000000 --- a/src/messages/html_component_reference_outside_of_component.cr +++ /dev/null @@ -1,9 +0,0 @@ -message HtmlComponentReferenceOutsideOfComponent do - title "Type Error" - - block do - text "Referencing components are not allowed outside of components." - end - - snippet node -end diff --git a/src/messages/html_content_type_mismatch.cr b/src/messages/html_content_type_mismatch.cr deleted file mode 100644 index a1637ec67..000000000 --- a/src/messages/html_content_type_mismatch.cr +++ /dev/null @@ -1,17 +0,0 @@ -message HtmlContentTypeMismatch do - title "Type Error" - - block do - text "A child node of an element or component has an invalid type." - end - - block do - text "I was expecting one of the following types:" - end - - pre "Html, String, Array(String), Array(Html)" - - type_with_text got, "Instead it is:" - - snippet node -end diff --git a/src/messages/html_element_class_name_forbidden.cr b/src/messages/html_element_class_name_forbidden.cr deleted file mode 100644 index 02697646c..000000000 --- a/src/messages/html_element_class_name_forbidden.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlElementClassNameForbidden do - title "Type Error" - - block do - text "The className attribute on elements are forbidden." - end - - block do - text "Please use" - bold "class" - text "instead." - end - - snippet node -end diff --git a/src/messages/html_element_expected_closing_bracket.cr b/src/messages/html_element_expected_closing_bracket.cr deleted file mode 100644 index 87d80a403..000000000 --- a/src/messages/html_element_expected_closing_bracket.cr +++ /dev/null @@ -1,17 +0,0 @@ -message HtmlElementExpectedClosingBracket do - title "Syntax Error" - - block do - text "I found a" - bold "slash" - code "/" - text "which indicates that the element does not have children. A" - bold "closing bracket" - code ">" - text "must follow the slash." - end - - was_looking_for "closing bracket", got, ">" - - snippet node -end diff --git a/src/messages/html_element_expected_closing_tag.cr b/src/messages/html_element_expected_closing_tag.cr deleted file mode 100644 index 803da03b8..000000000 --- a/src/messages/html_element_expected_closing_tag.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlElementExpectedClosingTag do - title "Syntax Error" - - block do - text "A none self closing HTML tag must have a" - bold "closing tag." - end - - snippet opening_tag, "I am looking for the closing tag of:" - - was_looking_for "closing tag", got - - snippet node -end diff --git a/src/messages/html_element_expected_reference.cr b/src/messages/html_element_expected_reference.cr deleted file mode 100644 index 62a144676..000000000 --- a/src/messages/html_element_expected_reference.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlElementExpectedReference do - title "Syntax Error" - - block do - text "I was looking for the" - bold "identifier" - text "of the element after the" - code "as" - text "keyword but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/html_element_expected_style.cr b/src/messages/html_element_expected_style.cr deleted file mode 100644 index e293e4c86..000000000 --- a/src/messages/html_element_expected_style.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlElementExpectedStyle do - title "Syntax Error" - - block do - text "I found a" - bold "double colon" - code "::" - text "which indicates that the element has a style associated with it." - end - - was_looking_for "style", got - - snippet node -end diff --git a/src/messages/html_element_ref_forbidden.cr b/src/messages/html_element_ref_forbidden.cr deleted file mode 100644 index fb1d30a3b..000000000 --- a/src/messages/html_element_ref_forbidden.cr +++ /dev/null @@ -1,13 +0,0 @@ -message HtmlElementRefForbidden do - title "Type Error" - - block do - text "The use of ref attribute is forbidden." - end - - block do - text "If you want to save a reference to an element, use the as keyword." - end - - snippet node -end diff --git a/src/messages/html_element_reference_outside_of_component.cr b/src/messages/html_element_reference_outside_of_component.cr deleted file mode 100644 index b7930a938..000000000 --- a/src/messages/html_element_reference_outside_of_component.cr +++ /dev/null @@ -1,9 +0,0 @@ -message HtmlElementReferenceOutsideOfComponent do - title "Type Error" - - block do - text "Referencing elements are not allowed outside of components." - end - - snippet node -end diff --git a/src/messages/html_element_style_outside_of_component.cr b/src/messages/html_element_style_outside_of_component.cr deleted file mode 100644 index c0ff8ca3c..000000000 --- a/src/messages/html_element_style_outside_of_component.cr +++ /dev/null @@ -1,9 +0,0 @@ -message HtmlElementStyleOutsideOfComponent do - title "Type Error" - - block do - text "Styling of elements are not allowed outside of components." - end - - snippet node -end diff --git a/src/messages/html_expression_expected_closing_tag.cr b/src/messages/html_expression_expected_closing_tag.cr deleted file mode 100644 index 4ae6e419a..000000000 --- a/src/messages/html_expression_expected_closing_tag.cr +++ /dev/null @@ -1,11 +0,0 @@ -message HtmlExpressionExpectedClosingTag do - title "Syntax Error" - - block do - text "A HTML expression needs to be closed with a closing tag." - end - - was_looking_for "closing tag", got, "}>" - - snippet node -end diff --git a/src/messages/html_fragment_expected_closing_bracket.cr b/src/messages/html_fragment_expected_closing_bracket.cr deleted file mode 100644 index bc77917c6..000000000 --- a/src/messages/html_fragment_expected_closing_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message HtmlFragmentExpectedClosingBracket do - title "Syntax Error" - - block do - text "I was looking for closing bracket" - code ">" - text "of a html fragment but got" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/html_fragment_expected_closing_tag.cr b/src/messages/html_fragment_expected_closing_tag.cr deleted file mode 100644 index 5d8fcfb36..000000000 --- a/src/messages/html_fragment_expected_closing_tag.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlFragmentExpectedClosingTag do - title "Syntax Error" - - block do - text "An" - bold "html fragment" - text "must have a" - bold "closing tag." - end - - was_looking_for "closing tag", got, "" - - snippet node -end diff --git a/src/messages/html_style_argument_size_mismatch.cr b/src/messages/html_style_argument_size_mismatch.cr deleted file mode 100644 index aecfa09d5..000000000 --- a/src/messages/html_style_argument_size_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message HtmlStyleArgumentSizeMismatch do - title "Type Error" - - block do - text "The style takes" - bold size - text "arguments, while you tried to call it with" - bold call_size - end - - snippet node, "You tried to call it here:" -end diff --git a/src/messages/html_style_argument_type_mismatch.cr b/src/messages/html_style_argument_type_mismatch.cr deleted file mode 100644 index 22dc51625..000000000 --- a/src/messages/html_style_argument_type_mismatch.cr +++ /dev/null @@ -1,14 +0,0 @@ -message HtmlStyleArgumentTypeMismatch do - title "Type Error" - - block do - text "The" - bold "#{index} argument" - text "to a style is causing a mismatch." - end - - type_with_text expected, "The style is expecting the #{index} argument to be:" - type_with_text got, "Instead it is:" - - snippet node, "You tried to call it here:" -end diff --git a/src/messages/html_style_expected_closing_parentheses.cr b/src/messages/html_style_expected_closing_parentheses.cr deleted file mode 100644 index d80f7b092..000000000 --- a/src/messages/html_style_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message HtmlStyleExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "arguments" - text "of a" - bold "style" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/html_style_not_found.cr b/src/messages/html_style_not_found.cr deleted file mode 100644 index 1bdc72a6f..000000000 --- a/src/messages/html_style_not_found.cr +++ /dev/null @@ -1,11 +0,0 @@ -message HtmlStyleNotFound do - title "Type Error" - - block do - text "I was looking for the style" - bold style - text "but it's not defined in the component." - end - - snippet node -end diff --git a/src/messages/if_condition_type_mismatch.cr b/src/messages/if_condition_type_mismatch.cr deleted file mode 100644 index 7b8d6a62a..000000000 --- a/src/messages/if_condition_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message IfConditionTypeMismatch do - title "Type Error" - - block do - text "The" - bold "condition of an if expression" - text "does not evaluate to a boolean." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/if_else_type_mismatch.cr b/src/messages/if_else_type_mismatch.cr deleted file mode 100644 index 129193a5f..000000000 --- a/src/messages/if_else_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message IfElseTypeMismatch do - title "Type Error" - - block do - text "The" - bold "falsy (else) branch of an if expression" - text "does not match the type of the truthy branch." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/if_expected_closing_parentheses.cr b/src/messages/if_expected_closing_parentheses.cr deleted file mode 100644 index 6b9ff9038..000000000 --- a/src/messages/if_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message IfExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "condition" - text "of an" - bold "if expression" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/if_expected_condition.cr b/src/messages/if_expected_condition.cr deleted file mode 100644 index 1bdad551a..000000000 --- a/src/messages/if_expected_condition.cr +++ /dev/null @@ -1,14 +0,0 @@ -message IfExpectedCondition do - title "Syntax Error" - - block do - text "The" - bold "condition" - text "of an if expression" - bold "must be a single expression." - end - - was_looking_for "condition", got - - snippet node -end diff --git a/src/messages/if_expected_else.cr b/src/messages/if_expected_else.cr deleted file mode 100644 index 1ad6e53c2..000000000 --- a/src/messages/if_expected_else.cr +++ /dev/null @@ -1,19 +0,0 @@ -message IfExpectedElse do - title "Type Error" - - block do - text "This" - bold "if expression" - text "must have an" - bold "else branch." - end - - block do - text "The elese branch can be omitted if the truthy branch returns one of:" - type_list expected - text "but it returns" - type got - end - - snippet node -end diff --git a/src/messages/if_expected_falsy_closing_bracket.cr b/src/messages/if_expected_falsy_closing_bracket.cr deleted file mode 100644 index bc55f4f16..000000000 --- a/src/messages/if_expected_falsy_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message IfExpectedFalsyClosingBracket do - title "Syntax Error" - - closing_bracket "else branch", got - - snippet node -end diff --git a/src/messages/if_expected_falsy_expression.cr b/src/messages/if_expected_falsy_expression.cr deleted file mode 100644 index 1844b8dd1..000000000 --- a/src/messages/if_expected_falsy_expression.cr +++ /dev/null @@ -1,13 +0,0 @@ -message IfExpectedFalsyExpression do - title "Syntax Error" - - block do - text "The" - bold "body of an else branch" - text "of an if expression must be a single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/if_expected_falsy_opening_bracket.cr b/src/messages/if_expected_falsy_opening_bracket.cr deleted file mode 100644 index 50826c64c..000000000 --- a/src/messages/if_expected_falsy_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message IfExpectedFalsyOpeningBracket do - title "Syntax Error" - - opening_bracket "else branch", got - - snippet node -end diff --git a/src/messages/if_expected_truthy_closing_bracket.cr b/src/messages/if_expected_truthy_closing_bracket.cr deleted file mode 100644 index ef8ef3901..000000000 --- a/src/messages/if_expected_truthy_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message IfExpectedTruthyClosingBracket do - title "Syntax Error" - - closing_bracket "if expression", got - - snippet node -end diff --git a/src/messages/if_expected_truthy_expression.cr b/src/messages/if_expected_truthy_expression.cr deleted file mode 100644 index b75eafc0b..000000000 --- a/src/messages/if_expected_truthy_expression.cr +++ /dev/null @@ -1,13 +0,0 @@ -message IfExpectedTruthyExpression do - title "Syntax Error" - - block do - text "The" - bold "body of an if expression" - text "must be a single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/if_expected_truthy_opening_bracket.cr b/src/messages/if_expected_truthy_opening_bracket.cr deleted file mode 100644 index eb026e918..000000000 --- a/src/messages/if_expected_truthy_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message IfExpectedTruthyOpeningBracket do - title "Syntax Error" - - opening_bracket "if expression", got - - snippet node -end diff --git a/src/messages/inline_directive_expected_closing_parentheses.cr b/src/messages/inline_directive_expected_closing_parentheses.cr deleted file mode 100644 index 8bab44bbd..000000000 --- a/src/messages/inline_directive_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message InlineDirectiveExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "path" - text "of an" - bold "inline directive" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/inline_directive_expected_file.cr b/src/messages/inline_directive_expected_file.cr deleted file mode 100644 index a2eb47d72..000000000 --- a/src/messages/inline_directive_expected_file.cr +++ /dev/null @@ -1,14 +0,0 @@ -message InlineDirectiveExpectedFile do - title "Syntax Error" - - block do - text "The path specified for an inline directive does not exists." - end - - block do - text "The file should be here: " - bold path - end - - snippet node -end diff --git a/src/messages/inline_directive_expected_opening_parentheses.cr b/src/messages/inline_directive_expected_opening_parentheses.cr deleted file mode 100644 index 26ffb370f..000000000 --- a/src/messages/inline_directive_expected_opening_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message InlineDirectiveExpectedOpeningParentheses do - title "Syntax Error" - - block do - text "I was looking for the " - bold "opening parenthesis " - code "(" - text "of an" - bold "inline directive " - text "but found " - code got - text " instead." - end - - snippet node -end diff --git a/src/messages/inline_directive_expected_path.cr b/src/messages/inline_directive_expected_path.cr deleted file mode 100644 index f8dabbcfb..000000000 --- a/src/messages/inline_directive_expected_path.cr +++ /dev/null @@ -1,11 +0,0 @@ -message InlineDirectiveExpectedPath do - title "Syntax Error" - - block do - text "An inline directive must specify the path to the file (relative to the current file)." - end - - was_looking_for "path", got - - snippet node -end diff --git a/src/messages/inline_function_expected_closing_bracket.cr b/src/messages/inline_function_expected_closing_bracket.cr deleted file mode 100644 index 32fffca7b..000000000 --- a/src/messages/inline_function_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message InlineFunctionExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "anonymous function", got - - snippet node -end diff --git a/src/messages/inline_function_expected_closing_parentheses.cr b/src/messages/inline_function_expected_closing_parentheses.cr deleted file mode 100644 index 586cf171c..000000000 --- a/src/messages/inline_function_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message InlineFunctionExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "arguments" - text "of an" - bold "anonymous function" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/inline_function_expected_expression.cr b/src/messages/inline_function_expected_expression.cr deleted file mode 100644 index 1d1dc3020..000000000 --- a/src/messages/inline_function_expected_expression.cr +++ /dev/null @@ -1,15 +0,0 @@ -message InlineFunctionExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "body" - text "of an" - bold "inline function" - text "must be a single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/inline_function_expected_opening_bracket.cr b/src/messages/inline_function_expected_opening_bracket.cr deleted file mode 100644 index c240a8514..000000000 --- a/src/messages/inline_function_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message InlineFunctionExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "anonymous function", got - - snippet node -end diff --git a/src/messages/inline_function_expected_type.cr b/src/messages/inline_function_expected_type.cr deleted file mode 100644 index 5688ef153..000000000 --- a/src/messages/inline_function_expected_type.cr +++ /dev/null @@ -1,13 +0,0 @@ -message InlineFunctionExpectedType do - title "Syntax Error" - - block do - text "The return type of an" - bold "anonymous function" - text "must be defined." - end - - was_looking_for "return type", got - - snippet node -end diff --git a/src/messages/inline_function_type_mismatch.cr b/src/messages/inline_function_type_mismatch.cr deleted file mode 100644 index 532c9f10f..000000000 --- a/src/messages/inline_function_type_mismatch.cr +++ /dev/null @@ -1,11 +0,0 @@ -message InlineFunctionTypeMismatch do - title "Type Error" - - block do - text "The return type of an anonymous function does not match its type definition." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/installer_failed_to_install.cr b/src/messages/installer_failed_to_install.cr deleted file mode 100644 index 5f690607d..000000000 --- a/src/messages/installer_failed_to_install.cr +++ /dev/null @@ -1,33 +0,0 @@ -message InstallerFailedToInstall do - title "Install Error" - - block do - text "Failed to satisfy the following constraint:" - end - - block do - bold "#{name} #{constraint}" - text "from" - bold package - end - - eliminated = @data["eliminated"]? - - case eliminated - when Array(String) - unless eliminated.empty? - block do - text "All versions of" - bold name - text "were eliminated:" - end - - list eliminated - - block do - text "There are no version available for:" - bold name - end - end - end -end diff --git a/src/messages/interpolation_expected_closing_bracket.cr b/src/messages/interpolation_expected_closing_bracket.cr deleted file mode 100644 index c1075032a..000000000 --- a/src/messages/interpolation_expected_closing_bracket.cr +++ /dev/null @@ -1,11 +0,0 @@ -message InterpolationExpectedClosingBracket do - title "Syntax Error" - - block do - text "A CSS interpolation must end with a closing bracket." - end - - was_looking_for "bracket", got, "}" - - snippet node -end diff --git a/src/messages/interpolation_expected_expression.cr b/src/messages/interpolation_expected_expression.cr deleted file mode 100644 index bfe1f3f35..000000000 --- a/src/messages/interpolation_expected_expression.cr +++ /dev/null @@ -1,13 +0,0 @@ -message InterpolationExpectedExpression do - title "Syntax Error" - - block do - text "I was looking for the" - bold "expression" - text "of a CSS interpolation but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/invalid_browser.cr b/src/messages/invalid_browser.cr deleted file mode 100644 index 5a54fb909..000000000 --- a/src/messages/invalid_browser.cr +++ /dev/null @@ -1,14 +0,0 @@ -message InvalidBrowser do - title "Test Runner Error" - - block do - text "I cannot run the tests in the given browser:" - bold browser - end - - block do - text "The available browsers are:" - end - - list %w[chrome firefox] -end diff --git a/src/messages/invalid_reporter.cr b/src/messages/invalid_reporter.cr deleted file mode 100644 index 4a52b3b18..000000000 --- a/src/messages/invalid_reporter.cr +++ /dev/null @@ -1,14 +0,0 @@ -message InvalidReporter do - title "Test Runner Error" - - block do - text "There is no reporter with the name:" - bold reporter - end - - block do - text "The available reporters are:" - end - - list %w[documentation dot] -end diff --git a/src/messages/invalid_self_reference.cr b/src/messages/invalid_self_reference.cr deleted file mode 100644 index 3caa6c9c0..000000000 --- a/src/messages/invalid_self_reference.cr +++ /dev/null @@ -1,10 +0,0 @@ -message InvalidSelfReference do - title "Type Error" - - block do - text "You are trying to reference an other entity in a top level entity before it is initialized." - end - - snippet referee, "Then entity you are referencing:" - snippet node, "The entity you are referencing from:" -end diff --git a/src/messages/js_expected_closing_tick.cr b/src/messages/js_expected_closing_tick.cr deleted file mode 100644 index 177dfa8cd..000000000 --- a/src/messages/js_expected_closing_tick.cr +++ /dev/null @@ -1,14 +0,0 @@ -message JsExpectedClosingTick do - title "Syntax Error" - - block do - text "A" - bold "JavaScript expression" - text "is enclosed by" - bold "backticks." - end - - was_looking_for "backtick", got, "`" - - snippet node -end diff --git a/src/messages/js_expected_type_or_variable.cr b/src/messages/js_expected_type_or_variable.cr deleted file mode 100644 index 684b0398a..000000000 --- a/src/messages/js_expected_type_or_variable.cr +++ /dev/null @@ -1,15 +0,0 @@ -message JsExpectedTypeOrVariable do - title "Syntax Error" - - block do - text "The type of" - bold "inlined JavaScript" - text "must be defined after the" - bold "as" - text "keyword." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/locale_expected_closing_bracket.cr b/src/messages/locale_expected_closing_bracket.cr deleted file mode 100644 index a6b94a825..000000000 --- a/src/messages/locale_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message LocaleExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "locale", got - - snippet node -end diff --git a/src/messages/locale_expected_language.cr b/src/messages/locale_expected_language.cr deleted file mode 100644 index 93af3a972..000000000 --- a/src/messages/locale_expected_language.cr +++ /dev/null @@ -1,13 +0,0 @@ -message LocaleExpectedLanguage do - title "Syntax Error" - - block do - text "I was looking for the" - bold "language of a locale" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/locale_expected_opening_bracket.cr b/src/messages/locale_expected_opening_bracket.cr deleted file mode 100644 index f109707cc..000000000 --- a/src/messages/locale_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message LocaleExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "locale", got - - snippet node -end diff --git a/src/messages/member_access_expected_variable.cr b/src/messages/member_access_expected_variable.cr deleted file mode 100644 index 181a51841..000000000 --- a/src/messages/member_access_expected_variable.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MemberAccessExpectedVariable do - title "Syntax Error" - - block do - text "I was looking for the name of the field of a record to access but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/mint_json_application_invalid.cr b/src/messages/mint_json_application_invalid.cr deleted file mode 100644 index 72a9b252a..000000000 --- a/src/messages/mint_json_application_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonApplicationInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "application object" - text "of a" - bold "mint.json" - text "file:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_application_invalid_key.cr b/src/messages/mint_json_application_invalid_key.cr deleted file mode 100644 index 334cd1dd0..000000000 --- a/src/messages/mint_json_application_invalid_key.cr +++ /dev/null @@ -1,14 +0,0 @@ -message MintJsonApplicationInvalidKey do - title "mint.json Error" - - block do - text "The" - bold "application object" - text "of a" - bold "mint.json" - text "file has an invalid key:" - bold key - end - - snippet node -end diff --git a/src/messages/mint_json_application_name_invalid.cr b/src/messages/mint_json_application_name_invalid.cr deleted file mode 100644 index 9663107d8..000000000 --- a/src/messages/mint_json_application_name_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonApplicationNameInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "name field" - text "of an" - bold "application" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_css_prefix_invalid.cr b/src/messages/mint_json_css_prefix_invalid.cr deleted file mode 100644 index e4135a49d..000000000 --- a/src/messages/mint_json_css_prefix_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonCssPrefixInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "css-prefix field" - text "of an" - bold "application" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_dependencies_invalid.cr b/src/messages/mint_json_dependencies_invalid.cr deleted file mode 100644 index b7005b2e6..000000000 --- a/src/messages/mint_json_dependencies_invalid.cr +++ /dev/null @@ -1,17 +0,0 @@ -message MintJsonDependenciesInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "dependencies" - text "field of a mint.json file." - end - - block do - text "The" - bold "dependencies" - text "field lists all the dependencies for the application." - end - - snippet node -end diff --git a/src/messages/mint_json_dependency_constraint_invalid.cr b/src/messages/mint_json_dependency_constraint_invalid.cr deleted file mode 100644 index 2bb3150b7..000000000 --- a/src/messages/mint_json_dependency_constraint_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonDependencyConstraintInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "constraint" - text "of a dependency:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_dependency_invalid.cr b/src/messages/mint_json_dependency_invalid.cr deleted file mode 100644 index b295dd7ee..000000000 --- a/src/messages/mint_json_dependency_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonDependencyInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing a" - bold "dependency" - text "of a mint.json file:" - end - - snippet node -end diff --git a/src/messages/mint_json_dependency_invalid_constraint.cr b/src/messages/mint_json_dependency_invalid_constraint.cr deleted file mode 100644 index 7275ae262..000000000 --- a/src/messages/mint_json_dependency_invalid_constraint.cr +++ /dev/null @@ -1,30 +0,0 @@ -message MintJsonDependencyInvalidConstraint do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "constraint" - text "of a dependency" - end - - block do - text "The constraint of a dependency is either in this format:" - end - block do - bold "0.0.0 <= v < 1.0.0" - end - - block do - text "or a git tag / commit / branch followed by the version:" - end - - block do - bold "master:0.1.0" - end - - block do - text "I could not find either." - end - - snippet node -end diff --git a/src/messages/mint_json_dependency_not_installed.cr b/src/messages/mint_json_dependency_not_installed.cr deleted file mode 100644 index 05715db9d..000000000 --- a/src/messages/mint_json_dependency_not_installed.cr +++ /dev/null @@ -1,23 +0,0 @@ -message MintJsonDependencyNotInstalled do - title "mint.json Error" - - block do - text "Not all" - bold "dependencies" - text "in your mint.json file are installed." - end - - block do - text "The dependency" - bold name - text "was expected to be in the" - bold ".mint/packages/#{name}" - text "directory." - end - - block do - text "Usually you can fix this by running the" - bold "mint install" - text "command." - end -end diff --git a/src/messages/mint_json_display_invalid.cr b/src/messages/mint_json_display_invalid.cr deleted file mode 100644 index fac76049b..000000000 --- a/src/messages/mint_json_display_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonDisplayInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "display field" - text "of an" - bold "application" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_external_invalid.cr b/src/messages/mint_json_external_invalid.cr deleted file mode 100644 index b8aa6da06..000000000 --- a/src/messages/mint_json_external_invalid.cr +++ /dev/null @@ -1,25 +0,0 @@ -message MintJsonExternalInvalid do - title "mint.json Error" - - block do - text "The" - bold "external" - text "field contain at least one item." - end - - block do - text "The" - bold "javascripts" - text "field lists all JavaScript files (relative to the mint.json file)" - text "which should be compiled alongside the application." - end - - block do - text "The" - bold "stylesheets" - text "field lists all CSS files (relative to the mint.json file)" - text "which should be included alongside the application." - end - - snippet node -end diff --git a/src/messages/mint_json_external_javascript_invalid.cr b/src/messages/mint_json_external_javascript_invalid.cr deleted file mode 100644 index 56b18cc3f..000000000 --- a/src/messages/mint_json_external_javascript_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonExternalJavascriptInvalid do - title "mint.json Error" - - block do - text "All entries in the" - bold "javascripts" - text "array should be string." - end - - snippet node, "I found one that it is not:" -end diff --git a/src/messages/mint_json_external_javascript_not_exists.cr b/src/messages/mint_json_external_javascript_not_exists.cr deleted file mode 100644 index 6a4d5ac4b..000000000 --- a/src/messages/mint_json_external_javascript_not_exists.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonExternalJavascriptNotExists do - title "mint.json Error" - - block do - text "The external JavaScript file" - bold path - text "does not exist." - end - - snippet node -end diff --git a/src/messages/mint_json_external_javascripts_invalid.cr b/src/messages/mint_json_external_javascripts_invalid.cr deleted file mode 100644 index 5a17a9421..000000000 --- a/src/messages/mint_json_external_javascripts_invalid.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonExternalJavascriptsInvalid do - title "mint.json Error" - - block do - text "The" - bold "javascripts" - text "field should be an array." - end - - block do - text "The" - bold "javascripts" - text "field lists all JavaScript files (relative to the mint.json file)" - text "which should be compiled alongside the application." - end - - snippet node -end diff --git a/src/messages/mint_json_external_stylesheet_invalid.cr b/src/messages/mint_json_external_stylesheet_invalid.cr deleted file mode 100644 index 3c1e7aed9..000000000 --- a/src/messages/mint_json_external_stylesheet_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonExternalStylesheetInvalid do - title "mint.json Error" - - block do - text "All entries in the" - bold "stylesheets" - text "array should be string." - end - - snippet node, "I found one that it is not:" -end diff --git a/src/messages/mint_json_external_stylesheet_not_exists.cr b/src/messages/mint_json_external_stylesheet_not_exists.cr deleted file mode 100644 index 9587badee..000000000 --- a/src/messages/mint_json_external_stylesheet_not_exists.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonExternalStylesheetNotExists do - title "mint.json Error" - - block do - text "The external stylesheet file" - bold path - text "does not exist." - end - - snippet node -end diff --git a/src/messages/mint_json_external_stylesheets_invalid.cr b/src/messages/mint_json_external_stylesheets_invalid.cr deleted file mode 100644 index 276436b4d..000000000 --- a/src/messages/mint_json_external_stylesheets_invalid.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonExternalStylesheetsInvalid do - title "mint.json Error" - - block do - text "The" - bold "stylesheets" - text "field should be an array." - end - - block do - text "The" - bold "stylesheets" - text "field lists all CSS files (relative to the mint.json file)" - text "which should be included alongside the application." - end - - snippet node -end diff --git a/src/messages/mint_json_formatter_config_invalid.cr b/src/messages/mint_json_formatter_config_invalid.cr deleted file mode 100644 index 2f993534b..000000000 --- a/src/messages/mint_json_formatter_config_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonFormatterConfigInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "formatter-config" - text "object of a" - bold "mint.json" - text "file:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_formatter_config_invalid_key.cr b/src/messages/mint_json_formatter_config_invalid_key.cr deleted file mode 100644 index a2843384f..000000000 --- a/src/messages/mint_json_formatter_config_invalid_key.cr +++ /dev/null @@ -1,14 +0,0 @@ -message MintJsonFormatterConfigInvalidKey do - title "mint.json Error" - - block do - text "The" - bold "formatter-config" - text "object of a" - bold "mint.json" - text "file has an invalid key:" - bold key - end - - snippet node -end diff --git a/src/messages/mint_json_head_not_exists.cr b/src/messages/mint_json_head_not_exists.cr deleted file mode 100644 index b3eef4144..000000000 --- a/src/messages/mint_json_head_not_exists.cr +++ /dev/null @@ -1,25 +0,0 @@ -message MintJsonHeadNotExists do - title "mint.json Error" - - block do - text "The" - bold "head" - text "field of" - bold "the application object" - text "points to a file that does not exists." - end - - block do - text "The" - bold "head" - text "field if exists should point to a HTML file." - end - - block do - text "That HTML file will be injected to the HEAD of the generated HTML." - text "It is used to include external dependencies" - text "(CSS, JS, analytics, etc...)" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_head_not_string.cr b/src/messages/mint_json_head_not_string.cr deleted file mode 100644 index eb3f28ccf..000000000 --- a/src/messages/mint_json_head_not_string.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonHeadNotString do - title "mint.json Error" - - block do - text "The" - bold "head" - text "field of" - bold "the application object" - text "is not string:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_icon_not_exists.cr b/src/messages/mint_json_icon_not_exists.cr deleted file mode 100644 index 77efa13e0..000000000 --- a/src/messages/mint_json_icon_not_exists.cr +++ /dev/null @@ -1,23 +0,0 @@ -message MintJsonIconNotExists do - title "mint.json Error" - - block do - text "The" - bold "icon" - text "field of" - bold "the application object" - text "points to a file that does not exists." - end - - block do - text "The" - bold "icon" - text "field if exists should point to an image." - end - - block do - text "That image will used to generate favicons for the application." - end - - snippet node, nil -end diff --git a/src/messages/mint_json_icon_not_string.cr b/src/messages/mint_json_icon_not_string.cr deleted file mode 100644 index ea9d0c175..000000000 --- a/src/messages/mint_json_icon_not_string.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonIconNotString do - title "mint.json Error" - - block do - text "The" - bold "icon" - text "field of" - bold "the application object" - text "is not string:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_indent_size_invalid.cr b/src/messages/mint_json_indent_size_invalid.cr deleted file mode 100644 index 3d65eb7a0..000000000 --- a/src/messages/mint_json_indent_size_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonIndentSizeInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "indent-size field" - text "of an" - bold "formatter-config" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_invalid_file.cr b/src/messages/mint_json_invalid_file.cr deleted file mode 100644 index 7223360bf..000000000 --- a/src/messages/mint_json_invalid_file.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonInvalidFile do - title "mint.json Error" - - block do - text "There was a problem when I was trying to open a" - bold "mint.json" - text "file:" - bold path - end - - block do - text "The error I got is this:" - end - - block do - bold result - end -end diff --git a/src/messages/mint_json_invalid_json.cr b/src/messages/mint_json_invalid_json.cr deleted file mode 100644 index 6d0a90c10..000000000 --- a/src/messages/mint_json_invalid_json.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonInvalidJson do - title "mint.json Error" - - block do - text "I could not parse the following" - bold "mint.json" - text "file:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_keyword_not_string.cr b/src/messages/mint_json_keyword_not_string.cr deleted file mode 100644 index b8c7ba17a..000000000 --- a/src/messages/mint_json_keyword_not_string.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonKeywordNotString do - title "mint.json Error" - - block do - text "A provided" - bold "keyword" - text "is not a string:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_keywords_invalid.cr b/src/messages/mint_json_keywords_invalid.cr deleted file mode 100644 index ade2362a1..000000000 --- a/src/messages/mint_json_keywords_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonKeywordsInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "keywords array" - text "of a meta object:" - end - - snippet node -end diff --git a/src/messages/mint_json_meta_invalid.cr b/src/messages/mint_json_meta_invalid.cr deleted file mode 100644 index d964f59da..000000000 --- a/src/messages/mint_json_meta_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonMetaInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "meta object" - text "of an" - bold "application object" - text "file:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_meta_value_not_string.cr b/src/messages/mint_json_meta_value_not_string.cr deleted file mode 100644 index 4ec0b783a..000000000 --- a/src/messages/mint_json_meta_value_not_string.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonMetaValueNotString do - title "mint.json Error" - - block do - text "The" - bold "value" - text "of a" - bold "meta field" - text "is not a string:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_mint_version_empty.cr b/src/messages/mint_json_mint_version_empty.cr deleted file mode 100644 index 9519c3ac8..000000000 --- a/src/messages/mint_json_mint_version_empty.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonMintVersionEmpty do - title "mint.json Error" - - block do - text "The" - bold "mint-version" - text "field in your" - bold "mint.json" - text "file is empty." - end - - snippet node, nil -end diff --git a/src/messages/mint_json_mint_version_invalid.cr b/src/messages/mint_json_mint_version_invalid.cr deleted file mode 100644 index 58243e961..000000000 --- a/src/messages/mint_json_mint_version_invalid.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonMintVersionInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "Mint version constraint." - end - - block do - text "The version constraint should be in this format:" - end - - block do - bold "0.0.0 <= v < 1.0.0" - end - - snippet node -end diff --git a/src/messages/mint_json_mint_version_mismatch.cr b/src/messages/mint_json_mint_version_mismatch.cr deleted file mode 100644 index c4814417f..000000000 --- a/src/messages/mint_json_mint_version_mismatch.cr +++ /dev/null @@ -1,22 +0,0 @@ -message MintJsonMintVersionMismatch do - title "mint.json Error" - - block do - text "The" - bold "mint-version" - text "field in your" - bold "mint.json" - text "file does not match your current version of Mint." - end - - block do - text "I was looking for" - code expected_version - - text "but found" - code current_version - text "instead." - end - - snippet node -end diff --git a/src/messages/mint_json_mint_version_not_string.cr b/src/messages/mint_json_mint_version_not_string.cr deleted file mode 100644 index e545d5c41..000000000 --- a/src/messages/mint_json_mint_version_not_string.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonMintVersionNotString do - title "mint.json Error" - - block do - text "The" - bold "mint-version" - text "field in your" - bold "mint.json" - text "file is not a string." - end - - snippet node, nil -end diff --git a/src/messages/mint_json_name_empty.cr b/src/messages/mint_json_name_empty.cr deleted file mode 100644 index 6d94a10ad..000000000 --- a/src/messages/mint_json_name_empty.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonNameEmpty do - title "mint.json Error" - - block do - text "The" - bold "name" - text "field of a" - bold "mint.json" - text "file is empty:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_name_not_string.cr b/src/messages/mint_json_name_not_string.cr deleted file mode 100644 index e2467cbc2..000000000 --- a/src/messages/mint_json_name_not_string.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonNameNotString do - title "mint.json Error" - - block do - text "The" - bold "name" - text "field of a" - bold "mint.json" - text "file is not a string." - end - - snippet node, nil -end diff --git a/src/messages/mint_json_orientation_invalid.cr b/src/messages/mint_json_orientation_invalid.cr deleted file mode 100644 index 95588ec60..000000000 --- a/src/messages/mint_json_orientation_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonOrientationInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "orientation field" - text "of an" - bold "application" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_root_invalid_key.cr b/src/messages/mint_json_root_invalid_key.cr deleted file mode 100644 index 879429d7d..000000000 --- a/src/messages/mint_json_root_invalid_key.cr +++ /dev/null @@ -1,12 +0,0 @@ -message MintJsonRootInvalidKey do - title "mint.json Error" - - block do - text "The root object of a" - bold "mint.json" - text "file has an invalid key:" - bold key - end - - snippet node -end diff --git a/src/messages/mint_json_root_not_an_object.cr b/src/messages/mint_json_root_not_an_object.cr deleted file mode 100644 index 0b740ac86..000000000 --- a/src/messages/mint_json_root_not_an_object.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonRootNotAnObject do - title "mint.json Error" - - block do - text "There was a problem when parsing" - bold "mint.json" - text "file." - end - - snippet node -end diff --git a/src/messages/mint_json_source_directories_empty.cr b/src/messages/mint_json_source_directories_empty.cr deleted file mode 100644 index 395ecd35f..000000000 --- a/src/messages/mint_json_source_directories_empty.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonSourceDirectoriesEmpty do - title "mint.json Error" - - block do - text "The" - bold "source-directories" - text "array should not be empty." - end - - block do - text "The" - bold "source-directories" - text "field lists all directories (relative to the mint.json file)" - text "which contain the source files of the application." - end - - snippet node -end diff --git a/src/messages/mint_json_source_directories_invalid.cr b/src/messages/mint_json_source_directories_invalid.cr deleted file mode 100644 index cb66509a1..000000000 --- a/src/messages/mint_json_source_directories_invalid.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonSourceDirectoriesInvalid do - title "mint.json Error" - - block do - text "The" - bold "source-directories" - text "field should be an array." - end - - block do - text "The" - bold "source-directories" - text "field lists all directories (relative to the mint.json file)" - text "which contain the source files of the application." - end - - snippet node -end diff --git a/src/messages/mint_json_source_directory_invalid.cr b/src/messages/mint_json_source_directory_invalid.cr deleted file mode 100644 index 68c77e230..000000000 --- a/src/messages/mint_json_source_directory_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonSourceDirectoryInvalid do - title "mint.json Error" - - block do - text "All entries in the" - bold "source-directories" - text "array should be string." - end - - snippet node, "I found one that it is not:" -end diff --git a/src/messages/mint_json_source_directory_not_exists.cr b/src/messages/mint_json_source_directory_not_exists.cr deleted file mode 100644 index 4847d0dcf..000000000 --- a/src/messages/mint_json_source_directory_not_exists.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonSourceDirectoryNotExists do - title "mint.json Error" - - block do - text "The source directory" - bold directory - text "does not exists." - end - - snippet node -end diff --git a/src/messages/mint_json_test_directories_invalid.cr b/src/messages/mint_json_test_directories_invalid.cr deleted file mode 100644 index 3a1612050..000000000 --- a/src/messages/mint_json_test_directories_invalid.cr +++ /dev/null @@ -1,18 +0,0 @@ -message MintJsonTestDirectoriesInvalid do - title "mint.json Error" - - block do - text "The" - bold "test-directories" - text "field should be an array." - end - - block do - text "The" - bold "test-directories" - text "field lists all directories (relative to the mint.json file)" - text "which contain the test files of the application." - end - - snippet node -end diff --git a/src/messages/mint_json_test_directory_invalid.cr b/src/messages/mint_json_test_directory_invalid.cr deleted file mode 100644 index d219474cf..000000000 --- a/src/messages/mint_json_test_directory_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonTestDirectoryInvalid do - title "mint.json Error" - - block do - text "All entries in the" - bold "test-directories" - text "array should be string." - end - - snippet node, "I found one that it is not:" -end diff --git a/src/messages/mint_json_test_directory_not_exists.cr b/src/messages/mint_json_test_directory_not_exists.cr deleted file mode 100644 index 86d7f789c..000000000 --- a/src/messages/mint_json_test_directory_not_exists.cr +++ /dev/null @@ -1,11 +0,0 @@ -message MintJsonTestDirectoryNotExists do - title "mint.json Error" - - block do - text "The test directory" - bold directory - text "does not exists." - end - - snippet node -end diff --git a/src/messages/mint_json_theme_invalid.cr b/src/messages/mint_json_theme_invalid.cr deleted file mode 100644 index 29e8fcb89..000000000 --- a/src/messages/mint_json_theme_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonThemeInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "theme field" - text "of an" - bold "application" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_title_empty.cr b/src/messages/mint_json_title_empty.cr deleted file mode 100644 index 0098d591e..000000000 --- a/src/messages/mint_json_title_empty.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonTitleEmpty do - title "mint.json Error" - - block do - text "The" - bold "title" - text "field of an" - bold "application object" - text "is empty:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_title_invalid.cr b/src/messages/mint_json_title_invalid.cr deleted file mode 100644 index 1e5b76c31..000000000 --- a/src/messages/mint_json_title_invalid.cr +++ /dev/null @@ -1,13 +0,0 @@ -message MintJsonTitleInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "title field" - text "of an" - bold "application" - text "object:" - end - - snippet node, nil -end diff --git a/src/messages/mint_json_web_components_invalid.cr b/src/messages/mint_json_web_components_invalid.cr deleted file mode 100644 index 3c972dff9..000000000 --- a/src/messages/mint_json_web_components_invalid.cr +++ /dev/null @@ -1,10 +0,0 @@ -message MintJsonWebComponentsInvalid do - title "mint.json Error" - - block do - text "There was a problem when parsing the" - bold "web-components object:" - end - - snippet node, nil -end diff --git a/src/messages/module_access_expected_function.cr b/src/messages/module_access_expected_function.cr deleted file mode 100644 index 51b3fdf4f..000000000 --- a/src/messages/module_access_expected_function.cr +++ /dev/null @@ -1,13 +0,0 @@ -message ModuleAccessExpectedFunction do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name of the function" - text "of a module, but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/module_access_not_found_function.cr b/src/messages/module_access_not_found_function.cr deleted file mode 100644 index 1a70e4f64..000000000 --- a/src/messages/module_access_not_found_function.cr +++ /dev/null @@ -1,12 +0,0 @@ -message ModuleAccessNotFoundFunction do - title "Type Error" - - block do - text "The entity" - bold name - text "you tried to reference does not exists in the module or store" - bold entity - end - - snippet node -end diff --git a/src/messages/module_access_not_found_module.cr b/src/messages/module_access_not_found_module.cr deleted file mode 100644 index 538c8e1ff..000000000 --- a/src/messages/module_access_not_found_module.cr +++ /dev/null @@ -1,10 +0,0 @@ -message ModuleAccessNotFoundModule do - title "Type Error" - - block do - text "I cannot find a module or store with the name" - bold name - end - - snippet node -end diff --git a/src/messages/module_entity_name_conflict.cr b/src/messages/module_entity_name_conflict.cr deleted file mode 100644 index 510895b43..000000000 --- a/src/messages/module_entity_name_conflict.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ModuleEntityNameConflict do - title "Type Error" - - block do - text "There is already a" - bold what - text "with the name" - bold name - text "in this module." - end - - snippet node, "You are trying to define something with the same name here:" - snippet other, "The #{what} is defined here:" -end diff --git a/src/messages/module_expected_closing_bracket.cr b/src/messages/module_expected_closing_bracket.cr deleted file mode 100644 index cf96e1bc4..000000000 --- a/src/messages/module_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ModuleExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "module", got - - snippet node -end diff --git a/src/messages/module_expected_name.cr b/src/messages/module_expected_name.cr deleted file mode 100644 index 775ab11ad..000000000 --- a/src/messages/module_expected_name.cr +++ /dev/null @@ -1,18 +0,0 @@ -message ModuleExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name of a module" - text "but found" - code got - text "instead." - end - - block do - text "The name of a module must start with an uppercase letter and only" - text "contain lowercase, uppercase letters and numbers." - end - - snippet node -end diff --git a/src/messages/module_expected_opening_bracket.cr b/src/messages/module_expected_opening_bracket.cr deleted file mode 100644 index deb8904ff..000000000 --- a/src/messages/module_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ModuleExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "module", got - - snippet node -end diff --git a/src/messages/negated_expression_expected_expression.cr b/src/messages/negated_expression_expected_expression.cr deleted file mode 100644 index 1a5086f52..000000000 --- a/src/messages/negated_expression_expected_expression.cr +++ /dev/null @@ -1,11 +0,0 @@ -message NegatedExpressionExpectedExpression do - title "Syntax Error" - - block do - text "A negated expression must have exactly one expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/negated_expression_not_bool.cr b/src/messages/negated_expression_not_bool.cr deleted file mode 100644 index 681521bd9..000000000 --- a/src/messages/negated_expression_not_bool.cr +++ /dev/null @@ -1,11 +0,0 @@ -message NegatedExpressionNotBool do - title "Type Error" - - block do - text "A negated expressions expression must evaluate to bool." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/next_call_expected_record.cr b/src/messages/next_call_expected_record.cr deleted file mode 100644 index a3a568ed7..000000000 --- a/src/messages/next_call_expected_record.cr +++ /dev/null @@ -1,15 +0,0 @@ -message NextCallExpectedRecord do - title "Syntax Error" - - block do - text "I was looking for a" - bold "record, record update or variable" - text "for a" - bold "next call" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/next_call_invalid_invocation.cr b/src/messages/next_call_invalid_invocation.cr deleted file mode 100644 index 739925767..000000000 --- a/src/messages/next_call_invalid_invocation.cr +++ /dev/null @@ -1,11 +0,0 @@ -message NextCallInvalidInvocation do - title "Type Error" - - block do - text "A" - bold "next call" - text "can only called inside a component or store." - end - - snippet node -end diff --git a/src/messages/next_call_state_not_found.cr b/src/messages/next_call_state_not_found.cr deleted file mode 100644 index 16c7d29f5..000000000 --- a/src/messages/next_call_state_not_found.cr +++ /dev/null @@ -1,11 +0,0 @@ -message NextCallStateNotFound do - title "Type Error" - - block do - text "I was looking for a state named" - bold name - text "but could not find it." - end - - snippet node -end diff --git a/src/messages/next_call_state_type_mismatch.cr b/src/messages/next_call_state_type_mismatch.cr deleted file mode 100644 index c1b99c390..000000000 --- a/src/messages/next_call_state_type_mismatch.cr +++ /dev/null @@ -1,20 +0,0 @@ -message NextCallStateTypeMismatch do - title "Type Error" - - block do - text "You were trying to assign an incompatible value to the status state." - end - - block do - text "The type of the state is:" - bold expected - end - - block do - text "But the type you are trying to assign to it:" - bold got - end - - snippet node, "Here is where you did the assignment:" - snippet state, "And here is where the state is defined:" -end diff --git a/src/messages/number_literal_expected_decimal.cr b/src/messages/number_literal_expected_decimal.cr deleted file mode 100644 index b96854656..000000000 --- a/src/messages/number_literal_expected_decimal.cr +++ /dev/null @@ -1,15 +0,0 @@ -message NumberLiteralExpectedDecimal do - title "Syntax Error" - - block do - text "I was looking for the" - bold "decimal part" - text "of a" - bold "number" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/operation_expected_expression.cr b/src/messages/operation_expected_expression.cr deleted file mode 100644 index 5ce66ad5f..000000000 --- a/src/messages/operation_expected_expression.cr +++ /dev/null @@ -1,15 +0,0 @@ -message OperationExpectedExpression do - title "Syntax Error" - - block do - text "I was looking for the" - bold "right side expression" - text "of an" - bold "operation" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/operation_numeric_type_mismatch.cr b/src/messages/operation_numeric_type_mismatch.cr deleted file mode 100644 index aa1c21bd6..000000000 --- a/src/messages/operation_numeric_type_mismatch.cr +++ /dev/null @@ -1,14 +0,0 @@ -message OperationNumericTypeMismatch do - title "Type Error" - - block do - text "The type of the" - bold side - text "operand does not match the type of the operation:" - bold operator - end - - was_expecting_type TypeChecker::NUMBER, value - - snippet node -end diff --git a/src/messages/operation_or_not_maybe_or_result.cr b/src/messages/operation_or_not_maybe_or_result.cr deleted file mode 100644 index 2d54f8988..000000000 --- a/src/messages/operation_or_not_maybe_or_result.cr +++ /dev/null @@ -1,15 +0,0 @@ -message OperationOrNotMaybeOrResult do - title "Type Error" - - block do - text "For the" - bold "or" - text "operation the" - bold "left operand" - text "is invalid." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/operation_or_type_mismatch.cr b/src/messages/operation_or_type_mismatch.cr deleted file mode 100644 index 36900dcfb..000000000 --- a/src/messages/operation_or_type_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message OperationOrTypeMismatch do - title "Type Error" - - block do - text "The type of the default value does not match the type of the" - text "parameter of the maybe." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/operation_pipe_ambiguous.cr b/src/messages/operation_pipe_ambiguous.cr deleted file mode 100644 index 32fe83901..000000000 --- a/src/messages/operation_pipe_ambiguous.cr +++ /dev/null @@ -1,13 +0,0 @@ -message OperationPipeAmbiguous do - title "Type Error" - - block do - text "We cannot determine the order of the operands because the pipe makes it ambiguous." - end - - block do - text "Wrap operands in parentheses to avoid ambiguity." - end - - snippet node -end diff --git a/src/messages/operation_plus_type_mismatch.cr b/src/messages/operation_plus_type_mismatch.cr deleted file mode 100644 index 05c99dae5..000000000 --- a/src/messages/operation_plus_type_mismatch.cr +++ /dev/null @@ -1,20 +0,0 @@ -message OperationPlusTypeMismatch do - title "Type Error" - - block do - text "The type of the" - bold side - text "operand does not match the type of the operation:" - bold "+" - end - - block do - text "I was expecting one of these types:" - end - - pre "Number, String" - - type_with_text value, "Instead it is:" - - snippet node -end diff --git a/src/messages/operation_type_mismatch.cr b/src/messages/operation_type_mismatch.cr deleted file mode 100644 index 5b6271d69..000000000 --- a/src/messages/operation_type_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message OperationTypeMismatch do - title "Type Error" - - block do - text "The type of the right operand does not match the type of the" - text "left operand." - end - - was_expecting_type left, right - - snippet node -end diff --git a/src/messages/pipe_expected_call.cr b/src/messages/pipe_expected_call.cr deleted file mode 100644 index 5d7e846fb..000000000 --- a/src/messages/pipe_expected_call.cr +++ /dev/null @@ -1,11 +0,0 @@ -message PipeExpectedCall do - title "Syntax Error" - - block do - text "I was looking for a function to pipe the result into but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/property_expected_default_value.cr b/src/messages/property_expected_default_value.cr deleted file mode 100644 index 0365703cd..000000000 --- a/src/messages/property_expected_default_value.cr +++ /dev/null @@ -1,13 +0,0 @@ -message PropertyExpectedDefaultValue do - title "Syntax Error" - - block do - text "The" - bold "default value" - text "of a property must be defined after the equal sign." - end - - was_looking_for "default value", got - - snippet node -end diff --git a/src/messages/property_expected_name.cr b/src/messages/property_expected_name.cr deleted file mode 100644 index ffe64e7fc..000000000 --- a/src/messages/property_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message PropertyExpectedName do - title "Syntax Error" - - was_looking_for "name of a property", got - - snippet node -end diff --git a/src/messages/property_expected_type.cr b/src/messages/property_expected_type.cr deleted file mode 100644 index d4772b137..000000000 --- a/src/messages/property_expected_type.cr +++ /dev/null @@ -1,11 +0,0 @@ -message PropertyExpectedType do - title "Syntax Error" - - block do - text "All properties must declare their type." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/property_type_mismatch.cr b/src/messages/property_type_mismatch.cr deleted file mode 100644 index 985da71ae..000000000 --- a/src/messages/property_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message PropertyTypeMismatch do - title "Type Error" - - block do - text "The type of the default value of the" - bold name - text "property does not match its type annotation." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/property_type_or_default_needed.cr b/src/messages/property_type_or_default_needed.cr deleted file mode 100644 index a079d65c7..000000000 --- a/src/messages/property_type_or_default_needed.cr +++ /dev/null @@ -1,13 +0,0 @@ -message PropertyTypeOrDefaultNeeded do - title "Type Error" - - block do - text "The" - bold "type" - text "or" - bold "default value" - text "of a property needs to be defined, but neither was." - end - - snippet node -end diff --git a/src/messages/property_with_type_variables.cr b/src/messages/property_with_type_variables.cr deleted file mode 100644 index 9bfe9d8dc..000000000 --- a/src/messages/property_with_type_variables.cr +++ /dev/null @@ -1,13 +0,0 @@ -message PropertyWithTypeVariables do - title "Type Error" - - block do - text "A properties type contains type variables." - end - - block do - text "Type variables in properties are not allow at this time." - end - - snippet node -end diff --git a/src/messages/provider_entity_name_conflict.cr b/src/messages/provider_entity_name_conflict.cr deleted file mode 100644 index 603f2c2dd..000000000 --- a/src/messages/provider_entity_name_conflict.cr +++ /dev/null @@ -1,14 +0,0 @@ -message ProviderEntityNameConflict do - title "Type Error" - - block do - text "There is already a" - bold what - text "with the name" - bold name - text "in this provider." - end - - snippet node, "You are trying to define something with the same name here:" - snippet other, "The #{what} is defined here:" -end diff --git a/src/messages/provider_expected_body.cr b/src/messages/provider_expected_body.cr deleted file mode 100644 index 64566fbdb..000000000 --- a/src/messages/provider_expected_body.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ProviderExpectedBody do - title "Syntax Error" - - was_looking_for "the implementation of a provider", got - - snippet node -end diff --git a/src/messages/provider_expected_closing_bracket.cr b/src/messages/provider_expected_closing_bracket.cr deleted file mode 100644 index 160fef141..000000000 --- a/src/messages/provider_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ProviderExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "provider", got - - snippet node -end diff --git a/src/messages/provider_expected_colon.cr b/src/messages/provider_expected_colon.cr deleted file mode 100644 index f2e069b36..000000000 --- a/src/messages/provider_expected_colon.cr +++ /dev/null @@ -1,17 +0,0 @@ -message ProviderExpectedColon do - title "Syntax Error" - - block do - text "The" - bold "name" - text "of a provider and the" - bold "type of its subscription" - text "must be separated by a" - bold "colon" - code ":" - end - - was_looking_for "colon", got, ":" - - snippet node -end diff --git a/src/messages/provider_expected_name.cr b/src/messages/provider_expected_name.cr deleted file mode 100644 index b832bb7ee..000000000 --- a/src/messages/provider_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ProviderExpectedName do - title "Syntax Error" - - was_looking_for "name of a provider", got - - snippet node -end diff --git a/src/messages/provider_expected_opening_bracket.cr b/src/messages/provider_expected_opening_bracket.cr deleted file mode 100644 index 694f50bfd..000000000 --- a/src/messages/provider_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message ProviderExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "provider", got - - snippet node -end diff --git a/src/messages/provider_expected_subscription.cr b/src/messages/provider_expected_subscription.cr deleted file mode 100644 index 9ec9ae717..000000000 --- a/src/messages/provider_expected_subscription.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ProviderExpectedSubscription do - title "Syntax Error" - - block do - text "I was looking for the" - bold "type of the subscription" - text "of a" - bold "provider" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/provider_not_found_subscription.cr b/src/messages/provider_not_found_subscription.cr deleted file mode 100644 index da5a74303..000000000 --- a/src/messages/provider_not_found_subscription.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ProviderNotFoundSubscription do - title "Type Error" - - block do - text "I was looking for the record type of the subscription" - bold name - text "but could not find it." - end - - snippet node -end diff --git a/src/messages/record_constructor_argument_size_mismatch.cr b/src/messages/record_constructor_argument_size_mismatch.cr deleted file mode 100644 index 28c69db1d..000000000 --- a/src/messages/record_constructor_argument_size_mismatch.cr +++ /dev/null @@ -1,14 +0,0 @@ -message RecordConstructorArgumentSizeMismatch do - title "Type Error" - - block do - text "The record you tried to create has" - bold size - text "fields, while you tried to create it with" - bold argument_size - end - - type record - - snippet node, "You tried to create it here:" -end diff --git a/src/messages/record_constructor_argument_type_mismatch.cr b/src/messages/record_constructor_argument_type_mismatch.cr deleted file mode 100644 index 72dcd6419..000000000 --- a/src/messages/record_constructor_argument_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message RecordConstructorArgumentTypeMismatch do - title "Type Error" - - block do - text "The supplied values type does not match the type" - text "of the field." - end - - type_with_text expected, "The type of the field is:" - type_with_text got, "You tried to supply it with:" - - snippet node -end diff --git a/src/messages/record_constructor_not_found_record.cr b/src/messages/record_constructor_not_found_record.cr deleted file mode 100644 index bfa76507f..000000000 --- a/src/messages/record_constructor_not_found_record.cr +++ /dev/null @@ -1,10 +0,0 @@ -message RecordConstructorNotFoundRecord do - title "Type Error" - - block do - text "I could not find a record with the name:" - bold name - end - - snippet node, "It was used here:" -end diff --git a/src/messages/record_definition_expected_closing_bracket.cr b/src/messages/record_definition_expected_closing_bracket.cr deleted file mode 100644 index 18a9103b7..000000000 --- a/src/messages/record_definition_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RecordDefinitionExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "record definition", got - - snippet node -end diff --git a/src/messages/record_definition_expected_name.cr b/src/messages/record_definition_expected_name.cr deleted file mode 100644 index 693c34e4a..000000000 --- a/src/messages/record_definition_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RecordDefinitionExpectedName do - title "Syntax Error" - - was_looking_for "name of a record", got - - snippet node -end diff --git a/src/messages/record_definition_expected_opening_bracket.cr b/src/messages/record_definition_expected_opening_bracket.cr deleted file mode 100644 index af680ae1e..000000000 --- a/src/messages/record_definition_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RecordDefinitionExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "record definition", got - - snippet node -end diff --git a/src/messages/record_definition_field_expected_colon.cr b/src/messages/record_definition_field_expected_colon.cr deleted file mode 100644 index c6631cfa4..000000000 --- a/src/messages/record_definition_field_expected_colon.cr +++ /dev/null @@ -1,17 +0,0 @@ -message RecordDefinitionFieldExpectedColon do - title "Syntax Error" - - block do - text "The" - bold "name" - text "of a record field and its" - bold "type" - text "must be separated by a" - bold "colon" - code ":" - end - - was_looking_for "colon", got, ":" - - snippet node -end diff --git a/src/messages/record_definition_field_expected_mapping.cr b/src/messages/record_definition_field_expected_mapping.cr deleted file mode 100644 index 2a4b8f422..000000000 --- a/src/messages/record_definition_field_expected_mapping.cr +++ /dev/null @@ -1,16 +0,0 @@ -message RecordDefinitionFieldExpectedMapping do - title "Syntax Error" - - block do - text "I was looking for the" - bold "key" - text "of which to decode the field from an object." - end - - block do - text "Instead I found" - code got - end - - snippet node -end diff --git a/src/messages/record_definition_field_expected_type.cr b/src/messages/record_definition_field_expected_type.cr deleted file mode 100644 index d9af1a3da..000000000 --- a/src/messages/record_definition_field_expected_type.cr +++ /dev/null @@ -1,11 +0,0 @@ -message RecordDefinitionFieldExpectedType do - title "Syntax Error" - - block do - text "All record fields must declare their type." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/record_fields_conflict.cr b/src/messages/record_fields_conflict.cr deleted file mode 100644 index cf92be2ef..000000000 --- a/src/messages/record_fields_conflict.cr +++ /dev/null @@ -1,12 +0,0 @@ -message RecordFieldsConflict do - title "Type Error" - - block do - text "There is already a" - bold "record" - text "with the same structure." - end - - snippet node, "One of them is here:" - snippet other, "The other is here:" -end diff --git a/src/messages/record_name_conflict.cr b/src/messages/record_name_conflict.cr deleted file mode 100644 index d09281e7d..000000000 --- a/src/messages/record_name_conflict.cr +++ /dev/null @@ -1,13 +0,0 @@ -message RecordNameConflict do - title "Type Error" - - block do - text "There is already a" - bold "record" - text "with the name:" - bold name - end - - snippet node, "One of them is here:" - snippet other, "The other is here:" -end diff --git a/src/messages/record_not_found_matching_record_definition.cr b/src/messages/record_not_found_matching_record_definition.cr deleted file mode 100644 index 564ee2a36..000000000 --- a/src/messages/record_not_found_matching_record_definition.cr +++ /dev/null @@ -1,11 +0,0 @@ -message RecordNotFoundMatchingRecordDefinition do - title "Type Error" - - block do - text "I could not find a record that matches this structure:" - end - - type structure - - snippet node, "It was used here:" -end diff --git a/src/messages/record_update_expected_closing_bracket.cr b/src/messages/record_update_expected_closing_bracket.cr deleted file mode 100644 index 346b7d33d..000000000 --- a/src/messages/record_update_expected_closing_bracket.cr +++ /dev/null @@ -1,13 +0,0 @@ -message RecordUpdateExpectedClosingBracket do - title "Syntax Error" - - block do - text "The" - bold "fields of a record update" - text "must be enclosed by brackets." - end - - was_looking_for "closing bracket", got, "}" - - snippet node -end diff --git a/src/messages/record_update_expected_fields.cr b/src/messages/record_update_expected_fields.cr deleted file mode 100644 index 742a33ac4..000000000 --- a/src/messages/record_update_expected_fields.cr +++ /dev/null @@ -1,13 +0,0 @@ -message RecordUpdateExpectedFields do - title "Syntax Error" - - block do - text "I was expecting" - bold "at least one field to update" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/record_update_not_found_key.cr b/src/messages/record_update_not_found_key.cr deleted file mode 100644 index 20ef0b607..000000000 --- a/src/messages/record_update_not_found_key.cr +++ /dev/null @@ -1,13 +0,0 @@ -message RecordUpdateNotFoundKey do - title "Type Error" - - block do - text "The field" - bold key - text "does not exists on the target record:" - end - - type target - - snippet node -end diff --git a/src/messages/record_update_not_updating_record.cr b/src/messages/record_update_not_updating_record.cr deleted file mode 100644 index 9951126e5..000000000 --- a/src/messages/record_update_not_updating_record.cr +++ /dev/null @@ -1,14 +0,0 @@ -message RecordUpdateNotUpdatingRecord do - title "Type Error" - - block do - text "The" - bold "target of a record update" - text "is not a record, instead it is:" - end - - type target - - snippet node, "Here is where you want to update it:" - snippet target_node, "Here is where the target is defined:" -end diff --git a/src/messages/record_update_type_mismatch.cr b/src/messages/record_update_type_mismatch.cr deleted file mode 100644 index 8ada06bf1..000000000 --- a/src/messages/record_update_type_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message RecordUpdateTypeMismatch do - title "Type Error" - - block do - text "One of the updated fields do not match its type." - end - - was_expecting_type expected, got - - snippet node, "The update is here:" - snippet target_node, "The target is defined here:" -end diff --git a/src/messages/record_with_holes.cr b/src/messages/record_with_holes.cr deleted file mode 100644 index fcce24176..000000000 --- a/src/messages/record_with_holes.cr +++ /dev/null @@ -1,9 +0,0 @@ -message RecordWithHoles do - title "Type Error" - - block do - text "Records with type variables are not allow at this time." - end - - snippet node, "The record in question is defined here:" -end diff --git a/src/messages/recursion.cr b/src/messages/recursion.cr deleted file mode 100644 index 0eb64ccc0..000000000 --- a/src/messages/recursion.cr +++ /dev/null @@ -1,11 +0,0 @@ -message Recursion do - title "Type Error" - - snippet node, "I found a recursion in the following snippet:" - - block do - text "Recursion is not supported at this time by the language." - end - - snippet caller_node, "The last step in the recursion was here:" -end diff --git a/src/messages/regexp_literal_expected_closing_slash.cr b/src/messages/regexp_literal_expected_closing_slash.cr deleted file mode 100644 index aed7acc2c..000000000 --- a/src/messages/regexp_literal_expected_closing_slash.cr +++ /dev/null @@ -1,16 +0,0 @@ -message RegexpLiteralExpectedClosingSlash do - title "Syntax Error" - - block do - text "I was looking for the" - bold "end slash" - code "/" - text "of a" - bold "regexp literal" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/repository_could_not_checkout.cr b/src/messages/repository_could_not_checkout.cr deleted file mode 100644 index 2a0228ca9..000000000 --- a/src/messages/repository_could_not_checkout.cr +++ /dev/null @@ -1,18 +0,0 @@ -message RepositoryCouldNotCheckout do - title "Install Error" - - block do - text "I could not checkout the version or tag:" - bold target - text "of the repository:" - bold url - end - - block do - text "The error I got from the git command is this:" - end - - block do - bold result.to_s.strip - end -end diff --git a/src/messages/repository_could_not_clone.cr b/src/messages/repository_could_not_clone.cr deleted file mode 100644 index faf268775..000000000 --- a/src/messages/repository_could_not_clone.cr +++ /dev/null @@ -1,16 +0,0 @@ -message RepositoryCouldNotClone do - title "Install Error" - - block do - text "I could not clone the repository:" - bold url - end - - block do - text "The error I got from the git command is this:" - end - - block do - bold result.to_s.strip - end -end diff --git a/src/messages/repository_could_not_get_versions.cr b/src/messages/repository_could_not_get_versions.cr deleted file mode 100644 index 451bf5088..000000000 --- a/src/messages/repository_could_not_get_versions.cr +++ /dev/null @@ -1,16 +0,0 @@ -message RepositoryCouldNotGetVersions do - title "Install Error" - - block do - text "I could not get the tags of the repository:" - bold url - end - - block do - text "The error I got from the git command is this:" - end - - block do - bold result.to_s.strip - end -end diff --git a/src/messages/repository_could_not_update.cr b/src/messages/repository_could_not_update.cr deleted file mode 100644 index 9bbf5048c..000000000 --- a/src/messages/repository_could_not_update.cr +++ /dev/null @@ -1,16 +0,0 @@ -message RepositoryCouldNotUpdate do - title "Install Error" - - block do - text "I could not update the repository:" - bold url - end - - block do - text "The error I got from the git command is this:" - end - - block do - bold result.to_s.strip - end -end diff --git a/src/messages/repository_invalid_mint_json.cr b/src/messages/repository_invalid_mint_json.cr deleted file mode 100644 index 42950b853..000000000 --- a/src/messages/repository_invalid_mint_json.cr +++ /dev/null @@ -1,10 +0,0 @@ -message RepositoryInvalidMintJson do - title "Install Error" - - block do - text "I could not parse the mint.json for the package:" - bold id - text "for the version or tag:" - bold target - end -end diff --git a/src/messages/repository_no_mint_json.cr b/src/messages/repository_no_mint_json.cr deleted file mode 100644 index 7bcac2a85..000000000 --- a/src/messages/repository_no_mint_json.cr +++ /dev/null @@ -1,10 +0,0 @@ -message RepositoryNoMintJson do - title "Install Error" - - block do - text "I could not find the mint.json for the package:" - bold id - text "for the version or tag:" - bold target - end -end diff --git a/src/messages/return_call_expected_expression.cr b/src/messages/return_call_expected_expression.cr deleted file mode 100644 index 572fc3aea..000000000 --- a/src/messages/return_call_expected_expression.cr +++ /dev/null @@ -1,15 +0,0 @@ -message ReturnCallExpectedExpression do - title "Syntax Error" - - block do - text "I was looking for an" - bold "expression" - text "for a" - bold "return call" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/return_call_invalid.cr b/src/messages/return_call_invalid.cr deleted file mode 100644 index 3fe2ec705..000000000 --- a/src/messages/return_call_invalid.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ReturnCallInvalid do - title "Type Error" - - block do - text "A" - bold "return call " - text "can only appear in a block as part of an or operation while destructuring or as a standalone expression." - end - - snippet node -end diff --git a/src/messages/return_call_type_mismatch.cr b/src/messages/return_call_type_mismatch.cr deleted file mode 100644 index cb45e65ab..000000000 --- a/src/messages/return_call_type_mismatch.cr +++ /dev/null @@ -1,11 +0,0 @@ -message ReturnCallTypeMismatch do - title "Type Error" - - block do - text "The type of a return call does not match the return type of the block." - end - - was_expecting_type expected, got - - snippet node, "It is here:" -end diff --git a/src/messages/route_expected_closing_bracket.cr b/src/messages/route_expected_closing_bracket.cr deleted file mode 100644 index 726955c5d..000000000 --- a/src/messages/route_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RouteExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "route", got - - snippet node -end diff --git a/src/messages/route_expected_closing_parentheses.cr b/src/messages/route_expected_closing_parentheses.cr deleted file mode 100644 index 8b6f6986b..000000000 --- a/src/messages/route_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message RouteExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "arguments" - text "of a" - bold "route" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/route_expected_expression.cr b/src/messages/route_expected_expression.cr deleted file mode 100644 index 8724a2234..000000000 --- a/src/messages/route_expected_expression.cr +++ /dev/null @@ -1,12 +0,0 @@ -message RouteExpectedExpression do - title "Syntax Error" - - block do - text "The body of a route must be a" - bold "single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/route_expected_opening_bracket.cr b/src/messages/route_expected_opening_bracket.cr deleted file mode 100644 index 522ff748f..000000000 --- a/src/messages/route_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RouteExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "route", got - - snippet node -end diff --git a/src/messages/route_param_invalid.cr b/src/messages/route_param_invalid.cr deleted file mode 100644 index 85182fb99..000000000 --- a/src/messages/route_param_invalid.cr +++ /dev/null @@ -1,22 +0,0 @@ -message RouteParamInvalid do - title "Type Error" - - block do - text "The type of parameter " - bold name - text "cannot be used in routes." - end - - type got - - block do - text "Only these types can be used as route params:" - end - - type_list [ - TypeChecker::STRING, - TypeChecker::NUMBER, - ] of TypeChecker::Checkable - - snippet node -end diff --git a/src/messages/routes_expected_closing_bracket.cr b/src/messages/routes_expected_closing_bracket.cr deleted file mode 100644 index a90e5af7a..000000000 --- a/src/messages/routes_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RoutesExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "routes block", got - - snippet node -end diff --git a/src/messages/routes_expected_opening_bracket.cr b/src/messages/routes_expected_opening_bracket.cr deleted file mode 100644 index cafbd0f4e..000000000 --- a/src/messages/routes_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message RoutesExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "routes block", got - - snippet node -end diff --git a/src/messages/routes_expected_route.cr b/src/messages/routes_expected_route.cr deleted file mode 100644 index bb11ef287..000000000 --- a/src/messages/routes_expected_route.cr +++ /dev/null @@ -1,13 +0,0 @@ -message RoutesExpectedRoute do - title "Syntax Error" - - block do - text "The body of a" - bold "routes block must contain at least" - bold "one route." - end - - was_looking_for "route", got - - snippet node -end diff --git a/src/messages/runtime_file_not_found.cr b/src/messages/runtime_file_not_found.cr deleted file mode 100644 index 0974f42ab..000000000 --- a/src/messages/runtime_file_not_found.cr +++ /dev/null @@ -1,9 +0,0 @@ -message RuntimeFileNotFound do - title "Runtime Error" - - block do - text "The specified runtime file" - code path - text "could not be found" - end -end diff --git a/src/messages/spread_expected_variable.cr b/src/messages/spread_expected_variable.cr deleted file mode 100644 index ee697a475..000000000 --- a/src/messages/spread_expected_variable.cr +++ /dev/null @@ -1,13 +0,0 @@ -message SpreadExpectedVariable do - title "Syntax Error" - - block do - text "Spread notation must have" - bold "a variable" - text "to hold the values." - end - - was_looking_for "variable", got - - snippet node -end diff --git a/src/messages/state_expected_default_value.cr b/src/messages/state_expected_default_value.cr deleted file mode 100644 index 3926c58eb..000000000 --- a/src/messages/state_expected_default_value.cr +++ /dev/null @@ -1,13 +0,0 @@ -message StateExpectedDefaultValue do - title "Syntax Error" - - block do - text "The" - bold "default value" - text "of a state must be defined after the equal sign." - end - - was_looking_for "default value", got - - snippet node -end diff --git a/src/messages/state_expected_equal_sign.cr b/src/messages/state_expected_equal_sign.cr deleted file mode 100644 index 269316fc1..000000000 --- a/src/messages/state_expected_equal_sign.cr +++ /dev/null @@ -1,16 +0,0 @@ -message StateExpectedEqualSign do - title "Syntax Error" - - block do - text "The" - bold "type" - text "of a state and its" - bold "default value" - text "must be separated by an" - bold "equal sign" - end - - was_looking_for "equal sign", got, "=" - - snippet node -end diff --git a/src/messages/state_expected_name.cr b/src/messages/state_expected_name.cr deleted file mode 100644 index 5066da67a..000000000 --- a/src/messages/state_expected_name.cr +++ /dev/null @@ -1,7 +0,0 @@ -message StateExpectedName do - title "Syntax Error" - - was_looking_for "name of a state", got - - snippet node -end diff --git a/src/messages/state_expected_type.cr b/src/messages/state_expected_type.cr deleted file mode 100644 index b781d4e35..000000000 --- a/src/messages/state_expected_type.cr +++ /dev/null @@ -1,11 +0,0 @@ -message StateExpectedType do - title "Syntax Error" - - block do - text "All states must declare their type." - end - - was_looking_for "type", got - - snippet node -end diff --git a/src/messages/state_type_mismatch.cr b/src/messages/state_type_mismatch.cr deleted file mode 100644 index e9b30f8aa..000000000 --- a/src/messages/state_type_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message StateTypeMismatch do - title "Type Error" - - block do - text "The type of the default value of the" - bold name - text "state does not match its type annotation." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/statement_last_target.cr b/src/messages/statement_last_target.cr deleted file mode 100644 index 799b110e7..000000000 --- a/src/messages/statement_last_target.cr +++ /dev/null @@ -1,13 +0,0 @@ -message StatementLastTarget do - title "Type Error" - - block do - text "The" - bold "last statement" - text "of a block cannot be an" - bold "assignment" - text "." - end - - snippet node -end diff --git a/src/messages/statement_return_required.cr b/src/messages/statement_return_required.cr deleted file mode 100644 index 302f27e09..000000000 --- a/src/messages/statement_return_required.cr +++ /dev/null @@ -1,13 +0,0 @@ -message StatementReturnRequired do - title "Type Error" - - block do - text "This" - bold "statement" - text "needs a " - bold "return call" - text "because the destructuring is not exhaustive." - end - - snippet node -end diff --git a/src/messages/store_entity_name_conflict.cr b/src/messages/store_entity_name_conflict.cr deleted file mode 100644 index aa92f82e6..000000000 --- a/src/messages/store_entity_name_conflict.cr +++ /dev/null @@ -1,14 +0,0 @@ -message StoreEntityNameConflict do - title "Type Error" - - block do - text "There is already a" - bold what - text "with the name:" - bold name - text "in this store." - end - - snippet node, "You are trying to define something with the same name here:" - snippet other, "The #{what} is defined here:" -end diff --git a/src/messages/store_expected_body.cr b/src/messages/store_expected_body.cr deleted file mode 100644 index 6987d1d7f..000000000 --- a/src/messages/store_expected_body.cr +++ /dev/null @@ -1,13 +0,0 @@ -message StoreExpectedBody do - title "Syntax Error" - - block do - text "I was looking for at least one" - bold "function, state or computed property" - text "for this store but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/store_expected_closing_bracket.cr b/src/messages/store_expected_closing_bracket.cr deleted file mode 100644 index f8f520787..000000000 --- a/src/messages/store_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message StoreExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "store", got - - snippet node -end diff --git a/src/messages/store_expected_name.cr b/src/messages/store_expected_name.cr deleted file mode 100644 index cd37df27e..000000000 --- a/src/messages/store_expected_name.cr +++ /dev/null @@ -1,18 +0,0 @@ -message StoreExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name of a store" - text "but found" - code got - text "instead." - end - - block do - text "The name of a store must start with an uppercase letter and only" - text "contain lowercase, uppercase letters and numbers." - end - - snippet node -end diff --git a/src/messages/store_expected_opening_bracket.cr b/src/messages/store_expected_opening_bracket.cr deleted file mode 100644 index b818b0aae..000000000 --- a/src/messages/store_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message StoreExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "store", got - - snippet node -end diff --git a/src/messages/string_expected_end_quote.cr b/src/messages/string_expected_end_quote.cr deleted file mode 100644 index bacb72854..000000000 --- a/src/messages/string_expected_end_quote.cr +++ /dev/null @@ -1,16 +0,0 @@ -message StringExpectedEndQuote do - title "Syntax Error" - - block do - text "I was looking for the" - bold "closing quote" - code "\"" - text "of a" - bold "string literal" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/string_expected_other_string.cr b/src/messages/string_expected_other_string.cr deleted file mode 100644 index 48ecf4456..000000000 --- a/src/messages/string_expected_other_string.cr +++ /dev/null @@ -1,16 +0,0 @@ -message StringExpectedOtherString do - title "Syntax Error" - - block do - text "I was looking for the" - bold "an other string literal" - text "after a" - bold "string separator" - code "\\" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/string_literal_interpolation_type_mismatch.cr b/src/messages/string_literal_interpolation_type_mismatch.cr deleted file mode 100644 index 388255a7d..000000000 --- a/src/messages/string_literal_interpolation_type_mismatch.cr +++ /dev/null @@ -1,12 +0,0 @@ -message StringLiteralInterpolationTypeMismatch do - title "Type Error" - - block do - text "An interpolation in string is causing a mismatch." - end - - type_with_text expected, "The expected type is:" - type_with_text got, "Instead it got:" - - snippet node, "It is here:" -end diff --git a/src/messages/style_expected_closing_bracket.cr b/src/messages/style_expected_closing_bracket.cr deleted file mode 100644 index dd7b6135a..000000000 --- a/src/messages/style_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message StyleExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "style", got - - snippet node -end diff --git a/src/messages/style_expected_closing_parentheses.cr b/src/messages/style_expected_closing_parentheses.cr deleted file mode 100644 index 6e1b59ab3..000000000 --- a/src/messages/style_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message StyleExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "arguments" - text "of a" - bold "style" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/style_expected_name.cr b/src/messages/style_expected_name.cr deleted file mode 100644 index 9d765c450..000000000 --- a/src/messages/style_expected_name.cr +++ /dev/null @@ -1,13 +0,0 @@ -message StyleExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name of a style" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/style_expected_opening_bracket.cr b/src/messages/style_expected_opening_bracket.cr deleted file mode 100644 index 44815638d..000000000 --- a/src/messages/style_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message StyleExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "style", got - - snippet node -end diff --git a/src/messages/suite_expected_closing_bracket.cr b/src/messages/suite_expected_closing_bracket.cr deleted file mode 100644 index aac00cae8..000000000 --- a/src/messages/suite_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message SuiteExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "test suite", got - - snippet node -end diff --git a/src/messages/suite_expected_name.cr b/src/messages/suite_expected_name.cr deleted file mode 100644 index 36fdc1c05..000000000 --- a/src/messages/suite_expected_name.cr +++ /dev/null @@ -1,15 +0,0 @@ -message SuiteExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name" - text "of a" - bold "test suite" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/suite_expected_opening_bracket.cr b/src/messages/suite_expected_opening_bracket.cr deleted file mode 100644 index 98e6cb38b..000000000 --- a/src/messages/suite_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message SuiteExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "test suite", got - - snippet node -end diff --git a/src/messages/suite_expected_tests.cr b/src/messages/suite_expected_tests.cr deleted file mode 100644 index 8426273b4..000000000 --- a/src/messages/suite_expected_tests.cr +++ /dev/null @@ -1,15 +0,0 @@ -message SuiteExpectedTests do - title "Syntax Error" - - block do - text "I was looking for at least one" - bold "test" - text "for a" - bold "test suite" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/svg_directive_expected_closing_parentheses.cr b/src/messages/svg_directive_expected_closing_parentheses.cr deleted file mode 100644 index 317024f14..000000000 --- a/src/messages/svg_directive_expected_closing_parentheses.cr +++ /dev/null @@ -1,15 +0,0 @@ -message SvgDirectiveExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "path" - text "of an" - bold "svg directive" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/svg_directive_expected_dimensions.cr b/src/messages/svg_directive_expected_dimensions.cr deleted file mode 100644 index 30a598037..000000000 --- a/src/messages/svg_directive_expected_dimensions.cr +++ /dev/null @@ -1,11 +0,0 @@ -message SvgDirectiveExpectedDimensions do - title "Syntax Error" - - block do - text "The svg specified for an svg directive does not have the following attributes:" - end - - list %w[width height viewBox] - - snippet node -end diff --git a/src/messages/svg_directive_expected_file.cr b/src/messages/svg_directive_expected_file.cr deleted file mode 100644 index 5a5a83a42..000000000 --- a/src/messages/svg_directive_expected_file.cr +++ /dev/null @@ -1,13 +0,0 @@ -message SvgDirectiveExpectedFile do - title "Syntax Error" - - block do - text "The svg specified for an svg directive does not exists." - end - - block do - text "The file should be here: #{path}" - end - - snippet node -end diff --git a/src/messages/svg_directive_expected_opening_parentheses.cr b/src/messages/svg_directive_expected_opening_parentheses.cr deleted file mode 100644 index 85a3151d2..000000000 --- a/src/messages/svg_directive_expected_opening_parentheses.cr +++ /dev/null @@ -1,16 +0,0 @@ -message SvgDirectiveExpectedOpeningParentheses do - title "Syntax Error" - - block do - text "I was looking for the " - bold "opening parenthesis " - code "(" - text "of an" - bold "svg directive " - text "but found " - code got - text " instead." - end - - snippet node -end diff --git a/src/messages/svg_directive_expected_path.cr b/src/messages/svg_directive_expected_path.cr deleted file mode 100644 index 8153e9e13..000000000 --- a/src/messages/svg_directive_expected_path.cr +++ /dev/null @@ -1,11 +0,0 @@ -message SvgDirectiveExpectedPath do - title "Syntax Error" - - block do - text "An svg directive must specify the path to the SVG file (relative to the current file)." - end - - was_looking_for "path", got - - snippet node -end diff --git a/src/messages/svg_directive_expected_svg.cr b/src/messages/svg_directive_expected_svg.cr deleted file mode 100644 index ec1b07bd7..000000000 --- a/src/messages/svg_directive_expected_svg.cr +++ /dev/null @@ -1,11 +0,0 @@ -message SvgDirectiveExpectedSvg do - title "Syntax Error" - - block do - text "The svg specified for an svg directive is not an SVG file (could not parse it)." - end - - list errors - - snippet node -end diff --git a/src/messages/svg_directive_expected_svg_tag.cr b/src/messages/svg_directive_expected_svg_tag.cr deleted file mode 100644 index ded067cb8..000000000 --- a/src/messages/svg_directive_expected_svg_tag.cr +++ /dev/null @@ -1,9 +0,0 @@ -message SvgDirectiveExpectedSvgTag do - title "Syntax Error" - - block do - text "The svg specified for an svg directive does not contain an svg tag." - end - - snippet node -end diff --git a/src/messages/test_expected_closing_bracket.cr b/src/messages/test_expected_closing_bracket.cr deleted file mode 100644 index d8e37950d..000000000 --- a/src/messages/test_expected_closing_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message TestExpectedClosingBracket do - title "Syntax Error" - - closing_bracket "test", got - - snippet node -end diff --git a/src/messages/test_expected_expression.cr b/src/messages/test_expected_expression.cr deleted file mode 100644 index 093c586b3..000000000 --- a/src/messages/test_expected_expression.cr +++ /dev/null @@ -1,19 +0,0 @@ -message TestExpectedExpression do - title "Syntax Error" - - block do - text "I was looking for the" - bold "expression" - text "of a" - bold "test" - text "but found" - code got - text "instead." - end - - block do - text "The expression of a test must evaluate to a boolean." - end - - snippet node -end diff --git a/src/messages/test_expected_name.cr b/src/messages/test_expected_name.cr deleted file mode 100644 index 8584b9f11..000000000 --- a/src/messages/test_expected_name.cr +++ /dev/null @@ -1,15 +0,0 @@ -message TestExpectedName do - title "Syntax Error" - - block do - text "I was looking for the" - bold "name" - text "of a" - bold "test" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/test_expected_opening_bracket.cr b/src/messages/test_expected_opening_bracket.cr deleted file mode 100644 index 507c82720..000000000 --- a/src/messages/test_expected_opening_bracket.cr +++ /dev/null @@ -1,7 +0,0 @@ -message TestExpectedOpeningBracket do - title "Syntax Error" - - opening_bracket "test", got - - snippet node -end diff --git a/src/messages/test_type_mismatch.cr b/src/messages/test_type_mismatch.cr deleted file mode 100644 index 9c90ab752..000000000 --- a/src/messages/test_type_mismatch.cr +++ /dev/null @@ -1,17 +0,0 @@ -message TestTypeMismatch do - title "Type Error" - - block do - text "The type of a test does not match any of the allowed types." - end - - block do - text "I was expecting one of:" - end - - pre "Bool, Test.Context(a)" - - type_with_text got, "Instead it is:" - - snippet node -end diff --git a/src/messages/translation_mismatch.cr b/src/messages/translation_mismatch.cr deleted file mode 100644 index 10db77b5f..000000000 --- a/src/messages/translation_mismatch.cr +++ /dev/null @@ -1,15 +0,0 @@ -message TranslationMismatch do - title "Type Error" - - block do - text "The type of the key" - bold value - text "in the language:" - bold language - text "does not match the type in another language." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/translation_missing.cr b/src/messages/translation_missing.cr deleted file mode 100644 index d22258ebd..000000000 --- a/src/messages/translation_missing.cr +++ /dev/null @@ -1,10 +0,0 @@ -message TranslationMissing do - title "Type Error" - - block do - text "Translations are not specified for the key:" - bold value - end - - snippet node -end diff --git a/src/messages/translation_not_translated.cr b/src/messages/translation_not_translated.cr deleted file mode 100644 index 4c74f2d3c..000000000 --- a/src/messages/translation_not_translated.cr +++ /dev/null @@ -1,12 +0,0 @@ -message TranslationNotTranslated do - title "Type Error" - - block do - text "There is no translation for the key:" - bold value - text "in the language:" - bold language - end - - snippet node -end diff --git a/src/messages/type_expected_closing_parentheses.cr b/src/messages/type_expected_closing_parentheses.cr deleted file mode 100644 index bdbc56427..000000000 --- a/src/messages/type_expected_closing_parentheses.cr +++ /dev/null @@ -1,13 +0,0 @@ -message TypeExpectedClosingParentheses do - title "Syntax Error" - - block do - text "The" - bold "type parameters" - text "must be enclosed by parenthesis." - end - - was_looking_for "closing parenthesis", got, ")" - - snippet node -end diff --git a/src/messages/type_expected_type.cr b/src/messages/type_expected_type.cr deleted file mode 100644 index c0e266654..000000000 --- a/src/messages/type_expected_type.cr +++ /dev/null @@ -1,13 +0,0 @@ -message TypeExpectedType do - title "Syntax Error" - - block do - text "I was looking for an" - bold "uppercase letter for a type" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/type_expected_type_or_variable.cr b/src/messages/type_expected_type_or_variable.cr deleted file mode 100644 index 6f1a0c9bc..000000000 --- a/src/messages/type_expected_type_or_variable.cr +++ /dev/null @@ -1,11 +0,0 @@ -message TypeExpectedTypeOrVariable do - title "Syntax Error" - - block do - text "A type with parameters must contain at least one parameter." - end - - was_looking_for "type or type parameter", got - - snippet node -end diff --git a/src/messages/unary_minus_not_number.cr b/src/messages/unary_minus_not_number.cr deleted file mode 100644 index f7e9c267f..000000000 --- a/src/messages/unary_minus_not_number.cr +++ /dev/null @@ -1,11 +0,0 @@ -message UnaryMinusNotNumber do - title "Type Error" - - block do - text "An unary minuses expression must evaluate to number." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/use_condition_mismatch.cr b/src/messages/use_condition_mismatch.cr deleted file mode 100644 index de5212d20..000000000 --- a/src/messages/use_condition_mismatch.cr +++ /dev/null @@ -1,13 +0,0 @@ -message UseConditionMismatch do - title "Type Error" - - block do - text "The expression of the" - bold "where condition" - text "must evaluate to a boolean value." - end - - was_expecting_type TypeChecker::BOOL, got - - snippet node -end diff --git a/src/messages/use_expected_closing_bracket.cr b/src/messages/use_expected_closing_bracket.cr deleted file mode 100644 index 2cef681f5..000000000 --- a/src/messages/use_expected_closing_bracket.cr +++ /dev/null @@ -1,15 +0,0 @@ -message UseExpectedClosingBracket do - title "Syntax Error" - - block do - text "The" - bold "expression" - text "for a" - bold "when codition" - text "must be enclosed by brackets." - end - - was_looking_for "closing bracket", got, "}" - - snippet node -end diff --git a/src/messages/use_expected_expression.cr b/src/messages/use_expected_expression.cr deleted file mode 100644 index cddde5f29..000000000 --- a/src/messages/use_expected_expression.cr +++ /dev/null @@ -1,15 +0,0 @@ -message UseExpectedExpression do - title "Syntax Error" - - block do - text "The" - bold "body" - text "of a" - bold "when codition" - text "must be a single expression." - end - - was_looking_for "expression", got - - snippet node -end diff --git a/src/messages/use_expected_opening_bracket.cr b/src/messages/use_expected_opening_bracket.cr deleted file mode 100644 index 2e11cb38f..000000000 --- a/src/messages/use_expected_opening_bracket.cr +++ /dev/null @@ -1,15 +0,0 @@ -message UseExpectedOpeningBracket do - title "Syntax Error" - - block do - text "The" - bold "expression" - text "for a" - bold "when codition" - text "must be enclosed by brackets." - end - - was_looking_for "opening bracket", got, "{" - - snippet node -end diff --git a/src/messages/use_expected_provider.cr b/src/messages/use_expected_provider.cr deleted file mode 100644 index ada21bbc4..000000000 --- a/src/messages/use_expected_provider.cr +++ /dev/null @@ -1,15 +0,0 @@ -message UseExpectedProvider do - title "Syntax Error" - - block do - text "I was looking for a" - bold "provider" - text "for a" - bold "use directive" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/use_expected_record.cr b/src/messages/use_expected_record.cr deleted file mode 100644 index 7fa13c6a0..000000000 --- a/src/messages/use_expected_record.cr +++ /dev/null @@ -1,15 +0,0 @@ -message UseExpectedRecord do - title "Syntax Error" - - block do - text "I was looking for the" - bold "data" - text "for a" - bold "use directive" - text "but found" - code got - text "instead." - end - - snippet node -end diff --git a/src/messages/use_not_found_provider.cr b/src/messages/use_not_found_provider.cr deleted file mode 100644 index fbc9080ed..000000000 --- a/src/messages/use_not_found_provider.cr +++ /dev/null @@ -1,10 +0,0 @@ -message UseNotFoundProvider do - title "Type Error" - - block do - text "I could not find the provider with the name:" - bold name - end - - snippet node -end diff --git a/src/messages/use_subscription_mismatch.cr b/src/messages/use_subscription_mismatch.cr deleted file mode 100644 index cf16694e4..000000000 --- a/src/messages/use_subscription_mismatch.cr +++ /dev/null @@ -1,11 +0,0 @@ -message UseSubscriptionMismatch do - title "Type Error" - - block do - text "The subscription of a provider does not match its definition." - end - - was_expecting_type expected, got - - snippet node -end diff --git a/src/messages/variable_missing.cr b/src/messages/variable_missing.cr deleted file mode 100644 index 468f98606..000000000 --- a/src/messages/variable_missing.cr +++ /dev/null @@ -1,10 +0,0 @@ -message VariableMissing do - title "Type Error" - - block do - text "I could not find a variable, function or property with the name:" - bold name - end - - snippet node -end diff --git a/src/messages/variable_reserved.cr b/src/messages/variable_reserved.cr deleted file mode 100644 index 3af0abbc8..000000000 --- a/src/messages/variable_reserved.cr +++ /dev/null @@ -1,11 +0,0 @@ -message VariableReserved do - title "Type Error" - - block do - text "The" - bold name - text "as a variable name is a reserved word please use something else." - end - - snippet node -end diff --git a/src/messages/variable_taken.cr b/src/messages/variable_taken.cr deleted file mode 100644 index ad5e61246..000000000 --- a/src/messages/variable_taken.cr +++ /dev/null @@ -1,11 +0,0 @@ -message VariableTaken do - title "Type Error" - - block do - text "There is already a variable with the same name in this scope:" - bold name - end - - snippet node, "You are trying to define the variable here:" - snippet existing, "But it is already defined here:" -end diff --git a/src/mint_json.cr b/src/mint_json.cr index b3185c340..d9cb10e57 100644 --- a/src/mint_json.cr +++ b/src/mint_json.cr @@ -1,5 +1,7 @@ module Mint class MintJson + include Errorable + class Application getter title, meta, icon, head, name, theme, display, orientation, css_prefix @@ -30,16 +32,36 @@ module Mint getter root : String getter name = "" - json_error MintJsonRootNotAnObject - json_error MintJsonRootInvalidKey - def initialize(@json : String, @root : String, @file : String) begin @parser = JSON::PullParser.new(@json) rescue exception : JSON::ParseException - raise MintJsonInvalidJson, { - "node" => node(exception), - } + error! :mint_json_invalid_json do + block do + text "I could not parse the following" + bold "mint.json" + text "file:" + end + + snippet node(exception) + end + rescue error + error! :mint_json_invalid_file do + block do + text "There was a problem when I was trying to open a" + bold "mint.json" + text "file:" + bold @file + end + + block do + text "The error! I got is this:" + end + + block do + bold error.to_s + end + end end parse_root @@ -70,13 +92,13 @@ module Mint position + @json[position..-1].lines.first.size - data = - Ast::Data.new(@json, @file) + file = + Parser::File.new(@json, @file) Ast::Node.new( to: to, from: position, - input: data) + file: file) end def node(exception : JSON::ParseException) @@ -101,9 +123,6 @@ module Mint # Parsing the root object # -------------------------------------------------------------------------- - json_error MintJsonInvalidJson - json_error MintJsonInvalidFile - def parse_root @parser.read_object do |key| case key @@ -126,24 +145,33 @@ module Mint when "web-components" parse_web_components else - raise MintJsonRootInvalidKey, { - "node" => current_node, - "key" => key, - } + error! :mint_json_root_invalid_key do + block do + text "The root object of a" + bold "mint.json" + text "file has an invalid key:" + bold key + end + + snippet current_node + end end end rescue exception : JSON::ParseException - raise MintJsonRootNotAnObject, { - "node" => node(exception), - } + error! :mint_json_root_not_an_object do + block do + text "There was a problem when parsing" + bold "mint.json" + text "file." + end + + snippet node(exception) + end end # Parsing the name # -------------------------------------------------------------------------- - json_error MintJsonNameNotString - json_error MintJsonNameEmpty - def parse_name location = @parser.location @@ -151,23 +179,34 @@ module Mint @name = @parser.read_string - raise MintJsonNameEmpty, { - "node" => node(location), - } if @name.empty? + error! :mint_json_name_empty do + block do + text "The" + bold "name" + text "field of a" + bold "mint.json" + text "file is empty:" + end + + snippet node(location) + end if @name.empty? rescue exception : JSON::ParseException - raise MintJsonNameNotString, { - "node" => node(exception), - } + error! :mint_json_name_not_string do + block do + text "The" + bold "name" + text "field of a" + bold "mint.json" + text "file is not a string." + end + + snippet node(exception) + end end # Parsing the mint version # -------------------------------------------------------------------------- - json_error MintJsonMintVersionNotString - json_error MintJsonMintVersionMismatch - json_error MintJsonMintVersionInvalid - json_error MintJsonMintVersionEmpty - def parse_mint_version location = @parser.location @@ -175,9 +214,17 @@ module Mint raw = @parser.read_string - raise MintJsonMintVersionEmpty, { - "node" => node(location), - } if raw.empty? + error! :mint_json_mint_version_empty do + block do + text "The" + bold "mint-version" + text "field in your" + bold "mint.json" + text "file is empty." + end + + snippet node(location) + end if raw.empty? match = raw.match(/(\d+\.\d+\.\d+)\s*<=\s*v\s*<\s*(\d+\.\d+\.\d+)/) @@ -190,37 +237,64 @@ module Mint upper = Installer::Semver.parse?(match[2]) - raise MintJsonMintVersionInvalid, { - "node" => node(location), - } if !upper || !lower + Installer::SimpleConstraint.new(lower, upper) if upper && lower + end - Installer::SimpleConstraint.new(lower, upper) - else - raise MintJsonMintVersionInvalid, { - "node" => node(location), - } + error! :mint_json_mint_version_invalid do + block do + text "There was a problem when parsing the" + bold "Mint version constraint." end + block "The version constraint should be in this format:" + + block do + bold "0.0.0 <= v < 1.0.0" + end + + snippet node(location) + end unless constraint + resolved = Installer::Semver.parse(VERSION.rchop("-devel")) - raise MintJsonMintVersionMismatch, { - "expected_version" => constraint.to_s, - "node" => node(location), - "current_version" => VERSION, - } unless resolved < upper && resolved >= lower + error! :mint_json_mint_version_mismatch do + block do + text "The" + bold "mint-version" + text "field in your" + bold "mint.json" + text "file does not match your current version of Mint." + end + + block do + text "I was looking for" + code constraint.to_s + + text "but found" + code VERSION + text "instead." + end + + snippet node(location) + end unless resolved < constraint.upper && resolved >= constraint.lower rescue exception : JSON::ParseException - raise MintJsonMintVersionNotString, { - "node" => node(exception), - } + error! :mint_json_mint_version_not_string do + block do + text "The" + bold "mint-version" + text "field in your" + bold "mint.json" + text "file is not a string." + end + + snippet node(exception) + end end # Parsing the head # -------------------------------------------------------------------------- - json_error MintJsonHeadNotString - json_error MintJsonHeadNotExists - def parse_head location = @parser.location @@ -231,23 +305,48 @@ module Mint path = Path[@root, head].to_s - raise MintJsonHeadNotExists, { - "node" => node(location), - } unless File.exists?(path) + error! :mint_json_head_not_exists do + block do + text "The" + bold "head" + text "field of" + bold "the application object" + text "points to a file that does not exists." + end + + block do + text "The" + bold "head" + text "field if exists should point to a HTML file." + end + + block do + text "That HTML file will be injected to the HEAD of the generated HTML." + text "It is used to include external dependencies" + text "(CSS, JS, analytics, etc...)" + end + + snippet node(location) + end unless File.exists?(path) File.read(path) rescue exception : JSON::ParseException - raise MintJsonHeadNotString, { - "node" => node(exception), - } + error! :mint_json_head_not_string do + block do + text "The" + bold "head" + text "field of" + bold "the application object" + text "is not string:" + end + + snippet node(exception) + end end # Parsing the icon # -------------------------------------------------------------------------- - json_error MintJsonIconNotString - json_error MintJsonIconNotExists - def parse_icon location = @parser.location @@ -255,22 +354,44 @@ module Mint icon = @parser.read_string - raise MintJsonIconNotExists, { - "node" => node(location), - } unless File.exists?(icon) + error! :mint_json_icon_not_exists do + block do + text "The" + bold "icon" + text "field of" + bold "the application object" + text "points to a file that does not exists." + end + + block do + text "The" + bold "icon" + text "field if exists should point to an image." + end + + block "That image will used to generate favicons for the application." + + snippet node(location) + end unless File.exists?(icon) icon rescue exception : JSON::ParseException - raise MintJsonIconNotString, { - "node" => node(exception), - } + error! :mint_json_icon_not_string do + block do + text "The" + bold "icon" + text "field of" + bold "the application object" + text "is not string:" + end + + snippet node(exception) + end end # Parsing external assets (JavaScripts, CSS) # -------------------------------------------------------------------------- - json_error MintJsonExternalInvalid - def parse_external_assets @parser.read_object do |key| case key @@ -279,26 +400,53 @@ module Mint when "stylesheets" parse_external_style_sheets else - raise MintJsonExternalInvalid, { - "node" => current_node, - "key" => key, - } + error! :mint_json_external_invalid do + block do + text "The" + bold "external" + text "field contain at least one item." + end + + block do + text "The" + bold "javascripts" + text "field lists all JavaScript files (relative to the mint.json file)" + text "which should be compiled alongside the application." + end + + block do + text "The" + bold "stylesheets" + text "field lists all CSS files (relative to the mint.json file)" + text "which should be included alongside the application." + end + + snippet current_node + end end end end - json_error MintJsonExternalJavascriptsInvalid - def parse_external_javascripts @parser.read_array { parse_external_javascript } rescue exception : JSON::ParseException - raise MintJsonExternalJavascriptsInvalid, { - "node" => node(exception), - } - end + error! :mint_json_external_javascripts_invalid do + block do + text "The" + bold "javascripts" + text "field should be an array." + end - json_error MintJsonExternalJavascriptNotExists - json_error MintJsonExternalJavascriptInvalid + block do + text "The" + bold "javascripts" + text "field lists all JavaScript files (relative to the mint.json file)" + text "which should be compiled alongside the application." + end + + snippet node(exception) + end + end def parse_external_javascript location = @@ -310,30 +458,49 @@ module Mint path = Path[@root, file].to_s - raise MintJsonExternalJavascriptNotExists, { - "node" => node(location), - "path" => path, - } if !File.exists?(path) || Dir.exists?(path) + error! :mint_json_external_javascript_not_exists do + block do + text "The external JavaScript file" + bold path + text "does not exist." + end + + snippet node(location) + end if !File.exists?(path) || Dir.exists?(path) @external_files["javascripts"] << path rescue exception : JSON::ParseException - raise MintJsonExternalJavascriptInvalid, { - "node" => node(exception), - } - end + error! :mint_json_external_javascript_invalid do + block do + text "All entries in the" + bold "javascripts" + text "array should be string." + end - json_error MintJsonExternalStylesheetsInvalid + snippet "I found one that it is not:", node(exception) + end + end def parse_external_style_sheets @parser.read_array { parse_external_style_sheet } rescue exception : JSON::ParseException - raise MintJsonExternalStylesheetsInvalid, { - "node" => node(exception), - } - end + error! :mint_json_external_stylesheets_invalid do + block do + text "The" + bold "stylesheets" + text "field should be an array." + end + + block do + text "The" + bold "stylesheets" + text "field lists all CSS files (relative to the mint.json file)" + text "which should be included alongside the application." + end - json_error MintJsonExternalStylesheetNotExists - json_error MintJsonExternalStylesheetInvalid + snippet node(exception) + end + end def parse_external_style_sheet location = @@ -345,40 +512,71 @@ module Mint path = Path[@root, file].to_s - raise MintJsonExternalStylesheetNotExists, { - "node" => node(location), - "path" => path, - } unless File.file?(path) + error! :mint_json_external_stylesheet_not_exists do + block do + text "The external stylesheet file" + bold path + text "does not exist." + end + + snippet node(location) + end unless File.file?(path) @external_files["stylesheets"] << file rescue exception : JSON::ParseException - raise MintJsonExternalStylesheetInvalid, { - "node" => node(exception), - } + error! :mint_json_external_stylesheet_invalid do + block do + text "All entries in the" + bold "stylesheets" + text "array should be string." + end + + snippet "I found one that it is not:", node(exception) + end end # Parsing the source directories # -------------------------------------------------------------------------- - json_error MintJsonSourceDirectoriesInvalid - json_error MintJsonSourceDirectoriesEmpty - - json_error MintJsonSourceDirectoryNotExists - json_error MintJsonSourceDirectoryInvalid - def parse_source_directories location = @parser.location @parser.read_array { parse_source_directory } - raise MintJsonSourceDirectoriesEmpty, { - "node" => node(location), - } if @source_directories.empty? + error! :mint_json_source_directories_empty do + block do + text "The" + bold "source-directories" + text "array should not be empty." + end + + block do + text "The" + bold "source-directories" + text "field lists all directories (relative to the mint.json file)" + text "which contain the source files of the application." + end + + snippet node(location) + end if @source_directories.empty? rescue exception : JSON::ParseException - raise MintJsonSourceDirectoriesInvalid, { - "node" => node(exception), - } + error! :mint_json_source_directories_invalid do + block do + text "The" + bold "source-directories" + text "field should be an array." + end + + block do + text "The" + bold "source-directories" + text "field lists all directories (relative to the mint.json file)" + text "which contain the source files of the application." + end + + snippet node(exception) + end end def parse_source_directory @@ -391,31 +589,51 @@ module Mint path = Path[@root, directory] - raise MintJsonSourceDirectoryNotExists, { - "node" => node(location), - "directory" => directory, - } unless Dir.exists?(path) + error! :mint_json_source_directory_not_exists do + block do + text "The source directory" + bold directory + text "does not exists." + end + + snippet node(location) + end unless Dir.exists?(path) @source_directories << directory rescue exception : JSON::ParseException - raise MintJsonSourceDirectoryInvalid, { - "node" => node(exception), - } + error! :mint_json_source_directory_invalid do + block do + text "All entries in the" + bold "source-directories" + text "array should be string." + end + + snippet "I found one that it is not:", node(exception) + end end # Parsing the test directories # -------------------------------------------------------------------------- - json_error MintJsonTestDirectoriesInvalid - json_error MintJsonTestDirectoryNotExists - json_error MintJsonTestDirectoryInvalid - def parse_test_directories @parser.read_array { parse_test_directory } rescue exception : JSON::ParseException - raise MintJsonTestDirectoriesInvalid, { - "node" => node(exception), - } + error! :mint_json_test_directories_invalid do + block do + text "The" + bold "test-directories" + text "field should be an array." + end + + block do + text "The" + bold "test-directories" + text "field lists all directories (relative to the mint.json file)" + text "which contain the test files of the application." + end + + snippet node(exception) + end end def parse_test_directory @@ -428,22 +646,31 @@ module Mint path = Path[@root, directory] - raise MintJsonTestDirectoryNotExists, { - "node" => node(location), - "directory" => directory, - } unless Dir.exists?(path) + error! :mint_json_test_directory_not_exists do + block do + text "The test directory" + bold directory + text "does not exists." + end + + snippet node(location) + end unless Dir.exists?(path) @test_directories << directory rescue exception : JSON::ParseException - raise MintJsonTestDirectoryInvalid, { - "node" => node(exception), - } + error! :mint_json_test_directory_invalid do + block do + text "All entries in the" + bold "test-directories" + text "array should be string." + end + + snippet "I found one that it is not:", node(exception) + end end # Parsing the formatter config # -------------------------------------------------------------------------- - json_error MintJsonFormatterConfigInvalidKey - json_error MintJsonFormatterConfigInvalid def parse_formatter indent_size = 2 @@ -453,49 +680,75 @@ module Mint when "indent-size" indent_size = parse_indent_size else - raise MintJsonApplicationInvalidKey, { - "node" => current_node, - "key" => key, - } + error! :mint_json_formatter_config_invalid_key do + block do + text "The" + bold "formatter-config" + text "object of a" + bold "mint.json" + text "file has an invalid key:" + bold key + end + + snippet current_node + end end end @formatter_config = Formatter::Config.new(indent_size: indent_size) + rescue exception : JSON::ParseException + error! :mint_json_formatter_config_invalid do + block do + text "There was a problem when parsing the" + bold "formatter-config" + text "object of a" + bold "mint.json" + text "file:" + end + + snippet node(exception) + end end - # Parsing the title + # Parsing the ident size # -------------------------------------------------------------------------- - json_error MintJsonIndentSizeInvalid - def parse_indent_size @parser.read_int.clamp(0, 100).to_i rescue exception : JSON::ParseException - raise MintJsonIndentSizeInvalid, { - "node" => node(exception), - } + error! :mint_json_indent_size_invalid do + block do + text "There was a problem when parsing the" + bold "indent-size field" + text "of an" + bold "formatter-config" + text "object:" + end + + snippet node(exception) + end end # Parsing web components # -------------------------------------------------------------------------- - json_error MintJsonWebComponentsInvalid - def parse_web_components @parser.read_object do |key| web_components[key] = @parser.read_string end rescue exception : JSON::ParseException - raise MintJsonWebComponentsInvalid, { - "node" => node(exception), - } + error! :mint_json_web_components_invalid do + block do + text "There was a problem when parsing the" + bold "web-components object:" + end + + snippet node(exception) + end end # Parsing the application # -------------------------------------------------------------------------- - json_error MintJsonApplicationInvalidKey - json_error MintJsonApplicationInvalid - def parse_application meta = {} of String => String @@ -530,10 +783,18 @@ module Mint when "css-prefix" css_prefix = parse_application_css_prefix else - raise MintJsonApplicationInvalidKey, { - "node" => current_node, - "key" => key, - } + error! :mint_json_application_invalid_key do + block do + text "The" + bold "application object" + text "of a" + bold "mint.json" + text "file has an invalid key:" + bold key + end + + snippet current_node + end end end @@ -549,20 +810,22 @@ module Mint display: display, css_prefix: css_prefix) rescue exception : JSON::ParseException - raise MintJsonApplicationInvalid, { - "node" => node(exception), - } + error! :mint_json_application_invalid do + block do + text "There was a problem when parsing the" + bold "application object" + text "of a" + bold "mint.json" + text "file:" + end + + snippet node(exception) + end end # Parsing the meta tags # -------------------------------------------------------------------------- - json_error MintJsonMetaValueNotString - json_error MintJsonMetaInvalid - - json_error MintJsonKeywordNotString - json_error MintJsonKeywordsInvalid - def parse_meta meta = {} of String => String @@ -580,9 +843,33 @@ module Mint meta rescue exception : JSON::ParseException - raise MintJsonMetaInvalid, { - "node" => node(exception), - } + error! :mint_json_meta_invalid do + block do + text "There was a problem when parsing the" + bold "meta object" + text "of an" + bold "application object" + text "file:" + end + + snippet node(exception) + end + end + + def parse_meta_value + @parser.read_string + rescue exception : JSON::ParseException + error! :mint_json_meta_value_not_string do + block do + text "The" + bold "value" + text "of a" + bold "meta field" + text "is not a string:" + end + + snippet node(exception) + end end def parse_keywords @@ -594,33 +881,34 @@ module Mint keywords.join(',') rescue exception : JSON::ParseException - raise MintJsonKeywordsInvalid, { - "node" => node(exception), - } + error! :mint_json_keywords_invalid do + block do + text "There was a problem when parsing the" + bold "keywords array" + text "of a meta object:" + end + + snippet node(exception) + end end def parse_keyword @parser.read_string rescue exception : JSON::ParseException - raise MintJsonKeywordNotString, { - "node" => node(exception), - } - end + error! :mint_json_keyword_not_string do + block do + text "A provided" + bold "keyword" + text "is not a string:" + end - def parse_meta_value - @parser.read_string - rescue exception : JSON::ParseException - raise MintJsonMetaValueNotString, { - "node" => node(exception), - } + snippet node(exception) + end end # Parsing the title # -------------------------------------------------------------------------- - json_error MintJsonTitleInvalid - json_error MintJsonTitleEmpty - def parse_title location = @parser.location @@ -628,98 +916,151 @@ module Mint title = @parser.read_string - raise MintJsonTitleEmpty, { - "node" => node(location), - } if title.empty? + error! :mint_json_title_empty do + block do + text "The" + bold "title" + text "field of an" + bold "application object" + text "is empty:" + end + + snippet node(location) + end if title.empty? title rescue exception : JSON::ParseException - raise MintJsonTitleInvalid, { - "node" => node(exception), - } + error! :mint_json_title_invalid do + block do + text "There was a problem when parsing the" + bold "title field" + text "of an" + bold "application" + text "object:" + end + + snippet node(exception) + end end # Parsing the name # -------------------------------------------------------------------------- - json_error MintJsonApplicationNameInvalid - def parse_application_name @parser.read_string rescue exception : JSON::ParseException - raise MintJsonApplicationNameInvalid, { - "node" => node(exception), - } + error! :mint_json_application_name_invalid do + block do + text "There was a problem when parsing the" + bold "name field" + text "of an" + bold "application" + text "object:" + end + + snippet node(exception) + end end # Parsing the theme # -------------------------------------------------------------------------- - json_error MintJsonThemeInvalid - def parse_theme @parser.read_string rescue exception : JSON::ParseException - raise MintJsonThemeInvalid, { - "node" => node(exception), - } + error! :mint_json_theme_invalid do + block do + text "There was a problem when parsing the" + bold "theme field" + text "of an" + bold "application" + text "object:" + end + + snippet node(exception) + end end # Parsing the orientation # -------------------------------------------------------------------------- - json_error MintJsonOrientationInvalid - def parse_orientation @parser.read_string rescue exception : JSON::ParseException - raise MintJsonOrientationInvalid, { - "node" => node(exception), - } + error! :mint_json_orientation_invalid do + block do + text "There was a problem when parsing the" + bold "orientation field" + text "of an" + bold "application" + text "object:" + end + + snippet node(exception) + end end # Parsing the display # -------------------------------------------------------------------------- - json_error MintJsonDisplayInvalid - def parse_display @parser.read_string rescue exception : JSON::ParseException - raise MintJsonDisplayInvalid, { - "node" => node(exception), - } + error! :mint_json_display_invalid do + block do + text "There was a problem when parsing the" + bold "display field" + text "of an" + bold "application" + text "object:" + end + + snippet node(exception) + end end # Parsing the css prefix # -------------------------------------------------------------------------- - json_error MintJsonCssPrefixInvalid - def parse_application_css_prefix @parser.read_string_or_null rescue exception : JSON::ParseException - raise MintJsonCssPrefixInvalid, { - "node" => node(exception), - } + error! :mint_json_css_prefix_invalid do + block do + text "There was a problem when parsing the" + bold "css-prefix field" + text "of an" + bold "application" + text "object:" + end + + snippet node(exception) + end end # Parsing the dependencies # -------------------------------------------------------------------------- - json_error MintJsonDependencyInvalidConstraint - json_error MintJsonDependencyConstraintInvalid - json_error MintJsonDependenciesInvalid - json_error MintJsonDependencyInvalid - def parse_dependencies @parser.read_object do |key| @dependencies << parse_dependency key end rescue exception : JSON::ParseException - raise MintJsonDependenciesInvalid, { - "node" => node(exception), - } + error! :mint_json_dependencies_invalid do + block do + text "There was a problem when parsing the" + bold "dependencies" + text "field of a mint.json file." + end + + block do + text "The" + bold "dependencies" + text "field lists all the dependencies for the application." + end + + snippet node(exception) + end end def parse_dependency(key) @@ -733,7 +1074,7 @@ module Mint when "constraint" constraint = parse_constraint else - raise Error.new + raise Error.new(:mint_json_unkown_dependency_field) end end @@ -742,9 +1083,15 @@ module Mint Installer::Dependency.new key, repository, constraint rescue exception : JSON::ParseException - raise MintJsonDependencyInvalid, { - "node" => node(exception), - } + error! :mint_json_dependency_invalid do + block do + text "There was a problem when parsing a" + bold "dependency" + text "of a mint.json file:" + end + + snippet node(exception) + end end def parse_constraint @@ -757,52 +1104,96 @@ module Mint match = raw.match(/(\d+\.\d+\.\d+)\s*<=\s*v\s*<\s*(\d+\.\d+\.\d+)/) - if match - lower = - Installer::Semver.parse?(match[1]) + constraint = + if match + lower = + Installer::Semver.parse?(match[1]) - upper = - Installer::Semver.parse?(match[2]) + upper = + Installer::Semver.parse?(match[2]) - raise MintJsonDependencyInvalidConstraint, { - "node" => node(location), - } if !upper || !lower + Installer::SimpleConstraint.new(lower, upper) if upper && lower + else + match = + raw.match(/(.*?):(\d+\.\d+\.\d+)/) - Installer::SimpleConstraint.new(lower, upper) - else - match = - raw.match(/(.*?):(\d+\.\d+\.\d+)/) + if match + version = + Installer::Semver.parse?(match[2]) - if match - version = - Installer::Semver.parse?(match[2]) + target = + match[1] - target = - match[1] + Installer::FixedConstraint.new(version, target) if version + end + end - raise MintJsonDependencyInvalidConstraint, { - "node" => node(location), - } unless version + error! :mint_json_dependency_invalid_constraint do + block do + text "There was a problem when parsing the" + bold "constraint" + text "of a dependency" + end - Installer::FixedConstraint.new(version, target) - else - raise MintJsonDependencyInvalidConstraint, { - "node" => node(location), - } + block do + text "The constraint of a dependency is either in this format:" end - end + block do + bold "0.0.0 <= v < 1.0.0" + end + + block do + text "or a git tag / commit / branch followed by the version:" + end + + block do + bold "master:0.1.0" + end + + block do + text "I could not find either." + end + + snippet node(location) + end unless constraint + + constraint rescue exception : JSON::ParseException - raise MintJsonDependencyConstraintInvalid, { - "node" => node(exception), - } - end + error! :mint_json_dependency_constraint_invalid do + block do + text "There was a problem when parsing the" + bold "constraint" + text "of a dependency:" + end - json_error MintJsonDependencyNotInstalled + snippet node(exception) + end + end def check_dependencies! dependencies.each do |dependency| next if dependency_exists?(dependency.name) - raise MintJsonDependencyNotInstalled, {"name" => dependency.name} + error! :mint_json_dependency_not_installed do + block do + text "Not all" + bold "dependencies" + text "in your mint.json file are installed." + end + + block do + text "The dependency" + bold dependency.name + text "was expected to be in the" + bold ".mint/packages/#{name}" + text "directory." + end + + block do + text "Usually you can fix this by running the" + bold "mint install" + text "command." + end + end end end diff --git a/src/parser.cr b/src/parser.cr index b03f3adea..fb42bf360 100644 --- a/src/parser.cr +++ b/src/parser.cr @@ -1,258 +1,257 @@ module Mint class Parser + include Errorable + include Helpers + + # The position of the cursor, which is at the character we are currently + # parsing. + getter position : Int64 = 0 + + # The input which is an array of characters because this way it's faster in + # cases where the original code contains multi-byte characters. getter input : Array(Char) - getter file : String + + # The abstract syntax tree. getter ast = Ast.new - getter data : Ast::Data - getter refs = [] of {Ast::Variable, Ast::HtmlComponent | Ast::HtmlElement} - getter locales = [] of Ast::LocaleKey - getter position = 0 - def initialize(input : String, @file) - @input = input.chars - @data = Ast::Data.new(input, @file) - end + # The parsed file, we save it so we can show parse errors. + getter file : File - def <<(node) - ast.nodes << node - node + def initialize(input : String, path : String) + @file = File.new(input, path) + @input = input.chars end - # Helpers for manipulating position - # ---------------------------------------------------------------------------- - - def start(&) - start_position = position - - nodes_size = ast.nodes.size - keywords_size = ast.keywords.size + # Parses a thing (an ast node). Yielding the start position so the thing + # getting parsed can use it. If the block returns nil or we rollback to + # the start position since it means the parsing has failed. + # track - if true we save the resulting node + def parse(*, track : Bool = true, &) operators_size = ast.operators.size + keywords_size = ast.keywords.size + nodes_size = ast.nodes.size + start_position = position - begin - node = yield position - @position = start_position unless node - - unless node - ast.nodes.delete_at(nodes_size...) - ast.keywords.delete_at(keywords_size...) + (yield position, nodes_size, @errors.size).tap do |node| + case node + when Ast::Node + ast.nodes << node if track + when Nil ast.operators.delete_at(operators_size...) + ast.keywords.delete_at(keywords_size...) + ast.nodes.delete_at(nodes_size...) + @position = start_position end - - node - rescue error : Error - @position = start_position - - ast.nodes.delete_at(nodes_size...) - ast.keywords.delete_at(keywords_size...) - ast.operators.delete_at(operators_size...) - - raise error end end + # Moves the cursor forward by one character. def step @position += 1 end + # Returns whether or not the cursor is at the end of the file. def eof? : Bool @position == input.size end - # Helpers for raising errors - # ---------------------------------------------------------------------------- - - def raise(error : SyntaxError.class, position : Int32, raw : Hash(String, T)) forall T - whitespace_index = next_whitespace_index - to = whitespace_index ? whitespace_index - position : 0 - - node = - Ast::Node.new( - to: position + to, - from: position, - input: data) - - part = - substring(position, to) - - raise error, { - "node" => node, - "got" => part, - }.merge(raw) + # Checks if we reached the end of the file raises an error otherwise. + def eof! : Bool + whitespace + error :expected_eof { expected "the end of the file", word } unless eof? + true end - def raise(error : SyntaxError.class, position : Int32) - raise error, position, {} of String => String + # Returns the current character. + def char : Char + input[position]? || '\0' end - def raise(error : SyntaxError.class) - raise error, position, {} of String => String + # If the character is parsed with the given block, moves the cursor forward. + def char(& : Char -> Bool) + step if yield char end - # Inspect current character, look ahead and look behind - # ---------------------------------------------------------------------------- - - def char : Char - input[position]? || '\0' + # If the character is the current character, moves the cursor forward. + def char!(expected : Char) + char { |current| current == expected } end + # Returns the next character. def next_char : Char input[position + 1]? || '\0' end - def prev_char : Char + # Returns the previous character. + def previous_char : Char input[position - 1]? || '\0' end - # Consuming characters - # ---------------------------------------------------------------------------- - - def letters_or_numbers - chars { |char| char.ascii_letter? || char.ascii_number? } - end - - def letters_numbers_or_dash - chars { |char| char.ascii_letter? || char.ascii_number? || char == '-' } - end + # Returns the current word (sequence of ascii lowercase letters). + def ascii_word : String + index = position + word = "" - def letters_numbers_or_underscore - chars { |char| char.ascii_letter? || char.ascii_number? || char == '_' } - end - - def char!(next_char : Char) - return false unless char == next_char - step - true - end + while (input[index]? || '\0').ascii_letter? + word += input[index] + index += 1 + end - def char(next_char : Char, error : SyntaxError.class) : Int32? - raise error unless char == next_char - step + word end - def char(& : Char -> Bool) - return unless yield char - step + # Parses any number of ascii latters or numbers. + def ascii_letters_or_numbers(*, extra_char : Char? = nil) + chars { |char| char.ascii_letter? || char.ascii_number? || char == extra_char } end - def char(error : SyntaxError.class, & : Char -> Bool) - raise error unless yield char - step + # Parses any number of ascii uppercase latters, numbers or underscore and + # must start with an uppercase letter. + def ascii_uppercase_and_underscore + chars { |char| char.ascii_uppercase? || char.ascii_number? || char == '_' } end + # Consumes characters while the yielded value is true or we reach the end + # of the file. def chars(& : Char -> Bool) while char != '\0' && (yield char) step end end - def chars(next_char : Char) - chars { |char| char == next_char } - end - + # Consumes characters while the yielded value is in one of the given + # characters. def chars(*next_chars : Char) chars &.in?(next_chars) end - def chars_until(& : Char -> Bool) - while char != '\0' && !(yield char) - step - end - end - - def chars_until(next_char : Char) - chars_until { |char| char == next_char } - end - - def chars_until(*next_chars : Char) - chars_until &.in?(next_chars) - end - - # Gathering many consumes - # ---------------------------------------------------------------------------- - + # Starts to parse something, if the cursor moved during, return the parsed + # string. def gather(&) : String? start_position = position yield if position > start_position - result = substring(start_position, position - start_position) + result = file.contents[start_position, position - start_position] result unless result.empty? end end - # Consuming keywords - # ---------------------------------------------------------------------------- + # Consumes characters until the yielded value is true. + def consume(& : -> Bool) : Nil + while yield + step + end + end + + # Returns the word (non whitespace sequence) a the cursor. + def word : String? + start_position = position + word = "" + + while !(eof? || whitespace?) + word += char + step + end - def keyword!(word, error) : Bool - keyword(word) || raise error + @position = start_position + word end - def keyword_ahead?(word) : Bool - word.each_char_with_index do |char, i| - return false unless input[position + i]? == char + # Returns whether or not the word is at the current position. + def word?(word) : Bool + word.chars.each_with_index.all? do |char, i| + input[position + i]? == char end - true end - def keyword(word) : Bool - if keyword_ahead?(word) - if word.chars.all?(&.ascii_lowercase?) && !word.blank? && word != "or" - @ast.keywords << {position, position + word.size} + # Consumes a word and steps the cursor forward if successful. + def word!(expected : String) : Bool + if word?(expected) + @position += expected.size + + if expected.chars.all?(&.ascii_lowercase?) && + !expected.blank? && + expected != "or" + @ast.keywords << {position - expected.size, position} end - @position += word.size true else false end end - # Consuming whitespaces - # ---------------------------------------------------------------------------- - - def whitespace!(error : SyntaxError.class) : String? - raise error unless whitespace? - whitespace + # Consumes all available whitespace. + def whitespace : Nil + chars &.ascii_whitespace? end - def whitespace? + # Returns whether the current character is a whitespace. + def whitespace? : Bool char.ascii_whitespace? end - def whitespace : String? - consume_while whitespace? - end - - def track_back_whitespace : Nil - while prev_char.ascii_whitespace? - @position -= 1 + # Consumes all available whitespace and returns true / false whether + # there were any. + def whitespace! : Bool + parse do |start_position| + whitespace + next false if position == start_position + true end end - # Consuming variables - # ---------------------------------------------------------------------------- - - def type_or_type_variable - type || type_variable + # Parses a variable identifier. + def identifier_variable : String? + return unless char.ascii_lowercase? + gather { ascii_letters_or_numbers } end - def type_or_type_variable!(error : SyntaxError.class) - type_or_type_variable || raise error + # Parses a constant identifier. + def identifier_constant : String? + return unless char.ascii_uppercase? + gather { ascii_uppercase_and_underscore } end - # Consuming many things - # ---------------------------------------------------------------------------- + # Parses a type identifier. + def identifier_type : String? + parse do + name = gather do + next unless char.ascii_uppercase? + ascii_letters_or_numbers + end + + next if char == '_' + next unless name + + parse do + next unless char! '.' + next unless other = identifier_type + + name += ".#{other}" + end + + name + end + end + # Parse many things separated by whitespace. def many(parse_whitespace : Bool = true, & : -> T?) : Array(T) forall T result = [] of T loop do - # Consume whitespace - whitespace if parse_whitespace + # Using parse here will not consume the whitespace if + # the parsing is not successfull. + item = parse(track: false) do + # Consume whitespace + whitespace if parse_whitespace + yield + end # Break if the block didn't yield anything - break unless item = yield + break unless item # Add item to results result << item @@ -261,46 +260,132 @@ module Mint result end + # Parses a list of things, which ends in the terminator character and are + # separated by the separator character. def list(terminator : Char?, separator : Char, & : -> T?) : Array(T) forall T result = [] of T loop do - # Break if we reached the end - break if char == terminator + item = parse(track: false) do + # Consume whitespace before the next thing + whitespace + + # Return nil if we reached the end + next if char == terminator + yield + end # Break if the block didn't yield anything - break unless item = yield + break unless item # Add item to results result << item - # Consume whitespace before the separator - whitespace + # Using parse here will not consume whitespace if there is no separator. + parsed_separator = parse do + # Consume whitespace before the separator + whitespace - # Break if there is no separator, consume it otherwise - break unless char! separator + # Break if there is no separator, consume it otherwise + next unless char! separator - # Consume whitespace - whitespace + # This is needed to actually finish the consuming. + true + end + + break unless parsed_separator end result end - # Gets substring out of the original string - def substring(from, to) - @data.input[from, to] + # Parses a block surrounded by brackets. + def brackets(opening_bracket_error : Proc(Nil)? = nil, + closing_bracket_error : Proc(Nil)? = nil, + empty_check : Proc(T, Nil)? = nil, + & : -> T?) : T? forall T + parse(track: false) do + unless char! '{' + case item = opening_bracket_error + when Proc(Nil) + next item.call + else + next + end + end + + whitespace + result = yield.tap { |value| empty_check.try(&.call(value)) } + whitespace + + unless char! '}' + case item = closing_bracket_error + when Proc(Nil) + next item.call + else + next + end + end + + result + end end - private def next_whitespace_index - current_position = position - while current_position < input.size - if input[current_position].whitespace? - return current_position + # Parses a thing, if succeeds it discards all errors while parsing it. + def oneof(& : -> T?) : T? forall T + # Copy the errors for later use. + errors = self.errors.dup + + # Empty the errors, since we want to gather them. + @errors = [] of Error + + yield.tap do |result| + if result + # Restore the original errors + @errors = errors + else + # Restore the original errors and add the new ones. + @errors = errors + @errors + end + end + end + + # Parses a raw part of the input until we reach the terminator or an + # interpolation (if it's needed). + def raw(terminator : Char, stop_on_interpolation : Bool = true) : String? + gather do + while char != '\0' + break if previous_char != '\\' && + char == terminator + + break if stop_on_interpolation && + previous_char != '\\' && + next_char == '{' && + char == '#' + + step + end + end + end + + # Parses a raw part of the input until we reach the terminator or an + # interpolation. + def raw(token : String) : String? + raw { !word?(token) } + end + + # Parses a raw part of the input until we reach the terminator or an + # interpolation. + def raw(& : -> Bool) : String? + gather do + while char != '\0' && yield + break if previous_char != '\\' && + next_char == '{' && + char == '#' + + step end - current_position &+= 1 end - nil end end end diff --git a/src/parser/file.cr b/src/parser/file.cr new file mode 100644 index 000000000..5e3cc50b5 --- /dev/null +++ b/src/parser/file.cr @@ -0,0 +1,14 @@ +module Mint + class Parser + class File + getter contents, path + + def initialize(@contents : String, @path : String) + end + + def to_s(io : IO) + io << '<' << file << ' ' << contents[0, 10] << "...>" + end + end + end +end diff --git a/src/parser/top_level.cr b/src/parser/top_level.cr new file mode 100644 index 000000000..3844ca073 --- /dev/null +++ b/src/parser/top_level.cr @@ -0,0 +1,54 @@ +module Mint + class Parser + def self.parse(file) : Ast + parse ::File.read(file), file + end + + def self.parse(contents, file) : Ast + parser = new(contents, file) + parser.parse + parser.eof! + parser.errors.first?.try { |error| raise error } + parser.ast + end + + def parse : Nil + # Comment needs to be last since other comments are parsed with the + # entities. + items = many do + module_definition || + type_definition || + component || + provider || + locale || + routes || + store || + suite || + comment + end + + items.each do |item| + case item + when Ast::TypeDefinition + ast.type_definitions << item + when Ast::Component + ast.components << item + when Ast::Provider + ast.providers << item + when Ast::Comment + ast.comments << item + when Ast::Locale + ast.locales << item + when Ast::Module + ast.modules << item + when Ast::Routes + ast.routes << item + when Ast::Store + ast.stores << item + when Ast::Suite + ast.suites << item + end + end + end + end +end diff --git a/src/parsers/access.cr b/src/parsers/access.cr index 3d38a2c47..7ba89410b 100644 --- a/src/parsers/access.cr +++ b/src/parsers/access.cr @@ -1,22 +1,32 @@ module Mint class Parser - syntax_error AccessExpectedVariable + def access(expression : Ast::Node) : Ast::Access? + parse do + # TODO: Remove this if chain in 0.21.0 when deprecation ends. + type = + if word! "::" + Ast::Access::Type::DoubleColon + elsif char! ':' + Ast::Access::Type::Colon + elsif char! '.' + Ast::Access::Type::Dot + end - def access(lhs : Ast::Expression) : Ast::Expression - start do |start_position| - next unless char! '.' + next unless type - field = variable! AccessExpectedVariable, track: false + next error :access_expected_field do + expected "the name of the accessed entity", word + snippet self + end unless field = value - node = self << Ast::Access.new( - from: start_position, + Ast::Access.new( + expression: expression, + from: expression.from, field: field, to: position, - input: data, - lhs: lhs) - - array_access_or_call(node) - end || lhs + file: file, + type: type) + end end end end diff --git a/src/parsers/argument.cr b/src/parsers/argument.cr index f18a0d8a1..77e2476dd 100644 --- a/src/parsers/argument.cr +++ b/src/parsers/argument.cr @@ -1,33 +1,52 @@ module Mint class Parser - syntax_error ArgumentExpectedTypeOrVariable - syntax_error ArgumentExpectedDefaultValue - syntax_error ArgumentExpectedColon - - def argument(parse_default_value : Bool = true) : Ast::Argument? - start do |start_position| + def argument(*, parse_default_value : Bool = true) : Ast::Argument? + parse do |start_position| next unless name = variable whitespace - char ':', ArgumentExpectedColon - whitespace + next error :argument_expected_colon do + snippet "A colon must separate the arguments name from its type, " \ + "here is an example:", "name : String" + expected "the colon of the argument", word + snippet self + end unless char! ':' - type = type_or_type_variable! ArgumentExpectedTypeOrVariable + whitespace + next error :argument_expected_type do + snippet "An argument must have its type defined, here is an " \ + "example:", "name : Type" + expected "the type of the argument", word + snippet self + end unless type = self.type || type_variable if parse_default_value whitespace - default = - if char! '=' - whitespace - expression! ArgumentExpectedDefaultValue - end + + if char! '=' + whitespace + default = expression + + next error :argument_expected_default_value do + block do + text "The" + bold "default value" + text "of an argument must be defined after the equal sign, " \ + "here is an example:" + end + + snippet %(name : String = "Joe") + expected "the default value of the argument", word + snippet self + end unless default + end end - self << Ast::Argument.new( + Ast::Argument.new( from: start_position, default: default, to: position, - input: data, + file: file, name: name, type: type) end diff --git a/src/parsers/array_access.cr b/src/parsers/array_access.cr index f51d72223..1adb89985 100644 --- a/src/parsers/array_access.cr +++ b/src/parsers/array_access.cr @@ -1,38 +1,28 @@ module Mint class Parser - syntax_error ArrayAccessExpectedClosingBracket - syntax_error ArrayAccessExpectedIndex - - def array_access(lhs : Ast::Expression) : Ast::Expression - start do |start_position| + def array_access(expression : Ast::Node) : Ast::ArrayAccess? + parse do |start_position| next unless char! '[' - whitespace - index = - gather { chars &.ascii_number? }.to_s - - index = - if index.empty? - expression! ArrayAccessExpectedIndex - else - index.to_i64 - end - + next error :array_access_expected_index do + expected "the index of an array access", word + snippet self + end unless index = self.expression whitespace - char ']', ArrayAccessExpectedClosingBracket + next error :array_access_expected_closing_bracket do + expected "the closing bracket of an array access", word + snippet self + end unless char! ']' - node = self << Ast::ArrayAccess.new( + Ast::ArrayAccess.new( + expression: expression, from: start_position, to: position, index: index, - input: data, - lhs: lhs, - ) - - array_access_or_call(node) - end || lhs + file: file) + end end end end diff --git a/src/parsers/array_destructuring.cr b/src/parsers/array_destructuring.cr index 46f77fec0..b7132a19f 100644 --- a/src/parsers/array_destructuring.cr +++ b/src/parsers/array_destructuring.cr @@ -1,34 +1,25 @@ module Mint class Parser - syntax_error ArrayDestructuringExpectedClosingBracket - def array_destructuring : Ast::ArrayDestructuring? - start do |start_position| - head = start do - next unless char! '[' - value = spread || destructuring - whitespace - char! ',' - whitespace - value - end - - next unless head + parse do |start_position| + next unless char! '[' items = - [head.as(Ast::Node)] &+ list(terminator: ']', separator: ',') do - spread || destructuring - end + list(terminator: ']', separator: ',') { spread || destructuring } + next if items.empty? whitespace - char ']', ArrayDestructuringExpectedClosingBracket + next error :array_destructuring_expected_closing_bracket do + expected "the closing bracket of an array destructuring", word + snippet self + end unless char! ']' Ast::ArrayDestructuring.new( from: start_position, items: items, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/array_literal.cr b/src/parsers/array_literal.cr index 384c32ace..1c1f725ef 100644 --- a/src/parsers/array_literal.cr +++ b/src/parsers/array_literal.cr @@ -1,34 +1,50 @@ module Mint class Parser - syntax_error ArrayLiteralExpectedTypeOrVariable - syntax_error ArrayExpectedClosingBracket - - def array : Ast::ArrayLiteral? - start do |start_position| + def array_literal : Ast::ArrayLiteral? + parse do |start_position| next unless char! '[' - whitespace + items = list( terminator: ']', separator: ',' ) { expression } whitespace - char ']', ArrayExpectedClosingBracket + next error :array_expected_closing_bracket do + expected "the closing bracket of an array", word + snippet self + end unless char! ']' + + type = + parse(track: false) do + whitespace + next unless word! "of" - type = start do - whitespace - next unless keyword "of" - whitespace - type_or_type_variable! ArrayLiteralExpectedTypeOrVariable - end + whitespace + next error :array_expected_type_or_variable do + block do + text "The type of an" + bold "array literal" + text "must be defined after the" + bold "of" + text "keyword, here is an example:" + end - self << Ast::ArrayLiteral.new( + snippet "[] of String" + expected "the type", word + snippet self + end unless item = self.type || type_variable + + item + end + + Ast::ArrayLiteral.new( from: start_position, items: items, - type: type, to: position, - input: data) + type: type, + file: file) end end end diff --git a/src/parsers/base_expression.cr b/src/parsers/base_expression.cr new file mode 100644 index 000000000..7e0374743 --- /dev/null +++ b/src/parsers/base_expression.cr @@ -0,0 +1,103 @@ +module Mint + class Parser + def base_expression : Ast::Node? + # Here we parse the nexus of the expression (the part without chains: + # access, array access or call). + # + # We are doing two big cases as an optimization: each parser can be used + # standalone and will return nil if it can't parse, but limiting what can + # pe parsed avoids a lot of unneccesary cycles. + left = + case char + when '(' + parenthesized_expression || inline_function + when '-', .ascii_number? + number_literal || unary_minus + when '!' + negated_expression + when '"' + string_literal + when '/' + regexp_literal + when '#' + tuple_literal + when '.' + member_access + when '[' + array_literal + when ':' + locale_key + when '`' + js + when '@' + documentation_directive || + highlight_directive || + format_directive || + inline_directive || + asset_directive || + svg_directive || + env + when '<' + html_expression || + html_component || + here_document || + html_element || + html_fragment + when '{' + record_update || + record || + tuple_literal || + block + else + case ascii_word + when "true", "false" + bool_literal + when "case" + case_expression + when "for" + for_expression + when "if" + if_expression + when "return" + return_call + when "next" + next_call + when "decode" + decode + when "encode" + encode + else + value + end + end + + return unless left + + # We try to chain accesses and calls until we can. + # + # TODO: Remove `::`, `:` cases in 0.21.0 when deprecation ends. + loop do + node = + if word? "::" + access(left) + else + case char + when ':' + access(left) + when '.' + access(left) + when '(' + call(left) + when '[' + array_access(left) + end + end + + break unless node + left = node + end + + left + end + end +end diff --git a/src/parsers/basic_expression.cr b/src/parsers/basic_expression.cr deleted file mode 100644 index ffb07f358..000000000 --- a/src/parsers/basic_expression.cr +++ /dev/null @@ -1,51 +0,0 @@ -module Mint - class Parser - # NOTE: The order of the parsing is important! - def basic_expression : Ast::Expression? - format_directive || - highlight_directive || - documentation_directive || - svg_directive || - asset_directive || - inline_directive || - env || - locale_key || - here_doc || - string_literal || - regexp_literal || - bool_literal || - number_literal || - unary_minus || - array || - record_update || - record || - tuple_literal || - code_block || - html_element || - html_expression || - html_component || - html_fragment || - member_access || - constant_access || - module_access || - decode || - encode || - if_expression || - for_expression || - next_call || - return_call || - case_expression || - parenthesized_expression || - inline_function || - enum_id || - negated_expression || - js || - void || - variable - end - - def basic_expression!(error : SyntaxError.class) : Ast::Expression - basic_expression || raise error - end - end -end diff --git a/src/parsers/block.cr b/src/parsers/block.cr index 0739d50fc..9bbaaff25 100644 --- a/src/parsers/block.cr +++ b/src/parsers/block.cr @@ -1,30 +1,55 @@ module Mint class Parser - def block(&) - start do - whitespace - next unless char! '{' - whitespace - - result = yield - whitespace + def block : Ast::Block? + block { many { comment || statement } } + end - next unless char! '}' - result - end + def block(opening_bracket_error : Proc(Nil)? = nil, + closing_bracket_error : Proc(Nil)? = nil, + items_empty_error : Proc(Nil)? = nil) : Ast::Block? + block( + opening_bracket_error, + closing_bracket_error, + items_empty_error) { comment || statement } end - def block(opening_bracket : SyntaxError.class, - closing_bracket : SyntaxError.class, &) - whitespace - char '{', opening_bracket - whitespace + def block(opening_bracket_error : Proc(Nil)? = nil, + closing_bracket_error : Proc(Nil)? = nil, + items_empty_error : Proc(Nil)? = nil, + & : -> Ast::Node?) : Ast::Block? + parse do |start_position| + expressions = + brackets(opening_bracket_error, closing_bracket_error) do + many { yield }.tap do |items| + next items_empty_error.call if items_empty_error && items.none? + end + end - result = yield - whitespace + next unless expressions - char '}', closing_bracket - result + returns = + expressions.compact_map do |item| + case item + when Ast::ReturnCall + item + when Ast::Statement + case expression = item.expression + when Ast::Operation + case right = expression.right + when Ast::ReturnCall + right + end + end + end + end + + Ast::Block.new( + expressions: expressions, + from: start_position, + returns: returns, + to: position, + file: file) + end end end end diff --git a/src/parsers/bool_literal.cr b/src/parsers/bool_literal.cr index 2d19702e5..a707bcb78 100644 --- a/src/parsers/bool_literal.cr +++ b/src/parsers/bool_literal.cr @@ -1,22 +1,22 @@ module Mint class Parser def bool_literal : Ast::BoolLiteral? - start do |start_position| + parse do |start_position| value = case - when keyword "true" + when word! "true" true - when keyword "false" + when word! "false" false else next end - self << Ast::BoolLiteral.new( + Ast::BoolLiteral.new( from: start_position, value: value, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/call.cr b/src/parsers/call.cr index 809034c0e..116940f23 100644 --- a/src/parsers/call.cr +++ b/src/parsers/call.cr @@ -1,29 +1,37 @@ module Mint class Parser - syntax_error CallExpectedClosingParentheses - - def call(lhs : Ast::Expression) : Ast::Expression - start do |start_position| + def call(expression : Ast::Node) : Ast::Call? + parse do |start_position| next unless char! '(' - whitespace + arguments = list( terminator: ')', separator: ',' - ) { call_expression.as(Ast::CallExpression?) } + ) { field(key_required: false) } + whitespace + next error :call_expected_closing_parenthesis do + block do + text "The" + bold "arguments" + text "of a" + bold "call" + text "must be enclosed by parenthesis, here is an example:" + end - char ')', CallExpectedClosingParentheses + snippet %(greet("Joe")) + expected "the closing parenthesis of a call", word + snippet self + end unless char! ')' - node = self << Ast::Call.new( + Ast::Call.new( + expression: expression, from: start_position, arguments: arguments, - expression: lhs, to: position, - input: data) - - array_access_or_call(node) - end || lhs + file: file) + end end end end diff --git a/src/parsers/call_expression.cr b/src/parsers/call_expression.cr deleted file mode 100644 index 532ca77c7..000000000 --- a/src/parsers/call_expression.cr +++ /dev/null @@ -1,27 +0,0 @@ -module Mint - class Parser - def call_expression : Ast::CallExpression? - start do |start_position| - name = - start do - next unless key = variable - whitespace - - next unless char! ':' - whitespace - - key - end - - return unless expression = self.expression - - Ast::CallExpression.new( - expression: expression, - from: start_position, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/case.cr b/src/parsers/case.cr index 2914179e3..8fec12956 100644 --- a/src/parsers/case.cr +++ b/src/parsers/case.cr @@ -1,36 +1,45 @@ module Mint class Parser - syntax_error CaseExpectedClosingParentheses - syntax_error CaseExpectedOpeningBracket - syntax_error CaseExpectedClosingBracket - syntax_error CaseExpectedCondition - syntax_error CaseExpectedBranches - - def case_expression(for_css : Bool = false) : Ast::Case? - start do |start_position| - next unless keyword "case" - + def case_expression(*, for_css : Bool = false) : Ast::Case? + parse do |start_position| + next unless word! "case" whitespace - parens = char! '(' + parenthesis = char! '(' + whitespace + await = word! "await" whitespace - await = keyword "await" + next error :case_expected_condition do + expected "the condition of a case", word + snippet self + end unless condition = expression whitespace - condition = expression! CaseExpectedCondition + + next error :case_expected_closing_parenthesis do + expected "the closing parenthesis of a case", word + snippet self + end if parenthesis && !char!(')') whitespace - char ')', CaseExpectedClosingParentheses if parens + body = brackets( + ->{ error :case_expected_opening_bracket do + expected "the opening bracket of a case", word + snippet self + end }, + ->{ error :case_expected_closing_bracket do + expected "the closing bracket of a case", word + snippet self + end }, + ->(items : Array(Ast::CaseBranch | Ast::Comment)) { + error :case_expected_branches do + expected "the branches of a case", word + snippet self + end if items.none?(Ast::CaseBranch) + }) { many { case_branch(for_css: for_css) || comment } } - body = block( - opening_bracket: CaseExpectedOpeningBracket, - closing_bracket: CaseExpectedClosingBracket - ) do - items = many { case_branch(for_css) || comment } - raise CaseExpectedBranches if items.empty? - items - end + next unless body branches = [] of Ast::CaseBranch comments = [] of Ast::Comment @@ -44,14 +53,14 @@ module Mint end end - self << Ast::Case.new( + Ast::Case.new( condition: condition, from: start_position, branches: branches, comments: comments, await: await, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/case_branch.cr b/src/parsers/case_branch.cr index d6c23452c..db3bcfc2e 100644 --- a/src/parsers/case_branch.cr +++ b/src/parsers/case_branch.cr @@ -1,13 +1,12 @@ module Mint class Parser - syntax_error CaseBranchExpectedExpression - - def case_branch(for_css : Bool = false) : Ast::CaseBranch? - start do |start_position| - unless keyword "=>" - match = destructuring + def case_branch(*, for_css : Bool = false) : Ast::CaseBranch? + parse do |start_position| + unless word! "=>" + pattern = destructuring whitespace - next unless keyword "=>" + + next unless word! "=>" end whitespace @@ -16,15 +15,24 @@ module Mint if for_css many { css_definition } else - expression! CaseBranchExpectedExpression + next error :case_branch_expected_expression do + snippet( + "A case branch must have an value, here is an example:", + "=> value") + + expected "the value of a case branch", word + snippet self + end unless item = self.expression + + item end - self << Ast::CaseBranch.new( - match: match.as(Ast::EnumDestructuring | Ast::TupleDestructuring | Ast::Expression?), + Ast::CaseBranch.new( expression: expression, from: start_position, + pattern: pattern, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/code_block.cr b/src/parsers/code_block.cr deleted file mode 100644 index 1b943e522..000000000 --- a/src/parsers/code_block.cr +++ /dev/null @@ -1,52 +0,0 @@ -module Mint - class Parser - def code_block_naked : Ast::Block? - start do |start_position| - statements = - many { comment || statement } - - self << Ast::Block.new( - statements: statements, - from: start_position, - to: position, - input: data) if statements - end - end - - def code_block : Ast::Block? - start do |start_position| - statements = - block do - many { comment || statement } - end - - self << Ast::Block.new( - statements: statements, - from: start_position, - to: position, - input: data) if statements - end - end - - def code_block(opening_bracket : SyntaxError.class, - closing_bracket : SyntaxError.class, - statement_error : SyntaxError.class = SyntaxError) : Ast::Block? - start do |start_position| - statements = - block( - opening_bracket: opening_bracket, - closing_bracket: closing_bracket) do - many { comment || statement }.tap do |items| - raise statement_error if items.none? - end - end - - self << Ast::Block.new( - statements: statements, - from: start_position, - to: position, - input: data) - end - end - end -end diff --git a/src/parsers/comment.cr b/src/parsers/comment.cr index 2ddad63b0..3d5ced3a1 100644 --- a/src/parsers/comment.cr +++ b/src/parsers/comment.cr @@ -1,35 +1,36 @@ module Mint class Parser def comment : Ast::Comment? - start do |start_position| - next unless keyword_ahead?("/*") || keyword_ahead?("//") + parse do |start_position| + content, type = + if word! "/*" + consumed = + gather { consume { !word?("*/") && !eof? } }.to_s - value = nil + next error :comment_expected_closing_tag do + expected "the closing tag of a comment", word + snippet self + end unless word! "*/" - if keyword_ahead? "/*" - keyword "/*" + {consumed, Ast::Comment::Type::Block} + elsif word! "//" + consumed = + gather { consume { char != '\n' && !eof? } }.to_s - type = Ast::Comment::Type::Block - value = - gather { consume_while((!keyword_ahead?("*/") || char == '\0') && !eof?) }.to_s + {consumed, Ast::Comment::Type::Inline} + else + {nil, Ast::Comment::Type::Block} + end - keyword "*/" - else - keyword "//" + whitespace # TODO: Figure out why is this is needed + next unless content - type = Ast::Comment::Type::Inline - value = - gather { consume_while(!(keyword_ahead?("\n") || char == '\0') && !eof?) }.to_s - end - - whitespace - - self << Ast::Comment.new( + Ast::Comment.new( from: start_position, - value: value, - type: type, + content: content, to: position, - input: data) + type: type, + file: file) end end end diff --git a/src/parsers/component.cr b/src/parsers/component.cr index 7d2a6a841..44b675b20 100644 --- a/src/parsers/component.cr +++ b/src/parsers/component.cr @@ -1,47 +1,59 @@ module Mint class Parser - syntax_error ComponentExpectedOpeningBracket - syntax_error ComponentExpectedClosingBracket - syntax_error ComponentExpectedBody - syntax_error ComponentExpectedName - def component : Ast::Component? - start do |start_position| + parse do |start_position, start_nodes_position| comment = self.comment - global = keyword "global" + global = word! "global" whitespace - next unless keyword "component" + next unless word! "component" whitespace - name = type_id! ComponentExpectedName + next error :component_expected_name do + block do + text "The name of a component must start with an uppercase letter" + text "and only contain lowercase, uppercase letters and numbers." + end - # Clear refs and locales here because it's on the parser - locales.clear - refs.clear + expected "name of the component", word + snippet self + end unless name = id + whitespace - body = block( - opening_bracket: ComponentExpectedOpeningBracket, - closing_bracket: ComponentExpectedClosingBracket + body = brackets( + ->{ error :component_expected_opening_bracket do + expected "the opening bracket of the component", word + snippet self + end }, + ->{ error :component_expected_closing_bracket do + expected "the closing bracket of the component", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :component_expected_body do + expected "the body of a component", word + snippet self + end if items.reject(Ast::Comment).empty? + } ) do - items = many do + many do property || - connect || constant || function || + connect || style || state || use || get || self.comment + # ^^ This needs to be last because it can eat the documentation + # comment of the sub entities. end - - raise ComponentExpectedBody if items.empty? - - items end + next unless body + properties = [] of Ast::Property functions = [] of Ast::Function constants = [] of Ast::Constant @@ -58,8 +70,6 @@ module Mint properties << item when Ast::Function functions << item - - item.keep_name = true if item.name.value == "render" when Ast::Constant constants << item when Ast::Connect @@ -77,8 +87,41 @@ module Mint end end - self << Ast::Component.new( - locales: !locales.empty?, + refs = [] of Tuple(Ast::Variable, Ast::Node) + locales = false + + ast.nodes[start_nodes_position...].each do |node| + case node + when Ast::LocaleKey + locales = true + when Ast::Function + if node.name.value.in?([ + "componentWillUnmount", + "componentDidUpdate", + "componentDidMount", + "render", + ]) + node.keep_name = true + end + when Ast::HtmlElement + node.styles.each do |style| + style.style_node = + styles.find(&.name.value.==(style.name.value)) + end + end + + case node + when Ast::HtmlComponent, + Ast::HtmlElement + node.in_component = true + + if ref = node.ref + refs << {ref, node} + end + end + end + + Ast::Component.new( global: global || false, properties: properties, functions: functions, @@ -87,15 +130,20 @@ module Mint connects: connects, comments: comments, comment: comment, + locales: locales, styles: styles, states: states, - refs: refs.dup, to: position, - input: data, + file: file, + refs: refs, name: name, uses: uses, gets: gets - ) + ).tap do |node| + ast.nodes[start_nodes_position...] + .select(Ast::NextCall) + .each(&.entity=(node)) + end end end end diff --git a/src/parsers/connect.cr b/src/parsers/connect.cr index 5229a4062..d53cc5e8b 100644 --- a/src/parsers/connect.cr +++ b/src/parsers/connect.cr @@ -1,35 +1,47 @@ module Mint class Parser - syntax_error ConnectExpectedOpeningBracket - syntax_error ConnectExpectedClosingBracket - syntax_error ConnectExpectedExposing - syntax_error ConnectExpectedType - syntax_error ConnectExpectedKeys - def connect : Ast::Connect? - start do |start_position| - next unless keyword "connect" + parse do |start_position| + next unless word! "connect" + whitespace + + next error :connect_expected_store do + expected "the name of the store for a connect", word + snippet self + end unless store = id whitespace - store = type_id! ConnectExpectedType + next error :connect_expected_exposing do + expected %(the "exposing" keyword for a connect), word + snippet self + end unless word! "exposing" whitespace - keyword! "exposing", ConnectExpectedExposing + keys = + brackets( + ->{ error :connect_expected_opening_bracket do + expected "the opening bracket of a connect", word + snippet self + end }, + ->{ error :connect_expected_closing_bracket do + expected "the closing bracket of a connect", word + snippet self + end }, + ->(items : Array(Ast::ConnectVariable)) { + error :connect_expected_keys do + expected "the exposed entities of a connect", word + snippet self + end if items.empty? + } + ) { list(terminator: '{', separator: ',') { connect_variable } } - keys = block( - opening_bracket: ConnectExpectedOpeningBracket, - closing_bracket: ConnectExpectedClosingBracket - ) do - items = list(terminator: '{', separator: ',') { connect_variable } - raise ConnectExpectedKeys if items.empty? - items - end + next unless keys - self << Ast::Connect.new( + Ast::Connect.new( from: start_position, store: store, to: position, - input: data, + file: file, keys: keys) end end diff --git a/src/parsers/connect_variable.cr b/src/parsers/connect_variable.cr index d1ab6cc7f..ae7e7c80b 100644 --- a/src/parsers/connect_variable.cr +++ b/src/parsers/connect_variable.cr @@ -1,25 +1,33 @@ module Mint class Parser - syntax_error ConnectVariableExpectedAs - def connect_variable - start do |start_position| - value = variable(track: false) || variable_constant - - next unless value + parse do |start_position| + next unless name = variable_constant(track: false) || + variable(track: false) whitespace - - if keyword "as" + if word! "as" whitespace - name = variable! ConnectVariableExpectedAs + + next error :connect_variable_expected_as do + block do + text "The" + bold "exposed name" + text "of a connection" + bold "must be specified, here is an example:" + end + + snippet "connect Store exposing { item as name }" + expected "the exposed name", word + snippet self + end unless target = variable end - self << Ast::ConnectVariable.new( + Ast::ConnectVariable.new( from: start_position, - variable: value, + target: target, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/constant.cr b/src/parsers/constant.cr index afe96bd84..347eafa6e 100644 --- a/src/parsers/constant.cr +++ b/src/parsers/constant.cr @@ -1,31 +1,36 @@ module Mint class Parser - syntax_error ConstantExpectedEqualSign - syntax_error ConstantExpectedValue - syntax_error ConstantExpectedName - def constant : Ast::Constant? - start do |start_position| + parse do |start_position| comment = self.comment whitespace - next unless keyword "const" + next unless word! "const" whitespace - name = variable_constant! - + next error :constant_expected_name do + expected "the name of a constant", word + snippet self + end unless name = variable_constant whitespace - char '=', ConstantExpectedEqualSign + + next error :constant_expected_equal_sign do + expected "the equal sign of a constant", word + snippet self + end unless char! '=' whitespace - value = expression! ConstantExpectedValue + next error :constant_expected_expression do + expected "the expression of a constant", word + snippet self + end unless expression = self.expression Ast::Constant.new( + expression: expression, from: start_position, comment: comment, - value: value, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/constant_access.cr b/src/parsers/constant_access.cr deleted file mode 100644 index 06df8587b..000000000 --- a/src/parsers/constant_access.cr +++ /dev/null @@ -1,28 +0,0 @@ -module Mint - class Parser - def constant_access : Ast::ModuleAccess? - start do |start_position| - name = start do - value = type_id - next unless char! ':' - value - end - - next unless name - - variable = - variable_constant - - next unless variable - - self << Ast::ModuleAccess.new( - from: start_position, - variable: variable, - constant: true, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/css_definition.cr b/src/parsers/css_definition.cr index 0b53aac92..ed7d60d78 100644 --- a/src/parsers/css_definition.cr +++ b/src/parsers/css_definition.cr @@ -1,44 +1,34 @@ module Mint class Parser - syntax_error CssDefinitionExpectedSemicolon - def css_definition : Ast::CssDefinition? - start do |start_position| + parse do |start_position| next unless char.ascii_lowercase? || char == '-' - - name = gather do - step - letters_numbers_or_dash - end.to_s - + next unless name = gather { ascii_letters_or_numbers(extra_char: '-') } next unless char! ':' whitespace value = - many(parse_whitespace: false) do - string_literal || - interpolation || - gather do - consume_while char.in_set?("^;{\0") && - !keyword_ahead?("\#{") && - char != '"' - end - end.map do |item| - if item.is_a?(Ast::StringLiteral) && item.static? - %("#{item.static_value}") + many(parse_whitespace: false) { + string_literal || interpolation || raw { char.in_set?("^;{\0\"") } + }.map do |item| + if item.is_a?(Ast::StringLiteral) && (raw = static_value(item)) + %("#{raw}") else item end end - char ';', CssDefinitionExpectedSemicolon + next error :css_definition_expected_semicolon do + expected "the semicolon of a CSS definition", word + snippet self + end unless char! ';' - self << Ast::CssDefinition.new( + Ast::CssDefinition.new( from: start_position, - name: name, - value: value, to: position, - input: data) + value: value, + name: name, + file: file) end end end diff --git a/src/parsers/css_font_face.cr b/src/parsers/css_font_face.cr index ecbd9493f..22b6df7fb 100644 --- a/src/parsers/css_font_face.cr +++ b/src/parsers/css_font_face.cr @@ -1,23 +1,34 @@ module Mint class Parser - syntax_error CssFontFaceExpectedOpeningBracket - syntax_error CssFontFaceExpectedClosingBracket - def css_font_face : Ast::CssFontFace? - start do |start_position| - next unless keyword "@font-face" + parse do |start_position| + next unless word! "@font-face" + whitespace + + definitions = + brackets( + ->{ error :css_font_face_expected_opening_bracket do + expected "the opening bracket of a CSS font-face rule", word + snippet self + end }, + ->{ error :css_font_face_expected_closing_bracket do + expected "the closing bracket of a CSS font-face rule", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :css_font_face_expected_definitions do + expected "the definitions of a CSS font-face rule", word + snippet self + end if items.none?(Ast::CssDefinition) + }) { many { comment || css_definition } } - definitions = block( - opening_bracket: CssFontFaceExpectedOpeningBracket, - closing_bracket: CssFontFaceExpectedClosingBracket) do - many { comment || css_definition } - end + next unless definitions Ast::CssFontFace.new( definitions: definitions, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/css_keyframes.cr b/src/parsers/css_keyframes.cr index ddb157c5c..c883500a3 100644 --- a/src/parsers/css_keyframes.cr +++ b/src/parsers/css_keyframes.cr @@ -1,31 +1,43 @@ module Mint class Parser - syntax_error CssKeyframesExpectedOpeningBracket - syntax_error CssKeyframesExpectedClosingBracket - syntax_error CssKeyframesExpectedName - def css_keyframes : Ast::CssKeyframes? - start do |start_position| - next unless keyword "@keyframes" - + parse do |start_position| + next unless word! "@keyframes" whitespace name = - gather { chars_until '{' }.presence.try(&.strip) + gather { chars { char != '{' } }.presence.try(&.strip) - raise CssKeyframesExpectedName unless name + next error :css_keyframes_expected_name do + expected "the name of a CSS keyframes rule", word + snippet self + end unless name - selectors = block( - opening_bracket: CssKeyframesExpectedOpeningBracket, - closing_bracket: CssKeyframesExpectedClosingBracket) do + selectors = brackets( + ->{ error :css_keyframes_expected_opening_bracket do + expected "the opening bracket of a CSS keyframes rule", word + snippet self + end }, + ->{ error :css_keyframes_expected_closing_bracket do + expected "the closing bracket of a CSS keyframes rule", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :css_keyframes_expected_selectors do + expected "the selectors of a CSS keyframes rule", word + snippet self + end if items.all?(Ast::Comment) + }) { many { comment || css_selector(only_definitions: true) } - end + } + + next unless selectors Ast::CssKeyframes.new( from: start_position, selectors: selectors, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/css_nested_at.cr b/src/parsers/css_nested_at.cr index d51834fe9..7e38c9c84 100644 --- a/src/parsers/css_nested_at.cr +++ b/src/parsers/css_nested_at.cr @@ -1,37 +1,42 @@ module Mint class Parser - syntax_error CssNestedAtExpectedOpeningBracket - syntax_error CssNestedAtExpectedClosingBracket - syntax_error CssNestedAtExpectedCondition - - syntax_error CssNestedAtExpectedSpaceAfterKeyword - def css_nested_at : Ast::CssNestedAt? - start do |start_position| + parse do |start_position| next unless char! '@' - - name = gather { keyword("media") || keyword("supports") } - - next unless name - - whitespace! CssNestedAtExpectedSpaceAfterKeyword + next unless name = gather { word!("media") || word!("supports") } content = - gather { chars_until '{' }.presence.try(&.strip) - - raise CssNestedAtExpectedCondition unless content - - body = block( - opening_bracket: CssNestedAtExpectedOpeningBracket, - closing_bracket: CssNestedAtExpectedClosingBracket) do - css_body - end - - self << Ast::CssNestedAt.new( + gather { chars { char != '{' } }.presence.try(&.strip) + + next error :css_nested_at_expected_condition do + expected "the condition of a CSS at rule", word + snippet self + end unless content + + body = + brackets( + ->{ error :css_nested_at_expected_opening_bracket do + expected "the opening bracket of a CSS at rule", word + snippet self + end }, + ->{ error :css_nested_at_expected_closing_bracket do + expected "the closing bracket of a CSS at rule", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :css_nested_at_expected_body do + expected "the body of a CSS at rule", word + snippet self + end if items.empty? + }) { many { css_node } } + + next unless body + + Ast::CssNestedAt.new( from: start_position, content: content, to: position, - input: data, + file: file, name: name, body: body) end diff --git a/src/parsers/css_node.cr b/src/parsers/css_node.cr new file mode 100644 index 000000000..537148742 --- /dev/null +++ b/src/parsers/css_node.cr @@ -0,0 +1,14 @@ +module Mint + class Parser + def css_node : Ast::Node? + oneof do + case_expression(for_css: true) || + if_expression(for_css: true) || + css_definition || + css_nested_at || + css_selector || + comment + end + end + end +end diff --git a/src/parsers/css_selector.cr b/src/parsers/css_selector.cr index 96df90955..53476e730 100644 --- a/src/parsers/css_selector.cr +++ b/src/parsers/css_selector.cr @@ -1,10 +1,9 @@ module Mint class Parser - syntax_error CssSelectorExpectedOpeningBracket - syntax_error CssSelectorExpectedClosingBracket - def css_selector(only_definitions : Bool = false) : Ast::CssSelector? - start do |start_position| + parse do |start_position| + next if char == '/' + selectors = list( terminator: '{', separator: ',' @@ -13,45 +12,38 @@ module Mint next if selectors.empty? next unless char == '{' - body = block( - opening_bracket: CssSelectorExpectedOpeningBracket, - closing_bracket: CssSelectorExpectedClosingBracket) do - if only_definitions - many { comment || css_definition } - else - css_body + body = + brackets( + ->{ error :css_selector_expected_opening_bracket do + expected "the opening bracket of a CSS selector", word + snippet self + end }, + ->{ error :css_selector_expected_closing_bracket do + expected "the opening closing of a CSS selector", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :css_selector_expected_body do + expected "the body of a CSS selector", word + snippet self + end if items.empty? + }) do + if only_definitions + many { comment || css_definition } + else + many { css_node } + end end - end - self << Ast::CssSelector.new( + next unless body + + Ast::CssSelector.new( selectors: selectors, from: start_position, to: position, - input: data, + file: file, body: body) end end - - def css_selector_name : String? - if ampersand = char! '&' - colon = char!(':') - double_colon = keyword("::") - dot = char!('.') - bracket = char!('[') - end - - name = - gather { chars_until ',', '{', '}' }.presence.try(&.strip) - - return unless name || ampersand - - case - when colon then ":#{name}" - when double_colon then "::#{name}" - when dot then ".#{name}" - when bracket then "[#{name}" - else " #{name}" - end - end end end diff --git a/src/parsers/css_selector_name.cr b/src/parsers/css_selector_name.cr new file mode 100644 index 000000000..ffba246e7 --- /dev/null +++ b/src/parsers/css_selector_name.cr @@ -0,0 +1,25 @@ +module Mint + class Parser + def css_selector_name : String? + if ampersand = char! '&' + double_colon = word!("::") + bracket = char!('[') + colon = char!(':') + dot = char!('.') + end + + name = + gather { chars { |char| !char.in?(',', '{', '}') } }.presence.try(&.strip) + + return unless name || ampersand + + case + when double_colon then "::#{name}" + when bracket then "[#{name}" + when colon then ":#{name}" + when dot then ".#{name}" + else " #{name}" + end + end + end +end diff --git a/src/parsers/decode.cr b/src/parsers/decode.cr index 473491522..4ab488c11 100644 --- a/src/parsers/decode.cr +++ b/src/parsers/decode.cr @@ -1,31 +1,36 @@ module Mint class Parser - syntax_error DecodeExpectedExpression - syntax_error DecodeExpectedType - syntax_error DecodeExpectedAs - def decode : Ast::Decode? - start do |start_position| - next unless keyword "decode" - next unless whitespace? + parse do |start_position| + next unless word! "decode" whitespace - unless keyword "as" - expression = expression! DecodeExpectedExpression + unless word! "as" + whitespace + next error :decode_expected_subject do + expected "the subject of a decode expression", word + snippet self + end unless expression = self.expression whitespace - keyword! "as", DecodeExpectedAs + next error :decode_expected_as do + expected %(the "as" keyword of a decode expression), word + snippet self + end unless word! "as" end whitespace - type = type! DecodeExpectedType + next error :decode_expected_type do + expected "the type of a decode expression", word + snippet self + end unless type = self.type - self << Ast::Decode.new( + Ast::Decode.new( expression: expression, from: start_position, - type: type, to: position, - input: data) + type: type, + file: file) end end end diff --git a/src/parsers/destructuring.cr b/src/parsers/destructuring.cr index 94a391145..fcf0307d3 100644 --- a/src/parsers/destructuring.cr +++ b/src/parsers/destructuring.cr @@ -1,10 +1,9 @@ module Mint class Parser def destructuring : Ast::Node? - constant_access || - array_destructuring || + array_destructuring || tuple_destructuring || - enum_destructuring || + type_destructuring || expression end end diff --git a/src/parsers/directives/asset.cr b/src/parsers/directives/asset.cr index a08f51e00..30553d6f8 100644 --- a/src/parsers/directives/asset.cr +++ b/src/parsers/directives/asset.cr @@ -1,26 +1,30 @@ module Mint class Parser - syntax_error AssetDirectiveExpectedOpeningParentheses - syntax_error AssetDirectiveExpectedClosingParentheses - syntax_error AssetDirectiveExpectedPath - def asset_directive : Ast::Directives::Asset? - start do |start_position| - next unless keyword "@asset" + parse do |start_position| + next unless word! "@asset" - char '(', AssetDirectiveExpectedOpeningParentheses + next error :asset_directive_expected_opening_parenthesis do + expected "the opening parenthesis of an asset directive", word + snippet self + end unless char! '(' whitespace - path = gather { chars_until ')' } - raise AssetDirectiveExpectedPath unless path - + next error :asset_directive_expected_path do + expected "the path (to the asset) of an asset directive", word + snippet self + end unless path = gather { chars { char != ')' } }.presence.try(&.strip) whitespace - char ')', AssetDirectiveExpectedClosingParentheses - self << Ast::Directives::Asset.new( + next error :asset_directive_expected_closing_parenthesis do + expected "the closing parenthesis of an asset directive", word + snippet self + end unless char! ')' + + Ast::Directives::Asset.new( from: start_position, to: position, - input: data, + file: file, path: path) end end diff --git a/src/parsers/directives/documentation.cr b/src/parsers/directives/documentation.cr index 3d36434d3..6391701be 100644 --- a/src/parsers/directives/documentation.cr +++ b/src/parsers/directives/documentation.cr @@ -1,24 +1,31 @@ module Mint class Parser - syntax_error DocumentationDirectiveExpectedClosingParentheses - syntax_error DocumentationDirectiveExpectedOpeningParentheses - syntax_error DocumentationDirectiveExpectedEntity - def documentation_directive : Ast::Directives::Documentation? - start do |start_position| - next unless keyword "@documentation" + parse do |start_position| + next unless word! "@documentation" - char '(', DocumentationDirectiveExpectedOpeningParentheses + next error :documentation_directive_expected_opening_parenthesis do + expected "the opening parenthesis of a documentation directive", word + snippet self + end unless char! '(' whitespace - entity = type_id! DocumentationDirectiveExpectedEntity + + next error :documentation_directive_expected_entity do + expected "the entity (component, module, etc...) of a documentation directive", word + snippet self + end unless entity = id whitespace - char ')', DocumentationDirectiveExpectedClosingParentheses - self << Ast::Directives::Documentation.new( + next error :documentation_directive_expected_closing_parenthesis do + expected "the closing parenthesis of a documentation directive", word + snippet self + end unless char! ')' + + Ast::Directives::Documentation.new( from: start_position, entity: entity, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/directives/format.cr b/src/parsers/directives/format.cr index f16a07470..ebc61e751 100644 --- a/src/parsers/directives/format.cr +++ b/src/parsers/directives/format.cr @@ -1,24 +1,32 @@ module Mint class Parser - syntax_error FormatDirectiveExpectedOpeningBracket - syntax_error FormatDirectiveExpectedClosingBracket - syntax_error FormatDirectiveExpectedExpression - def format_directive : Ast::Directives::Format? - start do |start_position| - next unless keyword "@format" + parse do |start_position| + next unless word! "@format" + whitespace content = - code_block( - opening_bracket: FormatDirectiveExpectedOpeningBracket, - closing_bracket: FormatDirectiveExpectedClosingBracket, - statement_error: FormatDirectiveExpectedExpression) + block( + ->{ error :format_directive_expected_opening_bracket do + expected "the opening bracket of a format directive", word + snippet self + end }, + ->{ error :format_directive_expected_closing_bracket do + expected "the closing bracket of a format directive", word + snippet self + end }, + ->{ error :format_directive_expected_body do + expected "the body of a format directive", word + snippet self + end }) + + next unless content - self << Ast::Directives::Format.new( + Ast::Directives::Format.new( from: start_position, content: content, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/directives/highlight.cr b/src/parsers/directives/highlight.cr index e273354a7..2466160f6 100644 --- a/src/parsers/directives/highlight.cr +++ b/src/parsers/directives/highlight.cr @@ -1,24 +1,32 @@ module Mint class Parser - syntax_error FormatDirectiveExpectedOpeningBracket - syntax_error FormatDirectiveExpectedClosingBracket - syntax_error FormatDirectiveExpectedExpression - def highlight_directive : Ast::Directives::Highlight? - start do |start_position| - next unless keyword "@highlight" + parse do |start_position| + next unless word! "@highlight" + whitespace content = - code_block( - opening_bracket: FormatDirectiveExpectedOpeningBracket, - closing_bracket: FormatDirectiveExpectedClosingBracket, - statement_error: FormatDirectiveExpectedExpression) + block( + ->{ error :highlight_directive_expected_opening_bracket do + expected "the opening bracket of a highlight directive", word + snippet self + end }, + ->{ error :highlight_directive_expected_closing_bracket do + expected "the closing bracket of a highlight directive", word + snippet self + end }, + ->{ error :highlight_directive_expected_body do + expected "the body of a highlight directive", word + snippet self + end }) + + next unless content - self << Ast::Directives::Highlight.new( + Ast::Directives::Highlight.new( from: start_position, content: content, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/directives/inline.cr b/src/parsers/directives/inline.cr index 600bc4abc..467b775b6 100644 --- a/src/parsers/directives/inline.cr +++ b/src/parsers/directives/inline.cr @@ -1,26 +1,30 @@ module Mint class Parser - syntax_error InlineDirectiveExpectedOpeningParentheses - syntax_error InlineDirectiveExpectedClosingParentheses - syntax_error InlineDirectiveExpectedPath - def inline_directive : Ast::Directives::Inline? - start do |start_position| - next unless keyword "@inline" + parse do |start_position| + next unless word! "@inline" - char '(', InlineDirectiveExpectedOpeningParentheses + next error :inline_directive_expected_opening_parenthesis do + expected "the opening parenthesis of an inline directive", word + snippet self + end unless char! '(' whitespace - path = gather { chars_until ')' } - raise InlineDirectiveExpectedPath unless path - + next error :inline_directive_expected_path do + expected "the path (to the file to be inlined) of an inline directive", word + snippet self + end unless path = gather { chars { char != ')' } }.presence.try(&.strip) whitespace - char ')', InlineDirectiveExpectedClosingParentheses - self << Ast::Directives::Inline.new( + next error :inline_directive_expected_closing_parenthesis do + expected "the closing parenthesis of an inline directive", word + snippet self + end unless char! ')' + + Ast::Directives::Inline.new( from: start_position, to: position, - input: data, + file: file, path: path) end end diff --git a/src/parsers/directives/svg.cr b/src/parsers/directives/svg.cr index 75b9b4acf..c86925b61 100644 --- a/src/parsers/directives/svg.cr +++ b/src/parsers/directives/svg.cr @@ -1,26 +1,30 @@ module Mint class Parser - syntax_error SvgDirectiveExpectedOpeningParentheses - syntax_error SvgDirectiveExpectedClosingParentheses - syntax_error SvgDirectiveExpectedPath - def svg_directive : Ast::Directives::Svg? - start do |start_position| - next unless keyword "@svg" + parse do |start_position| + next unless word! "@svg" - char '(', SvgDirectiveExpectedOpeningParentheses + next error :svg_directive_expected_opening_parenthesis do + expected "the opening parenthesis of an svg directive", word + snippet self + end unless char! '(' whitespace - path = gather { chars_until ')' } - raise SvgDirectiveExpectedPath unless path - + next error :svg_directive_expected_path do + expected "the path (to the svg) of an svg directive", word + snippet self + end unless path = gather { chars { char != ')' } }.presence.try(&.strip) whitespace - char ')', SvgDirectiveExpectedClosingParentheses - self << Ast::Directives::Svg.new( + next error :svg_directive_expected_closing_parenthesis do + expected "the closing parenthesis of an svg directive", word + snippet self + end unless char! ')' + + Ast::Directives::Svg.new( from: start_position, to: position, - input: data, + file: file, path: path) end end diff --git a/src/parsers/encode.cr b/src/parsers/encode.cr index 665d8fbd1..f7dc7d71e 100644 --- a/src/parsers/encode.cr +++ b/src/parsers/encode.cr @@ -1,20 +1,29 @@ module Mint class Parser - syntax_error EncodeExpectedExpression - def encode : Ast::Encode? - start do |start_position| - next unless keyword "encode" - next unless whitespace? + parse do |start_position| + next unless word! "encode" whitespace - expression = expression! EncodeExpectedExpression + next error :encode_expected_expression do + block do + text "The" + bold "object to be encoded" + text "must come from an" + bold "expression," + text "here is an example:" + end + + snippet %(encode "A string for example!") + expected "the expression", word + snippet self + end unless expression = self.expression - self << Ast::Encode.new( + Ast::Encode.new( expression: expression, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/enum.cr b/src/parsers/enum.cr deleted file mode 100644 index 1a54106d3..000000000 --- a/src/parsers/enum.cr +++ /dev/null @@ -1,63 +0,0 @@ -module Mint - class Parser - syntax_error EnumExpectedClosingParentheses - syntax_error EnumExpectedOpeningBracket - syntax_error EnumExpectedClosingBracket - syntax_error EnumExpectedName - - def enum - start do |start_position| - comment = self.comment - - next unless keyword "enum" - whitespace - - name = type_id! EnumExpectedName - whitespace - - parameters = [] of Ast::TypeVariable - - if char! '(' - whitespace - - parameters.concat list( - terminator: ')', - separator: ',' - ) { type_variable } - - whitespace - char ')', EnumExpectedClosingParentheses - end - - body = block( - opening_bracket: EnumExpectedOpeningBracket, - closing_bracket: EnumExpectedClosingBracket - ) do - many { enum_option || self.comment } - end - - options = [] of Ast::EnumOption - comments = [] of Ast::Comment - - body.each do |item| - case item - when Ast::EnumOption - options << item - when Ast::Comment - comments << item - end - end - - self << Ast::Enum.new( - parameters: parameters, - from: start_position, - comments: comments, - comment: comment, - options: options, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/enum_destructuring.cr b/src/parsers/enum_destructuring.cr deleted file mode 100644 index 7d6e8e7e4..000000000 --- a/src/parsers/enum_destructuring.cr +++ /dev/null @@ -1,38 +0,0 @@ -module Mint - class Parser - syntax_error EnumDestructuringExpectedDoubleColon - syntax_error EnumDestructuringExpectedOption - syntax_error EnumDestructuringExpectedClosingParentheses - - def enum_destructuring - start do |start_position| - next unless option = type_id track: false - - if keyword "::" - name = option - option = type_id! EnumDestructuringExpectedOption, track: false - end - - parameters = [] of Ast::Node - - if char! '(' - parameters.concat list( - terminator: ')', - separator: ',' - ) { destructuring } - - whitespace - char ')', EnumDestructuringExpectedClosingParentheses - end - - self << Ast::EnumDestructuring.new( - parameters: parameters, - from: start_position, - option: option, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/enum_id.cr b/src/parsers/enum_id.cr deleted file mode 100644 index aada4b458..000000000 --- a/src/parsers/enum_id.cr +++ /dev/null @@ -1,50 +0,0 @@ -module Mint - class Parser - syntax_error EnumIdExpectedClosingParentheses - syntax_error EnumIdExpectedDoubleColon - syntax_error EnumIdExpectedOption - - def enum_id_expressions - expressions = [] of Ast::Expression - - if char! '(' - whitespace - - item = enum_record - - if item - expressions << item - else - expressions.concat list( - terminator: ')', - separator: ',' - ) { expression } - end - - whitespace - return unless char! ')' - end - - expressions - end - - def enum_id - start do |start_position| - next unless option = type_id track: false - - if keyword "::" - name = option - option = type_id! EnumIdExpectedOption, track: false - end - - self << Ast::EnumId.new( - expressions: enum_id_expressions || [] of Ast::Expression, - from: start_position, - option: option, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/enum_option.cr b/src/parsers/enum_option.cr deleted file mode 100644 index ac815b9d6..000000000 --- a/src/parsers/enum_option.cr +++ /dev/null @@ -1,36 +0,0 @@ -module Mint - class Parser - syntax_error EnumOptionExpectedClosingParentheses - - def enum_option - start do |start_position| - comment = self.comment - - next unless value = type_id - whitespace - - parameters = [] of Ast::TypeVariable | Ast::Type - - if char! '(' - whitespace - - parameters.concat list( - terminator: ')', - separator: ',' - ) { enum_record_definition || type_variable || type } - - whitespace - char ')', EnumOptionExpectedClosingParentheses - end - - self << Ast::EnumOption.new( - parameters: parameters, - from: start_position, - comment: comment, - value: value, - to: position, - input: data) - end - end - end -end diff --git a/src/parsers/enum_record.cr b/src/parsers/enum_record.cr deleted file mode 100644 index d21d5dd35..000000000 --- a/src/parsers/enum_record.cr +++ /dev/null @@ -1,23 +0,0 @@ -module Mint - class Parser - def enum_record : Ast::EnumRecord? - start do |start_position| - fields = - list( - terminator: ')', - separator: ',' - ) { record_field } - - next if fields.empty? - - Ast::EnumRecord.new( - from: start_position, - fields: fields, - to: position, - input: data) - end - rescue error : SyntaxError - nil - end - end -end diff --git a/src/parsers/enum_record_definition.cr b/src/parsers/enum_record_definition.cr deleted file mode 100644 index 03ba50688..000000000 --- a/src/parsers/enum_record_definition.cr +++ /dev/null @@ -1,23 +0,0 @@ -module Mint - class Parser - def enum_record_definition - start do |start_position| - fields = - list( - terminator: ')', - separator: ',' - ) { record_definition_field } - - next if fields.empty? - - Ast::EnumRecordDefinition.new( - from: start_position, - fields: fields, - to: position, - input: data) - end - rescue error : SyntaxError - nil - end - end -end diff --git a/src/parsers/env.cr b/src/parsers/env.cr index 43621a023..30c44072a 100644 --- a/src/parsers/env.cr +++ b/src/parsers/env.cr @@ -1,26 +1,18 @@ module Mint class Parser - syntax_error EnvExpectedName - def env : Ast::Env? - start do |start_position| + parse do |start_position| next unless char! '@' - head = - gather { chars(&.ascii_uppercase?) }.to_s - - tail = - gather { chars { |char| char.ascii_uppercase? || char == '_' } }.to_s - - name = - "#{head}#{tail}" - - raise EnvExpectedName if name.empty? + next error :env_expected_name do + expected "the name of the environment variable", word + snippet self + end unless name = identifier_constant - self << Ast::Env.new( + Ast::Env.new( from: start_position, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/expression.cr b/src/parsers/expression.cr index 90ff18400..f15dadd49 100644 --- a/src/parsers/expression.cr +++ b/src/parsers/expression.cr @@ -1,35 +1,12 @@ module Mint class Parser - def expression!(error : SyntaxError.class) : Ast::Expression - expression || raise error - end - - def array_access_or_call(lhs) - case char - when '.' - access(lhs) - when '(' - call(lhs) - when '[' - array_access(lhs) - else - lhs - end - end - - def expression : Ast::Expression? - return unless left = basic_expression - - # Make sure there is no whitespace after an expression - track_back_whitespace - - # Handle array access - left = array_access_or_call(left) + def expression : Ast::Node? + return unless expression = base_expression if operator = self.operator - rollup_pipe operation(left, operator) + pipe operation(expression, operator) else - left + expression end end end diff --git a/src/parsers/field.cr b/src/parsers/field.cr new file mode 100644 index 000000000..aeb957587 --- /dev/null +++ b/src/parsers/field.cr @@ -0,0 +1,31 @@ +module Mint + class Parser + def field(*, key_required : Bool = true) : Ast::Field? + parse do |start_position| + comment = self.comment + + key = + parse(track: false) do + next unless item = variable + whitespace + + next unless char! ':' + whitespace + + item + end + + next if key_required && !key + next unless value = expression + + Ast::Field.new( + from: start_position, + comment: comment, + value: value, + to: position, + file: file, + key: key) + end + end + end +end diff --git a/src/parsers/for.cr b/src/parsers/for.cr index 34ba64a49..02e80257c 100644 --- a/src/parsers/for.cr +++ b/src/parsers/for.cr @@ -1,53 +1,81 @@ module Mint class Parser - syntax_error ForExpectedClosingParentheses - syntax_error ForExpectedOpeningBracket - syntax_error ForExpectedClosingBracket - syntax_error ForExpectedSubject - syntax_error ForExpectedBody - syntax_error ForExpectedOf - def for_expression : Ast::For? - start do |start_position| - next unless keyword "for" - next unless whitespace? + parse do |start_position| + next unless word! "for" whitespace parens = char! '(' whitespace - arguments = list( - terminator: parens ? ')' : '{', - separator: ',' - ) { variable } + arguments = + list(terminator: parens ? ')' : '{', separator: ',') { variable } whitespace - keyword! "of", ForExpectedOf + next error :for_expected_of do + expected %(the "of" keyword of a for expression), word + snippet self + end unless word! "of" whitespace - subject = expression! ForExpectedSubject - + next error :for_expected_subject do + expected "the subject of a for expression", word + snippet self + end unless subject = expression whitespace - char ')', ForExpectedClosingParentheses if parens + + next error :for_expected_closing_parenthesis do + expected "the closing parenthesis of a for expression", word + snippet self + end if parens && !char!(')') whitespace body = - code_block( - opening_bracket: ForExpectedOpeningBracket, - closing_bracket: ForExpectedClosingBracket, - statement_error: ForExpectedBody) + block( + ->{ error :for_expected_opening_bracket do + expected "the opening bracket of a for expression", word + snippet self + end }, + ->{ error :for_expected_closing_bracket do + expected "the closing bracket of a for expression", word + snippet self + end }, + ->{ error :for_expected_body do + expected "the body of a for expression", word + snippet self + end }) + + next unless body whitespace - condition = for_condition - whitespace + condition = + if word! "when" + whitespace + + block( + ->{ error :for_condition_expected_opening_bracket do + expected "the opening bracket of a for condition", word + snippet self + end }, + ->{ error :for_condition_expected_closing_bracket do + expected "the closing bracket of a for condition", word + snippet self + end }, + ->{ + error :for_condition_expected_body do + expected "the body of a for condition", word + snippet self + end + }) + end - self << Ast::For.new( + Ast::For.new( condition: condition, arguments: arguments, from: start_position, subject: subject, to: position, - input: data, + file: file, body: body) end end diff --git a/src/parsers/for_condition.cr b/src/parsers/for_condition.cr deleted file mode 100644 index 2b48d7db8..000000000 --- a/src/parsers/for_condition.cr +++ /dev/null @@ -1,26 +0,0 @@ -module Mint - class Parser - syntax_error ForConditionExpectedOpeningBracket - syntax_error ForConditionExpectedClosingBracket - syntax_error ForConditionExpectedBody - - def for_condition : Ast::ForCondition? - start do |start_position| - next unless keyword "when" - whitespace - - condition = - code_block( - opening_bracket: ForConditionExpectedOpeningBracket, - closing_bracket: ForConditionExpectedClosingBracket, - statement_error: ForConditionExpectedBody) - - self << Ast::ForCondition.new( - condition: condition, - from: start_position, - to: position, - input: data) - end - end - end -end diff --git a/src/parsers/function.cr b/src/parsers/function.cr index d1ab46238..5500c315b 100644 --- a/src/parsers/function.cr +++ b/src/parsers/function.cr @@ -1,58 +1,67 @@ module Mint class Parser - syntax_error FunctionExpectedClosingParentheses - syntax_error FunctionExpectedOpeningBracket - syntax_error FunctionExpectedClosingBracket - syntax_error FunctionExpectedTypeOrVariable - syntax_error FunctionExpectedExpression - syntax_error FunctionExpectedName - def function : Ast::Function? - start do |start_position| + parse do |start_position| comment = self.comment - next unless keyword "fun" + next unless word! "fun" whitespace - name = variable! FunctionExpectedName, track: false + next error :function_expected_name do + expected "the name of the function", word + snippet self + end unless name = variable track: false whitespace - arguments = [] of Ast::Argument - - if char! '(' - whitespace - - arguments.concat list( - terminator: ')', - separator: ',' - ) { argument } + arguments = + if char! '(' + whitespace + items = list(terminator: ')', separator: ',') { argument } + whitespace - whitespace - char ')', FunctionExpectedClosingParentheses - end + next error :function_expected_closing_parenthesis do + expected "the closing parenthesis of a function", word + snippet self + end unless char! ')' + whitespace - whitespace + items + end || [] of Ast::Argument type = if char! ':' whitespace - item = type_or_type_variable! FunctionExpectedTypeOrVariable + next error :function_expected_type_or_variable do + expected "the type of a function", word + snippet self + end unless item = self.type || type_variable whitespace item end body = - code_block( - opening_bracket: FunctionExpectedOpeningBracket, - closing_bracket: FunctionExpectedClosingBracket, - statement_error: FunctionExpectedExpression) + block( + ->{ error :function_expected_opening_bracket do + expected "the opening bracket of a function", word + snippet self + end }, + ->{ error :function_expected_closing_bracket do + expected "the closing bracket of a function", word + snippet self + end }, + ->{ error :function_expected_expression do + expected "the body of a function", word + snippet self + end }) + + next unless body - self << Ast::Function.new( + Ast::Function.new( arguments: arguments, from: start_position, comment: comment, to: position, - input: data, + file: file, body: body, name: name, type: type) diff --git a/src/parsers/get.cr b/src/parsers/get.cr index 54593ab7b..2df6308ea 100644 --- a/src/parsers/get.cr +++ b/src/parsers/get.cr @@ -1,43 +1,50 @@ module Mint class Parser - syntax_error GetExpectedOpeningBracket - syntax_error GetExpectedClosingBracket - syntax_error GetExpectedExpression - syntax_error GetExpectedColon - syntax_error GetExpectedName - syntax_error GetExpectedType - def get : Ast::Get? - start do |start_position| + parse do |start_position| comment = self.comment - next unless keyword "get" + next unless word! "get" whitespace - name = variable! GetExpectedName, track: false + next error :get_expected_name do + expected "the name of a get", word + snippet self + end unless name = variable track: false whitespace type = if char! ':' whitespace - item = type_or_type_variable! GetExpectedType + next error :get_expected_type do + expected "the type of a get", word + snippet self + end unless item = self.type || type_variable whitespace item end body = - code_block( - opening_bracket: GetExpectedOpeningBracket, - closing_bracket: GetExpectedClosingBracket, - statement_error: GetExpectedExpression) + block(->{ error :get_expected_opening_bracket do + expected "the opening bracket of a get", word + snippet self + end }, + ->{ error :get_expected_closing_bracket do + expected "the closing bracket of a get", word + snippet self + end }, + ->{ error :get_expected_expression do + expected "the body of a get", word + snippet self + end }) - whitespace + next unless body - self << Ast::Get.new( + Ast::Get.new( from: start_position, comment: comment, to: position, - input: data, + file: file, name: name, body: body, type: type) diff --git a/src/parsers/here_doc.cr b/src/parsers/here_doc.cr deleted file mode 100644 index c5939db69..000000000 --- a/src/parsers/here_doc.cr +++ /dev/null @@ -1,50 +0,0 @@ -module Mint - class Parser - syntax_error HereDocExpectedStart - syntax_error HereDocExpectedEnd - - def here_doc_part(token : String) - gather do - while char != '\0' && !keyword_ahead?(token) - break if char == '#' && - next_char == '{' && - prev_char != '\\' - step - end - end - end - - def here_doc(with_interpolation : Bool = true) : Ast::HereDoc? - start do |start_position| - next unless keyword "<<" - next unless char!('~') || char!('#') || char!('-') - - modifier = - prev_char - - head = - gather { chars &.ascii_uppercase? } - - tail = - gather { chars { |char| char.ascii_uppercase? || char.ascii_number? || char == '_' } } - - raise HereDocExpectedStart unless head || tail - - token = - "#{head}#{tail}" - - value = many(parse_whitespace: false) { here_doc_part(token) || interpolation } - - raise HereDocExpectedEnd unless keyword(token) - - Ast::HereDoc.new( - from: start_position, - modifier: modifier, - value: value, - to: position, - input: data, - token: token) - end - end - end -end diff --git a/src/parsers/here_document.cr b/src/parsers/here_document.cr new file mode 100644 index 000000000..161a044a5 --- /dev/null +++ b/src/parsers/here_document.cr @@ -0,0 +1,36 @@ +module Mint + class Parser + def here_document : Ast::HereDocument? + parse do |start_position| + next unless word! "<<" + next unless char!('~') || char!('#') || char!('-') + + modifier = + previous_char + + token = + identifier_constant + + next error :here_document_expected_start do + expected "the start tag of a here document", word + snippet self + end unless token + + value = many(parse_whitespace: false) { raw(token) || interpolation } + + next error :here_doc_expected_end do + expected "the end tag of a here document", word + snippet self + end unless word!(token) + + Ast::HereDocument.new( + from: start_position, + modifier: modifier, + token: token, + value: value, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/html_attribute.cr b/src/parsers/html_attribute.cr index 133d00653..553c4e798 100644 --- a/src/parsers/html_attribute.cr +++ b/src/parsers/html_attribute.cr @@ -1,38 +1,45 @@ module Mint class Parser - syntax_error HtmlAttributeExpectedOpeningBracket - syntax_error HtmlAttributeExpectedClosingBracket - syntax_error HtmlAttributeExpectedExpression - syntax_error HtmlAttributeExpectedEqualSign - - def html_attribute(with_dashes : Bool = true, fixed_name : String? = nil) : Ast::HtmlAttribute? - start do |start_position| - name = with_dashes ? variable_attribute_name : variable(track: false) - + def html_attribute(with_dashes : Bool = true) : Ast::HtmlAttribute? + parse do |start_position| + name = variable track: false, extra_chars: with_dashes ? ['-', ':'] : [] of Char next unless name - next if fixed_name && name.value != fixed_name - char '=', HtmlAttributeExpectedEqualSign + next error :html_attribute_expected_equal_sign do + expected "the equal sign of an HTML attribute", word + snippet self + end unless char! '=' case - when keyword_ahead?("<{") && (value = html_expression) + when word?("<{") && (value = html_expression) value when char == '"' && (value = string_literal) value - when char == '[' && (value = array) + when char == '[' && (value = array_literal) value else - value = code_block( - opening_bracket: HtmlAttributeExpectedOpeningBracket, - closing_bracket: HtmlAttributeExpectedClosingBracket, - statement_error: HtmlAttributeExpectedExpression) + value = block( + ->{ error :html_attribute_expected_opening_bracket do + expected "the opening bracket of an HTML attribute", word + snippet self + end }, + ->{ error :html_attribute_expected_closing_bracket do + expected "the closing bracket of an HTML attribute", word + snippet self + end }, + ->{ error :html_attribute_expected_expression do + expected "the expression of an HTML attribute", word + snippet self + end }) end - self << Ast::HtmlAttribute.new( - value: value.as(Ast::Expression), + next unless value + + Ast::HtmlAttribute.new( from: start_position, to: position, - input: data, + value: value, + file: file, name: name) end end diff --git a/src/parsers/html_body.cr b/src/parsers/html_body.cr index 85183c3dd..7cf7c1b68 100644 --- a/src/parsers/html_body.cr +++ b/src/parsers/html_body.cr @@ -1,70 +1,48 @@ module Mint class Parser - def html_content - here_doc || - svg_directive || - html_element || - html_component || - html_expression || - html_fragment || - string_literal || - array || - if_expression || - for_expression || - case_expression || - comment - end - - def html_body(expected_closing_bracket : SyntaxError.class, - expected_closing_tag : SyntaxError.class, - tag : Ast::Variable | Ast::TypeId, + def html_body(expected_closing_bracket : Proc(Nil), + expected_closing_tag : Proc(Nil), + tag : Ast::Variable | Ast::Id, with_dashes : Bool) - whitespace - attributes = many { html_attribute(with_dashes) } - whitespace + parse(track: false) do + attributes = many { html_attribute(with_dashes) } + whitespace - self_closing = char! '/' - char '>', expected_closing_bracket + self_closing = char! '/' + next expected_closing_bracket.call unless char! '>' - children = [] of Ast::Node - comments = [] of Ast::Comment + comments = [] of Ast::Comment + children = [] of Ast::Node - unless self_closing - items = many do - html_content.as(Ast::Node | Ast::Comment?) - end + unless self_closing + items = many { expression || comment } + whitespace - whitespace + closing_tag = + case tag + when Ast::Variable, Ast::Id + tag.value + else + tag + end - closing_tag = - case tag - when Ast::Variable, Ast::TypeId - tag.value - else - tag - end - - closing_tag_position = - position + 2 + closing_tag_position = + position + 2 - raise expected_closing_tag, position, { - "opening_tag" => tag, - } unless keyword "" + expected_closing_tag.call unless word! "" - items.each do |item| - case item - when Ast::Comment - comments << item - when Ast::Node - children << item + items.each do |item| + case item + when Ast::Comment + comments << item + when Ast::Node + children << item + end end end - end - {attributes, - children, - comments, - closing_tag_position} + {attributes, children, comments, closing_tag_position} + end end end end diff --git a/src/parsers/html_component.cr b/src/parsers/html_component.cr index 4147ac54e..da3b3013b 100644 --- a/src/parsers/html_component.cr +++ b/src/parsers/html_component.cr @@ -1,34 +1,42 @@ module Mint class Parser - syntax_error HtmlComponentExpectedClosingBracket - syntax_error HtmlComponentExpectedClosingTag - syntax_error HtmlComponentExpectedReference - syntax_error HtmlComponentExpectedType - def html_component : Ast::HtmlComponent? - start do |start_position| - component = start do - next unless char! '<' - type_id HtmlComponentExpectedType - end - - next unless component + parse do |start_position| + next unless char! '<' + next unless component = id + whitespace - ref = start do + if word! "as" whitespace - next unless keyword "as" - whitespace - variable! HtmlComponentExpectedReference + + next error :html_component_expected_reference do + expected "the reference of the HTML component", word + snippet self + end unless ref = variable end - attributes, children, comments, closing_tag_position = + body = html_body( - expected_closing_bracket: HtmlComponentExpectedClosingBracket, - expected_closing_tag: HtmlComponentExpectedClosingTag, with_dashes: false, - tag: component) + tag: component, + expected_closing_bracket: ->{ + error :html_component_expected_closing_bracket do + expected "the closing bracket of a HTML component", word + snippet self + end + }, + expected_closing_tag: ->{ + error :html_component_expected_closing_tag do + expected "the closing tag of a HTML component", word + snippet self + end + }) - node = self << Ast::HtmlComponent.new( + next unless body + + attributes, children, comments, closing_tag_position = body + + Ast::HtmlComponent.new( closing_tag_position: closing_tag_position, attributes: attributes, from: start_position, @@ -36,12 +44,8 @@ module Mint children: children, comments: comments, to: position, - input: data, + file: file, ref: ref) - - refs << {ref, node} if ref - - node end end end diff --git a/src/parsers/html_element.cr b/src/parsers/html_element.cr index 5c2db7e21..b74a76c80 100644 --- a/src/parsers/html_element.cr +++ b/src/parsers/html_element.cr @@ -1,43 +1,55 @@ module Mint class Parser - syntax_error HtmlElementExpectedClosingBracket - syntax_error HtmlElementExpectedClosingTag - syntax_error HtmlElementExpectedReference - syntax_error HtmlElementExpectedStyle - def html_element : Ast::HtmlElement? - start do |start_position| - tag = start do - next unless char! '<' - next unless value = variable_with_dashes track: false - value - end - - next unless tag + parse do |start_position| + next unless char! '<' + next unless tag = variable track: false, extra_chars: ['-'] styles = [] of Ast::HtmlStyle - if keyword_ahead? "::" + if word? "::" styles = many(parse_whitespace: false) { html_style } - raise HtmlElementExpectedStyle if styles.empty? + # We need to consume the double colon for the error. + @position += 2 if word? "::" + + next error :html_element_expected_style do + expected "the style for an HTML element", word + snippet self + end if styles.empty? end - ref = start do - whitespace - next unless keyword "as" + whitespace + if word! "as" whitespace - variable! HtmlElementExpectedReference + next error :html_element_expected_reference do + expected "the reference of an HTML element", word + snippet self + end unless ref = variable end - attributes, children, comments, closing_tag_position = + body = html_body( - expected_closing_bracket: HtmlElementExpectedClosingBracket, - expected_closing_tag: HtmlElementExpectedClosingTag, with_dashes: true, - tag: tag) + tag: tag, + expected_closing_bracket: ->{ + error :html_element_expected_closing_bracket do + expected "the closing bracket of an HTML element", word + snippet self + end + }, + expected_closing_tag: ->{ + error :html_element_expected_closing_tag do + expected "the closing tag of an HTML element", word + snippet self + end + }) - node = self << Ast::HtmlElement.new( + next unless body + + attributes, children, comments, closing_tag_position = body + + Ast::HtmlElement.new( closing_tag_position: closing_tag_position, attributes: attributes, from: start_position, @@ -45,13 +57,9 @@ module Mint comments: comments, styles: styles, to: position, - input: data, + file: file, tag: tag, ref: ref) - - refs << {ref, node} if ref - - node end end end diff --git a/src/parsers/html_expression.cr b/src/parsers/html_expression.cr index d6e623b4b..8bc141c39 100644 --- a/src/parsers/html_expression.cr +++ b/src/parsers/html_expression.cr @@ -1,22 +1,23 @@ module Mint class Parser - syntax_error HtmlExpressionExpectedClosingTag - def html_expression : Ast::HtmlExpression? - start do |start_position| - next unless keyword "<{" + parse do |start_position| + next unless word! "<{" whitespace expressions = many { expression } whitespace - keyword! "}>", HtmlExpressionExpectedClosingTag + next error :html_expression_expected_closing_tag do + expected "the closing tag of an HTML expression", word + snippet self + end unless word! "}>" - self << Ast::HtmlExpression.new( + Ast::HtmlExpression.new( expressions: expressions, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/html_fragment.cr b/src/parsers/html_fragment.cr index 40888e158..8bba3ec5e 100644 --- a/src/parsers/html_fragment.cr +++ b/src/parsers/html_fragment.cr @@ -1,29 +1,13 @@ module Mint class Parser - syntax_error HtmlFragmentExpectedClosingBracket - syntax_error HtmlFragmentExpectedClosingTag - def html_fragment : Ast::HtmlFragment? - start do |start_position| - next unless char! '<' - - # Test for closing tag - whitespace - next if char! '/' - - key = html_attribute false, "key" - whitespace + parse do |start_position| + next unless word! "<>" - char '>', HtmlFragmentExpectedClosingBracket - - children = [] of Ast::Node comments = [] of Ast::Comment + children = [] of Ast::Node - items = many do - html_content.as(Ast::Node | Ast::Comment?) - end - - items.each do |item| + many { expression || comment }.each do |item| case item when Ast::Comment comments << item @@ -33,15 +17,17 @@ module Mint end whitespace - keyword! "", HtmlFragmentExpectedClosingTag + next error :html_fragment_expected_closing_tag do + expected "the closing tag of an HTML fragment", word + snippet self + end unless word! "" - self << Ast::HtmlFragment.new( + Ast::HtmlFragment.new( from: start_position, children: children, comments: comments, to: position, - input: data, - key: key) + file: file) end end end diff --git a/src/parsers/html_style.cr b/src/parsers/html_style.cr index 74e72152e..36aaf5958 100644 --- a/src/parsers/html_style.cr +++ b/src/parsers/html_style.cr @@ -1,33 +1,28 @@ module Mint class Parser - syntax_error HtmlStyleExpectedClosingParentheses - def html_style : Ast::HtmlStyle? - start do |start_position| - name = start do - next unless keyword "::" - next unless value = variable_with_dashes track: false - value - end - - next unless name + parse do |start_position| + next unless word! "::" + next unless name = variable track: false, extra_chars: ['-'] arguments = [] of Ast::Node if char! '(' whitespace - arguments = list(terminator: ')', separator: ',') { expression } whitespace - char ')', HtmlStyleExpectedClosingParentheses + next error :html_style_expected_closing_parenthesis do + expected "the closing parenthesis of a style call", word + snippet self + end unless char! ')' end Ast::HtmlStyle.new( arguments: arguments, from: start_position, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/id.cr b/src/parsers/id.cr new file mode 100644 index 000000000..ce821f4b8 --- /dev/null +++ b/src/parsers/id.cr @@ -0,0 +1,15 @@ +module Mint + class Parser + def id(*, track : Bool = true) : Ast::Id? + parse(track: track) do |start_position| + return unless value = identifier_type + + Ast::Id.new( + from: start_position, + value: value, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/if.cr b/src/parsers/if.cr index 54f47a607..6ed704384 100644 --- a/src/parsers/if.cr +++ b/src/parsers/if.cr @@ -1,73 +1,76 @@ module Mint class Parser - syntax_error IfExpectedTruthyOpeningBracket - syntax_error IfExpectedTruthyClosingBracket - syntax_error IfExpectedFalsyOpeningBracket - syntax_error IfExpectedFalsyClosingBracket - syntax_error IfExpectedClosingParentheses - syntax_error IfExpectedTruthyExpression - syntax_error IfExpectedFalsyExpression - syntax_error IfExpectedCondition - def if_expression(for_css = false) : Ast::If? - start do |start_position| - next unless keyword "if" - + parse do |start_position| + next unless word! "if" whitespace + parens = char! '(' whitespace - condition = statement || expression!(IfExpectedCondition) + + next error :if_expected_condition do + expected "the condition", word + snippet self + end unless condition = statement || expression whitespace - char ')', IfExpectedClosingParentheses if parens + + next error :if_expected_closing_parenthesis do + expected "the closing parenthesis of the condition of an if expression", word + snippet self + end if parens && !char!(')') whitespace truthy = - if for_css - block( - opening_bracket: IfExpectedTruthyOpeningBracket, - closing_bracket: IfExpectedTruthyClosingBracket) do - many { css_definition } - end - else - code_block( - opening_bracket: IfExpectedTruthyOpeningBracket, - closing_bracket: IfExpectedTruthyClosingBracket, - statement_error: IfExpectedTruthyExpression) - end + block( + ->{ error :if_expected_truthy_opening_bracket do + expected "the opening bracket of the truthy branch", word + snippet self + end }, + ->{ error :if_expected_truthy_closing_bracket do + expected "the closing bracket of the truthy branch", word + snippet self + end }, + + ->{ error :if_expected_truthy_expression do + expected "an expression for the truthy branch", word + snippet self + end }) { for_css ? css_definition : comment || statement } - raise IfExpectedTruthyExpression unless truthy + next unless truthy falsy = nil whitespace - if keyword "else" + if word! "else" whitespace unless falsy = if_expression(for_css: for_css) falsy = - if for_css - block( - opening_bracket: IfExpectedFalsyOpeningBracket, - closing_bracket: IfExpectedFalsyClosingBracket) do - many { css_definition } - end - else - code_block( - opening_bracket: IfExpectedFalsyOpeningBracket, - closing_bracket: IfExpectedFalsyClosingBracket, - statement_error: IfExpectedFalsyExpression) - end + block( + ->{ error :if_expected_else_opening_bracket do + expected "the opening bracket of the else branch", word + snippet self + end }, + ->{ error :if_expected_else_closing_bracket do + expected "the closing bracket of the else branch", word + snippet self + end }, + ->{ error :if_expected_else_expression do + expected "an expression for the else branch", word + snippet self + end }) { for_css ? css_definition : comment || statement } - raise IfExpectedFalsyExpression unless falsy + next unless falsy end end - self << Ast::If.new( + Ast::If.new( branches: {truthy, falsy}, condition: condition, from: start_position, to: position, - input: data).tap do |node| + file: file + ).tap do |node| case condition when Ast::Statement condition.if_node = node diff --git a/src/parsers/inline_function.cr b/src/parsers/inline_function.cr index 2ae30a277..f7149c2e8 100644 --- a/src/parsers/inline_function.cr +++ b/src/parsers/inline_function.cr @@ -1,45 +1,55 @@ module Mint class Parser - syntax_error InlineFunctionExpectedClosingParentheses - syntax_error InlineFunctionExpectedOpeningBracket - syntax_error InlineFunctionExpectedClosingBracket - syntax_error InlineFunctionExpectedExpression - syntax_error InlineFunctionExpectedType - def inline_function : Ast::InlineFunction? - start do |start_position| + parse do |start_position| next unless char! '(' - whitespace arguments = list( terminator: ')', separator: ',' ) { argument } - whitespace - char ')', InlineFunctionExpectedClosingParentheses + + next error :inline_function_expected_closing_parenthesis do + expected "the closing parenthesis of an inline function", word + snippet self + end unless char! ')' whitespace type = if char! ':' whitespace - item = type_or_type_variable! InlineFunctionExpectedType + next error :inline_function_expected_type do + expected "the type of an inline function", word + snippet self + end unless item = self.type || type_variable whitespace item end body = - code_block( - opening_bracket: InlineFunctionExpectedOpeningBracket, - closing_bracket: InlineFunctionExpectedClosingBracket, - statement_error: InlineFunctionExpectedExpression) + block( + ->{ error :inline_function_expected_opening_bracket do + expected "the opening bracket of an inline function", word + snippet self + end }, + ->{ error :inline_function_expected_closing_bracket do + expected "the closing bracket of an inline function", word + snippet self + end }, + ->{ error :inline_function_expected_body do + expected "the body of an inline function", word + snippet self + end }) + + next unless body - self << Ast::InlineFunction.new( + Ast::InlineFunction.new( arguments: arguments, from: start_position, to: position, - input: data, + file: file, body: body, type: type) end diff --git a/src/parsers/interpolation.cr b/src/parsers/interpolation.cr index cc9fc6a14..ad50e5bfe 100644 --- a/src/parsers/interpolation.cr +++ b/src/parsers/interpolation.cr @@ -1,23 +1,26 @@ module Mint class Parser - syntax_error InterpolationExpectedClosingBracket - syntax_error InterpolationExpectedExpression - def interpolation : Ast::Interpolation? - start do |start_position| - next unless keyword "\#{" - + parse do |start_position| + next unless word! "\#{" whitespace - expression = expression! InterpolationExpectedExpression + + next error :interpolation_expected_expression do + expected "the expression of an interpolation", word + snippet self + end unless expression = self.expression whitespace - char '}', InterpolationExpectedClosingBracket + next error :interpolation_expected_closing_bracket do + expected "the closing bracket of an interpolation", word + snippet self + end unless char! '}' Ast::Interpolation.new( expression: expression, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/js.cr b/src/parsers/js.cr index 90e5c2d32..61599c07d 100644 --- a/src/parsers/js.cr +++ b/src/parsers/js.cr @@ -1,61 +1,34 @@ module Mint class Parser - syntax_error JsExpectedTypeOrVariable - syntax_error JsExpectedClosingTick - def js : Ast::Js? - start do |start_position| + parse do |start_position| next unless char! '`' - value = many(parse_whitespace: false) do - (not_interpolation_part('`') || interpolation).as(Ast::Interpolation | String?) - end + value = + many(parse_whitespace: false) do + raw('`').try(&.gsub("\\`", '`')) || interpolation + end - char '`', JsExpectedClosingTick + next error :js_expected_closing_tick do + expected "the closing tick of an inlined JavaScript", word + snippet self + end unless char! '`' + whitespace - type = start do - whitespace - next unless keyword "as" + if word! "as" whitespace - type_or_type_variable! JsExpectedTypeOrVariable + next error :js_expected_type_or_variable do + expected "the type of an inlined JavaScript", word + snippet self + end unless type = self.type || type_variable end - self << Ast::Js.new( + Ast::Js.new( from: start_position, value: value, type: type, to: position, - input: data) - end - end - - def not_interpolation_part(terminator : Char, stop_on_interpolation : Bool = true) : String? - value = - if stop_on_interpolation - # Until we find either a terminator or interpolation - gather { chars_until terminator, '#' } - else - # Until we find the terminator - gather { chars_until terminator } - end - - if prev_char == '\\' - # if we found backslashthen it means it's an escape so we consume it - step - - # if we are in an inline JavaScript - if prev_char == '`' && terminator == '`' - value.to_s.rchop + prev_char - else - value.to_s + prev_char - end - elsif char == '#' && next_char != '{' && stop_on_interpolation - # If we found a hashtag then it could be an interpolation, if - # not we consume the character and return. - step - value.to_s + '#' - else - value + file: file) end end end diff --git a/src/parsers/locale.cr b/src/parsers/locale.cr index c58db9f58..5b0714bc9 100644 --- a/src/parsers/locale.cr +++ b/src/parsers/locale.cr @@ -1,38 +1,43 @@ module Mint class Parser - syntax_error LocaleExpectedClosingBracket - syntax_error LocaleExpectedOpeningBracket - syntax_error LocaleExpectedLanguage - def locale : Ast::Locale? - start do |start_position| + parse do |start_position| comment = self.comment - next unless keyword "locale" + next unless word! "locale" whitespace - language = gather do - next unless char.ascii_lowercase? - chars { |char| char.ascii_letter? || char.ascii_number? } - end - - raise LocaleExpectedLanguage unless language + next error :locale_expected_language do + expected "the language code of the locale", word + snippet self + end unless language = identifier_variable whitespace - fields = block( - opening_bracket: LocaleExpectedOpeningBracket, - closing_bracket: LocaleExpectedClosingBracket - ) do - list(terminator: '}', separator: ',') { record_field } - end + fields = + brackets( + ->{ + error :locale_expected_opening_bracket do + expected "the opening bracket of a locale", word + snippet self + end + }, + ->{ + error :locale_expected_closing_bracket do + expected "the opening bracket of a locale", word + snippet self + end + } + ) { list(terminator: '}', separator: ',') { field } } + + next unless fields - self << Ast::Locale.new( + Ast::Locale.new( from: start_position, language: language, comment: comment, fields: fields, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/locale_key.cr b/src/parsers/locale_key.cr index 0173a5da5..83650f8c3 100644 --- a/src/parsers/locale_key.cr +++ b/src/parsers/locale_key.cr @@ -1,12 +1,12 @@ module Mint class Parser def locale_key : Ast::LocaleKey? - start do |start_position| + parse do |start_position| next unless char! ':' value = gather do next unless char.ascii_lowercase? - chars { |char| char.ascii_letter? || char.ascii_number? || char == '.' } + ascii_letters_or_numbers(extra_char: '.') end next unless value @@ -15,10 +15,7 @@ module Mint from: start_position, value: value, to: position, - input: data).tap do |node| - locales << node - self << node - end + file: file) end end end diff --git a/src/parsers/member_access.cr b/src/parsers/member_access.cr index 61fe5dc73..52bbfb0dc 100644 --- a/src/parsers/member_access.cr +++ b/src/parsers/member_access.cr @@ -1,17 +1,18 @@ module Mint class Parser - syntax_error MemberAccessExpectedVariable - def member_access : Ast::MemberAccess? - start do |start_position| + parse do |start_position| next unless char! '.' - name = variable! MemberAccessExpectedVariable + next error :member_access_expected_variable do + expected "the field of the accessed entity", word + snippet self + end unless name = variable Ast::MemberAccess.new( from: start_position, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/module.cr b/src/parsers/module.cr index f49d8b4dc..357325191 100644 --- a/src/parsers/module.cr +++ b/src/parsers/module.cr @@ -1,30 +1,48 @@ module Mint class Parser - syntax_error ModuleExpectedOpeningBracket - syntax_error ModuleExpectedClosingBracket - syntax_error ModuleExpectedName - def module_definition : Ast::Module? - start do |start_position| + parse do |start_position| comment = self.comment whitespace - next unless keyword "module" + next unless word! "module" whitespace - name = type_id! ModuleExpectedName + next error :module_expected_name do + block do + text "The name of a module must start with an uppercase letter and only" + text "contain lowercase, uppercase letters and numbers." + end - items = block( - opening_bracket: ModuleExpectedOpeningBracket, - closing_bracket: ModuleExpectedClosingBracket) do - many { function || constant || self.comment } - end + expected "name of the module", word + snippet self + end unless name = id + whitespace + + body = + brackets( + ->{ error :module_expected_opening_bracket do + expected "the opening bracket of a module", word + snippet self + end }, + ->{ error :module_expected_closing_bracket do + expected "the closing bracket of a module", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :module_expected_body do + expected "the body of the module", word + snippet self + end if items.reject(Ast::Comment).empty? + }) { many { function || constant || self.comment } } + + next unless body functions = [] of Ast::Function constants = [] of Ast::Constant comments = [] of Ast::Comment - items.each do |item| + body.each do |item| case item when Ast::Function functions << item @@ -35,14 +53,14 @@ module Mint end end - self << Ast::Module.new( + Ast::Module.new( functions: functions, constants: constants, from: start_position, comments: comments, comment: comment, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/module_access.cr b/src/parsers/module_access.cr deleted file mode 100644 index 87351c25f..000000000 --- a/src/parsers/module_access.cr +++ /dev/null @@ -1,27 +0,0 @@ -module Mint - class Parser - syntax_error ModuleAccessExpectedFunction - - def module_access : Ast::ModuleAccess? - start do |start_position| - name = start do - value = type_id - next unless char! '.' - value - end - - next unless name - - variable = - variable! ModuleAccessExpectedFunction, track: false - - self << Ast::ModuleAccess.new( - from: start_position, - variable: variable, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/negated_expression.cr b/src/parsers/negated_expression.cr index 16241fef8..8d9a93c76 100644 --- a/src/parsers/negated_expression.cr +++ b/src/parsers/negated_expression.cr @@ -1,23 +1,23 @@ module Mint class Parser - syntax_error NegatedExpressionExpectedExpression - def negated_expression : Ast::NegatedExpression? - start do |start_position| - negations = gather { chars '!' } - next unless negations + parse do |start_position| + next unless negations = gather { chars '!' } negations = negations.size % 2 == 0 ? "!!" : "!" - expression = expression! NegatedExpressionExpectedExpression + next error :negated_expression_expected_expression do + expected "the expression of a negated expression", word + snippet self + end unless expression = self.expression - self << Ast::NegatedExpression.new( + Ast::NegatedExpression.new( expression: expression, negations: negations, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/next_call.cr b/src/parsers/next_call.cr index 838995c7e..0924680fd 100644 --- a/src/parsers/next_call.cr +++ b/src/parsers/next_call.cr @@ -1,19 +1,19 @@ module Mint class Parser - syntax_error NextCallExpectedRecord - def next_call : Ast::NextCall? - start do |start_position| - next unless keyword "next" - next unless whitespace? + parse do |start_position| + next unless word! "next" whitespace - raise NextCallExpectedRecord unless item = record + next error :next_call_expected_fields do + expected "the fields for a next call", word + snippet self + end unless item = record - self << Ast::NextCall.new( + Ast::NextCall.new( from: start_position, to: position, - input: data, + file: file, data: item) end end diff --git a/src/parsers/number_literal.cr b/src/parsers/number_literal.cr index cd64fdf9c..8ea883b96 100644 --- a/src/parsers/number_literal.cr +++ b/src/parsers/number_literal.cr @@ -1,32 +1,32 @@ module Mint class Parser - syntax_error NumberLiteralExpectedDecimal - def number_literal : Ast::NumberLiteral? - start do |start_position| - negation = char! '-' - - value = gather { chars &.ascii_number? }.to_s + parse do |start_position| + negation = + char! '-' - next if value.empty? + next unless value = gather { chars &.ascii_number? } float = false if char! '.' - raise NumberLiteralExpectedDecimal unless char.ascii_number? - value += '.' + next error :number_literal_expected_decimal do + expected "the decimals for a number literal", word + snippet self + end unless char.ascii_number? + + value += '.' + gather { chars(&.ascii_number?) }.to_s float = true - value += gather { chars(&.ascii_number?) }.to_s end value = "-#{value}" if negation - self << Ast::NumberLiteral.new( + Ast::NumberLiteral.new( from: start_position, value: value, float: float, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/operation.cr b/src/parsers/operation.cr index 249db7cd0..e101087a8 100644 --- a/src/parsers/operation.cr +++ b/src/parsers/operation.cr @@ -1,71 +1,43 @@ module Mint class Parser - syntax_error OperationExpectedExpression - - OPERATORS = { - "|>" => 0, - "or" => 0, - "!=" => 10, - "==" => 10, - - "<=" => 11, - "<" => 11, - ">=" => 11, - ">" => 11, - - "-" => 13, - "+" => 13, - - "*" => 14, - "/" => 14, - "%" => 14, - - "**" => 15, - - "&&" => 6, - "||" => 5, - "!" => 16, - } - - def operator : String? - start do - whitespace - saved_position = position - operator = OPERATORS.keys.find { |item| keyword item } - next unless operator - next unless whitespace? - ast.operators << {saved_position, saved_position + operator.size} - whitespace - operator - end - end + # Parses an operation, switching the operands if the precedence of the + # next operation is higher than the current one. The precedences can be + # found in the operator parser file. + # + # Operations can be chained recursively with this method as seen below. + def operation(left : Ast::Node, operator : String) : Ast::Operation? + parse do + next error :operation_expected_expression do + expected "the right side expression of an operation", word + snippet self + end unless right = base_expression + + if next_operator = self.operator + if OPERATORS[next_operator] > OPERATORS[operator] + right = operation(right, next_operator) + else + return operation( + Ast::Operation.new( + operator: operator, + from: left.from, + to: right.to, + right: right, + file: file, + left: left), + next_operator) + end + end - def operation(left : Ast::Expression, operator : String) : Ast::Operation - right = array_access_or_call(basic_expression!(OperationExpectedExpression)) + next unless right - if next_operator = self.operator - if OPERATORS[next_operator] > OPERATORS[operator] - right = operation(right, next_operator) - else - return operation( - self << Ast::Operation.new( - right: right, - left: left, - operator: operator, - from: left.from, - to: right.to, - input: data), - next_operator) - end + Ast::Operation.new( + operator: operator, + from: left.from, + to: right.to, + right: right, + file: file, + left: left) end - - self << Ast::Operation.new( - operator: operator, - from: left.from, - to: right.to, - right: right, - input: data, - left: left) end end end diff --git a/src/parsers/operator.cr b/src/parsers/operator.cr new file mode 100644 index 000000000..e71d44314 --- /dev/null +++ b/src/parsers/operator.cr @@ -0,0 +1,62 @@ +module Mint + class Parser + # These are the supported operators with their precedences. + OPERATORS = { + "|>" => 0, + "or" => 0, + "!=" => 10, + "==" => 10, + + "<=" => 11, + "<" => 11, + ">=" => 11, + ">" => 11, + + "-" => 13, + "+" => 13, + + "*" => 14, + "/" => 14, + "%" => 14, + + "**" => 15, + + "&&" => 6, + "||" => 5, + "!" => 16, + } + + # Parses an operator. + # + # All operators must follow a whitespace because we don't have an end of + # line token, so the expression can leak through to the next entity, for + # example: + # + # const NAME = "Joe" + # + # /* This is a comment. */ + # fun greet (name : String = NAME) { ... } + # + # In this case the start token of the comment (/*) can be interpreted as an + # operation (/) and the whitespace prevents that. + def operator : String? + parse do + whitespace + + saved_position = + position + + operator = + OPERATORS.keys.find { |item| word! item } + + next unless operator + next if operator != "|>" && !whitespace? + + ast.operators << {saved_position, saved_position + operator.size} + whitespace + + operator + end + end + end +end diff --git a/src/parsers/option.cr b/src/parsers/option.cr deleted file mode 100644 index ae9a19f2d..000000000 --- a/src/parsers/option.cr +++ /dev/null @@ -1,15 +0,0 @@ -module Mint - class Parser - def option - start do |start_position| - next unless name = type_id - - self << Ast::Option.new( - from: start_position, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/parenthesized_expression.cr b/src/parsers/parenthesized_expression.cr index 32b45f4c4..2412a030d 100644 --- a/src/parsers/parenthesized_expression.cr +++ b/src/parsers/parenthesized_expression.cr @@ -1,22 +1,20 @@ module Mint class Parser def parenthesized_expression : Ast::ParenthesizedExpression? - start do |start_position| + parse do |start_position| next unless char! '(' - whitespace - expression = self.expression - next unless expression + next unless expression = self.expression whitespace next unless char! ')' - self << Ast::ParenthesizedExpression.new( + Ast::ParenthesizedExpression.new( expression: expression, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/pipe.cr b/src/parsers/pipe.cr index 1c6a692d9..d6b15a17d 100644 --- a/src/parsers/pipe.cr +++ b/src/parsers/pipe.cr @@ -1,10 +1,8 @@ module Mint class Parser - syntax_error PipeExpectedCall - - # This method rolls an operation where the operator is "|>" into a single - # call. Every other operation is passed trough. - def rollup_pipe(operation) : Ast::Pipe | Ast::Operation + # This method rolls up an operation where the operator is "|>" into a + # single call. Every other operation is passed trough. + def pipe(operation : Ast::Operation) : Ast::Pipe | Ast::Operation? return operation unless operation.operator == "|>" expression = operation.right @@ -13,17 +11,21 @@ module Mint argument = case argument when Ast::Operation - rollup_pipe(argument) + pipe(argument) else argument end Ast::Pipe.new( expression: expression, - argument: argument, from: argument.from, + argument: argument, to: expression.to, - input: data) + file: file) + end + + def pipe(operation : Nil) : Ast::Pipe | Ast::Operation? + nil end end end diff --git a/src/parsers/property.cr b/src/parsers/property.cr index 5e61b036f..f1d0c1703 100644 --- a/src/parsers/property.cr +++ b/src/parsers/property.cr @@ -1,42 +1,50 @@ module Mint class Parser - syntax_error PropertyExpectedDefaultValue - syntax_error PropertyExpectedName - syntax_error PropertyExpectedType - def property : Ast::Property? - start do + parse do |start_position| comment = self.comment whitespace - start_position = position - - next unless keyword "property" + next unless word! "property" whitespace - name = variable! PropertyExpectedName, track: false - whitespace + next error :property_expected_name do + expected "the name of a property", word + snippet self + end unless name = variable track: false type = - if char! ':' + parse(track: false) do whitespace - item = type! PropertyExpectedType + next unless char! ':' whitespace + + next error :property_expected_type do + expected "the type of a property", word + snippet self + end unless item = self.type item end default = - if char! '=' + parse(track: false) do whitespace - expression! PropertyExpectedDefaultValue + next unless char! '=' + whitespace + + next error :property_expected_default_value do + expected "the default value of a property", word + snippet self + end unless item = expression + item end - self << Ast::Property.new( + Ast::Property.new( from: start_position, default: default, comment: comment, to: position, - input: data, + file: file, type: type, name: name) end diff --git a/src/parsers/provider.cr b/src/parsers/provider.cr index b247bf75e..bb04d2b18 100644 --- a/src/parsers/provider.cr +++ b/src/parsers/provider.cr @@ -1,37 +1,47 @@ module Mint class Parser - syntax_error ProviderExpectedOpeningBracket - syntax_error ProviderExpectedClosingBracket - syntax_error ProviderExpectedSubscription - syntax_error ProviderExpectedColon - syntax_error ProviderExpectedName - syntax_error ProviderExpectedBody - def provider : Ast::Provider? - start do |start_position| + parse do |start_position, start_nodes_position| comment = self.comment - next unless keyword "provider" + next unless word! "provider" whitespace - name = type_id! ProviderExpectedName + next error :provider_expected_name do + expected "the name of a provider", word + snippet self + end unless name = id whitespace - char ':', ProviderExpectedColon - + next error :provider_expeceted_colon do + expected "the colon of a provider", word + snippet self + end unless char! ':' whitespace - subscription = type_id! ProviderExpectedSubscription - body = block( - opening_bracket: ProviderExpectedOpeningBracket, - closing_bracket: ProviderExpectedClosingBracket - ) do - items = many { function || state || get || constant || self.comment } + next error :provider_expected_subscription do + expected "the subscription type of a provider", word + snippet self + end unless subscription = id + whitespace - raise ProviderExpectedBody if items.none?(Ast::Function) + body = brackets( + ->{ error :provider_expected_opening_bracket do + expected "the opening bracket of a provider", word + snippet self + end }, + ->{ error :provider_expected_closing_bracket do + expected "the closing bracket of a provider", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :provider_expected_body do + expected "the body of a provider", word + snippet self + end if items.reject(Ast::Comment).empty? + }) { many { function || state || get || constant || self.comment } } - items - end + next unless body functions = [] of Ast::Function constants = [] of Ast::Constant @@ -43,20 +53,25 @@ module Mint case item when Ast::Function functions << item - - item.keep_name = true if item.name.value == "update" - when Ast::State - states << item when Ast::Constant constants << item when Ast::Comment comments << item + when Ast::State + states << item when Ast::Get gets << item end end - self << Ast::Provider.new( + ast.nodes[start_nodes_position...].each do |node| + case node + when Ast::Function + node.keep_name = true if node.name.value == "update" + end + end + + Ast::Provider.new( subscription: subscription, functions: functions, constants: constants, @@ -65,9 +80,14 @@ module Mint comment: comment, states: states, to: position, - input: data, + file: file, gets: gets, - name: name) + name: name + ).tap do |node| + ast.nodes[start_nodes_position...] + .select(Ast::NextCall) + .each(&.entity=(node)) + end end end end diff --git a/src/parsers/record.cr b/src/parsers/record.cr index 390d0c4f7..3ef6f6b1f 100644 --- a/src/parsers/record.cr +++ b/src/parsers/record.cr @@ -1,25 +1,24 @@ module Mint class Parser def record : Ast::Record? - start do |start_position| + parse do |start_position| next unless char! '{' - fields = [] of Ast::RecordField + fields = [] of Ast::Field unless char! '}' whitespace - - fields = list(terminator: '}', separator: ',') { record_field } - + fields = list(terminator: '}', separator: ',') { field } whitespace + next unless char! '}' end - self << Ast::Record.new( + Ast::Record.new( from: start_position, fields: fields, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/record_definition.cr b/src/parsers/record_definition.cr deleted file mode 100644 index 9da509ae4..000000000 --- a/src/parsers/record_definition.cr +++ /dev/null @@ -1,40 +0,0 @@ -module Mint - class Parser - syntax_error RecordDefinitionExpectedOpeningBracket - syntax_error RecordDefinitionExpectedClosingBracket - syntax_error RecordDefinitionExpectedName - - def record_definition : Ast::RecordDefinition? - start do |start_position| - comment = self.comment - - next unless keyword "record" - whitespace - - name = type_id! RecordDefinitionExpectedName - - fields, block_comment = block( - opening_bracket: RecordDefinitionExpectedOpeningBracket, - closing_bracket: RecordDefinitionExpectedClosingBracket - ) do - { - list( - terminator: '}', - separator: ',' - ) { record_definition_field }, - self.comment, - } - end - - self << Ast::RecordDefinition.new( - block_comment: block_comment, - from: start_position, - comment: comment, - fields: fields, - to: position, - input: data, - name: name) - end - end - end -end diff --git a/src/parsers/record_definition_field.cr b/src/parsers/record_definition_field.cr deleted file mode 100644 index e145bbf47..000000000 --- a/src/parsers/record_definition_field.cr +++ /dev/null @@ -1,39 +0,0 @@ -module Mint - class Parser - syntax_error RecordDefinitionFieldExpectedMapping - syntax_error RecordDefinitionFieldExpectedColon - syntax_error RecordDefinitionFieldExpectedType - - def record_definition_field : Ast::RecordDefinitionField? - start do |start_position| - comment = self.comment - - next unless key = variable - whitespace - - char ':', RecordDefinitionFieldExpectedColon - whitespace - - type = type! RecordDefinitionFieldExpectedType - - mapping = - start do - whitespace - next unless keyword "using" - whitespace - string_literal! RecordDefinitionFieldExpectedMapping, - with_interpolation: false - end - - self << Ast::RecordDefinitionField.new( - from: start_position, - comment: comment, - mapping: mapping, - to: position, - input: data, - type: type, - key: key) - end - end - end -end diff --git a/src/parsers/record_field.cr b/src/parsers/record_field.cr deleted file mode 100644 index d89dc6917..000000000 --- a/src/parsers/record_field.cr +++ /dev/null @@ -1,25 +0,0 @@ -module Mint - class Parser - def record_field : Ast::RecordField? - start do |start_position| - comment = self.comment - - next unless key = variable - whitespace - - next unless char! ':' - whitespace - - next unless value = expression - - self << Ast::RecordField.new( - value: value, - from: start_position, - comment: comment, - to: position, - input: data, - key: key) - end - end - end -end diff --git a/src/parsers/record_update.cr b/src/parsers/record_update.cr index 43a339e16..6b19ce750 100644 --- a/src/parsers/record_update.cr +++ b/src/parsers/record_update.cr @@ -1,19 +1,16 @@ module Mint class Parser - syntax_error RecordUpdateExpectedClosingBracket - syntax_error RecordUpdateExpectedFields - def record_update : Ast::RecordUpdate? - start do |start_position| - expression = start do + parse do |start_position| + expression = parse(track: false) do next unless char! '{' - whitespace + value = variable || self.expression whitespace next unless value - next if keyword_ahead?("|>") # Skip if tuple with a pipe `{ x |> Number.toString }` + next if word?("|>") # Skip if tuple with a pipe `{ x |> Number.toString }` next unless char! '|' value @@ -26,20 +23,26 @@ module Mint fields = list( terminator: '}', separator: ',' - ) { record_field.as(Ast::RecordField?) } + ) { field } - raise RecordUpdateExpectedFields if fields.empty? + next error :record_update_expected_fields do + expected "the fields for a record update", word + snippet self + end if fields.empty? whitespace - char '}', RecordUpdateExpectedClosingBracket + next error :record_update_expected_closing_bracket do + expected "the closing bracket of a record update", word + snippet self + end unless char! '}' - self << Ast::RecordUpdate.new( + Ast::RecordUpdate.new( expression: expression, from: start_position, fields: fields, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/regexp_literal.cr b/src/parsers/regexp_literal.cr index cd108e599..1340a4221 100644 --- a/src/parsers/regexp_literal.cr +++ b/src/parsers/regexp_literal.cr @@ -1,20 +1,22 @@ module Mint class Parser - syntax_error RegexpLiteralExpectedClosingSlash - def regexp_literal : Ast::RegexpLiteral? - start do |start_position| + parse do |start_position| next unless char! '/' # This is a safe check because a regexp cannot start # with a quantifier. next if char == '*' - value = many(parse_whitespace: false) do - not_interpolation_part('/', stop_on_interpolation: false) - end.join + value = + many(parse_whitespace: false) do + raw('/', stop_on_interpolation: false) + end.join - char '/', RegexpLiteralExpectedClosingSlash + next error :regexp_literal_expected_closing_slash do + expected "the closing slash of a regexp literal", word + snippet self + end unless char! '/' flags = gather { chars 'i', 'g', 'm', 's', 'u', 'y' }.to_s @@ -23,7 +25,7 @@ module Mint value: value, flags: flags, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/return.cr b/src/parsers/return.cr index 342e967e7..0ab6b97ea 100644 --- a/src/parsers/return.cr +++ b/src/parsers/return.cr @@ -1,20 +1,20 @@ module Mint class Parser - syntax_error ReturnCallExpectedExpression - def return_call : Ast::ReturnCall? - start do |start_position| - next unless keyword "return" - next unless whitespace? + parse do |start_position| + next unless word! "return" whitespace - raise ReturnCallExpectedExpression unless expression = self.expression + next error :return_call_expected_expression do + expected "the expression of a return call", word + snippet self + end unless expression = self.expression - self << Ast::ReturnCall.new( + Ast::ReturnCall.new( expression: expression, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/route.cr b/src/parsers/route.cr index 9231a4db3..7fe7d535e 100644 --- a/src/parsers/route.cr +++ b/src/parsers/route.cr @@ -1,46 +1,56 @@ module Mint class Parser - syntax_error RouteExpectedClosingParentheses - syntax_error RouteExpectedOpeningBracket - syntax_error RouteExpectedClosingBracket - syntax_error RouteExpectedExpression - def route : Ast::Route? - start do |start_position| + parse do |start_position| next unless char.in?('*', '/') url = - case char - when '*' - step + if char! '*' "*" else - gather { chars_until ' ', '\n', '\r', '\t', '{', '(' }.to_s + gather { chars { |char| !char.in?(' ', '\n', '\r', '\t', '{', '(') } }.to_s end - whitespace - arguments = [] of Ast::Argument + whitespace if char! '(' - arguments = list(terminator: ')', separator: ',') { argument(false) } + arguments = + list(terminator: ')', separator: ',') do + argument(parse_default_value: false) + end + whitespace - char ')', RouteExpectedClosingParentheses + next error :route_expected_closing_parenthesis do + expected "the closing parenthesis of a route", word + snippet self + end unless char! ')' whitespace end body = - code_block( - opening_bracket: RouteExpectedOpeningBracket, - closing_bracket: RouteExpectedClosingBracket, - statement_error: RouteExpectedExpression) + block( + ->{ error :route_expected_opening_bracket do + expected "the opening bracket of a route", word + snippet self + end }, + ->{ error :route_expected_closing_bracket do + expected "the closing bracket of a route", word + snippet self + end }, + ->{ error :route_expected_body do + expected "the body of a route", word + snippet self + end }) + + next unless body - self << Ast::Route.new( + Ast::Route.new( arguments: arguments, from: start_position, expression: body, to: position, - input: data, + file: file, url: url) end end diff --git a/src/parsers/routes.cr b/src/parsers/routes.cr index 1392b44a2..c90b970e1 100644 --- a/src/parsers/routes.cr +++ b/src/parsers/routes.cr @@ -1,42 +1,47 @@ module Mint class Parser - syntax_error RoutesExpectedOpeningBracket - syntax_error RoutesExpectedClosingBracket - syntax_error RoutesExpectedRoute - def routes : Ast::Routes? - start do |start_position| - next unless keyword "routes" - - body = block( - opening_bracket: RoutesExpectedOpeningBracket, - closing_bracket: RoutesExpectedClosingBracket - ) do - items = many { comment || route } + parse do |start_position| + next unless word! "routes" + whitespace - raise RoutesExpectedRoute if items.none?(Ast::Route) + body = + brackets( + ->{ error :routes_expected_opening_bracket do + expected "the opening bracket of a routes block", word + snippet self + end }, + ->{ error :routes_expected_closing_bracket do + expected "the closing bracket of a routes block", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :routes_expected_body do + expected "the body of a routes block", word + snippet self + end if items.none?(Ast::Route) + }) { many { comment || route } } - items - end + next unless body comments = [] of Ast::Comment routes = [] of Ast::Route body.each do |item| case item - when Ast::Route - routes << item when Ast::Comment comments << item + when Ast::Route + routes << item end end - self << Ast::Routes.new( + Ast::Routes.new( from: start_position, comments: comments, routes: routes, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/spread.cr b/src/parsers/spread.cr index c4c19c3a0..a5e43e4cb 100644 --- a/src/parsers/spread.cr +++ b/src/parsers/spread.cr @@ -1,18 +1,19 @@ module Mint class Parser - syntax_error SpreadExpectedVariable - def spread - start do |start_position| - next unless keyword "..." + parse do |start_position| + next unless word! "..." - variable = variable! SpreadExpectedVariable + next error :spread_expected_variable do + expected "the name of a spread", word + snippet self + end unless variable = self.variable Ast::Spread.new( from: start_position, variable: variable, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/state.cr b/src/parsers/state.cr index 2518a84c9..f3d46316b 100644 --- a/src/parsers/state.cr +++ b/src/parsers/state.cr @@ -1,41 +1,48 @@ module Mint class Parser - syntax_error StateExpectedDefaultValue - syntax_error StateExpectedEqualSign - syntax_error StateExpectedName - syntax_error StateExpectedType - def state : Ast::State? - start do |start_position| + parse do |start_position| comment = self.comment whitespace - next unless keyword "state" + next unless word! "state" whitespace - name = variable! StateExpectedName + next error :state_expected_name do + expected "the name of a state", word + snippet self + end unless name = variable whitespace type = if char! ':' whitespace - item = type! StateExpectedType + next error :state_expected_type do + expected "the type value of a state", word + snippet self + end unless item = self.type whitespace item end whitespace - char '=', StateExpectedEqualSign - whitespace + next error :state_expected_equal_sign do + expected "the equal sign of a state", word + snippet self + end unless char! '=' - default = expression! StateExpectedDefaultValue + whitespace + next error :state_expected_default_value do + expected "the default value of a state", word + snippet self + end unless default = expression - self << Ast::State.new( - default: default, + Ast::State.new( from: start_position, + default: default, comment: comment, to: position, - input: data, + file: file, type: type, name: name) end diff --git a/src/parsers/statement.cr b/src/parsers/statement.cr index 2cdc4d09a..9ea1b13cf 100644 --- a/src/parsers/statement.cr +++ b/src/parsers/statement.cr @@ -1,15 +1,15 @@ module Mint class Parser def statement : Ast::Statement? - start do |start_position| - target = start do - next unless keyword "let" + parse do |start_position| + target = parse(track: false) do + next unless word! "let" whitespace value = variable(track: false) || array_destructuring || tuple_destructuring || - enum_destructuring + type_destructuring whitespace next unless char! '=' @@ -19,27 +19,25 @@ module Mint end whitespace - await = keyword "await" + await = word! "await" whitespace - body = expression + next unless body = expression - next unless body - - self << Ast::Statement.new( + Ast::Statement.new( from: start_position, expression: body, target: target, await: await, to: position, - input: data + file: file ).tap do |node| case body when Ast::Operation case target - when Ast::EnumDestructuring, - Ast::ArrayDestructuring, - Ast::TupleDestructuring + when Ast::ArrayDestructuring, + Ast::TupleDestructuring, + Ast::TypeDestructuring case item = body.right when Ast::ReturnCall item.statement = node diff --git a/src/parsers/store.cr b/src/parsers/store.cr index 0f2f746e2..91a364fa5 100644 --- a/src/parsers/store.cr +++ b/src/parsers/store.cr @@ -1,32 +1,37 @@ module Mint class Parser - syntax_error StoreExpectedOpeningBracket - syntax_error StoreExpectedClosingBracket - syntax_error StoreExpectedBody - syntax_error StoreExpectedName - def store : Ast::Store? - start do |start_position| + parse do |start_position, start_nodes_position| comment = self.comment whitespace - next unless keyword "store" + next unless word! "store" whitespace - name = type_id! StoreExpectedName - - body = block( - opening_bracket: StoreExpectedOpeningBracket, - closing_bracket: StoreExpectedClosingBracket - ) do - items = many { state || function || get || constant || self.comment } + next error :store_expected_name do + expected "the name of a store", word + snippet self + end unless name = id + whitespace - if items.none?(Ast::Function | Ast::Constant | Ast::State | Ast::Get) - raise StoreExpectedBody - end + body = + brackets( + ->{ error :store_expected_opening_bracket do + expected "the opening bracket of a store", word + snippet self + end }, + ->{ error :store_expected_closing_bracket do + expected "the closing bracket of a store", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :store_expected_body do + expected "the body of a store", word + snippet self + end if items.all?(Ast::Comment) + }) { many { state || function || get || constant || self.comment } } - items - end + next unless body functions = [] of Ast::Function constants = [] of Ast::Constant @@ -49,7 +54,7 @@ module Mint end end - self << Ast::Store.new( + Ast::Store.new( functions: functions, from: start_position, constants: constants, @@ -57,9 +62,14 @@ module Mint comment: comment, states: states, to: position, - input: data, + file: file, gets: gets, - name: name) + name: name + ).tap do |node| + ast.nodes[start_nodes_position...] + .select(Ast::NextCall) + .each(&.entity=(node)) + end end end end diff --git a/src/parsers/string_literal.cr b/src/parsers/string_literal.cr index 360b19bb4..f2868d437 100644 --- a/src/parsers/string_literal.cr +++ b/src/parsers/string_literal.cr @@ -1,40 +1,48 @@ module Mint class Parser - syntax_error StringExpectedEndQuote - syntax_error StringExpectedOtherString - - def string_literal!(error : SyntaxError.class, with_interpolation : Bool = true) : Ast::StringLiteral - string_literal(with_interpolation) || raise error - end - - def string_literal(with_interpolation : Bool = true) : Ast::StringLiteral? - start do |start_position| + def string_literal(*, with_interpolation : Bool = true) : Ast::StringLiteral? + parse do |start_position| next unless char! '"' - value = many(parse_whitespace: false) do - if with_interpolation - not_interpolation_part('"') || interpolation - else - not_interpolation_part('"') - end.as(Ast::Interpolation | String?) - end + value = + many(parse_whitespace: false) do + if with_interpolation + raw('"') || interpolation + else + raw('"') + end + end - char '"', StringExpectedEndQuote - whitespace + next error :string_expected_closing_quote do + expected "the closing quoute of a string literal", word + snippet self + end unless char! '"' - broken = false + # Lookahead to see if there is a backslash (string separator), if + # parsing fails it will track the whitespace back. + broken = + parse do + whitespace + next unless char! '\\' + true + end || false - if char! '\\' + # If it's separated try to parse an other part. + if broken whitespace - literal = string_literal(with_interpolation) - raise StringExpectedOtherString unless literal - broken = true + + literal = + string_literal(with_interpolation: with_interpolation) + + next error :string_expected_other_string do + expected "another string literal after a string separator", word + snippet self + end unless literal + value.concat(literal.value) - else - track_back_whitespace end - # Normalize the value so there are consecutive Strings + # Normalize the value so there are consecutive strings. value = value.reduce([] of Ast::Interpolation | String) do |memo, item| if memo.last?.is_a?(String) && item.is_a?(String) @@ -46,12 +54,12 @@ module Mint memo end - self << Ast::StringLiteral.new( + Ast::StringLiteral.new( from: start_position, broken: broken, value: value, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/style.cr b/src/parsers/style.cr index 50352f5d3..bf7b4fda9 100644 --- a/src/parsers/style.cr +++ b/src/parsers/style.cr @@ -1,66 +1,57 @@ module Mint class Parser - syntax_error StyleExpectedClosingParentheses - syntax_error StyleExpectedOpeningBracket - syntax_error StyleExpectedClosingBracket - syntax_error StyleExpectedName - def style : Ast::Style? - start do |start_position| - next unless keyword "style" - + parse do |start_position| + next unless word! "style" whitespace - name = variable_with_dashes! StyleExpectedName + + next error :style_expected_name do + expected "the name of a style", word + snippet self + end unless name = variable extra_chars: ['-'] whitespace arguments = [] of Ast::Argument if char! '(' whitespace - arguments = list(terminator: ')', separator: ',') { argument } - whitespace - char ')', StyleExpectedClosingParentheses - end - body = block( - opening_bracket: StyleExpectedOpeningBracket, - closing_bracket: StyleExpectedClosingBracket - ) do - many { css_keyframes || css_font_face || css_node } + next error :style_expected_closing_parenthesis do + expected "the closing parenthesis of a style", word + snippet self + end unless char! ')' + whitespace end - self << Ast::Style.new( + body = + brackets( + ->{ error :style_expected_opening_bracket do + expected "the opening bracket of a style", word + snippet self + end }, + ->{ error :style_expected_closing_bracket do + expected "the closing bracket of a style", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :style_expected_body do + expected "the body of a style", word + snippet self + end if items.empty? + }) { many { css_keyframes || css_font_face || css_node } } + + next unless body + + Ast::Style.new( from: start_position, arguments: arguments, to: position, - input: data, + file: file, body: body, name: name) end end - - def css_node - comment || - case_expression(for_css: true) || - if_expression(for_css: true) || - css_nested_at || - css_definition_or_selector - end - - def css_body - many { css_node } - end - - def css_definition_or_selector - css_definition || css_selector - rescue ex : CssDefinitionExpectedSemicolon - begin - css_selector - rescue - raise ex - end - end end end diff --git a/src/parsers/suite.cr b/src/parsers/suite.cr index c22336995..10573ca38 100644 --- a/src/parsers/suite.cr +++ b/src/parsers/suite.cr @@ -1,54 +1,58 @@ module Mint class Parser - syntax_error SuiteExpectedOpeningBracket - syntax_error SuiteExpectedClosingBracket - syntax_error SuiteExpectedTests - syntax_error SuiteExpectedName - def suite : Ast::Suite? - start do |start_position| - next unless keyword "suite" - + parse do |start_position| + next unless word! "suite" whitespace - name = string_literal! SuiteExpectedName, - with_interpolation: false - + next error :suite_expected_name do + expected "the name of a suite", word + snippet self + end unless name = string_literal with_interpolation: false whitespace - body = block( - opening_bracket: SuiteExpectedOpeningBracket, - closing_bracket: SuiteExpectedClosingBracket - ) do - items = many { test || constant || comment } - - raise SuiteExpectedTests if items.none?(Ast::Test | Ast::Constant) + body = + brackets( + ->{ error :suite_expected_opening_bracket do + expected "the opening bracket of a suite", word + snippet self + end }, + ->{ error :suite_expected_closing_bracket do + expected "the closing bracket of a suite", word + snippet self + end }, + ->(items : Array(Ast::Node)) { + error :suite_expected_body do + expected "the body of a suite", word + snippet self + end if items.none?(Ast::Test | Ast::Constant) + } + ) { many { test || constant || comment } } + + next unless body - items - end - - comments = [] of Ast::Comment constants = [] of Ast::Constant + comments = [] of Ast::Comment tests = [] of Ast::Test body.each do |item| case item - when Ast::Comment - comments << item when Ast::Constant constants << item + when Ast::Comment + comments << item when Ast::Test tests << item end end - self << Ast::Suite.new( + Ast::Suite.new( from: start_position, - comments: comments, constants: constants, + comments: comments, tests: tests, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/test.cr b/src/parsers/test.cr index 8765f569e..130925739 100644 --- a/src/parsers/test.cr +++ b/src/parsers/test.cr @@ -1,32 +1,38 @@ module Mint class Parser - syntax_error TestExpectedOpeningBracket - syntax_error TestExpectedClosingBracket - syntax_error TestExpectedExpression - syntax_error TestExpectedName - def test : Ast::Test? - start do |start_position| - next unless keyword "test" - + parse do |start_position| + next unless word! "test" whitespace - name = string_literal! TestExpectedName, - with_interpolation: false - + next error :test_expected_name do + expected "the name of a test", word + snippet self + end unless name = string_literal with_interpolation: false whitespace expression = - code_block( - opening_bracket: TestExpectedOpeningBracket, - closing_bracket: TestExpectedClosingBracket, - statement_error: TestExpectedExpression) + block( + ->{ error :test_expected_opening_bracket do + expected "the opening bracket of a test", word + snippet self + end }, + ->{ error :test_expected_closing_bracket do + expected "the closing bracket of a test", word + snippet self + end }, + ->{ error :test_expected_body do + expected "the body of a test", word + snippet self + end }) + + next unless expression - self << Ast::Test.new( + Ast::Test.new( expression: expression, from: start_position, to: position, - input: data, + file: file, name: name) end end diff --git a/src/parsers/top_level.cr b/src/parsers/top_level.cr deleted file mode 100644 index 325bc2441..000000000 --- a/src/parsers/top_level.cr +++ /dev/null @@ -1,61 +0,0 @@ -module Mint - class Parser - syntax_error ExpectedEndOfFile - - def self.parse(file) : Ast - parse File.read(file), file - end - - def self.parse(contents, file) : Ast - parser = new(contents, file) - parser.top_levels - parser.eof! - parser.ast - end - - def eof! : Nil - whitespace - raise ExpectedEndOfFile unless char == '\0' - end - - def top_levels : Nil - items = many do - component || - module_definition || - record_definition || - self.enum || - provider || - locale || - routes || - store || - suite || - comment - end - - items.each do |item| - case item - when Ast::Suite - @ast.suites << item - when Ast::Provider - @ast.providers << item - when Ast::RecordDefinition - @ast.records << item - when Ast::Component - @ast.components << item - when Ast::Module - @ast.modules << item - when Ast::Store - @ast.stores << item - when Ast::Routes - @ast.routes << item - when Ast::Enum - @ast.enums << item - when Ast::Comment - @ast.comments << item - when Ast::Locale - @ast.locales << item - end - end - end - end -end diff --git a/src/parsers/tuple_destructuring.cr b/src/parsers/tuple_destructuring.cr index a6d683cf6..8673d0d1c 100644 --- a/src/parsers/tuple_destructuring.cr +++ b/src/parsers/tuple_destructuring.cr @@ -1,32 +1,33 @@ module Mint class Parser def tuple_destructuring : Ast::TupleDestructuring? - start do |start_position| - head = start do - next unless char! '{' - value = destructuring + parse do |start_position| + # TODO: Remove this branch in 0.21.0 when deprecation ends. + if char! '{' whitespace - next if char.in?('|', '=') # Don't parse record or record update as tuple destructuring - char! ',' - whitespace - value - end - next unless head - - parameters = [head] &+ list(terminator: '}', separator: ',') do - destructuring - end + items = list(terminator: '}', separator: ',') { destructuring } - whitespace + whitespace + next unless char! '}' + elsif word!("#(") + whitespace + items = list(terminator: '}', separator: ',') { destructuring } + whitespace - next unless char! '}' + next error :tuple_destructuring_expected_closing_parenthesis do + expected "the closing parenthesis of a tuple destructuring", word + snippet self + end unless char! ')' + else + next + end Ast::TupleDestructuring.new( - parameters: parameters, from: start_position, to: position, - input: data) + items: items, + file: file) end end end diff --git a/src/parsers/tuple_literal.cr b/src/parsers/tuple_literal.cr index 534db0c80..779f6f288 100644 --- a/src/parsers/tuple_literal.cr +++ b/src/parsers/tuple_literal.cr @@ -1,23 +1,33 @@ module Mint class Parser def tuple_literal : Ast::TupleLiteral? - start do |start_position| - next unless char! '{' + parse do |start_position| + # TODO: Remove this branch in 0.21.0 when deprecation ends. + if char! '{' + whitespace - whitespace - items = list( - terminator: '}', - separator: ',' - ) { expression } - whitespace + items = list(terminator: '}', separator: ',') { expression } - next unless char! '}' + whitespace + next unless char! '}' + elsif word!("#(") + whitespace + items = list(terminator: '}', separator: ',') { expression } + whitespace + + next error :tuple_literal_expected_closing_parenthesis do + expected "the closing parenthesis of a tuple", word + snippet self + end unless char! ')' + else + next + end Ast::TupleLiteral.new( from: start_position, to: position, items: items, - input: data) + file: file) end end end diff --git a/src/parsers/type.cr b/src/parsers/type.cr index bfbe3c5db..d07163579 100644 --- a/src/parsers/type.cr +++ b/src/parsers/type.cr @@ -1,40 +1,38 @@ module Mint class Parser - syntax_error TypeExpectedClosingParentheses - syntax_error TypeExpectedTypeOrVariable - syntax_error TypeExpectedType + def type : Ast::Type? + parse do |start_position| + next unless name = id - def type!(error : SyntaxError.class) : Ast::Type - start_position = position + if char! '(' + parameters = list(separator: ',', terminator: ')') do + whitespace + type = self.type || type_variable - name = type_id! error + whitespace + next error :type_expected_type_or_type_variable do + expected "a type or a type variable", word + snippet self + end unless type - if char! '(' - parameters = list(separator: ',', terminator: ')') do - whitespace - type = - self.type.as(Ast::Type?) || - type_variable.as(Ast::TypeVariable?) - whitespace - raise TypeExpectedTypeOrVariable unless type - type - end - char ')', TypeExpectedClosingParentheses - else - parameters = [] of Ast::Type | Ast::TypeVariable - end + type + end - self << Ast::Type.new( - parameters: parameters, - from: start_position, - to: position, - input: data, - name: name) - end + next error :type_expected_closing_parenthesis do + expected "the closing parenthesis of a type", word + snippet self + end unless char! ')' + else + parameters = [] of Ast::Type | Ast::TypeVariable + end - def type : Ast::Type? - return unless char.ascii_uppercase? - type! TypeExpectedType + Ast::Type.new( + parameters: parameters, + from: start_position, + to: position, + file: file, + name: name) + end end end end diff --git a/src/parsers/type_definition.cr b/src/parsers/type_definition.cr new file mode 100644 index 000000000..432d83bf2 --- /dev/null +++ b/src/parsers/type_definition.cr @@ -0,0 +1,65 @@ +module Mint + class Parser + def type_definition : Ast::TypeDefinition? + parse do |start_position| + comment = self.comment + + # TODO: Remove `record` and `enum` in 0.21.0 when deprecation ends. + next unless word!("type") || word!("record") || word!("enum") + whitespace + + next error :type_definition_expected_name do + expected "the name of a type", word + snippet self + end unless name = id + whitespace + + parameters = + if char! '(' + items = list(separator: ',', terminator: ')') { type_variable } + + whitespace + next error :type_definition_expected_closing_parenthesis do + expected "the closing parenthesis of a type definition", word + snippet self + end unless char! ')' + + items + end || [] of Ast::TypeVariable + + whitespace + + fields = begin + if char! '{' + variants = + list(separator: ',', terminator: '}') { type_definition_field } + + items = + if variants.empty? + many { type_variant } + else + variants + end + + whitespace + next error :type_definition_expected_closing_bracket do + expected "the closing bracket of a type definition", word + snippet self + end unless char! '}' + + items + end || [] of Ast::TypeDefinitionField + end + + Ast::TypeDefinition.new( + parameters: parameters, + from: start_position, + comment: comment, + fields: fields, + to: position, + name: name, + file: file) + end + end + end +end diff --git a/src/parsers/type_definition_field.cr b/src/parsers/type_definition_field.cr new file mode 100644 index 000000000..6e588798b --- /dev/null +++ b/src/parsers/type_definition_field.cr @@ -0,0 +1,50 @@ +module Mint + class Parser + def type_definition_field(*, raise_on_colon : Bool = true) : Ast::TypeDefinitionField? + parse do |start_position| + comment = self.comment + + next unless key = variable + whitespace + + if raise_on_colon + next error :type_definition_field_expected_colon do + expected "the colon separating a type field from the type", word + snippet self + end unless char! ':' + else + next unless char! ':' + end + + whitespace + next error :type_definition_field_expected_type do + expected "the type of a type field", word + snippet self + end unless type = self.type || type_variable + + mapping = + parse(track: false) do + whitespace + next unless word! "using" + whitespace + + next error :type_definition_field_expected_mapping do + expected "the mapping of a record field", word + snippet self + end unless item = string_literal with_interpolation: false + + item + end + + Ast::TypeDefinitionField.new( + from: start_position, + comment: comment, + mapping: mapping, + to: position, + type: type, + file: file, + key: key) + end + end + end +end diff --git a/src/parsers/type_destructuring.cr b/src/parsers/type_destructuring.cr new file mode 100644 index 000000000..ceaacc215 --- /dev/null +++ b/src/parsers/type_destructuring.cr @@ -0,0 +1,72 @@ +module Mint + class Parser + def type_destructuring : Ast::TypeDestructuring? + parse do |start_position| + next unless name = id track: false + + # TODO: Remove this branch in 0.21.0 when deprecation ends. + if word! "::" + next error :type_destructuring_expected_variant do + expected "the type of an type destructuring", word + snippet self + end unless variant = id(track: false) + else + parts = + name.value.split('.') + + name, variant = + if parts.size >= 2 + variant_name = + parts.pop + + parent_name = + parts.join('.') + + parent_to = + start_position + parent_name.size + + {Ast::Id.new( + from: start_position, + value: parent_name, + to: parent_to, + file: file), + Ast::Id.new( + to: parent_to + 1 + variant_name.size, + value: variant_name, + from: parent_to, + file: file)} + else + {nil, name} + end + end + + ast.nodes << variant + ast.nodes << name if name + + items = [] of Ast::Node + + if char! '(' + whitespace + items.concat list( + terminator: ')', + separator: ',' + ) { destructuring } + whitespace + + next error :type_destructuring_expected_closing_parenthesis do + expected "the closing parenthesis of an type destructuring", word + snippet self + end unless char! ')' + end + + Ast::TypeDestructuring.new( + from: start_position, + variant: variant, + items: items, + to: position, + file: file, + name: name) + end + end + end +end diff --git a/src/parsers/type_id.cr b/src/parsers/type_id.cr deleted file mode 100644 index d8734533c..000000000 --- a/src/parsers/type_id.cr +++ /dev/null @@ -1,67 +0,0 @@ -module Mint - class Parser - def type_id!(error : SyntaxError.class, *, track : Bool = true) : Ast::TypeId - start do |start_position| - value = gather do - char(error, &.ascii_uppercase?) - letters_numbers_or_underscore - end - - raise error unless value - - if char! '.' - other = type_id!(error, track: false) - value += ".#{other.value}" - end - - Ast::TypeId.new( - from: start_position, - value: value, - to: position, - input: data).tap do |node| - self << node if track - end - end - end - - def type_id(*, track : Bool = true) : Ast::TypeId? - start do |start_position| - value = gather do - return unless char.ascii_uppercase? - step - letters_numbers_or_underscore - end - - return unless value - - start do - if char == '.' - other = start do - step - next_part = type_id(track: false) - next unless next_part - next_part - end - - next unless other - - value += ".#{other.value}" - end - end - - Ast::TypeId.new( - from: start_position, - value: value, - to: position, - input: data).tap do |node| - self << node if track - end - end - end - - def type_id(error : SyntaxError.class, *, track : Bool = true) : Ast::TypeId? - return unless char.ascii_uppercase? - type_id! error, track: track - end - end -end diff --git a/src/parsers/type_variable.cr b/src/parsers/type_variable.cr index 8c9b16afb..ab0f3c37a 100644 --- a/src/parsers/type_variable.cr +++ b/src/parsers/type_variable.cr @@ -1,13 +1,15 @@ module Mint class Parser def type_variable : Ast::TypeVariable? - return unless var = variable + parse do |start_position| + next unless value = identifier_variable - self << Ast::TypeVariable.new( - value: var.value, - from: var.from, - input: data, - to: var.to) + Ast::TypeVariable.new( + from: start_position, + to: position, + value: value, + file: file) + end end end end diff --git a/src/parsers/type_variant.cr b/src/parsers/type_variant.cr new file mode 100644 index 000000000..cab773156 --- /dev/null +++ b/src/parsers/type_variant.cr @@ -0,0 +1,40 @@ +module Mint + class Parser + def type_variant : Ast::TypeVariant? + parse do |start_position| + comment = self.comment + + next unless value = id + whitespace + + parameters = + if char! '(' + whitespace + + items = + list(terminator: ')', separator: ',') do + type_definition_field(raise_on_colon: false) || + type_variable || + type + end + + whitespace + next error :type_variant_expected_closing_parenthesis do + expected "the closing parenthesis of an type variant", word + snippet self + end unless char! ')' + + items + end || [] of Ast::Node + + Ast::TypeVariant.new( + parameters: parameters, + from: start_position, + comment: comment, + value: value, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/unary_minus.cr b/src/parsers/unary_minus.cr index 3f8387df2..efd83ccc3 100644 --- a/src/parsers/unary_minus.cr +++ b/src/parsers/unary_minus.cr @@ -1,18 +1,15 @@ module Mint class Parser def unary_minus : Ast::UnaryMinus? - start do |start_position| + parse do |start_position| next unless char! '-' - - expression = self.expression - - next unless expression + next unless expression = self.expression Ast::UnaryMinus.new( expression: expression, from: start_position, to: position, - input: data) + file: file) end end end diff --git a/src/parsers/use.cr b/src/parsers/use.cr index 1dad13e69..3b1d6daff 100644 --- a/src/parsers/use.cr +++ b/src/parsers/use.cr @@ -1,38 +1,51 @@ module Mint class Parser - syntax_error UseExpectedOpeningBracket - syntax_error UseExpectedClosingBracket - syntax_error UseExpectedExpression - syntax_error UseExpectedProvider - syntax_error UseExpectedRecord - def use : Ast::Use? - start do |start_position| - next unless keyword "use" - + parse do |start_position| + next unless word! "use" whitespace - provider = type_id! UseExpectedProvider + next error :use_expected_provider do + expected "the provider of a use", word + snippet self + end unless provider = id whitespace - raise UseExpectedRecord unless item = record - whitespace - if keyword "when" - condition = block( - opening_bracket: UseExpectedOpeningBracket, - closing_bracket: UseExpectedClosingBracket - ) do - expression! UseExpectedExpression + next error :use_expected_record do + expected "the record of a use", word + snippet self + end unless data = record + + condition = + parse(track: false) do + whitespace + next unless word! "when" + whitespace + + brackets( + ->{ error :use_expected_condition_opening_bracket do + expected "the opening bracket of a use condition", word + snippet self + end }, + ->{ error :use_expected_condition_closing_bracket do + expected "the closing bracket of a use condition", word + snippet self + end }, + ->(item : Ast::Node?) { + error :use_expected_condition do + expected "the condition of a use", word + snippet self + end unless item + }) { expression } end - end - self << Ast::Use.new( + Ast::Use.new( from: start_position, condition: condition, provider: provider, to: position, - input: data, - data: item) + file: file, + data: data) end end end diff --git a/src/parsers/value.cr b/src/parsers/value.cr new file mode 100644 index 000000000..dc063e9cc --- /dev/null +++ b/src/parsers/value.cr @@ -0,0 +1,17 @@ +module Mint + class Parser + def value(subject : Symbol = :all) : Ast::Variable? + parse do |start_position| + name = gather { ascii_letters_or_numbers(extra_char: '_') } + + next unless name + + Ast::Variable.new( + from: start_position, + to: position, + value: name, + file: file) + end + end + end +end diff --git a/src/parsers/variable.cr b/src/parsers/variable.cr index 7042da0c1..aa2926891 100644 --- a/src/parsers/variable.cr +++ b/src/parsers/variable.cr @@ -1,94 +1,31 @@ module Mint class Parser - INVALID_VARIABLE_NAMES = %w[true false] - - def variable_attribute_name : Ast::Variable? - start do |start_position| - value = gather do - next unless char.ascii_lowercase? - chars { |char| char.ascii_letter? || char.ascii_number? || char == '-' || char == ':' } - end - - next unless value + def variable_constant(*, track = true) : Ast::Variable? + parse(track: track) do |start_position| + next unless value = identifier_constant Ast::Variable.new( from: start_position, value: value, to: position, - input: data) + file: file) end end - def variable_with_dashes!(error : SyntaxError.class, track = true) : Ast::Variable - variable_with_dashes(track) || raise error - end - - def variable_with_dashes(track = true) : Ast::Variable? - start do |start_position| + def variable(*, track = true, extra_chars = [] of Char) : Ast::Variable? + parse(track: track) do |start_position| value = gather do next unless char.ascii_lowercase? - letters_numbers_or_dash + chars { |char| char.ascii_letter? || char.ascii_number? || char.in?(extra_chars) } end next unless value - node = Ast::Variable.new( - from: start_position, - value: value, - to: position, - input: data) - - self << node if track - node - end - end - - def variable_constant : Ast::Variable? - start do |start_position| - head = - gather { chars &.ascii_uppercase? } - - tail = - gather { chars { |char| char.ascii_uppercase? || char.ascii_number? || char == '_' } } - - next unless head - - value = "#{head}#{tail}" - Ast::Variable.new( from: start_position, value: value, to: position, - input: data) - end - end - - def variable_constant! : Ast::Variable - variable_constant || raise ConstantExpectedName - end - - def variable!(error : SyntaxError.class, track = true) : Ast::Variable - variable(track) || raise error - end - - def variable(track = true) : Ast::Variable? - start do |start_position| - value = gather do - next unless char.ascii_lowercase? - letters_or_numbers - end - - next unless value - next if value.in?(INVALID_VARIABLE_NAMES) - - node = Ast::Variable.new( - from: start_position, - value: value, - to: position, - input: data) - - self << node if track - node + file: file) end end end diff --git a/src/parsers/void.cr b/src/parsers/void.cr deleted file mode 100644 index f35238456..000000000 --- a/src/parsers/void.cr +++ /dev/null @@ -1,14 +0,0 @@ -module Mint - class Parser - def void : Ast::Void? - start do |start_position| - next unless keyword "void" - - self << Ast::Void.new( - from: start_position, - to: position, - input: data) - end - end - end -end diff --git a/src/render/terminal.cr b/src/render/terminal.cr index 5358caf12..1dce912a0 100644 --- a/src/render/terminal.cr +++ b/src/render/terminal.cr @@ -96,6 +96,48 @@ module Mint end end + # class Block + # getter io + + # def initialize(@io = IO::Memory.new, @width = 50) + # @content = "" + # end + + # def bold(value) + # @content += value + " " + # end + + # def text(value) + # @content += value + " " + # end + + # def code(value) + # actual_content = + # case value + # when " ", "" + # "a space" + # when "\n" + # "a new line" + # when "\0" + # "end of file" + # else + # value + # end + + # @content += %("#{actual_content}" ) + # end + + # def close + # @io << @content.split("\n").map do |line| + # if line.size > @width + # line.gsub(/(.{1,#{@width}})(\s+|$)/, "\\1\n").strip + # else + # line + # end + # end.join("\n") + "\n" + # end + # end + STDOUT = Terminal.new(::STDOUT) getter width, io, position @@ -117,14 +159,6 @@ module Mint terminal.io end - def render(&) - with self yield - end - - def render(io) - print io - end - def block(&) block = Block.new(width: @width) with block yield @@ -165,8 +199,18 @@ module Mint print "\n\n" end - def snippet(node) - print TerminalSnippet.render(node.input.input, node.input.file, node.from, node.to, width: @width) + def snippet(node : Ast::Node) + print TerminalSnippet.render(node.file.contents, node.file.path, node.from, node.to, width: @width).indent + print "\n\n" + end + + def snippet(node : String) + print node.indent + print "\n\n" + end + + def snippet(type : TypeChecker::Checkable) + print type.to_pretty.indent print "\n\n" end @@ -187,7 +231,7 @@ module Mint end divider = - if content.size < @width + if content.uncolorize.size < @width ("░" * (@width - text.size - 3)).colorize.mode(:dim) end diff --git a/src/sandbox_server.cr b/src/sandbox_server.cr index 31cc27472..eeb12fcbe 100644 --- a/src/sandbox_server.cr +++ b/src/sandbox_server.cr @@ -41,9 +41,7 @@ module Mint def initialize(@host = "0.0.0.0", @port = ENV["PORT"]?.try(&.to_i) || 8080, runtime_path : String? = nil) @runtime = if runtime_path - raise RuntimeFileNotFound, { - "path" => runtime_path, - } unless ::File.exists?(runtime_path) + Cli.runtime_file_not_found(runtime_path) unless ::File.exists?(runtime_path) ::File.read(runtime_path) else Assets.read("runtime.js") diff --git a/src/scope.cr b/src/scope.cr new file mode 100644 index 000000000..37d9afbf6 --- /dev/null +++ b/src/scope.cr @@ -0,0 +1,370 @@ +module Mint + # The class is responsible for keeping track of which variable is pointing to + # which node. + # + # The data strucutre is a tree where leafs are the levels of the child nodes + # of an AST node and a level is a container for the possible targets. + # + # When resolving a variable we travese it's tree upwards to find the target + # which matches the value of the variable. + class Scope + # TODO: Move this somewhere else + def debug_name(node) + case node + when Target + "{#{debug_name(node.node)}, #{debug_name(node.parent)}}" + when Tuple(Ast::Node, Ast::Node) + "{#{debug_name(node[0])}, #{debug_name(node[1])}}" + else + suffix = + case node + when Ast::Component + node.name.value + when Ast::Function + node.name.value + when Ast::Argument + node.name.value + when Ast::Variable + node.value + end + + prefix = + if suffix + "#{node.class.name}(#{suffix})" + else + node.class.name + end + + "#{prefix}#{node.try(&.location.start)}" + end + end + + # Represents a level for a node. + record Level, node : Ast::Node, items : Item = Item.new + + # Represents a target. We need to track which other node the target + # belongs to. + record Target, node : Ast::Node, parent : Ast::Node + + # Represents a map of possible targets. + alias Item = Hash(String, Target) + + # We track the level stack of a node in here. + getter scopes = {} of Ast::Node => Array(Level) + + # We track the level of a node in here. + getter nodes = {} of Ast::Node => Level + + getter root = Level.new(Ast::Node.new(Parser::File.new("", ""), 0, 0)) + + def initialize(@ast : Ast) + (@ast.unified_locales + + @ast.unified_modules + + @ast.components + + @ast.providers + + @ast.suites + + @ast.stores + + @ast.routes).each { |item| build(item) } + + resolve + end + + # Resolves the targets which can be statically resolved, currently only + # the exposed variables of a connected store in a component. + def resolve + scopes.each do |node, stack| + next unless node.is_a?(Ast::Component) + + node.connects.each do |connect| + case store = @ast.stores.find(&.name.value.==(connect.store.value)) + when Ast::Store + connect.keys.each do |key| + @scopes[store][1].items[key.name.value]?.try do |value| + stack[1].items[key.target.try(&.value) || key.name.value] = Target.new(key, value.node) + end + end + end + end + end + end + + # Adds a target to the level of the given node. + def add(node : Ast::Node, key : String, value : Ast::Node) + @nodes[node].items[key] = Target.new(value, node) + end + + # Tries to find the target of the given variable. + def resolve(node : Ast::Variable) + resolve(node.value, node) + end + + def resolve(target : String, base : Ast::Node) + case stack = @scopes[base]? + when Array(Level) + stack.reverse_each do |level| + level.items.each do |key, value| + return value if key == target + end + end + end + end + + # Builds a level for the node and yields the parents scope. + def create(node : Ast::Node, parent : Ast::Node | Nil = nil) + # Copy the stack of the parent so we can `see` it's targets. + scopes[node] = + if parent + scopes[parent].dup + else + [root] of Level + end + + # Create a level for the node + level = + Level.new(node) + + # TODO: Can we push it to the front instead of the back? + # Push the level at the end of the stack + scopes[node] << level + + # Save the level in case we need to add to it later on for example + # during type checking. + nodes[node] = level + end + + # Builds an array of nodes. If `stack` is `true` then each node will be the + # child of the previous nodes. + def build(nodes : Array(Ast::Node), parent : Ast::Node, *, stack : Bool = false) + if stack + nodes.reduce(parent) do |memo, item| + # We don't create levels for comments. + next memo if item.is_a?(Ast::Comment) + + build(item, memo) + item + end + else + nodes.each { |item| build(item, parent) } + end + end + + # Builds the scope for the given node and it's child nodes. + def build(node : Ast::Node) + create(node) + + name = + case node + when Ast::Component + node.name.value if node.global? + when Ast::Provider, + Ast::Module, + Ast::Store + node.name.value + end + + root.items[name] = Target.new(node, root.node) if name + + case node + when Ast::Component + build(node.properties, node) + build(node.functions, node) + build(node.constants, node) + build(node.states, node) + build(node.styles, node) + build(node.gets, node) + build(node.uses, node) + when Ast::Provider + build(node.functions, node) + build(node.constants, node) + build(node.states, node) + build(node.gets, node) + + add(node, "subscriptions", node) + when Ast::Store + build(node.functions, node) + build(node.constants, node) + build(node.states, node) + build(node.gets, node) + when Ast::Module + build(node.constants, node) + build(node.functions, node) + when Ast::Suite + build(node.constants, node) + build(node.tests, node) + when Ast::Locale + build(node.fields, node) + when Ast::Routes + build(node.routes, node) + end + end + + def build(node : Ast::Node | Nil, parent : Ast::Node) + return unless node + + create(node, parent) + + case node + when Ast::Function, + Ast::Property, + Ast::Constant, + Ast::Argument, + Ast::State, + Ast::Get + add(parent, node.name.value, node) + end + + case node + when Ast::Directives::Documentation, + Ast::Directives::Highlight, + Ast::Directives::Inline, + Ast::Directives::Asset, + Ast::Directives::Svg, + Ast::ArrayDestructuring, + Ast::TupleDestructuring, + Ast::TypeDestructuring, + Ast::NumberLiteral, + Ast::RegexpLiteral, + Ast::MemberAccess, + Ast::BoolLiteral, + Ast::LocaleKey, + Ast::Comment, + Ast::Env + when Ast::StringLiteral, + Ast::HereDocument, + Ast::Js + build(node.value.select(Ast::Interpolation), node) + when Ast::ParenthesizedExpression, + Ast::NegatedExpression, + Ast::Interpolation, + Ast::UnaryMinus, + Ast::CaseBranch, + Ast::Encode, + Ast::Decode, + Ast::Test + build(node.expression, node) + when Ast::Function + build(node.arguments, node) + build(node.body, node) + when Ast::Style + build(node.arguments, node) + build(node.body, node) + when Ast::State, + Ast::Property + build(node.default, node) + when Ast::CssSelector, + Ast::CssNestedAt + build(node.body, node) + when Ast::Statement + build(node.expression, node) + build(node.target, node) + when Ast::CssDefinition + build(node.value.select(Ast::Node), node) + when Ast::CssFontFace + build(node.definitions, node) + when Ast::CssKeyframes + build(node.selectors, node) + when Ast::Get + build(node.body, node) + when Ast::If + build(node.branches[0], node) + build(node.branches[1], node) + build(node.condition, node) + when Ast::Case + build(node.condition, node) + build(node.branches, node) + when Ast::For + build(node.condition, node) + build(node.subject, node) + build(node.body, node) + when Ast::HtmlStyle + build(node.arguments, node) + build(node.name, node) + when Ast::InlineFunction + build(node.arguments, node) + build(node.body, node) + when Ast::Argument + build(node.default, node) + when Ast::Block + build(node.expressions, node, stack: true) + when Ast::Operation + build(node.left, node) + build(node.right, node) + when Ast::ReturnCall, + Ast::Constant, + Ast::Access + build(node.expression, node) + when Ast::Pipe + build(node.expression, node) + build(node.argument, node) + when Ast::HtmlExpression + build(node.expressions, node) + when Ast::HtmlFragment + build(node.children, node) + when Ast::HtmlAttribute + build(node.value, node) + when Ast::ArrayLiteral, + Ast::TupleLiteral + build(node.items, node) + when Ast::Call + build(node.arguments, node) + build(node.expression, node) + when Ast::Directives::Format + build(node.content, node) + when Ast::Variable + when Ast::ArrayAccess + build(node.expression, node) + + case node.index + when Ast::Node + build(node.index.as(Ast::Node), node) + end + when Ast::Use + build(node.condition, node) + build(node.data, node) + when Ast::Record + build(node.fields, node) + when Ast::NextCall + build(node.data, node) + when Ast::RecordUpdate + build(node.expression, node) + build(node.fields, node) + when Ast::Route + build(node.expression, node) + build(node.arguments, node) + when Ast::Field + build(node.value, node) + + case parent + when Ast::Record + build(node.key, node) + end + when Ast::HtmlElement + build(node.attributes, node) + build(node.children, node) + build(node.styles, node) + + if (root = scopes[parent][1].node).is_a?(Ast::Component) && + (ref = node.ref) + add(root, ref.value, node) + end + when Ast::HtmlComponent + build(node.attributes, node) + build(node.children, node) + + if (root = scopes[parent][1].node).is_a?(Ast::Component) && + (ref = node.ref) + component = + @ast.components.find(&.name.value.==(node.component.value)) + + case component + when Ast::Component + scopes[parent][1].items[ref.value] = Target.new(component, root) + end + end + else + # TODO: Raise errorable + raise "SCOPE!!!: #{node.class.name}" + end + end + end +end diff --git a/src/semantic_tokenizer.cr b/src/semantic_tokenizer.cr index c359bfcff..96e5eee6a 100644 --- a/src/semantic_tokenizer.cr +++ b/src/semantic_tokenizer.cr @@ -22,20 +22,19 @@ module Mint # This represents which token types are used for which node. TOKEN_MAP = { Ast::TypeVariable => TokenType::TypeParameter, - Ast::Variable => TokenType::Variable, Ast::Comment => TokenType::Comment, Ast::StringLiteral => TokenType::String, Ast::RegexpLiteral => TokenType::Regexp, Ast::NumberLiteral => TokenType::Number, - Ast::TypeId => TokenType::Type, + Ast::Id => TokenType::Type, } # Represents a semantic token using the positions of the token instead # of line / column (for the LSP it is converted to line /column). record Token, type : TokenType, - from : Int32, - to : Int32 + from : Int64, + to : Int64 # We keep a cache of all tokenized nodes to avoid duplications getter cache = Set(Ast::Node).new @@ -48,7 +47,7 @@ module Mint tokenizer.tokenize(ast) parts = [] of String | Tuple(SemanticTokenizer::TokenType, String) - contents = ast.nodes.first.input.input + contents = ast.nodes.first.file.contents position = 0 tokenizer.tokens.sort_by(&.from).each do |token| @@ -129,17 +128,16 @@ module Mint end end - def tokenize(node : Ast::CssDefinition) - add(node.from, node.from + node.name.size, :property) + def tokenize(node : Ast::Variable) + if node.value[0].ascii_lowercase? + add(node, TokenType::Variable) + else + add(node, TokenType::Type) + end end - def tokenize(node : Ast::ArrayAccess) - # TODO: The index should be parsed as a number literal when - # implemented remove this - case index = node.index - when Int64 - add(node.from + 1, node.from + 1 + index.to_s.size, :number) - end + def tokenize(node : Ast::CssDefinition) + add(node.from, node.from + node.name.size, :property) end def tokenize(node : Ast::HtmlElement) @@ -157,7 +155,7 @@ module Mint end end - def add(from : Int32, to : Int32, type : TokenType) + def add(from : Int64, to : Int64, type : TokenType) tokens << Token.new( type: type, from: from, diff --git a/src/test_runner.cr b/src/test_runner.cr index 1634ba591..21de06bd0 100644 --- a/src/test_runner.cr +++ b/src/test_runner.cr @@ -1,5 +1,7 @@ module Mint class TestRunner + include Errorable + class Message include JSON::Serializable @@ -25,10 +27,6 @@ module Mint }, } - error BrowserNotFound - error InvalidBrowser - error InvalidReporter - @artifacts : TypeChecker::Artifacts? @reporter : Reporter @browser_path : String? @@ -116,24 +114,35 @@ module Mint when "dot" DotReporter.new else - raise InvalidReporter, {"reporter" => @flags.reporter} + error! :invalid_reporter do + block do + text "There is no reporter with the name:" + bold @flags.reporter + end + + snippet "The available reporters are:", "documentation, dot" + end end end def resolve_browser_path : String - paths = BROWSER_PATHS[@flags.browser.downcase]? - - raise InvalidBrowser, { - "browser" => @flags.browser, - } unless paths + paths = + BROWSER_PATHS[@flags.browser.downcase] || [] of String path = paths .compact_map { |item| Process.find_executable(item) } .first? - raise BrowserNotFound, { - "browser" => @flags.browser, - } unless path + error! :browser_not_found do + block do + text "I cannot find the executable of browser:" + bold @flags.browser + end + + block do + text "Are you sure it's installed properly?" + end + end unless path path end @@ -160,7 +169,14 @@ module Mint url, ]) else - raise InvalidBrowser, {"browser" => @flags.browser} + error! :invalid_browser do + block do + text "I cannot run the tests in the given browser:" + bold @flags.browser + end + + snippet "The available browsers are:", "chrome, firefox" + end end end @@ -197,9 +213,7 @@ module Mint runtime = if runtime_path = @flags.runtime - raise RuntimeFileNotFound, { - "path" => runtime_path, - } unless ::File.exists?(runtime_path) + Cli.runtime_file_not_found(runtime_path) unless File.exists?(runtime_path) ::File.read(runtime_path) else Assets.read("runtime.js") diff --git a/src/type_checker.cr b/src/type_checker.cr index d47814e2f..973648f58 100644 --- a/src/type_checker.cr +++ b/src/type_checker.cr @@ -1,5 +1,8 @@ module Mint class TypeChecker + include Errorable + include Helpers + alias Checkable = Type | Record | Variable # Built in types @@ -37,43 +40,24 @@ module Mint HTML, ] of Checkable - getter records, scope, artifacts, formatter, web_components + getter records, artifacts, formatter, web_components property? checking = true delegate checked, record_field_lookup, component_records, to: artifacts - delegate types, variables, ast, lookups, cache, to: artifacts + delegate variables, ast, lookups, cache, scope, to: artifacts delegate assets, resolve_order, locales, argument_order, to: artifacts - delegate component?, component, stateful?, current_top_level_entity?, to: scope delegate format, to: formatter @record_names = {} of String => Ast::Node @formatter = Formatter.new @names = {} of String => Ast::Node - @types = {} of String => Ast::Node @records = [] of Record @top_level_entity : Ast::Node? @languages : Array(String) @referee : Ast::Node? - @returns : Hash(Ast::Node, Array(Ast::ReturnCall)) = {} of Ast::Node => Array(Ast::ReturnCall) - @returns_stack : Array(Ast::Node) = [] of Ast::Node - - def push_return(node : Ast::ReturnCall) - if item = @returns_stack.last - @returns[item] ||= [] of Ast::ReturnCall - @returns[item].push(node) - end - end - - def with_returns(node : Ast::Node, &) - @returns_stack.push(node) - yield - ensure - @returns_stack.delete(node) - end - @record_name_char : String = 'A'.pred.to_s @stack = [] of Ast::Node @@ -83,17 +67,12 @@ module Mint @languages = ast.unified_locales.map(&.language) @artifacts = Artifacts.new(ast) - @scope = Scope.new(ast, records) resolve_records ast.unified_locales.each { |locale| check_locale(locale) } end - def debug - puts Debugger.new(@scope).run - end - def print_stack @stack.each_with_index do |i, index| x = case i @@ -118,13 +97,15 @@ module Mint def resolve_records add_record Record.new("Unit"), Ast::Record.empty - ast.records.each do |record| - check! record - add_record check(record), record + ast.type_definitions.each do |definition| + next if definition.fields.is_a?(Array(Ast::TypeVariant)) + value = check(definition) + check! definition + add_record(value, definition) end ast.components.each do |component| - component_records[component] = static_type_signature(component) + component_records[component] = static_type_signature(component).as(Record) end end @@ -144,10 +125,10 @@ module Mint } MINT - node = Parser.parse(contents, "").records[0] + node = Parser.parse(contents, "").type_definitions[0] record = resolve(node) - ast.records.push(node) + ast.type_definitions.push(node) add_record record, node record end @@ -173,9 +154,9 @@ module Mint def resolve_record_definition(name) records.find(&.name.==(name)) || begin - node = ast.records.find(&.name.value.==(name)) + node = ast.type_definitions.find(&.name.value.==(name)) - if node + if node && node.fields.is_a?(Array(Ast::TypeDefinitionField)) record = check(node) add_record record, node record @@ -183,26 +164,28 @@ module Mint end end - type_error RecordFieldsConflict - type_error RecordNameConflict - type_error RecordWithHoles - def add_record(record, node) end def add_record(record : Record, node) - raise RecordWithHoles, { - "record" => record, - "node" => node, - } if record.have_holes? + error! :record_with_holes do + snippet "Records with type variables are not allow at this time. " \ + "I found one here:", node + end if record.have_holes? other = @record_names[record.name]? - raise RecordNameConflict, { - "name" => record.name, - "other" => other, - "node" => node, - } if other && node != other + error! :record_name_conflict do + block do + text "There is already a" + bold "record" + text "with the name:" + bold record.name + end + + snippet "One of them is here:", node + snippet "The other is here:", other + end if other && node != other records << record @record_names[record.name] = node @@ -212,58 +195,51 @@ module Mint # ---------------------------------------------------------------------------- def lookup(node : Ast::Variable) - scope.find(node.value) + scope.resolve(node).try(&.node) end def lookup_with_level(node : Ast::Variable) - scope.find_with_level(node.value).try do |item| - {item[0], item[1], scope.levels.dup} - end - end - - def scope(node : Scope::Node, &) - scope.with(node) { yield } - end - - def scope(nodes, &) - scope.with(nodes) { yield } - end - - type_error VariableTaken - - def check_variable(variable) - variable.try do |name| - existing = lookup(name) - - raise VariableTaken, { - "name" => name.value, - "existing" => existing, - "node" => name, - } if existing + # puts "----------------------" + # puts scope.debug_name(node) + + # scope.scopes[node].each_with_index do |item, index| + # puts scope.debug_name(item.node).indent(index * 2) + # item.items.each do |key, value| + # puts "#{" " * (index * 2)}#{key} -> #{value.class.name}" + # end + # end + + scope.resolve(node).try do |item| + {item.node, item.parent} end end # Helpers for checking things # -------------------------------------------------------------------------- - type_error Recursion - type_error InvalidSelfReference - def check!(node) checked.add(node) if checking? end + def invalid_self_reference(referee : Ast::Node, node : Ast::Node) + error! :invalid_self_reference do + block "You are trying to reference an other entity in a top level entity before it is initialized." + + snippet "Then entity you are referencing:", referee + snippet "The entity you are referencing it from:", node + end + end + def resolve(node : Ast::Node | Checkable, *args) : Checkable case node in Checkable node in Ast::Node if cached = cache[node]? - raise InvalidSelfReference, { - "referee" => @referee, - "node" => node, - } if @stack.none? { |item| item.is_a?(Ast::Function) || item.is_a?(Ast::InlineFunction) } && - @top_level_entity.try(&.owns?(node)) + invalid_self_reference( + referee: @referee.not_nil!, + node: node) if @stack.none? { |item| item.is_a?(Ast::Function) || item.is_a?(Ast::InlineFunction) } && + @top_level_entity.try { |item| owns?(node, item) } cached else @@ -274,16 +250,16 @@ module Mint when Ast::Function, Ast::InlineFunction static_type_signature(node) else - raise Recursion, { - "caller_node" => @stack.last, - "node" => node, - } + error! :recursion do + snippet "Recursion is only supported in specific cases " \ + "at this time. Unfortunatly here is not supported:", node + snippet "The previous step in the recursion was here:", @stack.last + end end else - raise InvalidSelfReference, { - "referee" => @referee, - "node" => node, - } if @top_level_entity.try(&.owns?(node)) + invalid_self_reference( + referee: @referee.not_nil!, + node: node) if @top_level_entity.try { |item| owns?(node, item) } @stack.push node @@ -314,29 +290,23 @@ module Mint node end - type_error GlobalNameConflict - - def check_global_types(name : String, node : Ast::Node) : Nil - other = @types[name]? - - if other && other != node - what = - case other - when Ast::Enum then "enum" - when Ast::RecordDefinition then "record" - else - "" - end + def global_name_conflict( + other : Ast::Node, + node : Ast::Node, + what : String, + name : String + ) + error! :global_name_conflict do + block do + text "There is already a" + bold what + text "with the name:" + bold name + end - raise GlobalNameConflict, { - "other" => other, - "name" => name, - "what" => what, - "node" => node, - } + snippet "You are trying to define something with the same name here:", node + snippet "The #{what} is defined here:", other end - - @types[name] = node end def check_global_names(name : String, node : Ast::Node) : Nil @@ -353,19 +323,18 @@ module Mint "" end - raise GlobalNameConflict, { - "other" => other, - "name" => name, - "what" => what, - "node" => node, - } + global_name_conflict( + other: other, + what: what, + node: node, + name: name) end @names[name] = node end def check_names(nodes : Array(Ast::Function | Ast::Get | Ast::Property | Ast::State), - error : Mint::TypeError.class, + error : String, resolved = {} of String => Ast::Node) : Nil nodes.reduce(resolved) do |memo, node| name = @@ -385,12 +354,19 @@ module Mint "" end - raise error, { - "other" => other, - "name" => name, - "what" => what, - "node" => node, - } + error! :entity_name_conflict do + block do + text "There is already a" + bold what + text "with the name" + bold %("#{name}") + text "in this #{error}:" + end + + snippet other + + snippet "You are trying to define something with the same name here:", node + end end memo[name] = node @@ -435,7 +411,7 @@ module Mint end def with_restricted_top_level_entity(@referee, &) - @top_level_entity = current_top_level_entity? + @top_level_entity = scope.scopes[@referee][1]?.try(&.node) yield ensure @top_level_entity = nil diff --git a/src/type_checker/artifacts.cr b/src/type_checker/artifacts.cr index eca101e43..a6cffae97 100644 --- a/src/type_checker/artifacts.cr +++ b/src/type_checker/artifacts.cr @@ -3,20 +3,20 @@ module Mint class Artifacts getter ast, lookups, cache, checked, record_field_lookup, assets getter types, variables, component_records, resolve_order, locales - getter argument_order + getter argument_order, scope def initialize(@ast : Ast, @component_records = {} of Ast::Component => Record, @record_field_lookup = {} of Ast::Node => String, - @variables = {} of Ast::Node => Scope::Lookup, - @lookups = {} of Ast::Node => Ast::Node, + @variables = {} of Ast::Node => Tuple(Ast::Node, Ast::Node), + @lookups = {} of Ast::Node => Tuple(Ast::Node, Ast::Node?), @assets = [] of Ast::Directives::Asset, - @types = {} of Ast::Node => Checkable, @cache = {} of Ast::Node => Checkable, @locales = {} of String => Hash(String, Ast::Node), @argument_order = [] of Ast::Node, @resolve_order = [] of Ast::Node, @checked = Set(Ast::Node).new) + @scope = Scope.new(@ast) end end end diff --git a/src/type_checker/scope.cr b/src/type_checker/scope.cr deleted file mode 100644 index b692dd8c0..000000000 --- a/src/type_checker/scope.cr +++ /dev/null @@ -1,333 +0,0 @@ -module Mint - class TypeChecker - class Scope - alias Node = Tuple(String, Checkable, Ast::Node) | - Ast::Statement | - Ast::Component | - Ast::InlineFunction | - Ast::Function | - Ast::Provider | - Ast::Module | - Ast::Store | - Ast::Style - - alias Level = Tuple(Ast::Node | Checkable, Node) - alias Lookup = Tuple(Ast::Node | Checkable, Node, Array(Node)) - - @functions = {} of Ast::Function | Ast::Get => Ast::Store | Ast::Module - @levels = [] of Node - - getter levels - - def initialize(@ast : Ast, @records : Array(Record)) - @ast.components.each do |store| - store.functions.each do |function| - @functions[function] = store - end - - store.gets.each do |get| - @functions[get] = store - end - end - - @ast.providers.each do |store| - store.functions.each do |function| - @functions[function] = store - end - - store.gets.each do |get| - @functions[get] = store - end - end - - @ast.stores.each do |store| - store.functions.each do |function| - @functions[function] = store - end - - store.gets.each do |get| - @functions[get] = store - end - end - - @ast.unified_modules.each do |item| - item.functions.each do |function| - @functions[function] = item - end - end - end - - def path : String - @levels.reverse.join(" -> ") { |node| path(node) } - end - - def path(node : Node) - case node - in Tuple(String, Checkable, Ast::Node) - node[0] - in Ast::Component, - Ast::Store, - Ast::Module, - Ast::Provider - node.name.value - in Ast::InlineFunction, - Ast::Function, - Ast::Style - node.name.value - end - end - - def includes?(node) - @levels.includes?(node) - end - - def find(variable : String) - if result = find_with_level(variable) - result[0] - end - end - - def find_with_level(variable : String) : Level? - @levels.each do |level| - if item = find(variable, level) - return {item, level} - end - end - end - - def component? - @levels.find(&.is_a?(Ast::Component)).as(Ast::Component?) - end - - def component - component?.not_nil! - end - - def current_top_level_entity? - @levels.find do |item| - item.is_a?(Ast::Store) || - item.is_a?(Ast::Provider) || - item.is_a?(Ast::Component) - end.as(Ast::Node?) - end - - def stateful? - @levels.find do |item| - item.is_a?(Ast::Component) || - item.is_a?(Ast::Store) || - item.is_a?(Ast::Provider) - end - end - - def find(variable : String, data : Tuple(String, Checkable, Ast::Node)) - data[0] == variable ? data[1] : nil - end - - def find(variable : String, node : Ast::Function) - node.arguments.find(&.name.value.==(variable)) - end - - def find(variable : String, node : Ast::Style) - node.arguments.find(&.name.value.==(variable)) - end - - def find(variable : String, node : Ast::InlineFunction) - node.arguments.find(&.name.value.==(variable)) - end - - def find(variable : String, node : Ast::Module) - node.functions.find(&.name.value.==(variable)) || - node.constants.find(&.name.value.==(variable)) - end - - def find(variable : String, node : Ast::Store) - node.functions.find(&.name.value.==(variable)) || - node.states.find(&.name.value.==(variable)) || - node.gets.find(&.name.value.==(variable)) || - node.constants.find(&.name.value.==(variable)) - end - - def find(variable : String, node : Ast::Provider) - if variable == "subscriptions" - type = @records.find(&.name.==(node.subscription.value)) || - Comparer.normalize(Type.new(node.subscription.value)) - Type.new("Array", [type.as(Checkable)]) - else - node.functions.find(&.name.value.==(variable)) || - node.states.find(&.name.value.==(variable)) || - node.gets.find(&.name.value.==(variable)) || - node.constants.find(&.name.value.==(variable)) - end - end - - def find(variable : String, node : Ast::Component) - node.functions.find(&.name.value.==(variable)) || - node.gets.find(&.name.value.==(variable)) || - node.properties.find(&.name.value.==(variable)) || - node.states.find(&.name.value.==(variable)) || - node.constants.find(&.name.value.==(variable)) || - refs(component)[variable]? || - store_constants(component)[variable]? || - store_states(component)[variable]? || - store_functions(component)[variable]? || - store_gets(component)[variable]? - end - - def find(variable : String, node : Ast::Suite) - node.constants.find(&.name.value.==(variable)) - end - - def find(variable : String, node : Ast::Node) - end - - def with(node : Node, &) - case node - when Ast::Component, - Ast::Provider, - Ast::Module, - Ast::Store - old_levels = @levels - @levels = [node] of Node - begin - return yield - ensure - @levels = old_levels - end - when Ast::LocaleKey - old_levels = @levels - @levels = [] of Node - begin - return yield - ensure - @levels = old_levels - end - when Ast::Function, - Ast::Get - if store = @functions[node]? - old_levels = @levels - @levels = [node, store] of Node - begin - return yield - ensure - @levels = old_levels - end - end - end - - push(node) { yield } - end - - def push(node : Node, &) - @levels.unshift node - yield - ensure - @levels.delete node - end - - def with(nodes, &) - nodes.each { |node| @levels.unshift node } - yield - ensure - nodes.each { |node| @levels.delete node } - end - - private def refs(component) - component.refs.reduce({} of String => Ast::Node | Checkable) do |memo, (variable, item)| - case item - when Ast::HtmlComponent - @ast - .components - .find(&.name.value.==(item.component.value)) - .try do |entity| - memo[variable.value] = entity - end - when Ast::HtmlElement - memo[variable.value] = item - end - - memo - end - end - - private def store_states(component) - component.connects.reduce({} of String => Ast::State) do |memo, item| - @ast - .stores - .find(&.name.value.==(item.store.value)) - .try do |store| - item.keys.each do |key| - store - .states - .find(&.name.value.==(key.variable.value)) - .try do |state| - memo[(key.name || key.variable).value] = state - end - end - end - - memo - end - end - - private def store_gets(component) - component.connects.reduce({} of String => Ast::Get) do |memo, item| - @ast - .stores - .find(&.name.value.==(item.store.value)) - .try do |store| - item.keys.each do |key| - store - .gets - .find(&.name.value.==(key.variable.value)) - .try do |get| - memo[(key.name || key.variable).value] = get - end - end - end - - memo - end - end - - private def store_functions(component) - component.connects.reduce({} of String => Ast::Function) do |memo, item| - @ast - .stores - .find(&.name.value.==(item.store.value)) - .try do |store| - item.keys.each do |key| - store - .functions - .find(&.name.value.==(key.variable.value)) - .try do |function| - memo[(key.name || key.variable).value] = function - end - end - end - - memo - end - end - - private def store_constants(component) - component.connects.reduce({} of String => Ast::Constant) do |memo, item| - @ast - .stores - .find(&.name.value.==(item.store.value)) - .try do |store| - item.keys.each do |key| - store - .constants - .find(&.name.value.==(key.variable.value)) - .try do |function| - memo[(key.name || key.variable).value] = function - end - end - end - - memo - end - end - end - end -end diff --git a/src/type_checker/static_type_signature.cr b/src/type_checker/static_type_signature.cr new file mode 100644 index 000000000..7fa052343 --- /dev/null +++ b/src/type_checker/static_type_signature.cr @@ -0,0 +1,62 @@ +module Mint + class TypeChecker + # This method computes the static type signature of an entity. + def static_type_signature(node) : Checkable + case node + when Ast::InlineFunction, + Ast::Function + arguments = + node.arguments.map { |argument| resolve argument.type } + + return_type = + static_type_signature node.type + + defined_type = + Type.new("Function", arguments + [return_type]) + + Comparer.normalize(defined_type) + when Ast::Component + fields = {} of String => Checkable + + node.gets.each do |item| + fields[item.name.value] = static_type_signature(item) + end + + node.functions.each do |item| + fields[item.name.value] = static_type_signature(item) + end + + node.properties.each do |item| + fields[item.name.value] = static_type_signature(item) + end + + node.states.each do |item| + fields[item.name.value] = static_type_signature(item) + end + + node.refs.each do |variable, ref| + case ref + when Ast::Component + fields[variable.value] = + Type.new("Maybe", [static_type_signature(ref)] of Checkable) + when Ast::HtmlElement + fields[variable.value] = + Type.new("Maybe", [static_type_signature(ref)] of Checkable) + end + end + + Record.new(node.name.value, fields) + when Ast::Property, + Ast::State, + Ast::Get + static_type_signature node.type + when Type + resolve node + when Ast::HtmlElement + Type.new("Dom.Element") + else + Variable.new("a") + end + end + end +end diff --git a/src/type_checkers/access.cr b/src/type_checkers/access.cr index f9e850901..04d3df609 100644 --- a/src/type_checkers/access.cr +++ b/src/type_checkers/access.cr @@ -1,24 +1,118 @@ module Mint class TypeChecker - type_error AccessFieldNotFound - type_error AccessNotRecord + def unwind_access(node : Ast::Access, stack = [] of Ast::Node) : Array(Ast::Node) + case item = node.expression + when Ast::Access + stack.unshift(item.field) + unwind_access(item, stack) + when Ast::Variable + stack.unshift(node.expression) + end + + stack + end + + def to_function_type(node : Ast::TypeVariant, parent : Ast::TypeDefinition) + parent_type = + resolve parent + + option_type = + resolve node + + if node.parameters.empty? + parent_type + else + parameters = + case fields = node.fields + when Array(Ast::TypeDefinitionField) + fields.map do |field| + type = + resolve field.type + + type.label = field.key.value + type + end + else + option_type.parameters.dup + end + + parameters << parent_type.as(Checkable) + Comparer.normalize(Type.new("Function", parameters)) + end + end def check(node : Ast::Access) : Checkable + possibilities = [] of String + + case variable = node.expression + when Ast::Access + stack = unwind_access(node) + target = "" + + loop do + case item = stack.shift? + when Ast::Variable + target += + if target.blank? + item.value + else + "." + item.value + end + + possibilities.unshift target + else + break + end + end + when Ast::Variable + possibilities << variable.value + end + + possibilities.each do |possibility| + if parent = ast.type_definitions.find(&.name.value.==(possibility)) + case fields = parent.fields + when Array(Ast::TypeVariant) + if option = fields.find(&.value.value.==(node.field.value)) + variables[node] = {option, parent} + return to_function_type(option, parent) + end + end + end + + if entity = scope.resolve(possibility, node).try(&.node) + if entity && possibility[0].ascii_uppercase? + variables[node.expression] = {entity, entity} + check!(entity) + if target_node = scope.resolve(node.field.value, entity).try(&.node) + variables[node] = {target_node, entity} + variables[node.field] = {target_node, entity} + return resolve target_node + end + end + end + end + target = - resolve node.lhs + resolve node.expression - raise AccessNotRecord, { - "object" => target, - "node" => node, - } unless target.is_a?(Record) + error! :access_not_record do + snippet "You are trying to access a field on an entity which is not " \ + "a record:", target + snippet "The access in question is here:", node + end unless target.is_a?(Record) new_target = target.fields[node.field.value]? - raise AccessFieldNotFound, { - "field" => node.field.value, - "node" => node.field, - "target" => target, - } unless new_target + error! :access_field_not_found do + block do + text "The accessed field" + code node.field.value + text "does not exists on the entity:" + end + + snippet target + snippet "The access in question is here:", node + end unless new_target if item = component_records.find(&.last.==(target)) component, _ = item @@ -29,8 +123,8 @@ module Mint when Ast::HtmlComponent component_records .find(&.first.name.value.==(ref.component.value)) - .try do |entity| - memo[variable.value] = entity.first + .try do |record| + memo[variable.value] = record.first end when Ast::HtmlElement memo[variable.value] = variable @@ -39,16 +133,16 @@ module Mint memo end - lookups[node.field] = + lookups[node.field] = { (component.gets.find(&.name.value.==(node.field.value)) || - component.functions.find(&.name.value.==(node.field.value)) || - component.properties.find(&.name.value.==(node.field.value)) || - refs[node.field.value]? || - component.states.find(&.name.value.==(node.field.value))).not_nil! + component.functions.find(&.name.value.==(node.field.value)) || + component.properties.find(&.name.value.==(node.field.value)) || + refs[node.field.value]? || + component.states.find(&.name.value.==(node.field.value))).not_nil!, + component, + } - scope(component) do - resolve lookups[node.field] - end + resolve lookups[node.field][0] else record_field_lookup[node.field] = new_target.name end diff --git a/src/type_checkers/array_access.cr b/src/type_checkers/array_access.cr index 54246e7c7..e73e4846c 100644 --- a/src/type_checkers/array_access.cr +++ b/src/type_checkers/array_access.cr @@ -1,56 +1,54 @@ module Mint class TypeChecker - type_error ArrayAccessIndexNotNumber - type_error ArrayAccessInvalidTuple - type_error ArrayAccessNotAnArray - def check(node : Ast::ArrayAccess) : Checkable index = node.index - lhs = - node.lhs + expression = + node.expression type = - resolve lhs + resolve expression case index - in Ast::Expression - index_type = - resolve index - - raise ArrayAccessIndexNotNumber, { - "got" => index_type, - "expected" => NUMBER, - "node" => index, - } unless Comparer.compare(index_type, NUMBER) - - check_array_access(lhs, type) - in Int64 + when Ast::NumberLiteral if type.name == "Tuple" parameter = - type.parameters[index]? + type.parameters[index.value.to_i]? - raise ArrayAccessInvalidTuple, { - "size" => type.parameters.size.to_s, - "index" => ordinal(index), - "got" => type, - "node" => lhs, - } unless parameter + error! :array_access_invalid_tuple do + snippet( + "The tuple have only #{type.parameters.size} members, but " \ + "you wanted to access the #{ordinal(index.value.to_i + 1)}" \ + ". The exact type of the tuple is:", type) + snippet "The tuple in question is here:", expression + end unless parameter parameter else - check_array_access(lhs, type) + check_array_access(expression, type) end + end || begin + index_type = + resolve index + + error! :array_access_index_not_number do + block "The type of the index of an array access is not a number." + expected NUMBER, index_type + snippet "The index in question is here:", index + end unless Comparer.compare(index_type, NUMBER) + + check_array_access(expression, type) end end - def check_array_access(lhs, type) - raise ArrayAccessNotAnArray, { - "expected" => ARRAY, - "got" => type, - "node" => lhs, - } unless resolved = Comparer.compare(type, ARRAY) + def check_array_access(expression, type) + error! :array_access_not_an_array do + block "The entity you are trying to access an item from is not an " \ + "array or a tuple." + expected "Array(a), Tuple(...)", type + snippet "The array in question is here:", expression + end unless resolved = Comparer.compare(type, ARRAY) Type.new("Maybe", [resolved.parameters.first] of Checkable) end diff --git a/src/type_checkers/array_literal.cr b/src/type_checkers/array_literal.cr index 333929de2..eb27206a9 100644 --- a/src/type_checkers/array_literal.cr +++ b/src/type_checkers/array_literal.cr @@ -1,8 +1,5 @@ module Mint class TypeChecker - type_error ArrayNotMatchesDefinedType - type_error ArrayNotMatches - def check(node : Ast::ArrayLiteral) : Checkable defined_type = node.type.try do |type| @@ -25,12 +22,17 @@ module Mint rest.each_with_index do |item, index| type = resolve item - raise ArrayNotMatches, { - "index" => (index + 2).to_s, - "expected" => first, - "got" => type, - "node" => item, - } unless Comparer.compare(type, first) + return error! :array_not_matches do + block do + text "The" + bold "#{ordinal(index + 2)} item" + text "of an array does not match the type of the 1st item." + end + + snippet "I was expecting the type of the 1st item:", first + snippet "Instead it is:", type + snippet "The item in question is here:", item + end unless Comparer.compare(type, first) end inferred_type = @@ -40,11 +42,16 @@ module Mint final_type = Comparer.compare(inferred_type, defined_type) - raise ArrayNotMatchesDefinedType, { - "expected" => defined_type, - "got" => inferred_type, - "node" => node, - } unless final_type + error! :array_not_matches_defined_type do + block do + text "The" + bold "defined type" + text "of an array does not match the type of its items." + end + + expected defined_type, inferred_type + snippet "The array in question is here:", node.type.not_nil! + end unless final_type final_type else diff --git a/src/type_checkers/block.cr b/src/type_checkers/block.cr index 12def4e0c..18b7589e0 100644 --- a/src/type_checkers/block.cr +++ b/src/type_checkers/block.cr @@ -1,54 +1,72 @@ module Mint class TypeChecker - type_error StatementLastTarget - type_error ReturnCallTypeMismatch - def check(node : Ast::Block) : Checkable - statements = - node.statements.select(Ast::Statement) + if node.expressions.all?(Ast::CssDefinition) + resolve node.expressions + VOID + else + expressions = + node.expressions.select(Ast::Statement) + + error! :block_no_expressions do + block "This block doesn't have any statements. It should have at least one." + snippet node + end if expressions.empty? - with_returns(node) do - statements.dup.tap do |items| + expressions.dup.tap do |items| variables = [] of VariableScope while item = items.shift? + variables.each do |var| + scope.add(node, var[0], var[2]) + end + # This is to allow recursion case target = item.target when Ast::Variable case value = item.expression when Ast::InlineFunction - variables << {target.value, static_type_signature(value), target} + cache[target] = + static_type_signature(value) + + scope.add(item, target.value, target) end end - scope variables do - type = resolve item - variables.concat(destructure(item.target, type)) - end + type = resolve item + variables = destructure(item.target, type) end end last = - cache[statements.last] - - raise StatementLastTarget, { - "node" => node, - } if statements.last.target - - if returns = @returns[node]? - returns.each do |item| - type = - cache[item] - - raise ReturnCallTypeMismatch, { - "node" => item, - "expected" => last, - "got" => type, - } unless Comparer.compare(last, type) + cache[expressions.last] + + error! :statement_last_target do + block do + text "The" + bold "last statement" + text "of a block cannot be an" + bold "assignment:" end + + snippet node + end if expressions.last.target + + node.returns.each do |item| + type = + cache[item] + + error! :statement_return_type_mismatch do + snippet "The type of a return call does not match the return " \ + "type of the block:", type + + snippet "I was expecting:", last + snippet "It return call in question is here:", item + snippet "The returned value of the block is here:", expressions.last + end unless Comparer.compare(last, type) end - if node.async? && last.name != "Promise" + if async?(node) && last.name != "Promise" Type.new("Promise", [last] of Checkable) else last diff --git a/src/type_checkers/call.cr b/src/type_checkers/call.cr index 0b80919ef..19ba15cd1 100644 --- a/src/type_checkers/call.cr +++ b/src/type_checkers/call.cr @@ -1,18 +1,5 @@ module Mint class TypeChecker - type_error CallArgumentSizeMismatch - type_error CallArgumentTypeMismatch - type_error CallWithMixedArguments - type_error CallNotFoundArgument - type_error CallTypeMismatch - type_error CallNotAFunction - - def check(node : Ast::CallExpression) - resolve(node.expression) - .dup - .tap(&.label = node.name.try(&.value)) - end - def check(node : Ast::Call) function_type = resolve node.expression @@ -21,9 +8,10 @@ module Mint end def check_call(node, function_type) : Checkable - raise CallNotAFunction, { - "node" => node, - } unless function_type.name == "Function" + return error! :call_not_a_function do + snippet "The entity you called is not a function, instead it is:", function_type + snippet "The call in question is here:", node + end unless function_type.name == "Function" argument_size = function_type.parameters.size - 1 @@ -39,36 +27,48 @@ module Mint parameters = [] of Checkable - raise CallArgumentSizeMismatch, { - "call_size" => node.arguments.size.to_s, - "size" => argument_size.to_s, - "node" => node, - } if node.arguments.size > argument_size || # If it's more than the maximum - node.arguments.size < required_argument_size # If it's less then the minimum + error! :call_argument_size_mismatch do + block do + text "The function you called takes" + bold argument_size.to_s + text "arguments, while you tried to call it with" + bold "#{node.arguments.size}." + end + + snippet "The type of the function is:", function_type + snippet "The call in question is here:", node + end if node.arguments.size > argument_size || # If it's more than the maximum + node.arguments.size < required_argument_size # If it's less then the minimum args = - case node.arguments - when .all?(&.name.nil?) + if node.arguments.all?(&.key.nil?) node.arguments - when .none?(&.name.nil?) + elsif node.arguments.all?(&.key.!=(nil)) node.arguments.sort_by do |argument| index = function_type .parameters - .index { |param| param.label == argument.name.try(&.value) } + .index { |param| param.label == argument.key.try(&.value) } + + error! :call_not_found_argument do + snippet( + "I was looking for a named argument but I can't find it:", + argument.key.try(&.value).to_s) - raise CallNotFoundArgument, { - "function_type" => function_type, - "name" => argument.name.try(&.value).to_s, - "node" => node, - } unless index + snippet "The type of the function is:", function_type + snippet "The call in question is here:", node + end unless index index end else - raise CallWithMixedArguments, { - "node" => node, - } + error! :call_with_mixed_arguments do + block "A call cannot have named and unamed arguments at the same " \ + "time because in specific cases I cannot pair the arguments " \ + "with the values." + + snippet "The call in question is here:", node + end end argument_order.concat args @@ -80,13 +80,20 @@ module Mint function_argument_type = function_type.parameters[index] - raise CallArgumentTypeMismatch, { - "index" => ordinal(index + 1), - "expected" => function_argument_type, - "got" => argument_type, - "function" => function_type, - "node" => node, - } unless Comparer.compare(function_argument_type, argument_type) + error! :call_argument_type_mismatch do + ordinal = + ordinal(index + 1) + + block do + text "The" + bold "#{ordinal} argument" + text "to a function is causing a mismatch." + end + + snippet "The function is expecting the #{ordinal} argument to be:", function_argument_type + snippet "Instead it is:", argument_type + snippet "The call in question is here:", node + end unless Comparer.compare(function_argument_type, argument_type) parameters << argument_type end @@ -101,11 +108,10 @@ module Mint result = Comparer.compare(function_type, call_type) - raise CallTypeMismatch, { - "expected" => function_type, - "got" => call_type, - "node" => node, - } unless result + error! :impossible_error do + block "You have run into an impossible error. Please file an issue " \ + "with a reproducible example in the GithubRepository." + end unless result resolve_type(result.parameters.last) end diff --git a/src/type_checkers/case.cr b/src/type_checkers/case.cr index e942c7897..8cd238e75 100644 --- a/src/type_checkers/case.cr +++ b/src/type_checkers/case.cr @@ -1,10 +1,5 @@ module Mint class TypeChecker - type_error CaseBranchNotMatches - type_error CaseUnnecessaryAll - type_error CaseEnumNotCovered - type_error CaseNotCovered - def check(node : Ast::Case) : Checkable condition = resolve node.condition @@ -32,64 +27,89 @@ module Mint unified_branch = Comparer.compare(type, resolved) + error! :case_branch_not_matches do + block do + text "The return type of the" + bold "#{ordinal(index + 2)} branch" + text "of a case expression does not match the type of the 1st branch." + end - raise CaseBranchNotMatches, { - "index" => (index + 2).to_s, - "expected" => resolved, - "got" => type, - "node" => branch, - } unless unified_branch + snippet "I was expecting the type of the 1st branch:", resolved + snippet "Instead it is:", type + snippet "The branch in question is here:", branch + end unless unified_branch unified_branch end catch_all = - node.branches.find(&.match.nil?) + node.branches.find(&.pattern.nil?) + + case_unnecessary_all = + ->(catch_node : Ast::Node) { error! :case_unnecessary_all do + snippet "All possibilities of the case expression are covered so " \ + "this branch is not needed and can be safely removed.", catch_node + end } + + case_not_covered = ->{ error! :case_not_covered do + snippet( + "Not all possibilities of a case expression are covered. To " \ + "cover all remaining possibilities add an empty case branch:", + "=> returnValue") + + snippet "The case in question is here:", node + end } # At this point all branches have been checked the # type should be the same. case condition when Type parent = - ast.enums.find(&.name.value.==(condition.name)) + ast.type_definitions.find(&.name.value.==(condition.name)) if parent not_matched = - parent.options.reject do |option| - node - .branches - .any? do |branch| - case match = branch.match - when Ast::EnumDestructuring - match.option.value == option.value.value && - !match.parameters.any? do |item| - item.is_a?(Ast::TupleDestructuring) || - item.is_a?(Ast::EnumDestructuring) || - item.is_a?(Ast::ArrayDestructuring) - end - else - false + case fields = parent.fields + when Array(Ast::TypeVariant) + fields.reject do |field| + node + .branches + .any? do |branch| + case pattern = branch.pattern + when Ast::TypeDestructuring + pattern.variant.value == field.value.value && + !pattern.items.any? do |item| + item.is_a?(Ast::TupleDestructuring) || + item.is_a?(Ast::TypeDestructuring) || + item.is_a?(Ast::ArrayDestructuring) + end + else + false + end end - end + end + else + [] of Ast::TypeVariant end - raise CaseUnnecessaryAll, { - "node" => catch_all, - } if not_matched.empty? && catch_all + case_unnecessary_all.call(catch_all) if not_matched.empty? && catch_all - options = - not_matched.map do |option| - "#{format parent.name}::#{formatter.replace_skipped(format(option.value))}" - end + cases = + not_matched.map do |variant| + "#{format parent.name}::#{formatter.replace_skipped(format(variant.value))}" + end.join('\n') - raise CaseEnumNotCovered, { - "options" => options, - "node" => node, - } if !not_matched.empty? && !catch_all + error! :case_type_not_covered do + snippet "Not all possibilities of a case expression are covered. " \ + "To cover all remaining possibilities create branches " \ + "for the following cases:", cases + + snippet "The case in question is here:", node + end if !not_matched.empty? && !catch_all elsif condition.name == "Array" destructurings = node.branches - .map(&.match) + .map(&.pattern) .select(Ast::ArrayDestructuring) .select! do |branch| branch.items.all? do |item| @@ -103,51 +123,39 @@ module Mint true else (1..destructurings.max_of(&.items.size)).to_a.all? do |length| - destructurings.any?(&.covers?(length)) + destructurings.any? { |item| covers?(item, length) } end end covers_empty = node.branches - .map(&.match) + .map(&.pattern) .select(Ast::ArrayLiteral) .any?(&.items.empty?) covers_infitiy = - destructurings.any?(&.spread?) + destructurings.any? { |item| spread?(item) } covered = covers_cases && covers_infitiy && covers_empty - raise CaseUnnecessaryAll, { - "node" => catch_all, - } if covered && catch_all - - raise CaseNotCovered, { - "node" => node, - } if !covered && !catch_all + case_unnecessary_all.call(catch_all) if covered && catch_all + case_not_covered.call if !covered && !catch_all elsif condition.name == "Tuple" destructured = node.branches.any? do |branch| - case match = branch.match + case pattern = branch.pattern when Ast::TupleDestructuring - match.exhaustive? + exhaustive?(pattern) else false end end - raise CaseUnnecessaryAll, { - "node" => catch_all, - } if destructured && catch_all - - raise CaseNotCovered, { - "node" => node, - } if !destructured && !catch_all + case_unnecessary_all.call(catch_all) if destructured && catch_all + case_not_covered.call if !destructured && !catch_all elsif !catch_all - raise CaseNotCovered, { - "node" => node, - } + case_not_covered.call end end diff --git a/src/type_checkers/case_branch.cr b/src/type_checkers/case_branch.cr index a38b9e248..3a05c5df8 100644 --- a/src/type_checkers/case_branch.cr +++ b/src/type_checkers/case_branch.cr @@ -2,13 +2,15 @@ module Mint class TypeChecker def check(node : Ast::CaseBranch, condition : Checkable) : Checkable type = - node.match.try do |item| + node.pattern.try do |item| variables = destructure(item, condition) - scope(variables) do - resolve(node.expression) + variables.each do |var| + scope.add(node, var[0], var[2]) end + + resolve(node.expression) end || resolve(node.expression) if node.expression.is_a?(Array(Ast::CssDefinition)) diff --git a/src/type_checkers/component.cr b/src/type_checkers/component.cr index 505142f58..7afd401b0 100644 --- a/src/type_checkers/component.cr +++ b/src/type_checkers/component.cr @@ -1,59 +1,11 @@ module Mint class TypeChecker - type_error ComponentReferenceNameConflict - type_error ComponentFunctionTypeMismatch - type_error ComponentExposedNameConflict - type_error ComponentRenderTypeMismatch - type_error ComponentEntityNameConflict - type_error ComponentStateNameConflict - type_error ComponentStyleNameConflict - type_error ComponentMultipleConnects - type_error ComponentMultipleExposed - type_error ComponentNotFoundRender - type_error ComponentMultipleUses - type_error ComponentMainProperty - - def static_type_signature(node : Ast::Component) - fields = {} of String => Checkable - - node.gets.each do |item| - fields[item.name.value] = static_type_signature(item) - end - - node.functions.each do |item| - fields[item.name.value] = static_type_signature(item) - end - - node.properties.each do |item| - fields[item.name.value] = static_type_signature(item) - end - - node.states.each do |item| - fields[item.name.value] = static_type_signature(item) - end - - node.refs.each do |variable, ref| - case ref - when Ast::Component - fields[variable.value] = - Type.new("Maybe", [static_type_signature(ref)] of Checkable) - when Ast::HtmlElement - fields[variable.value] = - Type.new("Maybe", [static_type_signature(ref)] of Checkable) - end - end - - Record.new(node.name.value, fields) - end - # Check all nodes that were not checked before def check_all(node : Ast::Component) : Checkable resolve node - scope node do - resolve node.gets - resolve node.functions - end + resolve node.gets + resolve node.functions VOID end @@ -66,47 +18,51 @@ module Mint checked = {} of String => Ast::Node - check_names(node.properties, ComponentEntityNameConflict, checked) - check_names(node.functions, ComponentEntityNameConflict, checked) - check_names(node.states, ComponentStateNameConflict, checked) - check_names(node.gets, ComponentEntityNameConflict, checked) + check_names(node.properties, "component", checked) + check_names(node.functions, "component", checked) + check_names(node.states, "component", checked) + check_names(node.gets, "component", checked) # Checking for properties in Main - if node.name.value == "Main" && (property = node.properties.first?) - raise ComponentMainProperty, { - "property_node" => property, - "node" => node, - } + error! :component_main_properties do + block do + text "The" + bold "Main" + text "component cannot have properties because there is no way " \ + "to pass values to them." + end + + snippet "A property is defined here:", property + snippet "The component in question is here:", node + end end # Checking for ref conflicts node.refs.reduce({} of String => Ast::Node) do |memo, (variable, ref)| name = variable.value + other = memo[name]? - if other = memo[name]? - raise ComponentReferenceNameConflict, { - "other" => other, - "name" => name, - "node" => ref, - } - end + error! :component_reference_name_conflict do + snippet "There are multiple references with the name:", name + snippet "One reference is here:", variable + snippet "The other reference is here:", other + end if other - memo[name] = ref + memo[name] = variable memo end # Checking for style name conflicts node.styles.reduce({} of String => Ast::Node) do |memo, style| name = style.name.value + other = memo[name]? - if other = memo[name]? - raise ComponentStyleNameConflict, { - "node" => style, - "other" => other, - "name" => name, - } - end + error! :component_style_name_conflict do + snippet "There are multiple styles with the name:", name + snippet "One style is here:", style + snippet "An other style is here:", other + end if other memo[name] = style memo @@ -116,38 +72,53 @@ module Mint node.connects.each do |connect| other = (node.connects - [connect]).find(&.store.value.==(connect.store.value)) - raise ComponentMultipleConnects, { - "name" => connect.store, - "node" => connect, - "other" => other, - } if other + return error! :component_multiple_stores do + block do + text "The component is connected to the store" + bold %("#{connect.store.value}") + text "multiple times." + end + + snippet "It is connected here:", other + snippet "It is also connected here:", connect + end if other end # Checking for conflict between exposed entity and own entity node.connects.each do |connect| connect.keys.each do |key| - variable = key.name || key.variable + variable = key.target || key.name other = checked[variable.value]? - raise ComponentExposedNameConflict, { - "name" => variable.value, - "other" => other, - "node" => key, - } if other + error! :component_exposed_name_conflict do + block do + text "You cannot expose" + bold %("#{variable.value}") + text "from the store because the name is already taken." + end + + snippet "The entity with the same name is here:", other + snippet "The expose in question is here:", key + end if other end end # Checking for multiple connects exposing the same value node.connects.reduce({} of String => Ast::Node) do |memo, connect| connect.keys.each do |key| - variable = key.name || key.variable + variable = key.target || key.name other = memo[variable.value]? - raise ComponentMultipleExposed, { - "name" => variable.value, - "other" => other, - "node" => key, - } if other + error! :component_multiple_exposed do + block do + text "The entity" + bold %("#{variable.value}") + text "from a store is exposed multiple times." + end + + snippet "It is exposed here:", other + snippet "It is also exposed here:", key + end if other memo[variable.value] = key end @@ -158,52 +129,79 @@ module Mint node.uses.each do |use| other = (node.uses - [use]).find(&.provider.value.==(use.provider.value)) - raise ComponentMultipleUses, { - "name" => use.provider, - "other" => other, - "node" => use, - } if other + error! :component_multiple_providers do + block do + text "You are subcribing to the provider" + bold %("#{other.provider.value}") + text "in a component multiple times." + end + + snippet "A subscription is here:", other + snippet "An other subscription is here:", use + end if other end # Type checking the entities - scope node do - resolve node.connects - resolve node.properties - resolve node.states - resolve node.uses - - raise ComponentNotFoundRender, { - "node" => node, - } unless node.functions.any?(&.name.value.==("render")) - - node.functions.each do |function| - case function.name.value - when "render" - type = - resolve function - - matches = - [HTML, STRING, HTML_CHILDREN, TEXT_CHILDREN].any? do |item| - Comparer.compare(type, Type.new("Function", [item] of Checkable)) - end - - raise ComponentRenderTypeMismatch, { - "node" => function, - "got" => type.parameters.first, - } unless matches - when "componentDidMount", - "componentDidUpdate", - "componentWillUnmount" - type = - resolve function - - raise ComponentFunctionTypeMismatch, { - "name" => function.name.value, - "expected" => VOID_FUNCTION, - "node" => function, - "got" => type, - } unless Comparer.compare(type, VOID_FUNCTION) - end + resolve node.connects + resolve node.properties + resolve node.states + resolve node.uses + + error! :component_no_render_function do + block do + text "A component must have a" + bold "render" + text "function. This component does not have one:" + end + + snippet node + end unless node.functions.any?(&.name.value.==("render")) + + node.functions.each do |function| + case function.name.value + when "render" + type = + resolve function + + matches = + [HTML, STRING, HTML_CHILDREN, TEXT_CHILDREN].any? do |item| + Comparer.compare(type, Type.new("Function", [item] of Checkable)) + end + + error! :component_render_function_mismatch do + block do + text "I was expecting the type of the" + bold "render" + text "function to match one of these types:" + end + + snippet <<-PLAIN + Function(Array(String)) + Function(Array(Html)) + Function(String) + Function(Html) + PLAIN + + snippet "Instead the type of the function is:", type.parameters.first + snippet "The function in question is here:", function + end unless matches + when "componentDidMount", + "componentDidUpdate", + "componentWillUnmount" + type = + resolve function + + error! :component_lifecycle_function_mismatch do + block do + text "The type of the function" + bold %("#{function.name.value}") + text "of a component must be:" + end + + snippet VOID_FUNCTION + snippet "Instead it is:", type + snippet "The function in question is here:", function + end unless Comparer.compare(type, VOID_FUNCTION) end end diff --git a/src/type_checkers/connect.cr b/src/type_checkers/connect.cr index f4332a0a2..2c41e647f 100644 --- a/src/type_checkers/connect.cr +++ b/src/type_checkers/connect.cr @@ -1,20 +1,22 @@ module Mint class TypeChecker - type_error ConnectNotFoundMember - type_error ConnectNotFoundStore - def check(node : Ast::Connect) : Checkable store = ast.stores.find(&.name.value.==(node.store.value)) - raise ConnectNotFoundStore, { - "store" => node.store.value, - "node" => node, - } unless store + error! :connect_not_found_store do + block do + text "I was looking for the store" + bold node.store.value + text "but could not find it." + end + + snippet node.store + end unless store resolve store node.keys.each do |key| - key_value = key.variable.value + key_value = key.name.value found = store.functions.find(&.name.value.==(key_value)) || @@ -22,14 +24,18 @@ module Mint store.gets.find(&.name.value.==(key_value)) || store.constants.find(&.name.value.==(key_value)) - raise ConnectNotFoundMember, { - "key" => key_value, - "store" => node.store.value, - "node" => node, - } unless found + error! :connect_not_found_member do + block do + text "The entity" + bold %("#{key_value}") + text "does not exist in the connected store." + end + + snippet "The connect in question is here:", node + end unless found cache[key] = resolve found - lookups[key] = found + lookups[key] = {found, store} end VOID diff --git a/src/type_checkers/constant.cr b/src/type_checkers/constant.cr index 26764bd6a..779334420 100644 --- a/src/type_checkers/constant.cr +++ b/src/type_checkers/constant.cr @@ -1,7 +1,7 @@ module Mint class TypeChecker def check(node : Ast::Constant) : Checkable - resolve node.value + resolve node.expression end end end diff --git a/src/type_checkers/css_definition.cr b/src/type_checkers/css_definition.cr index 992f80a52..96e54cc13 100644 --- a/src/type_checkers/css_definition.cr +++ b/src/type_checkers/css_definition.cr @@ -5,9 +5,6 @@ module Mint .strip .lines - type_error CssDefinitionTypeMismatch - type_error CssNoProperty - def check(node : Ast::CssDefinition) : Checkable node.value.each do |item| type = @@ -19,17 +16,27 @@ module Mint end unless node.name.starts_with?('-') - raise CssNoProperty, { - "name" => node.name, - "node" => node, - } unless CSS_PROPERTY_NAMES.includes?(node.name) + error! :css_definition_no_property do + block do + text "There is no CSS property with the name:" + bold %("#{node.name}") + end + + snippet node + end unless CSS_PROPERTY_NAMES.includes?(node.name) end - raise CssDefinitionTypeMismatch, { - "name" => node.name, - "node" => node, - "got" => type, - } unless Comparer.matches_any?(type, [STRING, NUMBER]) + error! :css_definition_type_mismatch do + block do + text "The type of the value for the CSS property" + bold %("#{node.name}") + text "is invalid." + end + + snippet "I was expecting one of these types:", "String\nNumber" + snippet "Instead it is:", type + snippet "The css definition in question is here:", node + end unless Comparer.matches_any?(type, [STRING, NUMBER]) end VOID diff --git a/src/type_checkers/css_font_face.cr b/src/type_checkers/css_font_face.cr index e6ab48b6a..9f9ab11ef 100644 --- a/src/type_checkers/css_font_face.cr +++ b/src/type_checkers/css_font_face.cr @@ -1,7 +1,5 @@ module Mint class TypeChecker - type_error CssFontFaceInterpolation - def check(node : Ast::CssFontFace) : Checkable resolve node.definitions @@ -12,9 +10,11 @@ module Mint interpolation = definition.value.find(&.is_a?(Ast::Interpolation)) - raise CssFontFaceInterpolation, { - "node" => interpolation, - } if interpolation + error! :css_font_face_interpolation do + block "Interpolations are not allowed inside a font-face rule." + + snippet interpolation + end if interpolation end VOID diff --git a/src/type_checkers/decode.cr b/src/type_checkers/decode.cr index 800e0a93e..8ec678398 100644 --- a/src/type_checkers/decode.cr +++ b/src/type_checkers/decode.cr @@ -1,20 +1,31 @@ module Mint class TypeChecker - type_error DecodeExpectedObject - type_error DecodeComplexType - def check(node : Ast::Decode) : Checkable type = resolve node.type raise "" unless type - raise DecodeComplexType, { - "got" => type, - "node" => node, - } unless check_decode(type) + error! :decode_complex_type do + snippet "This type cannot be automatically decoded:", type + + snippet( + "Only these types and records containing them cantext be " \ + "automatically decoded:", + <<-MINT + Map(String, a) + Array(a) + Maybe(a) + String + Number + Object + Time + Bool + MINT + ) - types[node] = type + snippet "The decode question is here:", node + end unless check_decode(type) result_type = Type.new("Result", [OBJECT_ERROR, type] of Checkable) @@ -23,11 +34,16 @@ module Mint expression = resolve item - raise DecodeExpectedObject, { - "expected" => OBJECT, - "got" => expression, - "node" => node, - } unless Comparer.compare(expression, OBJECT) + error! :decode_expected_object do + block do + text "Only the" + bold %("Object") + text "type can be decoded but you tried to decode:" + end + + snippet expression + snippet "The decode question is here:", node + end unless Comparer.compare(expression, OBJECT) result_type else diff --git a/src/type_checkers/destructuring.cr b/src/type_checkers/destructuring.cr index 191409689..780b9c41e 100644 --- a/src/type_checkers/destructuring.cr +++ b/src/type_checkers/destructuring.cr @@ -10,10 +10,15 @@ module Mint # An alias for the variable scope (of Mint::Typechecker::Scope) alias VariableScope = Tuple(String, Checkable, Ast::Node) - type_error DestructuringMultipleSpreads - type_error DestructuringTupleMismatch - type_error DestructuringTypeMismatch - type_error DestructuringNoParameter + def destructuring_type_mismatch(expected : Checkable, got : Checkable, node : Ast::Node) + error! :destructuring_type_mismatch do + block "A value does not match its supposed type in a destructuring." + + expected expected, got + + snippet "The destructuring in question is here:", node + end + end def destructure( node : Nil, @@ -31,11 +36,10 @@ module Mint type = resolve(node) - raise DestructuringTypeMismatch, { - "expected" => condition, - "got" => type, - "node" => node, - } unless Comparer.compare(type, condition) + destructuring_type_mismatch( + expected: condition, + node: node, + got: type) unless Comparer.compare(type, condition) variables end @@ -46,6 +50,7 @@ module Mint condition : Checkable, variables : Array(VariableScope) = [] of VariableScope ) + cache[node] = condition variables.tap(&.push({node.value, condition, node})) end @@ -54,23 +59,33 @@ module Mint condition : Checkable, variables : Array(VariableScope) = [] of VariableScope ) - raise DestructuringTypeMismatch, { - "expected" => ARRAY, - "got" => condition, - "node" => node, - } unless Comparer.compare(ARRAY, condition) + destructuring_type_mismatch( + expected: ARRAY, + got: condition, + node: node, + ) unless Comparer.compare(ARRAY, condition) spreads = node.items.select(Ast::Spread).size - raise DestructuringMultipleSpreads, { - "count" => spreads.to_s, - "node" => node, - } if spreads > 1 + error! :destructuring_multiple_spreads do + block "An array destructuring can only contain one spread notation " \ + "because otherwise I don't know how to distribute the " \ + "leftover items." + + block do + text "This array destructuring contains" + bold spreads.to_s + text "spread notations:" + end + + snippet node + end if spreads > 1 node.items.each do |item| case item when Ast::Spread + cache[item] = condition variables << {item.variable.value, condition, item} else destructure(item, condition.parameters[0], variables) @@ -85,19 +100,25 @@ module Mint condition : Checkable, variables : Array(VariableScope) = [] of VariableScope ) - raise DestructuringTypeMismatch, { - "expected" => Type.new("Tuple"), - "got" => condition, - "node" => node, - } unless condition.name == "Tuple" - - raise DestructuringTupleMismatch, { - "size" => node.parameters.size.to_s, - "got" => condition, - "node" => node, - } if node.parameters.size > condition.parameters.size - - node.parameters.each_with_index do |item, index| + destructuring_type_mismatch( + expected: Type.new("Tuple"), + got: condition, + node: node, + ) unless condition.name == "Tuple" + + error! :destructuring_tuple_mismatch do + block do + text "This destructuring of a tuple does not match the given " \ + "tuple. I was expecting a tuple with" + bold node.items.size.to_s + text "items." + end + + snippet "Instead it is this:", condition + snippet "The destructuring in question is here:", node + end if node.items.size > condition.parameters.size + + node.items.each_with_index do |item, index| destructure(item, condition.parameters[index], variables) end @@ -105,80 +126,108 @@ module Mint end def destructure( - node : Ast::EnumDestructuring, + node : Ast::TypeDestructuring, condition : Checkable, variables : Array(VariableScope) = [] of VariableScope ) + name = + node.name.try(&.value) || condition.name + parent = - ast.enums.find(&.name.value.==(node.name.try &.value)) + ast.type_definitions.find(&.name.value.==(name)) - raise EnumIdTypeMissing, { - "name" => node.name, - "node" => node, - } unless parent + error! :destructuring_type_missing do + snippet "I could not find the type for a destructuring with the name:", name.to_s + snippet "The destructuring in question is here:", node + end unless parent - option = - parent.options.find(&.value.value.==(node.option.value)) + variant = + case fields = parent.fields + when Array(Ast::TypeVariant) + fields.find(&.value.value.==(node.variant.value)) + end + + error! :destructuring_type_variant_missing do + block do + text "I could not find the variant" + bold %("#{node.variant.value}") + text "of type" + bold %("#{parent.name.value}") + text "for a destructuring:" + end - raise EnumIdEnumMissing, { - "parent_name" => parent.name.value, - "name" => node.option.value, - "parent" => parent, - "node" => node, - } unless option + snippet node + snippet "The type is defined here:", parent + end unless variant - lookups[node] = option + lookups[node] = {variant, parent} type = resolve(parent) unified = Comparer.compare(type, condition) - raise DestructuringTypeMismatch, { - "expected" => condition, - "got" => type, - "node" => node, - } unless unified - - case option_param = option.parameters.first? - when Ast::EnumRecordDefinition - node.parameters.each_with_index do |param, index| - record = - resolve(option_param).as(Record) + destructuring_type_mismatch( + expected: condition, + node: node, + got: type, + ) unless unified + case fields = variant.fields + when Array(Ast::TypeDefinitionField) + node.items.each_with_index do |param, index| case param when Ast::Variable - found = option_param.fields.find do |field| + found = fields.find do |field| case param when Ast::Variable param.value == field.key.value end end - raise TypeError.new unless found + error! :destructuring_type_field_missing do + snippet "I could not find a field for a destructuring:", param.value + snippet "The destructuring in question is here:", param + end unless found + + type = + resolve(found.type) - destructure(param, record.fields[param.value], variables) + destructure(param, type, variables) else - name = - option_param.fields[index].key.value + field = + fields[index] - destructure(param, record.fields[name], variables) + type = + resolve(field.type) + + destructure(param, type, variables) end end else - node.parameters.each_with_index do |param, index| + node.items.each_with_index do |param, index| case param when Ast::Variable - raise DestructuringNoParameter, { - "size" => option.parameters.size.to_s, - "index" => index.to_s, - "name" => option.value, - "option" => option, - "node" => param, - } unless option.parameters[index]? + error! :destructuring_no_parameter do + block do + text "You are trying to destructure the" + bold index.to_s + text "parameter from the type variant:" + bold variant.value.value + end + + block do + text "The variant only has" + bold variant.parameters.size.to_s + text "parameters." + end + + snippet "You are trying to destructure it here:", param + snippet "The option is defined here:", variant + end unless variant.parameters[index]? - option_type = - resolve(option.parameters[index]).not_nil! + variant_type = + resolve(variant.parameters[index]).not_nil! mapping = {} of String => Checkable @@ -187,16 +236,16 @@ module Mint end resolved_type = - Comparer.fill(option_type, mapping).not_nil! + Comparer.fill(variant_type, mapping).not_nil! destructure(param, resolved_type, variables) else sub_type = - case item = option.parameters[index] + case item = variant.parameters[index] when Ast::Type resolve(item) when Ast::TypeVariable - unified.parameters[parent.parameters.index! { |enum_item| enum_item.value == item.value }] + unified.parameters[parent.parameters.index! { |variable| variable.value == item.value }] else VOID # Can't happen end diff --git a/src/type_checkers/directives/asset.cr b/src/type_checkers/directives/asset.cr index a3ee791d2..bdea2b294 100644 --- a/src/type_checkers/directives/asset.cr +++ b/src/type_checkers/directives/asset.cr @@ -1,12 +1,11 @@ module Mint class TypeChecker - type_error AssetDirectiveExpectedFile - def check(node : Ast::Directives::Asset) : Checkable - raise AssetDirectiveExpectedFile, { - "path" => node.real_path.to_s, - "node" => node, - } unless node.exists? + error! :asset_directive_expected_file do + block "The path specified for an asset directive does not exist: " + snippet node.real_path.to_s + snippet "The asset directive in question is here:", node + end unless node.exists? assets << node if checking? STRING diff --git a/src/type_checkers/directives/documentation.cr b/src/type_checkers/directives/documentation.cr index bb4ba9b0a..c0a94f453 100644 --- a/src/type_checkers/directives/documentation.cr +++ b/src/type_checkers/directives/documentation.cr @@ -1,17 +1,18 @@ module Mint class TypeChecker - type_error DocumentationDirectiveEntityNotFound - def check(node : Ast::Directives::Documentation) : Checkable component = ast.components.find(&.name.value.==(node.entity.value)) - raise DocumentationDirectiveEntityNotFound, { - "name" => node.entity.value, - "node" => node, - } unless component + error! :documentation_directive_entity_not_found do + snippet( + "The entity for the documentation directive does not exist:", + node.entity.value) + + snippet "The documentation directive in question is here:", node + end unless component - lookups[node] = component + lookups[node] = {component, nil} OBJECT end diff --git a/src/type_checkers/directives/inline.cr b/src/type_checkers/directives/inline.cr index 5af50bf5f..4e767103b 100644 --- a/src/type_checkers/directives/inline.cr +++ b/src/type_checkers/directives/inline.cr @@ -1,12 +1,11 @@ module Mint class TypeChecker - type_error InlineDirectiveExpectedFile - def check(node : Ast::Directives::Inline) : Checkable - raise InlineDirectiveExpectedFile, { - "path" => node.real_path.to_s, - "node" => node, - } unless node.exists? + error! :inline_directive_expected_file do + block "The path specified for an inline directive does not exist:" + snippet node.real_path.to_s + snippet "The inline directive in question is here:", node + end unless node.exists? STRING end diff --git a/src/type_checkers/directives/svg.cr b/src/type_checkers/directives/svg.cr index 0f0ba17bc..bf785f7bf 100644 --- a/src/type_checkers/directives/svg.cr +++ b/src/type_checkers/directives/svg.cr @@ -1,41 +1,59 @@ module Mint class TypeChecker - type_error SvgDirectiveExpectedDimensions - type_error SvgDirectiveExpectedSvgTag - type_error SvgDirectiveExpectedFile - type_error SvgDirectiveExpectedSvg - def check(node : Ast::Directives::Svg) : Checkable - raise SvgDirectiveExpectedFile, { - "path" => node.real_path.to_s, - "node" => node, - } unless node.exists? + error! :svg_directive_expected_file do + snippet( + "The specified file for an svg directive does not exist:", + node.real_path.to_s) + + snippet "The svg directive in question is here:", node + end unless node.exists? + + contents = + node.file_contents document = - XML.parse(node.file_contents) + XML.parse(contents) errors = document.errors.try(&.map(&.to_s)) || %w[] - raise SvgDirectiveExpectedSvg, { - "errors" => errors, - "node" => node, - } unless errors.empty? + error! :svg_directive_expected_svg do + snippet( + "The specified file for an svg directive is not an SVG file " \ + "because I could not parse it. These are the errors I found:", + errors.join("\n")) + + snippet( + "These are the first few lines of the file:", + contents.lines[0..4].join("\n")) + + snippet "The svg directive in question is here:", node + end unless errors.empty? svg = document.first_element_child - raise SvgDirectiveExpectedSvgTag, { - "node" => node, - } unless svg + error! :svg_directive_expected_svg_tag do + snippet( + "The specified file for an svg directive does not contain an " \ + " tag. These are the first few lines of the file:", + contents.lines[0..4].join("\n")) + + snippet "The svg directive in question is here:", node + end if !svg || svg.name != "svg" + + error! :svg_directive_expected_dimensions do + snippet "I need certain attributes for an svg for it to render " \ + "correctly. The specified file for an svg directive does " \ + "not have these required attributes:", "width, height, viewBox" - raise SvgDirectiveExpectedSvgTag, { - "node" => node, - } unless svg.name == "svg" + snippet( + "These are the first few lines of the file:", + contents.lines[0..4].join("\n")) - raise SvgDirectiveExpectedDimensions, { - "node" => node, - } unless svg["width"]? && svg["height"]? && svg["viewBox"]? + snippet "The svg directive in question is here:", node + end unless svg["width"]? && svg["height"]? && svg["viewBox"]? HTML end diff --git a/src/type_checkers/encode.cr b/src/type_checkers/encode.cr index 1a15f92f1..326eb845c 100644 --- a/src/type_checkers/encode.cr +++ b/src/type_checkers/encode.cr @@ -1,7 +1,5 @@ module Mint class TypeChecker - type_error EncodeComplexType - def check(node : Ast::Encode) : Checkable expression = node.expression.try do |item| @@ -13,10 +11,27 @@ module Mint end end - raise EncodeComplexType, { - "got" => expression, - "node" => node, - } unless check_decode(expression) + error! :encode_complex_type do + snippet "This type cannot be automatically encoded:", expression + + block do + text "Only these types and records containing them can" + text "be automatically decoded:" + end + + snippet <<-MINT + Map(String, a) + Array(a) + Maybe(a) + String + Number + Object + Time + Bool + MINT + + snippet "The encode in question is here:", node + end unless check_decode(expression) OBJECT end diff --git a/src/type_checkers/enum.cr b/src/type_checkers/enum.cr deleted file mode 100644 index 812c67e59..000000000 --- a/src/type_checkers/enum.cr +++ /dev/null @@ -1,49 +0,0 @@ -module Mint - class TypeChecker - type_error EnumNotDefinedParameter - type_error EnumUnusedParameter - - def check(node : Ast::Enum) : Checkable - check_global_types node.name.value, node - - parameters = - resolve node.parameters - - used_parameters = Set(Ast::TypeVariable).new - - node.options.each do |option| - check option.parameters, node.parameters, used_parameters - end - - node.parameters.each do |parameter| - raise EnumUnusedParameter, { - "name" => parameter.value, - "node" => parameter, - } unless used_parameters.includes?(parameter) - end - - Type.new(node.name.value, parameters) - end - - def check(parameters : Array(Ast::Node), - names : Array(Ast::TypeVariable), - used_parameters : Set(Ast::TypeVariable)) - parameters.each do |parameter| - case parameter - when Ast::Type - check parameter.parameters, names, used_parameters - when Ast::TypeVariable - param = - names.find(&.value.==(parameter.value)) - - raise EnumNotDefinedParameter, { - "name" => parameter.value, - "node" => parameter, - } unless param - - used_parameters.add param - end - end - end - end -end diff --git a/src/type_checkers/enum_id.cr b/src/type_checkers/enum_id.cr deleted file mode 100644 index 2e0706611..000000000 --- a/src/type_checkers/enum_id.cr +++ /dev/null @@ -1,102 +0,0 @@ -module Mint - class TypeChecker - type_error EnumIdTypeMismatch - type_error EnumIdTypeMissing - type_error EnumIdEnumMissing - - # This checks all entities that starts with an uppercase character - # - enums - # - record constructors - # - constants - def check(node : Ast::EnumId) : Checkable - parent = - ast.enums.find(&.name.value.==(node.name.try &.value)) - - if parent - check(node, parent) - elsif parent = records.find(&.name.==(node.option.value)) - check(node, parent) - elsif name = node.name - raise EnumIdTypeMissing, { - "name" => name.value, - "node" => node, - } - else - variable = Ast::Variable.new( - value: node.option.value, - input: node.input, - from: node.from, - to: node.to) - - lookups[node] = variable - resolve(variable) - end - end - - def check(node : Ast::EnumId, parent : Ast::Enum) - parent_type = - resolve parent - - option = - parent.options.find(&.value.value.==(node.option.value)) - - raise EnumIdEnumMissing, { - "parent_name" => parent.name.value, - "name" => node.option.value, - "parent" => parent, - "node" => node, - } unless option - - option_type = - resolve option - - parameters = - resolve node.expressions - - resolved_type = - Type.new(node.option.value, parameters) - - unified = - Comparer.compare_raw(option_type, resolved_type) - - raise EnumIdTypeMismatch, { - "got" => resolved_type, - "expected" => option_type, - "option" => option, - "node" => node, - } unless unified - - extracted = - extract_variables unified - - final_parameters = - parent_type.parameters.map do |param| - case param - when Variable - extracted[param.name]? || param - else - param - end - end - - lookups[node] = option - - Type.new(parent_type.name, final_parameters) - end - - def extract_variables(node : Checkable) : Hash(String, Checkable) - extracted = {} of String => Checkable - - case node - when Type - node.parameters.each do |param| - extracted.merge!(extract_variables(param)) - end - when Variable - extracted[node.name] = Comparer.prune(node) - end - - extracted - end - end -end diff --git a/src/type_checkers/enum_record_definition.cr b/src/type_checkers/enum_record_definition.cr deleted file mode 100644 index f8ba0493e..000000000 --- a/src/type_checkers/enum_record_definition.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Mint - class TypeChecker - def check(node : Ast::EnumRecordDefinition) : Checkable - fields = - node - .fields - .to_h { |field| {field.key.value, resolve(field).as(Checkable)} } - - mappings = - node - .fields - .to_h { |field| {field.key.value, field.mapping.try(&.string_value)} } - - Record.new("", fields, mappings) - end - end -end diff --git a/src/type_checkers/env.cr b/src/type_checkers/env.cr index 2598414ce..9f9c7e5fe 100644 --- a/src/type_checkers/env.cr +++ b/src/type_checkers/env.cr @@ -1,14 +1,12 @@ module Mint class TypeChecker - type_error EnvNotFoundVariable - def check(node : Ast::Env) : Checkable return STRING unless @check_env - raise EnvNotFoundVariable, { - "name" => node.name, - "node" => node, - } unless MINT_ENV[node.name]? + error! :env_not_found_variable do + snippet "I cannot find the environment variable with the name:", node.name + snippet "Here is where it is referenced:", node + end unless MINT_ENV[node.name]? STRING end diff --git a/src/type_checkers/record_field.cr b/src/type_checkers/field.cr similarity index 57% rename from src/type_checkers/record_field.cr rename to src/type_checkers/field.cr index 56b4179f2..25ec94cd5 100644 --- a/src/type_checkers/record_field.cr +++ b/src/type_checkers/field.cr @@ -1,11 +1,13 @@ module Mint class TypeChecker - def check(node : Ast::RecordField, should_create_record : Bool = false) : Checkable + def check(node : Ast::Field, should_create_record : Bool = false) : Checkable case expression = node.value when Ast::Record resolve expression, should_create_record else resolve expression + end.dup.tap do |item| + item.label = node.key.try(&.value) end end end diff --git a/src/type_checkers/for_expression.cr b/src/type_checkers/for_expression.cr index 916f4665a..c0f2f98eb 100644 --- a/src/type_checkers/for_expression.cr +++ b/src/type_checkers/for_expression.cr @@ -1,10 +1,5 @@ module Mint class TypeChecker - type_error ForArrayOrSetArgumentsMismatch - type_error ForConditionTypeMismatch - type_error ForMapArgumentsMismatch - type_error ForTypeMismatch - def check(node : Ast::For) : Checkable subject = resolve node.subject @@ -18,40 +13,52 @@ module Mint is_valid = is_array_or_set || is_map - raise ForTypeMismatch, { - "node" => node, - "got" => subject, - } unless is_valid - - raise ForMapArgumentsMismatch, { - "node" => node, - } if is_map && !node.arguments.size.in?(2, 3) - - raise ForArrayOrSetArgumentsMismatch, { - "node" => node, - } if is_array_or_set && !node.arguments.size.in?(1, 2) - - arguments = - node - .arguments - .each_with_index - .reduce([] of Tuple(String, Checkable, Ast::Node)) do |memo, (argument, index)| - memo << if (is_map && index == 2) || (is_array_or_set && index == 1) - {argument.value, NUMBER, argument} - else - {argument.value, subject.parameters[index], argument} - end + error! :for_type_mismatch do + block "The iterable object of a for expression has an invalid type." + block "I was expecting one of the following types:" + + snippet "Array(a), Set(a), Map(a, b)" + snippet "Instead it is:", subject + snippet "The iterable object in question is here:", node.subject + end unless is_valid + + error! :for_map_arguments_mismatch do + snippet "If the iterable object of a for expression is a map, then " \ + "it needs to the have 2 arguments:", node.arguments.first + end if is_map && !node.arguments.size.in?(2, 3) + + error! :for_array_or_set_arguments_mismatch do + snippet( + "If the iterable object of a for expression is a set or an " \ + "array. Then it needs to the have only 1 argument:", + node.arguments.first) + end if is_array_or_set && !node.arguments.size.in?(1, 2) + + node + .arguments + .each_with_index do |argument, index| + if (is_map && index == 2) || (is_array_or_set && index == 1) + cache[argument] = NUMBER + + scope.add(node, argument.value, argument) + else + cache[argument] = subject.parameters[index] + + scope.add(node, argument.value, argument) end + end - type = scope(arguments) do + type = begin node.condition.try do |condition| - condition_type = resolve condition.condition + condition_type = resolve condition + + error! :for_condition_type_mismatch do + snippet "The condition of a for expression has an invalid type. " \ + "I was expecting:", BOOL - raise ForConditionTypeMismatch, { - "node" => condition, - "got" => condition_type, - "expected" => BOOL, - } unless Comparer.compare(BOOL, condition_type) + snippet "Instead it is:", condition_type + snippet "The value in question is here:", condition.expressions.last + end unless Comparer.compare(BOOL, condition_type) end resolve node.body diff --git a/src/type_checkers/function.cr b/src/type_checkers/function.cr index eac19bb44..918de9fae 100644 --- a/src/type_checkers/function.cr +++ b/src/type_checkers/function.cr @@ -1,23 +1,5 @@ module Mint class TypeChecker - type_error FunctionArgumentMustHaveADefaultValue - type_error FunctionArgumentConflict - type_error FunctionTypeMismatch - type_error FunctionTypeNeeded - - def static_type_signature(node : Ast::Function) : Checkable - arguments = - node.arguments.map { |argument| resolve argument.type } - - return_type = - node.type.try { |type| resolve type } || Variable.new("a") - - defined_type = - Type.new("Function", arguments + [return_type]) - - Comparer.normalize(defined_type) - end - def check_arguments(arguments : Array(Ast::Argument)) was_default = false @@ -28,59 +10,72 @@ module Mint other = (arguments - [argument]).find(&.name.value.==(name)) - raise FunctionArgumentMustHaveADefaultValue, { - "node" => argument, - "name" => name, - } if was_default && !argument.default + error! :function_argument_must_have_a_default_value do + block do + text "The argument" + bold %("#{name}") + text "is declared after one that had a default value." + end + + block "Arguments that come after ones that have a default value must also have a default value." + + snippet "The argument in question is here:", argument + end if was_default && !argument.default was_default = true if argument.default - raise FunctionArgumentConflict, { - "node" => argument, - "other" => other, - "name" => name, - } if other + error! :function_argument_conflict do + block do + text "The argument" + bold %("#{name}") + text "is declared multiple times." + end + + snippet "It is declared here:", other + snippet "It is also declared here:", argument + end if other end end def check(node : Ast::Function) : Checkable - scope node do - check_arguments(node.arguments) + check_arguments(node.arguments) - arguments = - resolve node.arguments + arguments = + resolve node.arguments - body_type = - resolve node.body + body_type = + resolve node.body - final_type = - Type.new("Function", arguments + [body_type]) + final_type = + Type.new("Function", arguments + [body_type]) - resolved_type = - if type = node.type - return_type = - resolve type + resolved_type = + if type = node.type + return_type = + resolve type - defined_type = - Comparer.normalize(Type.new("Function", arguments + [return_type])) + defined_type = + Comparer.normalize(Type.new("Function", arguments + [return_type])) - resolved = - Comparer.compare(defined_type, final_type) + resolved = + Comparer.compare(defined_type, final_type) - raise FunctionTypeMismatch, { - "expected" => return_type, - "got" => body_type, - "node" => node, - } unless resolved + error! :function_type_mismatch do + block "The return type of a function does not match its type definition." - resolved - else - Comparer.normalize(final_type) - end + snippet "I was expecting:", return_type + snippet "Which is defined here:", type + snippet "Instead it is:", body_type + snippet "Which is returned here:", node.body.expressions.last + end unless resolved - resolved_type.optional_count = node.arguments.count(&.default) - resolved_type - end + resolved + else + Comparer.normalize(final_type) + end + + resolved_type.optional_count = node.arguments.count(&.default) + resolved_type end end end diff --git a/src/type_checkers/get.cr b/src/type_checkers/get.cr index 78a445e08..3e28f7530 100644 --- a/src/type_checkers/get.cr +++ b/src/type_checkers/get.cr @@ -1,11 +1,5 @@ module Mint class TypeChecker - type_error GetTypeMismatch - - def static_type_signature(node : Ast::Get) : Checkable - node.type.try { |type| resolve type } || Variable.new("a") - end - def check(node : Ast::Get) : Checkable body_type = resolve node.body @@ -17,11 +11,14 @@ module Mint resolved = Comparer.compare(body_type, return_type) - raise GetTypeMismatch, { - "expected" => return_type, - "got" => body_type, - "node" => node, - } unless resolved + error! :get_type_mismatch do + block "The return type of a get does not match its type definition." + + snippet "I was expecting:", return_type + snippet "Which is defined here:", type + snippet "Instead it is:", body_type + snippet "Which is returned here:", node.body.expressions.last + end unless resolved resolved else diff --git a/src/type_checkers/here_doc.cr b/src/type_checkers/here_doc.cr index a1cd48e4c..9fe0432e9 100644 --- a/src/type_checkers/here_doc.cr +++ b/src/type_checkers/here_doc.cr @@ -1,8 +1,18 @@ module Mint class TypeChecker - type_error HereDocInterpolationTypeMismatch + def here_doc_interpolation_type_mismatch( + type : Checkable, + got : Checkable, + node : Ast::Node + ) + error! :here_doc_interpolation_type_mismatch do + block "An interpolation in here document is causing a mismatch." + expected type, got + snippet "The interpolation in question is here:", node + end + end - def check(node : Ast::HereDoc) : Checkable + def check(node : Ast::HereDocument) : Checkable if node.modifier == '#' node.value.each do |item| case item @@ -10,11 +20,11 @@ module Mint item_type = resolve item - raise HereDocInterpolationTypeMismatch, { - "expected" => HTML, - "got" => item_type, - "node" => item, - } unless Comparer.matches_any?(item_type, [STRING, NUMBER, HTML]) + here_doc_interpolation_type_mismatch( + type: HTML, + got: item_type, + node: item, + ) unless Comparer.matches_any?(item_type, [STRING, NUMBER, HTML]) end end @@ -26,11 +36,11 @@ module Mint item_type = resolve item - raise HereDocInterpolationTypeMismatch, { - "expected" => STRING, - "got" => item_type, - "node" => item, - } unless Comparer.matches_any?(item_type, [STRING, NUMBER]) + here_doc_interpolation_type_mismatch( + type: STRING, + got: item_type, + node: item, + ) unless Comparer.matches_any?(item_type, [STRING, NUMBER]) end end diff --git a/src/type_checkers/html_attribute.cr b/src/type_checkers/html_attribute.cr index 7a2b1ddef..67e864933 100644 --- a/src/type_checkers/html_attribute.cr +++ b/src/type_checkers/html_attribute.cr @@ -1,22 +1,21 @@ module Mint class TypeChecker - type_error HtmlAttributeComponentPropertyTypeMismatch - type_error HtmlAttributeElementAttributeTypeMismatch - type_error HtmlAttributeNotFoundComponentProperty - type_error HtmlAttributeComponentKeyTypeMismatch - type_error HtmlAttributeFragmentKeyTypeMismatch - type_error HtmlElementClassNameForbidden - type_error HtmlElementRefForbidden - def check(node : Ast::HtmlAttribute, element : Ast::HtmlFragment) got = resolve node.value - raise HtmlAttributeFragmentKeyTypeMismatch, { - "expected" => STRING, - "node" => node, - "got" => got, - } unless Comparer.compare(STRING, got) + error! :html_attribute_fragment_key_type_mismatch do + block do + text "The" + bold "key" + text "attribute of a fragment has an invalid type. It can only be:" + code "String" + end + + expected STRING, got + + snippet node + end unless Comparer.compare(STRING, got) got end @@ -28,30 +27,51 @@ module Mint expected = case node.name.value.downcase when "ref" - raise HtmlElementRefForbidden, { - "node" => node, - } + error! :html_element_ref_forbidden do + snippet %(The use of "ref" attribute is forbidden:), node + snippet "If you want to assign a variable to an element, use the " \ + "as keyword:", "
" + end when .starts_with?("on") [EVENT_FUNCTION, VOID_FUNCTION] when "readonly", "disabled", "checked" [BOOL] when "className" - raise HtmlElementClassNameForbidden, { - "node" => node, - } + error! :html_element_class_name_forbidden do + block "The className attribute on elements are forbidden." + + block do + text "Please use" + bold "class" + text "instead." + end + + snippet node + end when "style" [STYLE_MAP, STRING] else [STRING] end - raise HtmlAttributeElementAttributeTypeMismatch, { - "expected" => expected.join(", "), - "tag" => element.tag.value, - "name" => node.name.value, - "node" => node, - "got" => got, - } unless expected.any? { |item| Comparer.compare(item, got) } + error! :html_attribute_element_attribute_type_mismatch do + block do + text "The type of the value for the property" + bold %("#{node.name.value}") + text "of element" + bold %("#{element.tag.value}") + text "does not match its type." + end + + if expected.size > 1 + snippet "I was expecting one of the following types:", expected.join(", ") + snippet "Instead it is:", got + else + expected expected.first, got + end + + snippet "The attribute in question is here:", node + end unless expected.any? { |item| Comparer.compare(item, got) } got end @@ -61,39 +81,55 @@ module Mint case node.name.value when "key" - raise HtmlAttributeComponentKeyTypeMismatch, { - "component" => component.name, - "expected" => STRING, - "got" => type, - "node" => node, - } unless Comparer.compare(type, STRING) + error! :html_attribute_component_key_type_mismatch do + block do + text "The" + bold %("key") + text "attribute of a component has an invalid type." + end + + expected STRING, type + snippet "The attribute in question is here:", node + end unless Comparer.compare(type, STRING) else prop = component .properties .find(&.name.value.==(node.name.value)) - raise HtmlAttributeNotFoundComponentProperty, { - "properties" => component.properties.map(&.name.value), - "name" => node.name.value, - "component" => component.name.value, - "node" => node, - } unless prop + error! :html_attribute_not_found_component_property do + block do + text "I was looking for a property in component" + bold %("#{component.name.value}") + text "but could not find it:" + end + + snippet node.name.value + + snippet "Maybe you want one of its properties:", + component.properties.map(&.name.value).join("\n") + + snippet "The attribute in question is here:", node + end unless prop - lookups[node] = prop + lookups[node] = {prop, component} prop_type = - scope component do - resolve prop + resolve prop + + error! :html_attribute_component_property_type_mismatch do + block do + text "The type of the value for the property" + bold %("#{prop.name.value}") + text "of the component" + bold %("#{component.name.value}") + text "does not match its definition." end - raise HtmlAttributeComponentPropertyTypeMismatch, { - "name" => prop.name.value, - "component" => component.name.value, - "expected" => prop_type, - "node" => node, - "got" => type, - } unless Comparer.compare(prop_type, type) + expected prop_type, type + + snippet "The attribute in question is here:", node + end unless Comparer.compare(prop_type, type) end type diff --git a/src/type_checkers/html_component.cr b/src/type_checkers/html_component.cr index 310b647fb..becb069fd 100644 --- a/src/type_checkers/html_component.cr +++ b/src/type_checkers/html_component.cr @@ -1,23 +1,20 @@ module Mint class TypeChecker - type_error HtmlComponentReferenceOutsideOfComponent - type_error HtmlComponentAttributeRequired - type_error HtmlComponentNotFoundComponent - type_error HtmlComponentGlobalComponent - def check(node : Ast::HtmlComponent) : Checkable component = - ast.components.find(&.name.value.==(node.component.value)) + node.component_node + + error! :html_component_not_found_component do + snippet "I was looking for a component but could not find one with " \ + "the name:", node.component.value - raise HtmlComponentNotFoundComponent, { - "name" => node.component.value, - "node" => node, - } unless component + snippet "It's used here:", node + end unless component - raise HtmlComponentGlobalComponent, { - "name" => node.component.value, - "node" => node, - } if component.global? + error! :html_component_global_component do + snippet "Global components are added to the body and always rendered " \ + "and cannot be used as regular components:", node + end if component.global? resolve component @@ -32,21 +29,23 @@ module Mint component.properties.each do |property| next if property.default - raise HtmlComponentAttributeRequired, { - "property_node" => property, - "node" => node, - } unless attributes.includes?(property.name.value) + error! :html_component_attribute_required do + snippet "One of the required properties were not specified for " \ + "a component:", property + snippet "The component was referenced here:", node + end unless attributes.includes?(property.name.value) end node.ref.try do |ref| - raise HtmlComponentReferenceOutsideOfComponent, { - "node" => ref, - } unless component? + error! :html_component_reference_outside_of_component do + snippet "Referencing components outside of components is not " \ + "allowed:", ref + end unless node.in_component? end check_html node.children - lookups[node] = component + lookups[node] = {component, nil} HTML end diff --git a/src/type_checkers/html_content.cr b/src/type_checkers/html_content.cr index 1a9a9b05e..422f5c8a3 100644 --- a/src/type_checkers/html_content.cr +++ b/src/type_checkers/html_content.cr @@ -1,7 +1,5 @@ module Mint class TypeChecker - type_error HtmlContentTypeMismatch - def check_html(nodes : Array(Ast::Node)) : Checkable nodes.each do |child| type = resolve child @@ -11,10 +9,14 @@ module Mint Comparer.compare(HTML_CHILDREN, type) || Comparer.compare(TEXT_CHILDREN, type) else - raise HtmlContentTypeMismatch, { - "node" => child, - "got" => type, - } + error! :html_content_type_mismatch do + block "A child node of an element or component has an invalid type." + block "I was expecting one of the following types:" + + snippet "Array(String)\nArray(Html)\nString\nHtml" + snippet "Instead it is:", type + snippet child + end end end diff --git a/src/type_checkers/html_element.cr b/src/type_checkers/html_element.cr index 736abbb1f..2703be3c7 100644 --- a/src/type_checkers/html_element.cr +++ b/src/type_checkers/html_element.cr @@ -1,25 +1,20 @@ module Mint class TypeChecker - type_error HtmlElementReferenceOutsideOfComponent - type_error HtmlElementStyleOutsideOfComponent - - def static_type_signature(node : Ast::HtmlElement) : Checkable - Type.new("Dom.Element") - end - def check(node : Ast::HtmlElement) : Checkable unless node.styles.empty? - raise HtmlElementStyleOutsideOfComponent, { - "node" => node, - } unless component? + error! :html_element_style_outside_of_component do + snippet "Styling of elements outside of components is not " \ + "allowed:", node + end unless node.in_component? resolve node.styles end node.ref.try do |ref| - raise HtmlElementReferenceOutsideOfComponent, { - "node" => ref, - } unless component? + error! :html_element_reference_outside_of_component do + snippet "Referencing elements outside of components is not " \ + "allowed:", ref + end unless node.in_component? end node.attributes.each { |attribute| resolve attribute, node } diff --git a/src/type_checkers/html_fragment.cr b/src/type_checkers/html_fragment.cr index 3246289a6..67d89e85c 100644 --- a/src/type_checkers/html_fragment.cr +++ b/src/type_checkers/html_fragment.cr @@ -3,8 +3,6 @@ module Mint def check(node : Ast::HtmlFragment) : Checkable check_html node.children - node.key.try { |key| resolve key, node } - HTML end end diff --git a/src/type_checkers/html_style.cr b/src/type_checkers/html_style.cr index f7abe9769..bd92ef9be 100644 --- a/src/type_checkers/html_style.cr +++ b/src/type_checkers/html_style.cr @@ -1,29 +1,30 @@ module Mint class TypeChecker - type_error HtmlStyleArgumentSizeMismatch - type_error HtmlStyleArgumentTypeMismatch - type_error HtmlStyleNotFound - def check(node : Ast::HtmlStyle) : Checkable style = - component.styles.find(&.name.value.==(node.name.value)) + node.style_node - raise HtmlStyleNotFound, { - "style" => node.name.value, - "node" => node, - } unless style + error! :html_style_not_found do + snippet "I was looking for a style but it's not defined in the " \ + "component:", node + end unless style resolve style required_count = style.arguments.count { |arg| !arg.default } - raise HtmlStyleArgumentSizeMismatch, { - "call_size" => node.arguments.size.to_s, - "size" => required_count.to_s, - "node" => node, - } if node.arguments.size > style.arguments.size || - node.arguments.size < required_count + error! :html_style_argument_size_mismatch do + block do + text "The style call takes" + bold required_count.to_s + text "arguments, while you tried to call it with" + bold %(#{node.arguments.size}:) + end + + snippet node + end if node.arguments.size > style.arguments.size || + node.arguments.size < required_count node.arguments .zip(style.arguments[0, node.arguments.size]) @@ -34,15 +35,23 @@ module Mint call_arg_type = resolve(call_arg) - raise HtmlStyleArgumentTypeMismatch, { - "index" => ordinal(index + 1), - "expected" => style_arg_type, - "got" => call_arg_type, - "node" => node, - } unless Comparer.compare(style_arg_type, call_arg_type) + error! :html_style_argument_type_mismatch do + ordinal = + ordinal(index + 1) + + block do + text "The" + bold "#{ordinal} argument" + text "to a style call is causing a mismatch." + end + + snippet "The style is expecting the #{ordinal} argument to be:", style_arg_type + snippet "Instead it is:", call_arg_type + snippet "The style call in question is here:", node + end unless Comparer.compare(style_arg_type, call_arg_type) end - lookups[node] = style + lookups[node] = {style, nil} VOID end diff --git a/src/type_checkers/if.cr b/src/type_checkers/if.cr index e2e2e61c4..d2ccb331c 100644 --- a/src/type_checkers/if.cr +++ b/src/type_checkers/if.cr @@ -1,9 +1,5 @@ module Mint class TypeChecker - type_error IfConditionTypeMismatch - type_error IfElseTypeMismatch - type_error IfExpectedElse - def check(node : Ast::If) : Checkable condition = resolve node.condition @@ -11,53 +7,75 @@ module Mint variables = case item = node.condition when Ast::Statement - if item.target.is_a?(Ast::EnumDestructuring) - destructure(item.target.as(Ast::EnumDestructuring), condition) + if item.target.is_a?(Ast::TypeDestructuring) + destructure(item.target.as(Ast::TypeDestructuring), condition) end - end || [] of Ast::Node + end || [] of VariableScope + + error! :if_condition_type_mismatch do + block do + text "The type of the" + bold "condition of an if expression" + text "is not a boolean but instead it is:" + end - raise IfConditionTypeMismatch, { - "node" => node.condition, - "got" => condition, - "expected" => BOOL, - } if variables.empty? && !Comparer.compare(condition, BOOL) + snippet condition + snippet "The condition in question is here:", node.condition + end if variables.empty? && !Comparer.compare(condition, BOOL) truthy_item, falsy_item = node.branches - if truthy_item.is_a?(Ast::Node) - truthy = - scope(variables) do - resolve truthy_item.as(Ast::Node) + variables.each do |var| + scope.add(truthy_item, var[0], var[2]) + end + + truthy = + resolve truthy_item + + if falsy_item + falsy = + resolve falsy_item + + error! :if_else_type_mismatch do + block do + text "The" + bold "falsy (else) branch of an if expression" + text "does not match the type of the truthy branch." end - if falsy_item - falsy = - resolve falsy_item.as(Ast::Node) - - raise IfElseTypeMismatch, { - "node" => falsy_item.as(Ast::Node), - "expected" => truthy, - "got" => falsy, - } unless Comparer.compare(truthy, falsy) - else - raise IfExpectedElse, { - "expected" => VALID_IF_TYPES, - "got" => truthy, - "node" => node, - } unless Comparer.matches_any?(truthy, VALID_IF_TYPES) - end + expected truthy, falsy + + error_node = + case falsy_item + when Ast::Block + falsy_item.expressions.last + else + falsy_item + end - truthy + snippet "The value for the else branch is here:", + error_node.as(Ast::Node) + end unless Comparer.compare(truthy, falsy) else - scope(variables) do - resolve truthy_item - end + error! :if_expected_else do + block do + text "This" + bold "if expression" + text "must have an" + bold "else branch." + end - falsy_item.try { |data| resolve data } + block "The elese branch can be omitted if the truthy branch returns one of:" + snippet VALID_IF_TYPES.map(&.to_pretty).join("\n") + block "but it returns" + snippet truthy - VOID + snippet node + end unless Comparer.matches_any?(truthy, VALID_IF_TYPES) end + + truthy end end end diff --git a/src/type_checkers/inline_function.cr b/src/type_checkers/inline_function.cr index 04596a82f..52f034f72 100644 --- a/src/type_checkers/inline_function.cr +++ b/src/type_checkers/inline_function.cr @@ -1,58 +1,44 @@ module Mint class TypeChecker - type_error InlineFunctionTypeMismatch - - def static_type_signature(node : Ast::InlineFunction) : Checkable - arguments = - node.arguments.map { |argument| resolve argument.type } - - return_type = - node.type.try { |type| resolve type } || Variable.new("a") - - defined_type = - Type.new("Function", arguments + [return_type]) - - Comparer.normalize(defined_type) - end - def check(node : Ast::InlineFunction) : Checkable - scope node do - check_arguments(node.arguments) + check_arguments(node.arguments) - body_type = - resolve node.body + body_type = + resolve node.body + + arguments = + resolve node.arguments - arguments = - resolve node.arguments + final_type = + Type.new("Function", arguments + [body_type]) - final_type = - Type.new("Function", arguments + [body_type]) + resolved_type = + if type = node.type + return_type = + resolve type - resolved_type = - if type = node.type - return_type = - resolve type + defined_type = + Comparer.normalize(Type.new("Function", arguments + [return_type])) - defined_type = - Comparer.normalize(Type.new("Function", arguments + [return_type])) + resolved = + Comparer.compare(defined_type, final_type) - resolved = - Comparer.compare(defined_type, final_type) + error! :inline_function_type_mismatch do + block "The return type of an anonymous function does not match its type definition." - raise InlineFunctionTypeMismatch, { - "expected" => return_type, - "got" => body_type, - "node" => node, - } unless resolved + snippet "I was expecting:", return_type + snippet "Which is defined here:", type + snippet "Instead it is:", body_type + snippet "Which is returned here:", node.body.expressions.last + end unless resolved - Comparer.normalize(defined_type) - else - Comparer.normalize(final_type) - end + Comparer.normalize(defined_type) + else + Comparer.normalize(final_type) + end - resolved_type.optional_count = node.arguments.count(&.default) - resolved_type - end + resolved_type.optional_count = node.arguments.count(&.default) + resolved_type end end end diff --git a/src/type_checkers/locale.cr b/src/type_checkers/locale.cr index d8261c6f9..ed992beaa 100644 --- a/src/type_checkers/locale.cr +++ b/src/type_checkers/locale.cr @@ -6,12 +6,14 @@ module Mint end end - def check_locale_record(node : Ast::RecordField, prefix : String?, language : String) + def check_locale_record(node : Ast::Field, prefix : String?, language : String) + return unless key = node.key + field_prefix = if prefix - "#{prefix}.#{node.key.value}" + "#{prefix}.#{key.value}" else - node.key.value + key.value end case item = node.value diff --git a/src/type_checkers/locale_key.cr b/src/type_checkers/locale_key.cr index 60990780d..5cd30f3d4 100644 --- a/src/type_checkers/locale_key.cr +++ b/src/type_checkers/locale_key.cr @@ -1,48 +1,54 @@ module Mint class TypeChecker - type_error TranslationNotTranslated - type_error TranslationMismatch - type_error TranslationMissing - def check(node : Ast::LocaleKey) : Checkable - raise TranslationMissing, { - "value" => node.value, - "node" => node, - } unless translations = locales[node.value]? - - scope(node) do - result = nil - - @languages.each do |language| - raise TranslationNotTranslated, { - "value" => node.value, - "language" => language, - "node" => node, - } unless value = translations[language]? - - type = - resolve(value) - - result = - if result - resolved = Comparer.compare(result, type) - - raise TranslationMismatch, { - "value" => node.value, - "language" => language, - "expected" => result, - "got" => type, - "node" => node, - } unless resolved - - resolved - else - type - end - end - - result.not_nil! + error! :translation_missing do + snippet "Translations are not specified for this key:", node + end unless translations = locales[node.value]? + + result = nil + + @languages.each do |language| + error! :translation_not_translated do + block do + text "There is no translation for the key" + bold %("#{node.value}") + text "in the language" + bold %("#{language}".) + end + + snippet "The locale key in question is here:", node + end unless value = translations[language]? + + type = + resolve(value) + + result = + if result + resolved = Comparer.compare(result[0], type) + + error! :translation_mismatch do + block do + text "The type of the key" + bold %("#{node.value}") + text "in the language" + bold %("#{language}") + text "does not match the type in language" + bold %("#{result[1]}".) + end + + expected result[0], type + snippet %(The defined value in language "#{language}" is here:), value + snippet %(The defined value in language "#{result[1]}" is here:), result[2] + snippet "The locale key in question is here:", node + end unless resolved + + {resolved, language, value} + else + {type, language, value} + end end + + result.not_nil![0] end end end diff --git a/src/type_checkers/module.cr b/src/type_checkers/module.cr index 679125aa8..854c2fc8a 100644 --- a/src/type_checkers/module.cr +++ b/src/type_checkers/module.cr @@ -1,19 +1,14 @@ module Mint class TypeChecker - type_error ModuleEntityNameConflict - def check_all(node : Ast::Module) : Checkable resolve node - - scope node do - resolve node.functions - end + resolve node.functions VOID end def check(node : Ast::Module) : Checkable - check_names node.functions, ModuleEntityNameConflict + check_names node.functions, "module" check_global_names node.name.value, node VOID diff --git a/src/type_checkers/module_access.cr b/src/type_checkers/module_access.cr deleted file mode 100644 index a6e4fc235..000000000 --- a/src/type_checkers/module_access.cr +++ /dev/null @@ -1,79 +0,0 @@ -module Mint - class TypeChecker - type_error ModuleAccessNotFoundFunction - type_error ModuleAccessNotFoundModule - - def check(node : Ast::ModuleAccess) : Checkable - name = - node.name - - entity = - ast.unified_modules.find(&.name.value.==(name.value)) || - ast.stores.find(&.name.value.==(name.value)) || - ast.providers.find(&.name.value.==(name.value)) || - ast.components - .select(&.global?) - .find(&.name.value.==(name.value)) - - variable_value = - node.variable.value - - item = - case entity - when Ast::Provider - if node.variable.value == "subscriptions" - subscription = - scope entity do - lookup(node.variable) - end - - case subscription - when Type - check!(entity) - lookups[node] = entity - return subscription - else - # Should not happen - raise TypeError - end - else - entity.functions.find(&.name.value.==(variable_value)) - end - when Ast::Module - entity.functions.find(&.name.value.==(variable_value)) || - entity.constants.find(&.name.value.==(variable_value)) - when Ast::Component - entity.properties.find(&.name.value.==(variable_value)) || - entity.functions.find(&.name.value.==(variable_value)) || - entity.states.find(&.name.value.==(variable_value)) || - entity.constants.find(&.name.value.==(variable_value)) || - entity.gets.find(&.name.value.==(variable_value)) - when Ast::Store - entity.functions.find(&.name.value.==(variable_value)) || - entity.states.find(&.name.value.==(variable_value)) || - entity.gets.find(&.name.value.==(variable_value)) || - entity.constants.find(&.name.value.==(variable_value)) - else - raise ModuleAccessNotFoundModule, { - "name" => name.value, - "node" => node, - } - end - - raise ModuleAccessNotFoundFunction, { - "name" => variable_value, - "entity" => name.value, - "node" => node, - } unless item - - lookups[node] = entity - lookups[node.variable] = item - - check!(entity) - - scope entity do - resolve item - end - end - end -end diff --git a/src/type_checkers/negated_expression.cr b/src/type_checkers/negated_expression.cr index 83dafa51e..ae39bce86 100644 --- a/src/type_checkers/negated_expression.cr +++ b/src/type_checkers/negated_expression.cr @@ -1,16 +1,14 @@ module Mint class TypeChecker - type_error NegatedExpressionNotBool - def check(node : Ast::NegatedExpression) : Checkable expression = resolve node.expression - raise NegatedExpressionNotBool, { - "got" => expression, - "expected" => BOOL, - "node" => node, - } unless Comparer.compare(BOOL, expression) + error! :negated_expression_not_bool do + snippet "A negated expressions expression must evaluate to a " \ + "boolean, but it is:", expression + snippet "The negated expression in question is here:", node + end unless Comparer.compare(BOOL, expression) expression end diff --git a/src/type_checkers/next_call.cr b/src/type_checkers/next_call.cr index 8ca2c70d1..dd09f4838 100644 --- a/src/type_checkers/next_call.cr +++ b/src/type_checkers/next_call.cr @@ -1,42 +1,40 @@ module Mint class TypeChecker - type_error NextCallInvalidInvocation - type_error NextCallStateTypeMismatch - type_error NextCallStateNotFound - def check(node : Ast::NextCall) : Checkable - entity = stateful? + entity = node.entity + + error! :next_call_invalid_invocation do + block do + text "A" + bold "next call" + text "can only called inside a component, store or provider but " \ + "you tried to call it here:" + end - raise NextCallInvalidInvocation, { - "node" => node, - } unless entity + snippet node + end unless entity node.data.fields.each do |item| + next unless key = item.key + name = - item.key.value + key.value state = case entity - when Ast::Provider - lookups[node] = - entity - - entity - .states - .find(&.name.value.==(name)) - when Ast::Component, Ast::Store + when Ast::Component, Ast::Store, Ast::Provider lookups[node] = - entity + {entity, nil} entity .states .find(&.name.value.==(name)) end - raise NextCallStateNotFound, { - "name" => name, - "node" => node, - } unless state + error! :next_call_state_not_found do + snippet "I was looking for a state but could not find it:", name + snippet "The next call in question is here:", node + end unless state type = resolve item.value @@ -44,13 +42,14 @@ module Mint state_type = resolve state - raise NextCallStateTypeMismatch, { - "name" => name, - "expected" => state_type, - "state" => state, - "node" => item, - "got" => type, - } unless Comparer.compare(state_type, type) + error! :next_call_state_type_mismatch do + snippet "You were trying to assign an incompatible value " \ + "to the state:", name + snippet "The type of the state is:", state_type + snippet "But the type you are trying to assign to it is:", type + snippet "Here is where you did the assignment:", item + snippet "And here is where the state is defined:", state + end unless Comparer.compare(state_type, type) end Type.new("Promise", [VOID] of Checkable) diff --git a/src/type_checkers/operation.cr b/src/type_checkers/operation.cr index 8a2e7b057..16ef66973 100644 --- a/src/type_checkers/operation.cr +++ b/src/type_checkers/operation.cr @@ -1,13 +1,58 @@ module Mint class TypeChecker - type_error OperationNumericTypeMismatch - type_error OperationTypeMismatch + def operation_type_mismatch( + right : TypeChecker::Checkable, + left : TypeChecker::Checkable, + node : Ast::Node + ) + error! :operation_type_mismatch do + block do + text "The type of the right operand does not match the type of the" + text "left operand." + end + + expected left, right + snippet node + end + end + + def operation_plus_type_mismatch( + value : TypeChecker::Checkable, + node : Ast::Node, + side : String + ) + error! :operation_plus_type_mismatch do + block do + text "The type of the" + bold side + text "operand does not match the type of an operation." + end + + block "I was expecting one of these types:" + + snippet "Number, String" + snippet "Instead it is:", value + snippet "The operation in question is here:", node + end + end - type_error OperationPlusTypeMismatch - type_error OperationPipeAmbiguous + def operation_numeric_type_mismatch( + value : TypeChecker::Checkable, + operator : String, + node : Ast::Node, + side : String + ) + error! :operation_numeric_type_mismatch do + block do + text "The type of the" + bold side + text "operand does not match the type of an operation." + end - type_error OperationOrNotMaybeOrResult - type_error OperationOrTypeMismatch + expected TypeChecker::NUMBER, value + snippet "The operation in question is here:", node + end + end def check(node : Ast::Operation) : Checkable case node.operator @@ -15,67 +60,71 @@ module Mint right = resolve node.right left = resolve node.left - raise OperationTypeMismatch, { - "right" => right, - "left" => left, - "node" => node, - } unless Comparer.compare(left, right) + operation_type_mismatch( + right: right, + left: left, + node: node, + ) unless Comparer.compare(left, right) BOOL when "+" right = resolve node.right left = resolve node.left - raise OperationPlusTypeMismatch, { - "side" => "left", - "value" => left, - "node" => node, - } unless Comparer.compare(left, NUMBER) || + operation_plus_type_mismatch( + side: "left", + value: left, + node: node, + ) unless Comparer.compare(left, NUMBER) || Comparer.compare(left, STRING) - raise OperationPlusTypeMismatch, { - "side" => "right", - "value" => right, - "node" => node, - } unless Comparer.compare(right, NUMBER) || + operation_plus_type_mismatch( + side: "right", + value: right, + node: node, + ) unless Comparer.compare(right, NUMBER) || Comparer.compare(right, STRING) - raise OperationTypeMismatch, { - "right" => right, - "left" => left, - "node" => node, - } unless Comparer.compare(left, right) + operation_type_mismatch( + right: right, + left: left, + node: node, + ) unless Comparer.compare(left, right) left when "-", "*", "/", "%", "**" right = resolve node.right left = resolve node.left - raise OperationNumericTypeMismatch, { - "operator" => node.operator, - "side" => "left", - "value" => left, - "node" => node, - } unless Comparer.compare(left, NUMBER) - - raise OperationNumericTypeMismatch, { - "operator" => node.operator, - "side" => "right", - "value" => right, - "node" => node, - } unless Comparer.compare(right, NUMBER) - - raise OperationTypeMismatch, { - "right" => right, - "left" => left, - "node" => node, - } unless Comparer.compare(left, right) + operation_numeric_type_mismatch( + operator: node.operator, + side: "left", + value: left, + node: node, + ) unless Comparer.compare(left, NUMBER) + + operation_numeric_type_mismatch( + operator: node.operator, + side: "right", + value: right, + node: node, + ) unless Comparer.compare(right, NUMBER) + + operation_type_mismatch( + right: right, + left: left, + node: node, + ) unless Comparer.compare(left, right) NUMBER when "|>" - raise OperationPipeAmbiguous, { - "node" => node, - } + error! :operation_pipe_ambiguous do + block "I cannot determine the order of the operands because the " \ + "pipe makes it ambiguous. Wrap operands in parentheses " \ + "to avoid ambiguity." + + snippet "The piped call in question is here:", node + end when "or" right = resolve node.right left = resolve node.left @@ -84,14 +133,21 @@ module Mint when Ast::ReturnCall left else - raise OperationOrNotMaybeOrResult, { - "expected" => MAYBE, - "node" => node, - "got" => left, - } unless Comparer.compare(left, MAYBE) || - Comparer.compare(left, RESULT) - - expected = + error! :operation_or_not_maybe_or_result do + block do + text "For the" + bold "or" + text "operation the" + bold "left operand" + text "is invalid." + end + + expected MAYBE, left + snippet "The operation in question is here:", node + end unless Comparer.compare(left, MAYBE) || + Comparer.compare(left, RESULT) + + type = case left.name when "Result" left.parameters[1] @@ -99,16 +155,20 @@ module Mint left.parameters[0] end - raise OperationOrTypeMismatch, { - "expected" => expected, - "got" => right, - "node" => node, - } unless Comparer.compare(expected, right) + error! :operation_or_type_mismatch do + block do + text "The type of the default value does not match the type of the" + text "parameter of the maybe." + end + + expected type, right + snippet "The operation in question is here:", node + end unless Comparer.compare(type, right) - expected + type end else - raise Mint::TypeError # Can never happen + raise Mint::Error.new(:never) # Can never happen end end end diff --git a/src/type_checkers/property.cr b/src/type_checkers/property.cr index 2baa20eb2..ff5e6aabf 100644 --- a/src/type_checkers/property.cr +++ b/src/type_checkers/property.cr @@ -1,13 +1,5 @@ module Mint class TypeChecker - type_error PropertyTypeOrDefaultNeeded - type_error PropertyWithTypeVariables - type_error PropertyTypeMismatch - - def static_type_signature(node : Ast::Property) : Checkable - node.type.try { |type| resolve type } || Variable.new("a") - end - def check(node : Ast::Property) : Checkable default = with_restricted_top_level_entity(node) do @@ -27,12 +19,13 @@ module Mint resolved = Comparer.compare type, default - raise PropertyTypeMismatch, { - "name" => node.name.value, - "got" => default, - "expected" => type, - "node" => node, - } unless resolved + error! :property_type_mismatch do + block "The type of the default value of a property does not " \ + "match its type annotation." + + expected type, default + snippet "The property in question is here:", node + end unless resolved resolved when {Checkable, Nil} @@ -40,15 +33,28 @@ module Mint when {Nil, Checkable} type else - raise PropertyTypeOrDefaultNeeded, { - "node" => node, - } + error! :property_type_or_default_needed do + block do + text "The" + bold "type" + text "or" + bold "default value" + text "of a property needs to be defined, but neither was." + end + + snippet node + end end - raise PropertyWithTypeVariables, { - "type" => final, - "node" => node, - } if final.have_holes? + error! :property_with_type_variables do + block "The type of a property contains type variables. Type " \ + "variables in properties are not allow at this time since " \ + "that would make the compoennt generic and it is not " \ + "supported this time." + + snippet "The type is:", final + snippet "The property in question is here:", node + end if final.have_holes? final end diff --git a/src/type_checkers/provider.cr b/src/type_checkers/provider.cr index 33dc9d792..fa5458873 100644 --- a/src/type_checkers/provider.cr +++ b/src/type_checkers/provider.cr @@ -1,8 +1,5 @@ module Mint class TypeChecker - type_error ProviderNotFoundSubscription - type_error ProviderEntityNameConflict - def check(node : Ast::Provider) : Checkable # Checking for global naming conflict check_global_names node.name.value, node @@ -11,26 +8,29 @@ module Mint checked = {} of String => Ast::Node - check_names node.functions, ProviderEntityNameConflict, checked - check_names node.states, ProviderEntityNameConflict, checked - check_names node.gets, ProviderEntityNameConflict, checked + check_names node.functions, "provider", checked + check_names node.states, "provider", checked + check_names node.gets, "provider", checked # Checking for subscription subscription = records.find(&.name.==(node.subscription.value)) - raise ProviderNotFoundSubscription, { - "name" => node.subscription, - "node" => node, - } unless subscription + error! :provider_not_found_subscription do + block do + text "I was looking for the record type of the subscription" + bold %("#{node.subscription.value}") + text "but could not find it:" + end + + snippet node + end unless subscription # Type checking the entities - scope node do - resolve node.constants - resolve node.functions - resolve node.states - resolve node.gets - end + resolve node.constants + resolve node.functions + resolve node.states + resolve node.gets VOID end diff --git a/src/type_checkers/record.cr b/src/type_checkers/record.cr index 3f68a1df5..f96415a75 100644 --- a/src/type_checkers/record.cr +++ b/src/type_checkers/record.cr @@ -1,40 +1,32 @@ module Mint class TypeChecker - type_error RecordNotFoundMatchingRecordDefinition - def check(node : Ast::Record, should_create_record : Bool = false) : Checkable fields = node .fields - .to_h { |field| {field.key.value, resolve(field, should_create_record)} } - - case node - when Ast::EnumRecord - params = - fields.each_with_object({} of String => Checkable) do |(key, type), memo| - memo[key] = type + .compact_map do |field| + next unless key = field.key + {key.value, resolve(field, should_create_record)} end + .to_h - Record.new("", params) - else - record = - records.find(&.==(fields)) + record = + records.find(&.==(fields)) - record = create_record(fields) if should_create_record && !record + record = create_record(fields) if should_create_record && !record - raise RecordNotFoundMatchingRecordDefinition, { - "structure" => Record.new("", fields), - "node" => node, - } unless record + error! :record_not_found_matching_record_definition do + block "I could not find a record that matches this structure:" - types[node] = record + snippet Record.new("", fields) + snippet "It was used here:", node + end unless record - node.fields.each do |field| - record_field_lookup[field] = record.name - end - - record + node.fields.each do |field| + record_field_lookup[field] = record.name end + + record end end end diff --git a/src/type_checkers/record_constructor.cr b/src/type_checkers/record_constructor.cr deleted file mode 100644 index b8040f89c..000000000 --- a/src/type_checkers/record_constructor.cr +++ /dev/null @@ -1,37 +0,0 @@ -module Mint - class TypeChecker - type_error RecordConstructorArgumentSizeMismatch - type_error RecordConstructorArgumentTypeMismatch - type_error RecordConstructorNotFoundRecord - - def check(node : Ast::EnumId, record : Record) : Checkable - fields = - record.fields.values - - raise RecordConstructorArgumentSizeMismatch, { - "argument_size" => node.expressions.size.to_s, - "size" => fields.size.to_s, - "record" => record, - "node" => node, - } if node.expressions.size > fields.size - - node.expressions.each_with_index do |argument, index| - type = resolve argument - - raise RecordConstructorArgumentTypeMismatch, { - "expected" => fields[index], - "node" => argument, - "got" => type, - } unless Comparer.compare(type, fields[index]) - end - - types[node] = record - - if record.fields.size == node.expressions.size - record - else - Type.new("Function", fields.skip(node.expressions.size) + [record]) - end - end - end -end diff --git a/src/type_checkers/record_definition.cr b/src/type_checkers/record_definition.cr deleted file mode 100644 index 67bdc58ee..000000000 --- a/src/type_checkers/record_definition.cr +++ /dev/null @@ -1,22 +0,0 @@ -module Mint - class TypeChecker - def check(node : Ast::RecordDefinition) : Checkable - check_global_types node.name.value, node - - fields = - node - .fields - .to_h { |field| {field.key.value, resolve(field).as(Checkable)} } - - mappings = - node - .fields - .to_h { |field| {field.key.value, field.mapping.try(&.string_value)} } - - type = Record.new(node.name.value, fields, mappings) - types[node] = type - - type - end - end -end diff --git a/src/type_checkers/record_update.cr b/src/type_checkers/record_update.cr index 517827292..490154bbd 100644 --- a/src/type_checkers/record_update.cr +++ b/src/type_checkers/record_update.cr @@ -1,9 +1,5 @@ module Mint class TypeChecker - type_error RecordUpdateNotUpdatingRecord - type_error RecordUpdateTypeMismatch - type_error RecordUpdateNotFoundKey - def check(node : Ast::RecordUpdate) : Checkable target = resolve node.expression @@ -16,33 +12,49 @@ module Mint item end - raise RecordUpdateNotUpdatingRecord, { - "target_node" => target_node, - "target" => target, - "node" => node, - } unless target.is_a?(Record) + error! :record_update_not_updating_record do + block do + text "The" + bold "target of a record update" + text "is not a record, instead it is:" + end + + snippet target + + snippet "Here is where you want to update it:", node + snippet "Here is where the target is defined:", target_node + end unless target.is_a?(Record) node.fields.each do |field| + next unless key = field.key + type = resolve field record_field_lookup[field] = target.name value_type = - target.fields[field.key.value]? - - raise RecordUpdateNotFoundKey, { - "key" => field.key.value, - "target" => target, - "node" => field, - } unless value_type - - raise RecordUpdateTypeMismatch, { - "target_node" => target_node, - "expected" => value_type, - "node" => field, - "got" => type, - } unless Comparer.compare(type, value_type) + target.fields[key.value]? + + error! :record_update_not_found_key do + block do + text "The field" + bold %("#{key.value}") + text "does not exists on the target record:" + end + + snippet target + snippet "Here is where you tried to assign a value to it:", field + end unless value_type + + error! :record_update_type_mismatch do + snippet "One of the updated fields of a record do not " \ + "match its type:", field + + expected value_type, type + + snippet "The record is here:", target_node + end unless Comparer.compare(type, value_type) end target diff --git a/src/type_checkers/return_call.cr b/src/type_checkers/return_call.cr index f8d22b5e8..6ac427117 100644 --- a/src/type_checkers/return_call.cr +++ b/src/type_checkers/return_call.cr @@ -1,17 +1,19 @@ module Mint class TypeChecker - type_error ReturnCallInvalid - def check(node : Ast::ReturnCall) : Checkable - raise ReturnCallInvalid, { - "node" => node, - } unless node.statement + error! :return_call_invalid do + block do + text "A" + bold "return call" + text "can only appear in a block as part of an or operation while destructuring or as a standalone expression." + end + + snippet node + end unless node.statement type = resolve node.expression - push_return(node) - type end end diff --git a/src/type_checkers/route.cr b/src/type_checkers/route.cr index fa5853645..ebe3a70dd 100644 --- a/src/type_checkers/route.cr +++ b/src/type_checkers/route.cr @@ -1,24 +1,20 @@ module Mint class TypeChecker - type_error RouteParamInvalid - def check(node : Ast::Route) : Checkable - args = node.arguments.map do |argument| - argument_type = + node.arguments.map do |argument| + type = resolve argument - raise RouteParamInvalid, { - "name" => argument.name.value, - "got" => argument_type, - "node" => argument, - } unless Comparer.matches_any?(argument_type, [STRING, NUMBER]) + error! :route_param_invalid do + snippet "The type of a route parameter cannot be used in routes:", argument.type + snippet "Only these types can be used as route parameters:", "String\nNumber" + end if type.is_a?(Variable) || + !Comparer.matches_any?(type, [STRING, NUMBER]) - {argument.name.value, argument_type, argument} + {argument.name.value, type, argument} end - scope args do - resolve node.expression - end + resolve node.expression end end end diff --git a/src/type_checkers/state.cr b/src/type_checkers/state.cr index 6c69bbb8b..48b171f39 100644 --- a/src/type_checkers/state.cr +++ b/src/type_checkers/state.cr @@ -1,11 +1,5 @@ module Mint class TypeChecker - type_error StateTypeMismatch - - def static_type_signature(node : Ast::State) : Checkable - node.type.try { |type| resolve type } || Variable.new("a") - end - def check(node : Ast::State) : Checkable default = with_restricted_top_level_entity(node) do @@ -19,12 +13,12 @@ module Mint resolved = Comparer.compare(type, default) - raise StateTypeMismatch, { - "expected" => type, - "name" => node.name.value, - "node" => node.default, - "got" => default, - } unless resolved + error! :state_type_mismatch do + snippet "The type of the default value of the a state does " \ + "not match its type annotation:", node.default + + expected type, default + end unless resolved resolved else diff --git a/src/type_checkers/statement.cr b/src/type_checkers/statement.cr index 20c7da602..a9fd2d91e 100644 --- a/src/type_checkers/statement.cr +++ b/src/type_checkers/statement.cr @@ -1,25 +1,30 @@ module Mint class TypeChecker - type_error StatementReturnRequired - def check(node : Ast::Statement) : Checkable - case target = node.target - when Ast::TupleDestructuring, - Ast::ArrayDestructuring, - Ast::EnumDestructuring - case item = node.expression - when Ast::Operation - raise StatementReturnRequired, { - "node" => node, - } unless item.right.is_a?(Ast::ReturnCall) - else - unless target.exhaustive? - raise StatementReturnRequired, { - "node" => node, - } unless node.if_node + required = + case target = node.target + when Ast::TupleDestructuring, + Ast::ArrayDestructuring, + Ast::TypeDestructuring + case item = node.expression + when Ast::Operation + !item.right.is_a?(Ast::ReturnCall) + else + !exhaustive?(target) && !node.if_node end end - end + + error! :statement_return_required do + block do + text "This" + bold "statement" + text "needs a" + bold "return call" + text "because the destructuring is not exhaustive:" + end + + snippet node + end if required type = resolve node.expression @@ -27,7 +32,7 @@ module Mint type = type.parameters.first if node.await && type.name == "Promise" - types[node] = type + type end end end diff --git a/src/type_checkers/store.cr b/src/type_checkers/store.cr index e4d591406..1234ef121 100644 --- a/src/type_checkers/store.cr +++ b/src/type_checkers/store.cr @@ -1,7 +1,5 @@ module Mint class TypeChecker - type_error StoreEntityNameConflict - def check(node : Ast::Store) : Checkable # Checking for global naming conflict check_global_names node.name.value, node @@ -10,17 +8,15 @@ module Mint checked = {} of String => Ast::Node - check_names(node.functions, StoreEntityNameConflict, checked) - check_names(node.states, StoreEntityNameConflict, checked) - check_names(node.gets, StoreEntityNameConflict, checked) + check_names(node.functions, "store", checked) + check_names(node.states, "store", checked) + check_names(node.gets, "store", checked) # Type checking the entities - scope node do - resolve node.constants - resolve node.functions - resolve node.states - resolve node.gets - end + resolve node.constants + resolve node.functions + resolve node.states + resolve node.gets VOID end diff --git a/src/type_checkers/string_literal.cr b/src/type_checkers/string_literal.cr index 2bd368c74..2e1019ca7 100644 --- a/src/type_checkers/string_literal.cr +++ b/src/type_checkers/string_literal.cr @@ -1,43 +1,5 @@ module Mint class TypeChecker - type_error StringLiteralInterpolationTypeMismatch - - def check(node : Ast::HereDoc) : Checkable - if node.modifier == '#' - node.value.each do |item| - case item - when Ast::Node - item_type = - resolve item - - raise TypeError, { - "expected" => HTML, - "got" => item_type, - "node" => item, - } unless Comparer.matches_any?(item_type, [STRING, NUMBER, HTML]) - end - end - - HTML - else - node.value.each do |item| - case item - when Ast::Node - item_type = - resolve item - - raise StringLiteralInterpolationTypeMismatch, { - "expected" => STRING, - "got" => item_type, - "node" => item, - } unless Comparer.matches_any?(item_type, [STRING, NUMBER]) - end - end - - STRING - end - end - def check(node : Ast::StringLiteral) : Checkable node.value.each do |item| case item @@ -45,11 +7,12 @@ module Mint item_type = resolve item - raise StringLiteralInterpolationTypeMismatch, { - "expected" => STRING, - "got" => item_type, - "node" => item, - } unless Comparer.matches_any?(item_type, [STRING, NUMBER]) + error! :string_literal_interpolation_type_mismatch do + snippet "An interpolation in string is causing a mismatch. " \ + "The expected type is:", STRING + snippet "Instead it is:", item_type + snippet "The interpolation in question is here:", item + end unless Comparer.matches_any?(item_type, [STRING, NUMBER]) end end diff --git a/src/type_checkers/style.cr b/src/type_checkers/style.cr index 415370f77..3104fed33 100644 --- a/src/type_checkers/style.cr +++ b/src/type_checkers/style.cr @@ -1,10 +1,8 @@ module Mint class TypeChecker def check(node : Ast::Style) : Checkable - scope node do - resolve node.arguments - resolve node.body - end + resolve node.arguments + resolve node.body VOID end diff --git a/src/type_checkers/suite.cr b/src/type_checkers/suite.cr index 85ef1aeb1..db4ae017b 100644 --- a/src/type_checkers/suite.cr +++ b/src/type_checkers/suite.cr @@ -1,10 +1,8 @@ module Mint class TypeChecker def check(node : Ast::Suite) - scope node do - resolve node.name - resolve node.tests - end + resolve node.name + resolve node.tests VOID end diff --git a/src/type_checkers/test.cr b/src/type_checkers/test.cr index f09d70819..641895f04 100644 --- a/src/type_checkers/test.cr +++ b/src/type_checkers/test.cr @@ -1,7 +1,5 @@ module Mint class TypeChecker - type_error TestTypeMismatch - def check(node : Ast::Test) resolve node.name @@ -11,10 +9,14 @@ module Mint if Comparer.compare(type, BOOL) || Comparer.compare(type, TEST_CONTEXT) else - raise TestTypeMismatch, { - "node" => node.expression, - "got" => type, - } + error! :test_type_mismatch do + block "The type of a test does not match any of the allowed types." + block "I was expecting one of:" + + snippet "Test.Context(a)\nBool" + snippet "Instead it is:", type + snippet "The test in question is here:", node.expression.expressions.last + end end VOID diff --git a/src/type_checkers/top_level.cr b/src/type_checkers/top_level.cr index e8cfc3bbe..222f13639 100644 --- a/src/type_checkers/top_level.cr +++ b/src/type_checkers/top_level.cr @@ -12,12 +12,12 @@ module Mint .try { |component| resolve component } node - .enums + .type_definitions .find(&.name.value.==("Maybe")) .try { |item| resolve item } node - .enums + .type_definitions .find(&.name.value.==("Result")) .try { |item| resolve item } @@ -31,9 +31,7 @@ module Mint .functions .find(&.name.value.==("fromEvent")) .try do |function| - scope item do - resolve function - end + resolve function end end @@ -57,7 +55,7 @@ module Mint resolve node.providers resolve node.stores - resolve node.enums + resolve node.type_definitions VOID end diff --git a/src/type_checkers/tuple_literal.cr b/src/type_checkers/tuple_literal.cr index c5b36c9ae..139c7517d 100644 --- a/src/type_checkers/tuple_literal.cr +++ b/src/type_checkers/tuple_literal.cr @@ -1,7 +1,5 @@ module Mint class TypeChecker - type_error ArrayNotMatches - def check(node : Ast::TupleLiteral) : Checkable items = resolve node.items diff --git a/src/type_checkers/type_definition.cr b/src/type_checkers/type_definition.cr new file mode 100644 index 000000000..6245602a9 --- /dev/null +++ b/src/type_checkers/type_definition.cr @@ -0,0 +1,58 @@ +module Mint + class TypeChecker + def check(node : Ast::TypeDefinition) : Checkable + case items = node.fields + in Array(Ast::TypeDefinitionField) + fields = + items.to_h { |item| {item.key.value, resolve(item).as(Checkable)} } + + mappings = + items.to_h { |item| {item.key.value, static_value(item.mapping)} } + + type = Record.new(node.name.value, fields, mappings) + + Comparer.normalize(type) + in Array(Ast::TypeVariant) + parameters = + resolve node.parameters + + used_parameters = Set(Ast::TypeVariable).new + + items.each do |option| + check option.parameters, node.parameters, used_parameters + end + + node.parameters.each do |parameter| + error! :type_definition_unused_parameter do + snippet "Type parameters must be used by at least one option. " \ + "This parameter was not used by any of the options:", parameter + end unless used_parameters.includes?(parameter) + end + + Comparer.normalize(Type.new(node.name.value, parameters)) + end + end + + def check(parameters : Array(Ast::Node), + names : Array(Ast::TypeVariable), + used_parameters : Set(Ast::TypeVariable)) + parameters.each do |parameter| + case parameter + when Ast::Type + check parameter.parameters, names, used_parameters + when Ast::TypeVariable + param = + names.find(&.value.==(parameter.value)) + + error! :type_definition_not_defined_parameter do + snippet "Parameters used by options must be defined in the " \ + "the type definition. This parameter was not defined " \ + "in the type definition:", parameter + end unless param + + used_parameters.add param + end + end + end + end +end diff --git a/src/type_checkers/record_definition_field.cr b/src/type_checkers/type_definition_field.cr similarity index 54% rename from src/type_checkers/record_definition_field.cr rename to src/type_checkers/type_definition_field.cr index 5f774cfb6..079df41b6 100644 --- a/src/type_checkers/record_definition_field.cr +++ b/src/type_checkers/type_definition_field.cr @@ -1,6 +1,6 @@ module Mint class TypeChecker - def check(node : Ast::RecordDefinitionField) : Checkable + def check(node : Ast::TypeDefinitionField) : Checkable resolve node.type end end diff --git a/src/type_checkers/enum_option.cr b/src/type_checkers/type_variant.cr similarity index 74% rename from src/type_checkers/enum_option.cr rename to src/type_checkers/type_variant.cr index 9ce8ad0e4..e8ced703b 100644 --- a/src/type_checkers/enum_option.cr +++ b/src/type_checkers/type_variant.cr @@ -1,6 +1,6 @@ module Mint class TypeChecker - def check(node : Ast::EnumOption) : Checkable + def check(node : Ast::TypeVariant) : Checkable parameters = resolve node.parameters diff --git a/src/type_checkers/unary_minus.cr b/src/type_checkers/unary_minus.cr index 119f8d425..c2f924b0c 100644 --- a/src/type_checkers/unary_minus.cr +++ b/src/type_checkers/unary_minus.cr @@ -1,16 +1,14 @@ module Mint class TypeChecker - type_error UnaryMinusNotNumber - def check(node : Ast::UnaryMinus) : Checkable expression = resolve node.expression - raise UnaryMinusNotNumber, { - "got" => expression, - "expected" => NUMBER, - "node" => node, - } unless Comparer.compare(NUMBER, expression) + error! :unary_minus_not_number do + snippet "An unary minuses expression must evaluate to number. " \ + "Instead it is:", expression + snippet "The unary minus in question is here:", node + end unless Comparer.compare(NUMBER, expression) expression end diff --git a/src/type_checkers/use.cr b/src/type_checkers/use.cr index 9db1fbae8..f11a071f7 100644 --- a/src/type_checkers/use.cr +++ b/src/type_checkers/use.cr @@ -1,9 +1,5 @@ module Mint class TypeChecker - type_error UseSubscriptionMismatch - type_error UseConditionMismatch - type_error UseNotFoundProvider - def check(node : Ast::Use) : Checkable condition = node.condition @@ -11,14 +7,13 @@ module Mint provider = ast.providers.find(&.name.value.==(node.provider.value)) - raise UseNotFoundProvider, { - "name" => node.provider.value, - "node" => node, - } unless provider + error! :use_not_found_provider do + snippet "I could not find a provider:", node.provider + end unless provider resolve provider - lookups[node] = provider + lookups[node] = {provider, nil} # This is checked by the provider so we assume it's there subscription = @@ -27,19 +22,25 @@ module Mint record = resolve node.data - raise UseSubscriptionMismatch, { - "expected" => subscription, - "got" => record, - "node" => node, - } unless Comparer.compare(record, subscription) + error! :use_subscription_mismatch do + block "The subsctipion of a provider does not match its definition." + expected subscription, record + snippet "The provider in question is here:", node + end unless Comparer.compare(record, subscription) if condition condition_type = resolve condition - raise UseConditionMismatch, { - "got" => condition_type, - "node" => condition, - } unless Comparer.compare(condition_type, BOOL) + error! :use_condition_mismatch do + block do + text "The expression of the" + bold "where condition" + text "must evaluate to a boolean value. Instead it is:" + end + + snippet condition_type + snippet "The condition in question is here:", condition + end unless Comparer.compare(condition_type, BOOL) end resolve node.data diff --git a/src/type_checkers/variable.cr b/src/type_checkers/variable.cr index e08db2fee..357f7292c 100644 --- a/src/type_checkers/variable.cr +++ b/src/type_checkers/variable.cr @@ -1,65 +1,75 @@ module Mint class TypeChecker - type_error VariableReserved - type_error VariableMissing - RESERVED = %w(break case class const continue debugger default delete do else export extends for if import in instanceof new return super - switch this throw typeof var void while yield state) + switch this throw typeof var while yield state) def check(node : Ast::Variable) : Checkable - raise VariableReserved, { - "name" => node.value, - "node" => node, - } if RESERVED.includes?(node.value) + if node.value == "void" + VOID + else + error! :variable_reserved do + snippet "This name for a variable is a reserved word please use something else:", node + end if RESERVED.includes?(node.value) - item = lookup_with_level(node) + item = lookup_with_level(node) - raise VariableMissing, { - "name" => node.value, - "node" => node, - } unless item + error! :variable_missing do + snippet "I can't find the entity with the name:", node.value + snippet "Here is where it is referenced:", node + end unless item - variables[node] = item + variables[node] = item - case - when item[0].is_a?(Ast::HtmlElement) && item[1].is_a?(Ast::Component) - Type.new("Maybe", [Type.new("Dom.Element")] of Checkable) - when item[0].is_a?(Ast::Component) && item[1].is_a?(Ast::Component) - Type.new("Maybe", [component_records[item[0]]] of Checkable) - else - case value = item[0] - when Ast::Statement - resolve value - when Tuple(Ast::Node, Int32 | Array(Int32)) - item = value[0] + case + when node.value == "subscriptions" && item[1].is_a?(Ast::Provider) + subscription = + records.find(&.name.==(item[1].as(Ast::Provider).subscription.value)) - type = - resolve item - - case item + case subscription + when Record + Type.new("Array", [subscription] of Checkable) + else + raise "Cannot happen!" + end + when item[0].is_a?(Ast::HtmlElement) && item[1].is_a?(Ast::Component) + Type.new("Maybe", [Type.new("Dom.Element")] of Checkable) + when item[0].is_a?(Ast::Component) && item[1].is_a?(Ast::Component) + Type.new("Maybe", [component_records[item[0]]] of Checkable) + else + case value = item[0] when Ast::Statement - case item.target - when Ast::TupleDestructuring - case val = value[1] - in Int32 - type.parameters[val] - in Array(Int32) - val.reduce(type) { |curr_type, curr_val| curr_type.parameters[curr_val] } + resolve value + when Tuple(Ast::Node, Int32 | Array(Int32)) + item = value[0] + + type = + resolve item + + case item + when Ast::Statement + case item.target + when Ast::TupleDestructuring + case val = value[1] + in Int32 + type.parameters[val] + in Array(Int32) + val.reduce(type) { |curr_type, curr_val| curr_type.parameters[curr_val] } + end + else + type end else type end + when Ast::Node + resolve value + when Checkable + value else - type + VOID end - when Ast::Node - resolve value - when Checkable - value - else - VOID end end end diff --git a/src/utils/html_snippet.cr b/src/utils/html_snippet.cr index efd261b8a..8659cbfc6 100644 --- a/src/utils/html_snippet.cr +++ b/src/utils/html_snippet.cr @@ -6,7 +6,7 @@ module Mint def render(node : Ast::Node) input = - node.input.input + node.file.contents start_line = input[0, node.from].lines.size @@ -55,7 +55,7 @@ module Mint <<-HTML
- #{node.input.file} + #{node.file.path}
diff --git a/src/utils/terminal_snippet.cr b/src/utils/terminal_snippet.cr index 9e5dd2e68..cd4063201 100644 --- a/src/utils/terminal_snippet.cr +++ b/src/utils/terminal_snippet.cr @@ -1,10 +1,14 @@ module Mint module TerminalSnippet - record Line, contents : String, index : Int32, offset : Int32 do + record Line, contents : String, index : Int64, offset : Int64 do def contains?(position) position >= offset && position <= (offset + size) end + def fully_contains?(from, to) + contains?(from, to) && (to - from) < contents.size + end + def contains?(from, to) diff_from = from - offset @@ -30,12 +34,18 @@ module Mint self[0, diff_from] center = - self[diff_from, diff_to].colorize(:light_yellow).mode(:bright).to_s + self[diff_from, diff_to].colorize.on(:white).fore(:red).to_s right = self[diff_to, contents.size] - left + center + right + highlighted = + left + center + right + + arrows = + (" " * left.size) + ("⌃" * center.uncolorize.size) + + {highlighted, arrows} end def [](from, to) @@ -47,8 +57,9 @@ module Mint extend self - def render(input : String, filename : String, from : Int32, to : Int32, padding = 4, width = 80) - lines, _ = + def render(input : String, filename : String, from : Int64, to : Int64, padding = 4, width = 80) + # Transform each line into a record for further use. + lines = input.lines.reduce({[] of Line, 0}) do |memo, raw| items, index = memo @@ -59,14 +70,23 @@ module Mint Line.new(contents: raw, index: index, offset: offset) {items + [line], index + 1} - end + end[0] + selected = + lines.select(&.contains?(from, to)) + + fully_highlighted = + selected.size == lines.size + + # Get the first line which is the one we want to highlight minus the padding. start_line = {0, (lines.find(&.contains?(from)).try(&.index) || 0) - padding}.max + # Get the last line which is the one we want to highlight plus the padding. end_line = {(lines.find(&.contains?(to)).try(&.index) || 0) + padding + 1, lines.size}.min + # We need to calucluate the width of the gutter so we can pad later lon. gutter_width = { (start_line + 1).to_s.size, (end_line + 1).to_s.size, @@ -75,37 +95,72 @@ module Mint relevant_lines = lines[start_line, end_line - start_line] - min_width = { - relevant_lines.max_of(&.size) + gutter_width + 5, - width, - }.max - result = relevant_lines.map do |line| line_number = (line.index + 1).to_s.rjust(gutter_width) - line_padding = - " " * (min_width - gutter_width - 3 - line.size - 2) - highlighted = - line.contains?(from, to) + line.fully_contains?(from, to) gutter = if highlighted - "│#{line_number}│".colorize(:light_yellow).mode(:bright) + "#{line_number}│".colorize(:light_yellow).mode(:bright) else - "│#{line_number}│".colorize.mode(:dim) + "#{line_number}│".colorize.mode(:dim) end - divider = - if highlighted - "│".colorize(:light_yellow).mode(:bright) - else - "│".colorize.mode(:dim) - end - - "#{gutter} #{line.highlight(from, to)} #{line_padding}#{divider}" + if fully_highlighted + elsif selected.size > 1 && selected.last == line + max_size = + selected.max_of(&.contents.size) + + whitespace = + selected.min_of do |item| + count = 0 + item.contents.each_char do |char| + break unless char.ascii_whitespace? + count += 1 + end || 0 + count + end + + content_size = + max_size - whitespace + + arrows = + "#{" " * whitespace}#{"⌃"*content_size}" + + "#{gutter} #{line.contents}\n#{" " * gutter_width}│ #{arrows}" + elsif selected.size > 1 && selected.first == line + max_size = + selected.max_of(&.contents.size) + + whitespace = + selected.min_of do |item| + count = 0 + item.contents.each_char do |char| + break unless char.ascii_whitespace? + count += 1 + end || 0 + count + end + + content_size = + max_size - whitespace + + arrows = + "#{" " * whitespace}#{"⌄"*content_size}" + + "#{" " * gutter_width}│ #{arrows}\n#{gutter} #{line.contents}" + elsif highlighted + a, b = + line.highlight(from, to) + + "#{gutter} #{a}\n#{" " * gutter_width}│ #{b}" + elsif from == input.size && line.offset + line.contents.size == from + "#{gutter} #{line.contents}\n#{" " * gutter_width}│ #{" " * line.contents.size}⌃⌃⌃⌃" + end || "#{gutter} #{line.contents}" end line = @@ -117,34 +172,25 @@ module Mint title = "#{filename}:#{line}:#{column}" - divider = - ("─" * (min_width - title.size - gutter_width - 5).clamp(0, nil)).colorize.mode(:dim) - gutter_divider = - "─" * gutter_width - - footer_divider = - "─" * (min_width - gutter_width - 3).clamp(0, nil) - - footer = - ("└#{gutter_divider}┴#{footer_divider}┘").colorize.mode(:dim) + " " * gutter_width header_start = - "┌#{gutter_divider}┬".colorize.mode(:dim) - - header_end = - "┐".colorize.mode(:dim).to_s + "#{gutter_divider}┌ ".colorize.mode(:dim) title_colorized = title.colorize.mode(:bold) header = - "#{header_start} #{title_colorized} #{divider}#{header_end}" + "#{header_start}#{title_colorized}" + + header_divider = + "#{gutter_divider}├" + ("─" * (header.uncolorize.size - (gutter_width + 1))) result = result.join('\n') - "#{header}\n#{result}\n#{footer}" + "#{header}\n#{header_divider}\n#{result}" end end end