machine-dialect 0.1.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- machine_dialect/__main__.py +667 -0
- machine_dialect/agent/__init__.py +5 -0
- machine_dialect/agent/agent.py +360 -0
- machine_dialect/ast/__init__.py +95 -0
- machine_dialect/ast/ast_node.py +35 -0
- machine_dialect/ast/call_expression.py +82 -0
- machine_dialect/ast/dict_extraction.py +60 -0
- machine_dialect/ast/expressions.py +439 -0
- machine_dialect/ast/literals.py +309 -0
- machine_dialect/ast/program.py +35 -0
- machine_dialect/ast/statements.py +1433 -0
- machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
- machine_dialect/ast/tests/test_boolean_literal.py +29 -0
- machine_dialect/ast/tests/test_collection_hir.py +138 -0
- machine_dialect/ast/tests/test_define_statement.py +142 -0
- machine_dialect/ast/tests/test_desugar.py +541 -0
- machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
- machine_dialect/cfg/__init__.py +6 -0
- machine_dialect/cfg/config.py +156 -0
- machine_dialect/cfg/examples.py +221 -0
- machine_dialect/cfg/generate_with_ai.py +187 -0
- machine_dialect/cfg/openai_generation.py +200 -0
- machine_dialect/cfg/parser.py +94 -0
- machine_dialect/cfg/tests/__init__.py +1 -0
- machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
- machine_dialect/cfg/tests/test_config.py +188 -0
- machine_dialect/cfg/tests/test_examples.py +391 -0
- machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
- machine_dialect/cfg/tests/test_openai_generation.py +256 -0
- machine_dialect/codegen/__init__.py +5 -0
- machine_dialect/codegen/bytecode_module.py +89 -0
- machine_dialect/codegen/bytecode_serializer.py +300 -0
- machine_dialect/codegen/opcodes.py +101 -0
- machine_dialect/codegen/register_codegen.py +1996 -0
- machine_dialect/codegen/symtab.py +208 -0
- machine_dialect/codegen/tests/__init__.py +1 -0
- machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
- machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
- machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
- machine_dialect/codegen/tests/test_symtab.py +418 -0
- machine_dialect/codegen/vm_serializer.py +621 -0
- machine_dialect/compiler/__init__.py +18 -0
- machine_dialect/compiler/compiler.py +197 -0
- machine_dialect/compiler/config.py +149 -0
- machine_dialect/compiler/context.py +149 -0
- machine_dialect/compiler/phases/__init__.py +19 -0
- machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
- machine_dialect/compiler/phases/codegen.py +40 -0
- machine_dialect/compiler/phases/hir_generation.py +39 -0
- machine_dialect/compiler/phases/mir_generation.py +86 -0
- machine_dialect/compiler/phases/optimization.py +110 -0
- machine_dialect/compiler/phases/parsing.py +39 -0
- machine_dialect/compiler/pipeline.py +143 -0
- machine_dialect/compiler/tests/__init__.py +1 -0
- machine_dialect/compiler/tests/test_compiler.py +568 -0
- machine_dialect/compiler/vm_runner.py +173 -0
- machine_dialect/errors/__init__.py +32 -0
- machine_dialect/errors/exceptions.py +369 -0
- machine_dialect/errors/messages.py +82 -0
- machine_dialect/errors/tests/__init__.py +0 -0
- machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
- machine_dialect/errors/tests/test_name_errors.py +118 -0
- machine_dialect/helpers/__init__.py +0 -0
- machine_dialect/helpers/stopwords.py +225 -0
- machine_dialect/helpers/validators.py +30 -0
- machine_dialect/lexer/__init__.py +9 -0
- machine_dialect/lexer/constants.py +23 -0
- machine_dialect/lexer/lexer.py +907 -0
- machine_dialect/lexer/tests/__init__.py +0 -0
- machine_dialect/lexer/tests/helpers.py +86 -0
- machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
- machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
- machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
- machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
- machine_dialect/lexer/tests/test_comments.py +200 -0
- machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
- machine_dialect/lexer/tests/test_lexer_position.py +113 -0
- machine_dialect/lexer/tests/test_list_tokens.py +282 -0
- machine_dialect/lexer/tests/test_stopwords.py +80 -0
- machine_dialect/lexer/tests/test_strict_equality.py +129 -0
- machine_dialect/lexer/tests/test_token.py +41 -0
- machine_dialect/lexer/tests/test_tokenization.py +294 -0
- machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
- machine_dialect/lexer/tests/test_url_literals.py +169 -0
- machine_dialect/lexer/tokens.py +487 -0
- machine_dialect/linter/__init__.py +10 -0
- machine_dialect/linter/__main__.py +144 -0
- machine_dialect/linter/linter.py +154 -0
- machine_dialect/linter/rules/__init__.py +8 -0
- machine_dialect/linter/rules/base.py +112 -0
- machine_dialect/linter/rules/statement_termination.py +99 -0
- machine_dialect/linter/tests/__init__.py +1 -0
- machine_dialect/linter/tests/mdrules/__init__.py +0 -0
- machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
- machine_dialect/linter/tests/test_linter.py +81 -0
- machine_dialect/linter/tests/test_rules.py +110 -0
- machine_dialect/linter/tests/test_violations.py +71 -0
- machine_dialect/linter/violations.py +51 -0
- machine_dialect/mir/__init__.py +69 -0
- machine_dialect/mir/analyses/__init__.py +20 -0
- machine_dialect/mir/analyses/alias_analysis.py +315 -0
- machine_dialect/mir/analyses/dominance_analysis.py +49 -0
- machine_dialect/mir/analyses/escape_analysis.py +286 -0
- machine_dialect/mir/analyses/loop_analysis.py +272 -0
- machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
- machine_dialect/mir/analyses/type_analysis.py +448 -0
- machine_dialect/mir/analyses/use_def_chains.py +232 -0
- machine_dialect/mir/basic_block.py +385 -0
- machine_dialect/mir/dataflow.py +445 -0
- machine_dialect/mir/debug_info.py +208 -0
- machine_dialect/mir/hir_to_mir.py +1738 -0
- machine_dialect/mir/mir_dumper.py +366 -0
- machine_dialect/mir/mir_function.py +167 -0
- machine_dialect/mir/mir_instructions.py +1877 -0
- machine_dialect/mir/mir_interpreter.py +556 -0
- machine_dialect/mir/mir_module.py +225 -0
- machine_dialect/mir/mir_printer.py +480 -0
- machine_dialect/mir/mir_transformer.py +410 -0
- machine_dialect/mir/mir_types.py +367 -0
- machine_dialect/mir/mir_validation.py +455 -0
- machine_dialect/mir/mir_values.py +268 -0
- machine_dialect/mir/optimization_config.py +233 -0
- machine_dialect/mir/optimization_pass.py +251 -0
- machine_dialect/mir/optimization_pipeline.py +355 -0
- machine_dialect/mir/optimizations/__init__.py +84 -0
- machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
- machine_dialect/mir/optimizations/branch_prediction.py +372 -0
- machine_dialect/mir/optimizations/constant_propagation.py +634 -0
- machine_dialect/mir/optimizations/cse.py +398 -0
- machine_dialect/mir/optimizations/dce.py +288 -0
- machine_dialect/mir/optimizations/inlining.py +551 -0
- machine_dialect/mir/optimizations/jump_threading.py +487 -0
- machine_dialect/mir/optimizations/licm.py +405 -0
- machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
- machine_dialect/mir/optimizations/strength_reduction.py +422 -0
- machine_dialect/mir/optimizations/tail_call.py +207 -0
- machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
- machine_dialect/mir/optimizations/type_narrowing.py +397 -0
- machine_dialect/mir/optimizations/type_specialization.py +447 -0
- machine_dialect/mir/optimizations/type_specific.py +906 -0
- machine_dialect/mir/optimize_mir.py +89 -0
- machine_dialect/mir/pass_manager.py +391 -0
- machine_dialect/mir/profiling/__init__.py +26 -0
- machine_dialect/mir/profiling/profile_collector.py +318 -0
- machine_dialect/mir/profiling/profile_data.py +372 -0
- machine_dialect/mir/profiling/profile_reader.py +272 -0
- machine_dialect/mir/profiling/profile_writer.py +226 -0
- machine_dialect/mir/register_allocation.py +302 -0
- machine_dialect/mir/reporting/__init__.py +17 -0
- machine_dialect/mir/reporting/optimization_reporter.py +314 -0
- machine_dialect/mir/reporting/report_formatter.py +289 -0
- machine_dialect/mir/ssa_construction.py +342 -0
- machine_dialect/mir/tests/__init__.py +1 -0
- machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
- machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
- machine_dialect/mir/tests/test_algebraic_division.py +126 -0
- machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
- machine_dialect/mir/tests/test_basic_block.py +425 -0
- machine_dialect/mir/tests/test_branch_prediction.py +459 -0
- machine_dialect/mir/tests/test_call_lowering.py +168 -0
- machine_dialect/mir/tests/test_collection_lowering.py +604 -0
- machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
- machine_dialect/mir/tests/test_custom_passes.py +166 -0
- machine_dialect/mir/tests/test_debug_info.py +285 -0
- machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
- machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
- machine_dialect/mir/tests/test_double_negation.py +231 -0
- machine_dialect/mir/tests/test_escape_analysis.py +233 -0
- machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
- machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
- machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
- machine_dialect/mir/tests/test_inlining.py +435 -0
- machine_dialect/mir/tests/test_licm.py +472 -0
- machine_dialect/mir/tests/test_mir_dumper.py +313 -0
- machine_dialect/mir/tests/test_mir_instructions.py +445 -0
- machine_dialect/mir/tests/test_mir_module.py +860 -0
- machine_dialect/mir/tests/test_mir_printer.py +387 -0
- machine_dialect/mir/tests/test_mir_types.py +123 -0
- machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
- machine_dialect/mir/tests/test_mir_validation.py +378 -0
- machine_dialect/mir/tests/test_mir_values.py +168 -0
- machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
- machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
- machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
- machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
- machine_dialect/mir/tests/test_pass_manager.py +294 -0
- machine_dialect/mir/tests/test_pass_registration.py +64 -0
- machine_dialect/mir/tests/test_profiling.py +356 -0
- machine_dialect/mir/tests/test_register_allocation.py +307 -0
- machine_dialect/mir/tests/test_report_formatters.py +372 -0
- machine_dialect/mir/tests/test_ssa_construction.py +433 -0
- machine_dialect/mir/tests/test_tail_call.py +236 -0
- machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
- machine_dialect/mir/tests/test_type_narrowing.py +277 -0
- machine_dialect/mir/tests/test_type_specialization.py +421 -0
- machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
- machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
- machine_dialect/mir/type_inference.py +368 -0
- machine_dialect/parser/__init__.py +12 -0
- machine_dialect/parser/enums.py +45 -0
- machine_dialect/parser/parser.py +3655 -0
- machine_dialect/parser/protocols.py +11 -0
- machine_dialect/parser/symbol_table.py +169 -0
- machine_dialect/parser/tests/__init__.py +0 -0
- machine_dialect/parser/tests/helper_functions.py +193 -0
- machine_dialect/parser/tests/test_action_statements.py +334 -0
- machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
- machine_dialect/parser/tests/test_call_statements.py +154 -0
- machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
- machine_dialect/parser/tests/test_collection_mutations.py +264 -0
- machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
- machine_dialect/parser/tests/test_define_integration.py +468 -0
- machine_dialect/parser/tests/test_define_statements.py +311 -0
- machine_dialect/parser/tests/test_dict_extraction.py +115 -0
- machine_dialect/parser/tests/test_empty_literal.py +155 -0
- machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
- machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
- machine_dialect/parser/tests/test_if_empty_block.py +61 -0
- machine_dialect/parser/tests/test_if_statements.py +299 -0
- machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
- machine_dialect/parser/tests/test_infix_expressions.py +680 -0
- machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
- machine_dialect/parser/tests/test_interaction_statements.py +269 -0
- machine_dialect/parser/tests/test_list_literals.py +277 -0
- machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
- machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
- machine_dialect/parser/tests/test_parse_errors.py +114 -0
- machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
- machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
- machine_dialect/parser/tests/test_program.py +13 -0
- machine_dialect/parser/tests/test_return_statements.py +89 -0
- machine_dialect/parser/tests/test_set_statements.py +152 -0
- machine_dialect/parser/tests/test_strict_equality.py +258 -0
- machine_dialect/parser/tests/test_symbol_table.py +217 -0
- machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
- machine_dialect/parser/tests/test_utility_statements.py +423 -0
- machine_dialect/parser/token_buffer.py +159 -0
- machine_dialect/repl/__init__.py +3 -0
- machine_dialect/repl/repl.py +426 -0
- machine_dialect/repl/tests/__init__.py +0 -0
- machine_dialect/repl/tests/test_repl.py +606 -0
- machine_dialect/semantic/__init__.py +12 -0
- machine_dialect/semantic/analyzer.py +906 -0
- machine_dialect/semantic/error_messages.py +189 -0
- machine_dialect/semantic/tests/__init__.py +1 -0
- machine_dialect/semantic/tests/test_analyzer.py +364 -0
- machine_dialect/semantic/tests/test_error_messages.py +104 -0
- machine_dialect/tests/edge_cases/__init__.py +10 -0
- machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
- machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
- machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
- machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
- machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
- machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
- machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
- machine_dialect/tests/integration/test_list_compilation.py +395 -0
- machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
- machine_dialect/type_checking/__init__.py +21 -0
- machine_dialect/type_checking/tests/__init__.py +1 -0
- machine_dialect/type_checking/tests/test_type_system.py +230 -0
- machine_dialect/type_checking/type_system.py +270 -0
- machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
- machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
- machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
- machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
- machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
- machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
- machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
"""Edge case tests for mixed-type collections."""
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from machine_dialect.parser.parser import Parser
|
6
|
+
|
7
|
+
|
8
|
+
class TestTypeMixing:
|
9
|
+
"""Test collections with mixed types."""
|
10
|
+
|
11
|
+
def test_mixed_type_unordered_list(self) -> None:
|
12
|
+
"""Test unordered list with various types."""
|
13
|
+
source = """
|
14
|
+
Define `mixed` as unordered list.
|
15
|
+
Set `mixed` to:
|
16
|
+
- _42_.
|
17
|
+
- _3.14_.
|
18
|
+
- _"string"_.
|
19
|
+
- _yes_.
|
20
|
+
- _no_.
|
21
|
+
- empty.
|
22
|
+
|
23
|
+
Define `first` as Text.
|
24
|
+
Define `last` as Text.
|
25
|
+
|
26
|
+
Set `first` to the first item of `mixed`.
|
27
|
+
Set `last` to the last item of `mixed`.
|
28
|
+
"""
|
29
|
+
parser = Parser()
|
30
|
+
parser.parse(source, check_semantics=False)
|
31
|
+
|
32
|
+
# Should parse successfully
|
33
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
34
|
+
|
35
|
+
def test_mixed_type_ordered_list(self) -> None:
|
36
|
+
"""Test ordered list with various types."""
|
37
|
+
source = """
|
38
|
+
Define `mixed` as ordered list.
|
39
|
+
Set `mixed` to:
|
40
|
+
1. _42_.
|
41
|
+
2. _"text"_.
|
42
|
+
3. _yes_.
|
43
|
+
4. empty.
|
44
|
+
5. _-5_.
|
45
|
+
6. _0.0_.
|
46
|
+
|
47
|
+
Add _no_ to `mixed`.
|
48
|
+
Remove empty from `mixed`.
|
49
|
+
"""
|
50
|
+
parser = Parser()
|
51
|
+
parser.parse(source, check_semantics=False)
|
52
|
+
|
53
|
+
# Should parse successfully
|
54
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
55
|
+
|
56
|
+
@pytest.mark.skip(reason="TODO: Statement count mismatch - needs investigation")
|
57
|
+
def test_empty_value_in_collections(self) -> None:
|
58
|
+
"""Test handling of 'empty' literal in collections.""" # TODO: Fix statement count mismatch
|
59
|
+
source = """
|
60
|
+
Define `list_with_empty` as unordered list.
|
61
|
+
Set `list_with_empty` to:
|
62
|
+
- _"before"_.
|
63
|
+
- empty.
|
64
|
+
- _"after"_.
|
65
|
+
|
66
|
+
Define `x` as Text.
|
67
|
+
Set `x` to item _2_ of `list_with_empty`. # Should be empty
|
68
|
+
|
69
|
+
Remove empty from `list_with_empty`.
|
70
|
+
Add empty to `list_with_empty`.
|
71
|
+
"""
|
72
|
+
parser = Parser()
|
73
|
+
parser.parse(source, check_semantics=False)
|
74
|
+
|
75
|
+
# Should parse successfully
|
76
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
77
|
+
|
78
|
+
@pytest.mark.skip(reason="TODO: Fix assertion counts after parser updates")
|
79
|
+
def test_identifier_vs_literal_mixing(self) -> None:
|
80
|
+
"""Test mixing identifiers and literals in collections.""" # TODO: Fix assertion counts after parser updates
|
81
|
+
source = """
|
82
|
+
Define `var1` as Whole Number.
|
83
|
+
Define `var2` as Text.
|
84
|
+
Set `var1` to _10_.
|
85
|
+
Set `var2` to _"hello"_.
|
86
|
+
|
87
|
+
Define `mixed` as unordered list.
|
88
|
+
Set `mixed` to:
|
89
|
+
- `var1`.
|
90
|
+
- _20_.
|
91
|
+
- `var2`.
|
92
|
+
- _"world"_.
|
93
|
+
|
94
|
+
Define `x` as Text.
|
95
|
+
Define `y` as Text.
|
96
|
+
|
97
|
+
Set `x` to the first item of `mixed`. # Identifier value
|
98
|
+
Set `y` to the second item of `mixed`. # Literal value
|
99
|
+
"""
|
100
|
+
parser = Parser()
|
101
|
+
parser.parse(source, check_semantics=False)
|
102
|
+
|
103
|
+
# Should parse successfully
|
104
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
105
|
+
|
106
|
+
@pytest.mark.skip(reason="TODO: Fix assertion counts after parser updates")
|
107
|
+
def test_boolean_mixing(self) -> None:
|
108
|
+
"""Test collections with boolean values.""" # TODO: Fix assertion counts after parser updates
|
109
|
+
source = """
|
110
|
+
Define `booleans` as unordered list.
|
111
|
+
Set `booleans` to:
|
112
|
+
- _yes_.
|
113
|
+
- _no_.
|
114
|
+
- _yes_.
|
115
|
+
- _no_.
|
116
|
+
|
117
|
+
# Operations with boolean values
|
118
|
+
Remove _yes_ from `booleans`.
|
119
|
+
Add _no_ to `booleans`.
|
120
|
+
Set item _1_ of `booleans` to _yes_.
|
121
|
+
"""
|
122
|
+
parser = Parser()
|
123
|
+
parser.parse(source, check_semantics=False)
|
124
|
+
|
125
|
+
# Should parse successfully
|
126
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
127
|
+
|
128
|
+
@pytest.mark.skip(reason="TODO: Fix assertion counts after parser updates")
|
129
|
+
def test_numeric_type_mixing(self) -> None:
|
130
|
+
"""Test mixing integer and float types.""" # TODO: Fix assertion counts after parser updates
|
131
|
+
source = """
|
132
|
+
Define `numbers` as ordered list.
|
133
|
+
Set `numbers` to:
|
134
|
+
1. _1_.
|
135
|
+
2. _1.0_.
|
136
|
+
3. _2_.
|
137
|
+
4. _2.0_.
|
138
|
+
5. _-3_.
|
139
|
+
6. _-3.14_.
|
140
|
+
|
141
|
+
# Operations with mixed numeric types
|
142
|
+
Remove _1_ from `numbers`. # Integer
|
143
|
+
Remove _2.0_ from `numbers`. # Float
|
144
|
+
Add _0_ to `numbers`. # Integer zero
|
145
|
+
Add _0.0_ to `numbers`. # Float zero
|
146
|
+
"""
|
147
|
+
parser = Parser()
|
148
|
+
parser.parse(source, check_semantics=False)
|
149
|
+
|
150
|
+
# Should parse successfully
|
151
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
152
|
+
|
153
|
+
@pytest.mark.skip(reason="TODO: Fix test - remove comments and verify assertions")
|
154
|
+
def test_nested_mixed_types(self) -> None:
|
155
|
+
"""Test nested collections with mixed types.""" # TODO: Fix test - remove comments and verify assertions
|
156
|
+
source = """
|
157
|
+
Define `inner1` as unordered list.
|
158
|
+
Set `inner1` to:
|
159
|
+
- _1_.
|
160
|
+
- _"text"_.
|
161
|
+
|
162
|
+
Define `inner2` as ordered list.
|
163
|
+
Set `inner2` to:
|
164
|
+
1. _yes_.
|
165
|
+
2. empty.
|
166
|
+
|
167
|
+
Define `nested` as unordered list.
|
168
|
+
Set `nested` to:
|
169
|
+
- `inner1`.
|
170
|
+
- _42_.
|
171
|
+
- `inner2`.
|
172
|
+
- _"standalone"_.
|
173
|
+
|
174
|
+
Define `x` as Text.
|
175
|
+
Define `y` as Text.
|
176
|
+
|
177
|
+
Set `x` to the first item of `nested`. # A list
|
178
|
+
Set `y` to the second item of `nested`. # A number
|
179
|
+
"""
|
180
|
+
parser = Parser()
|
181
|
+
parser.parse(source, check_semantics=False)
|
182
|
+
|
183
|
+
# Should parse successfully
|
184
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
185
|
+
|
186
|
+
@pytest.mark.skip(reason="TODO: Fix assertion counts after parser updates")
|
187
|
+
def test_type_changing_operations(self) -> None:
|
188
|
+
"""Test operations that change element types.""" # TODO: Fix assertion counts after parser updates
|
189
|
+
source = """
|
190
|
+
Define `list` as unordered list.
|
191
|
+
Set `list` to:
|
192
|
+
- _1_.
|
193
|
+
- _2_.
|
194
|
+
- _3_.
|
195
|
+
|
196
|
+
# Change numeric to string
|
197
|
+
Set item _1_ of `list` to _"one"_.
|
198
|
+
|
199
|
+
# Change to boolean
|
200
|
+
Set item _2_ of `list` to _yes_.
|
201
|
+
|
202
|
+
# Change to empty
|
203
|
+
Set item _3_ of `list` to empty.
|
204
|
+
|
205
|
+
# Now list has mixed types
|
206
|
+
Add _4_ to `list`. # Add number to mixed list
|
207
|
+
Add _"five"_ to `list`. # Add string to mixed list
|
208
|
+
"""
|
209
|
+
parser = Parser()
|
210
|
+
parser.parse(source, check_semantics=False)
|
211
|
+
|
212
|
+
# Should parse successfully
|
213
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
214
|
+
|
215
|
+
@pytest.mark.skip(reason="TODO: Fix assertion counts after parser updates")
|
216
|
+
def test_comparison_with_mixed_types(self) -> None:
|
217
|
+
"""Test accessing and comparing mixed type elements.""" # TODO: Fix assertion counts after parser updates
|
218
|
+
source = """
|
219
|
+
Define `mixed` as unordered list.
|
220
|
+
Set `mixed` to:
|
221
|
+
- _1_.
|
222
|
+
- _"1"_.
|
223
|
+
- _yes_.
|
224
|
+
- empty.
|
225
|
+
|
226
|
+
Define `num` as Whole Number.
|
227
|
+
Define `str` as Text.
|
228
|
+
Define `bool` as Yes/No.
|
229
|
+
Define `null` as Text.
|
230
|
+
|
231
|
+
Set `num` to item _1_ of `mixed`. # Number 1
|
232
|
+
Set `str` to item _2_ of `mixed`. # String "1"
|
233
|
+
Set `bool` to item _3_ of `mixed`. # Boolean yes
|
234
|
+
Set `null` to item _4_ of `mixed`. # empty/null
|
235
|
+
"""
|
236
|
+
parser = Parser()
|
237
|
+
parser.parse(source, check_semantics=False)
|
238
|
+
|
239
|
+
# Should parse successfully
|
240
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
241
|
+
|
242
|
+
@pytest.mark.skip(reason="TODO: Fix assertion counts after parser updates")
|
243
|
+
def test_large_mixed_collection(self) -> None:
|
244
|
+
"""Test large collection with many different types.""" # TODO: Fix assertion counts after parser updates
|
245
|
+
source = """
|
246
|
+
Define `large_mixed` as unordered list.
|
247
|
+
Set `large_mixed` to:
|
248
|
+
- _0_.
|
249
|
+
- _"zero"_.
|
250
|
+
- _yes_.
|
251
|
+
- _1_.
|
252
|
+
- _"one"_.
|
253
|
+
- _no_.
|
254
|
+
- _2_.
|
255
|
+
- _"two"_.
|
256
|
+
- empty.
|
257
|
+
- _3.14_.
|
258
|
+
- _"pi"_.
|
259
|
+
- _-1_.
|
260
|
+
- _"negative"_.
|
261
|
+
- _0.0_.
|
262
|
+
- _""_.
|
263
|
+
|
264
|
+
Define `a` as Text.
|
265
|
+
Define `b` as Text.
|
266
|
+
Define `c` as Text.
|
267
|
+
|
268
|
+
# Access various elements
|
269
|
+
Set `a` to item _1_ of `large_mixed`.
|
270
|
+
Set `b` to item _9_ of `large_mixed`.
|
271
|
+
Set `c` to the last item of `large_mixed`.
|
272
|
+
"""
|
273
|
+
parser = Parser()
|
274
|
+
parser.parse(source, check_semantics=False)
|
275
|
+
|
276
|
+
# Should parse successfully
|
277
|
+
# assert len(parser.program.statements) if hasattr(parser, "program") else pass
|
@@ -0,0 +1,248 @@
|
|
1
|
+
"""Integration tests for emulated array operations."""
|
2
|
+
|
3
|
+
import tempfile
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from machine_dialect.compiler.config import CompilerConfig
|
8
|
+
from machine_dialect.compiler.pipeline import CompilationPipeline
|
9
|
+
|
10
|
+
|
11
|
+
def compile_source(source: str) -> Any:
|
12
|
+
"""Helper function to compile source string."""
|
13
|
+
config = CompilerConfig(verbose=False)
|
14
|
+
pipeline = CompilationPipeline(config)
|
15
|
+
|
16
|
+
# Write source to temporary file
|
17
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
|
18
|
+
f.write(source)
|
19
|
+
temp_path = Path(f.name)
|
20
|
+
|
21
|
+
try:
|
22
|
+
context = pipeline.compile_file(temp_path)
|
23
|
+
return context
|
24
|
+
finally:
|
25
|
+
temp_path.unlink(missing_ok=True)
|
26
|
+
|
27
|
+
|
28
|
+
class TestArrayOperationsEmulation:
|
29
|
+
"""Test that array operations compile and generate correct bytecode."""
|
30
|
+
|
31
|
+
def test_insert_operation_compiles(self) -> None:
|
32
|
+
"""Test that insert operations compile to bytecode."""
|
33
|
+
source = """
|
34
|
+
Define `items` as Ordered List.
|
35
|
+
Set `items` to:
|
36
|
+
1. _"first"_.
|
37
|
+
2. _"second"_.
|
38
|
+
3. _"third"_.
|
39
|
+
|
40
|
+
Insert _"new"_ at position _2_ in `items`.
|
41
|
+
"""
|
42
|
+
|
43
|
+
context = compile_source(source)
|
44
|
+
|
45
|
+
# Should compile without errors
|
46
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
47
|
+
|
48
|
+
# Should generate bytecode
|
49
|
+
assert context.bytecode_module is not None
|
50
|
+
assert len(context.bytecode_module.chunks) > 0
|
51
|
+
bytecode = context.bytecode_module.chunks[0].bytecode
|
52
|
+
assert len(bytecode) > 0
|
53
|
+
|
54
|
+
# Should have substantial bytecode (insert is complex)
|
55
|
+
assert len(bytecode) > 100, "Insert should generate substantial bytecode"
|
56
|
+
|
57
|
+
def test_remove_by_value_compiles(self) -> None:
|
58
|
+
"""Test that remove by value operations compile."""
|
59
|
+
source = """
|
60
|
+
Define `fruits` as Unordered List.
|
61
|
+
Set `fruits` to:
|
62
|
+
- _"apple"_.
|
63
|
+
- _"banana"_.
|
64
|
+
- _"cherry"_.
|
65
|
+
|
66
|
+
Remove _"banana"_ from `fruits`.
|
67
|
+
"""
|
68
|
+
|
69
|
+
context = compile_source(source)
|
70
|
+
|
71
|
+
# Should compile without errors
|
72
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
73
|
+
|
74
|
+
# Should generate bytecode
|
75
|
+
assert context.bytecode_module is not None
|
76
|
+
assert len(context.bytecode_module.chunks) > 0
|
77
|
+
bytecode = context.bytecode_module.chunks[0].bytecode
|
78
|
+
assert len(bytecode) > 0
|
79
|
+
|
80
|
+
# Remove by value uses ArrayFindIndex + ArrayRemove, so lots of code
|
81
|
+
assert len(bytecode) > 150, "Remove by value should generate substantial bytecode"
|
82
|
+
|
83
|
+
def test_multiple_operations(self) -> None:
|
84
|
+
"""Test that multiple array operations work together."""
|
85
|
+
source = """
|
86
|
+
Define `tasks` as Ordered List.
|
87
|
+
Set `tasks` to:
|
88
|
+
1. _"Task A"_.
|
89
|
+
2. _"Task B"_.
|
90
|
+
3. _"Task C"_.
|
91
|
+
|
92
|
+
Insert _"Task A.5"_ at position _2_ in `tasks`.
|
93
|
+
Remove _"Task B"_ from `tasks`.
|
94
|
+
Add _"Task D"_ to `tasks`.
|
95
|
+
"""
|
96
|
+
|
97
|
+
context = compile_source(source)
|
98
|
+
|
99
|
+
# Should compile without errors
|
100
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
101
|
+
|
102
|
+
# Should generate bytecode
|
103
|
+
assert context.bytecode_module is not None
|
104
|
+
assert len(context.bytecode_module.chunks) > 0
|
105
|
+
bytecode = context.bytecode_module.chunks[0].bytecode
|
106
|
+
assert len(bytecode) > 0
|
107
|
+
|
108
|
+
def test_insert_at_beginning(self) -> None:
|
109
|
+
"""Test inserting at the beginning of a list."""
|
110
|
+
source = """
|
111
|
+
Define `numbers` as Unordered List.
|
112
|
+
Set `numbers` to:
|
113
|
+
- _10_.
|
114
|
+
- _20_.
|
115
|
+
- _30_.
|
116
|
+
|
117
|
+
Insert _5_ at position _1_ in `numbers`.
|
118
|
+
"""
|
119
|
+
|
120
|
+
context = compile_source(source)
|
121
|
+
|
122
|
+
# Should compile without errors
|
123
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
124
|
+
|
125
|
+
# Should generate bytecode
|
126
|
+
assert context.bytecode_module is not None
|
127
|
+
|
128
|
+
def test_insert_at_end(self) -> None:
|
129
|
+
"""Test inserting at the end of a list (like append but with position)."""
|
130
|
+
source = """
|
131
|
+
Define `items` as Ordered List.
|
132
|
+
Set `items` to:
|
133
|
+
1. _"one"_.
|
134
|
+
2. _"two"_.
|
135
|
+
|
136
|
+
Define `length` as Whole Number.
|
137
|
+
Set `length` to _3_.
|
138
|
+
Insert _"three"_ at position `length` in `items`.
|
139
|
+
"""
|
140
|
+
|
141
|
+
context = compile_source(source)
|
142
|
+
|
143
|
+
# Should compile without errors
|
144
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
145
|
+
|
146
|
+
def test_remove_nonexistent_value(self) -> None:
|
147
|
+
"""Test removing a value that doesn't exist in the list."""
|
148
|
+
source = """
|
149
|
+
Define `colors` as Unordered List.
|
150
|
+
Set `colors` to:
|
151
|
+
- _"red"_.
|
152
|
+
- _"green"_.
|
153
|
+
- _"blue"_.
|
154
|
+
|
155
|
+
Remove _"yellow"_ from `colors`.
|
156
|
+
"""
|
157
|
+
|
158
|
+
context = compile_source(source)
|
159
|
+
|
160
|
+
# Should compile without errors (runtime will handle -1 index)
|
161
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
162
|
+
|
163
|
+
def test_nested_list_operations(self) -> None:
|
164
|
+
"""Test operations on lists containing lists."""
|
165
|
+
source = """
|
166
|
+
Define `matrix` as Unordered List.
|
167
|
+
Define `row1` as Unordered List.
|
168
|
+
Set `row1` to:
|
169
|
+
- _1_.
|
170
|
+
- _2_.
|
171
|
+
|
172
|
+
Define `row2` as Unordered List.
|
173
|
+
Set `row2` to:
|
174
|
+
- _3_.
|
175
|
+
- _4_.
|
176
|
+
|
177
|
+
Set `matrix` to:
|
178
|
+
- `row1`.
|
179
|
+
- `row2`.
|
180
|
+
|
181
|
+
Define `row3` as Unordered List.
|
182
|
+
Set `row3` to:
|
183
|
+
- _5_.
|
184
|
+
- _6_.
|
185
|
+
|
186
|
+
Add `row3` to `matrix`.
|
187
|
+
"""
|
188
|
+
|
189
|
+
context = compile_source(source)
|
190
|
+
|
191
|
+
# Should compile without errors
|
192
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
193
|
+
|
194
|
+
def test_bytecode_contains_loops(self) -> None:
|
195
|
+
"""Test that generated bytecode contains loop structures."""
|
196
|
+
source = """
|
197
|
+
Define `items` as Unordered List.
|
198
|
+
Set `items` to:
|
199
|
+
- _1_.
|
200
|
+
- _2_.
|
201
|
+
- _3_.
|
202
|
+
|
203
|
+
Remove _2_ from `items`.
|
204
|
+
"""
|
205
|
+
|
206
|
+
context = compile_source(source)
|
207
|
+
|
208
|
+
assert not context.has_errors()
|
209
|
+
assert context.bytecode_module is not None
|
210
|
+
assert len(context.bytecode_module.chunks) > 0
|
211
|
+
|
212
|
+
# Check for jump instructions (indicate loops)
|
213
|
+
bytecode = context.bytecode_module.chunks[0].bytecode
|
214
|
+
has_jumps = False
|
215
|
+
|
216
|
+
# Look for jump opcodes (0x16 = JUMP_R, 0x17 = JUMP_IF_R, 0x18 = JUMP_IF_NOT_R)
|
217
|
+
for byte in bytecode:
|
218
|
+
if byte in [0x16, 0x17, 0x18]:
|
219
|
+
has_jumps = True
|
220
|
+
break
|
221
|
+
|
222
|
+
assert has_jumps, "Should contain jump instructions for loops"
|
223
|
+
|
224
|
+
def test_operations_with_variables(self) -> None:
|
225
|
+
"""Test array operations using variables for positions and values."""
|
226
|
+
source = """
|
227
|
+
Define `data` as Ordered List.
|
228
|
+
Set `data` to:
|
229
|
+
1. _100_.
|
230
|
+
2. _200_.
|
231
|
+
3. _300_.
|
232
|
+
|
233
|
+
Define `pos` as Whole Number.
|
234
|
+
Set `pos` to _2_.
|
235
|
+
|
236
|
+
Define `val` as Whole Number.
|
237
|
+
Set `val` to _150_.
|
238
|
+
|
239
|
+
Insert `val` at position `pos` in `data`.
|
240
|
+
"""
|
241
|
+
|
242
|
+
context = compile_source(source)
|
243
|
+
|
244
|
+
# Should compile without errors
|
245
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
246
|
+
|
247
|
+
# Should generate bytecode
|
248
|
+
assert context.bytecode_module is not None
|