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,395 @@
|
|
1
|
+
"""Integration tests for list compilation to bytecode.
|
2
|
+
|
3
|
+
Tests the full compilation pipeline from source code to bytecode
|
4
|
+
for list literal types.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from pathlib import Path
|
8
|
+
|
9
|
+
from machine_dialect.codegen.register_codegen import generate_bytecode_from_mir
|
10
|
+
from machine_dialect.compiler.config import CompilerConfig
|
11
|
+
from machine_dialect.compiler.pipeline import CompilationPipeline
|
12
|
+
|
13
|
+
|
14
|
+
class TestListCompilation:
|
15
|
+
"""Test compilation of list literals to bytecode."""
|
16
|
+
|
17
|
+
def test_compile_unordered_list(self) -> None:
|
18
|
+
"""Test compiling an unordered list."""
|
19
|
+
source = """
|
20
|
+
Define `shopping` as unordered list.
|
21
|
+
Set `shopping` to:
|
22
|
+
- _"milk"_.
|
23
|
+
- _"bread"_.
|
24
|
+
- _"eggs"_.
|
25
|
+
"""
|
26
|
+
config = CompilerConfig(verbose=False)
|
27
|
+
pipeline = CompilationPipeline(config)
|
28
|
+
|
29
|
+
# Create temp file
|
30
|
+
test_file = Path("test_unordered.md")
|
31
|
+
test_file.write_text(source)
|
32
|
+
|
33
|
+
try:
|
34
|
+
context = pipeline.compile_file(test_file)
|
35
|
+
|
36
|
+
# Check no errors
|
37
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
38
|
+
|
39
|
+
# Check MIR was generated
|
40
|
+
assert hasattr(context, "mir_module"), "No MIR module generated"
|
41
|
+
assert context.mir_module is not None
|
42
|
+
|
43
|
+
# Generate bytecode
|
44
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
45
|
+
|
46
|
+
# Check bytecode was generated
|
47
|
+
assert bytecode_module is not None
|
48
|
+
serialized = bytecode_module.serialize()
|
49
|
+
assert len(serialized) > 0, "No bytecode generated"
|
50
|
+
|
51
|
+
# Verify bytecode contains array creation opcode (0x21 = NEW_ARRAY_R)
|
52
|
+
assert b"\x21" in serialized, "No array creation instruction found"
|
53
|
+
|
54
|
+
finally:
|
55
|
+
test_file.unlink(missing_ok=True)
|
56
|
+
|
57
|
+
def test_compile_ordered_list(self) -> None:
|
58
|
+
"""Test compiling an ordered list."""
|
59
|
+
source = """
|
60
|
+
Define `steps` as ordered list.
|
61
|
+
Set `steps` to:
|
62
|
+
1. _"First"_.
|
63
|
+
2. _"Second"_.
|
64
|
+
3. _"Third"_.
|
65
|
+
"""
|
66
|
+
config = CompilerConfig(verbose=False)
|
67
|
+
pipeline = CompilationPipeline(config)
|
68
|
+
|
69
|
+
test_file = Path("test_ordered.md")
|
70
|
+
test_file.write_text(source)
|
71
|
+
|
72
|
+
try:
|
73
|
+
context = pipeline.compile_file(test_file)
|
74
|
+
|
75
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
76
|
+
assert hasattr(context, "mir_module")
|
77
|
+
assert context.mir_module is not None
|
78
|
+
|
79
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
80
|
+
serialized = bytecode_module.serialize()
|
81
|
+
|
82
|
+
# Check for array creation
|
83
|
+
assert b"\x21" in serialized, "No array creation instruction"
|
84
|
+
# Check for array set operations (0x23 = ARRAY_SET_R)
|
85
|
+
assert b"\x23" in serialized, "No array set instructions"
|
86
|
+
|
87
|
+
finally:
|
88
|
+
test_file.unlink(missing_ok=True)
|
89
|
+
|
90
|
+
def test_compile_named_list(self) -> None:
|
91
|
+
"""Test compiling a named list (dictionary)."""
|
92
|
+
source = """
|
93
|
+
Define `person` as named list.
|
94
|
+
Set `person` to:
|
95
|
+
- _"name"_: _"Alice"_.
|
96
|
+
- _"age"_: _30_.
|
97
|
+
- _"active"_: _yes_.
|
98
|
+
"""
|
99
|
+
config = CompilerConfig(verbose=False)
|
100
|
+
pipeline = CompilationPipeline(config)
|
101
|
+
|
102
|
+
test_file = Path("test_named.md")
|
103
|
+
test_file.write_text(source)
|
104
|
+
|
105
|
+
try:
|
106
|
+
context = pipeline.compile_file(test_file)
|
107
|
+
|
108
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
109
|
+
assert hasattr(context, "mir_module")
|
110
|
+
assert context.mir_module is not None
|
111
|
+
|
112
|
+
# Check that dictionary operations are generated in MIR
|
113
|
+
main_func = context.mir_module.get_function("__main__")
|
114
|
+
assert main_func is not None
|
115
|
+
|
116
|
+
# Verify DictCreate instruction exists in MIR
|
117
|
+
from machine_dialect.mir.mir_instructions import DictCreate, DictSet
|
118
|
+
|
119
|
+
dict_creates = []
|
120
|
+
dict_sets = []
|
121
|
+
for block in main_func.cfg.blocks.values():
|
122
|
+
for inst in block.instructions:
|
123
|
+
if isinstance(inst, DictCreate):
|
124
|
+
dict_creates.append(inst)
|
125
|
+
elif isinstance(inst, DictSet):
|
126
|
+
dict_sets.append(inst)
|
127
|
+
|
128
|
+
assert len(dict_creates) > 0, "No DictCreate instructions found in MIR"
|
129
|
+
assert len(dict_sets) >= 3, "Expected at least 3 DictSet instructions for name, age, and active"
|
130
|
+
|
131
|
+
# TODO: Bytecode generation for dictionary operations not yet implemented
|
132
|
+
# Once implemented, the bytecode should contain dictionary creation/set instructions
|
133
|
+
# For now, we just verify the MIR is correct
|
134
|
+
|
135
|
+
finally:
|
136
|
+
test_file.unlink(missing_ok=True)
|
137
|
+
|
138
|
+
def test_compile_mixed_type_list(self) -> None:
|
139
|
+
"""Test compiling a list with mixed types."""
|
140
|
+
source = """
|
141
|
+
Define `data` as unordered list.
|
142
|
+
Set `data` to:
|
143
|
+
- _42_.
|
144
|
+
- _"text"_.
|
145
|
+
- _3.14_.
|
146
|
+
- _yes_.
|
147
|
+
- _empty_.
|
148
|
+
"""
|
149
|
+
config = CompilerConfig(verbose=False)
|
150
|
+
pipeline = CompilationPipeline(config)
|
151
|
+
|
152
|
+
test_file = Path("test_mixed.md")
|
153
|
+
test_file.write_text(source)
|
154
|
+
|
155
|
+
try:
|
156
|
+
context = pipeline.compile_file(test_file)
|
157
|
+
|
158
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
159
|
+
assert context.mir_module is not None
|
160
|
+
|
161
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
162
|
+
serialized = bytecode_module.serialize()
|
163
|
+
|
164
|
+
# Should handle all types
|
165
|
+
assert len(serialized) > 50, "Bytecode too small for mixed list"
|
166
|
+
assert b"\x21" in serialized, "No array creation"
|
167
|
+
assert b"\x23" in serialized, "No array set operations"
|
168
|
+
|
169
|
+
finally:
|
170
|
+
test_file.unlink(missing_ok=True)
|
171
|
+
|
172
|
+
def test_compile_nested_lists(self) -> None:
|
173
|
+
"""Test compiling nested lists."""
|
174
|
+
source = """
|
175
|
+
Define `matrix` as unordered list.
|
176
|
+
Define `row1` as unordered list.
|
177
|
+
Define `row2` as unordered list.
|
178
|
+
|
179
|
+
Set `row1` to:
|
180
|
+
- _1_.
|
181
|
+
- _2_.
|
182
|
+
- _3_.
|
183
|
+
|
184
|
+
Set `row2` to:
|
185
|
+
- _4_.
|
186
|
+
- _5_.
|
187
|
+
- _6_.
|
188
|
+
|
189
|
+
Set `matrix` to:
|
190
|
+
- `row1`.
|
191
|
+
- `row2`.
|
192
|
+
"""
|
193
|
+
config = CompilerConfig(verbose=False)
|
194
|
+
pipeline = CompilationPipeline(config)
|
195
|
+
|
196
|
+
test_file = Path("test_nested.md")
|
197
|
+
test_file.write_text(source)
|
198
|
+
|
199
|
+
try:
|
200
|
+
context = pipeline.compile_file(test_file)
|
201
|
+
|
202
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
203
|
+
assert context.mir_module is not None
|
204
|
+
|
205
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
206
|
+
serialized = bytecode_module.serialize()
|
207
|
+
|
208
|
+
# Should have multiple array creations
|
209
|
+
array_create_count = serialized.count(b"\x21")
|
210
|
+
assert array_create_count >= 3, f"Expected at least 3 arrays, found {array_create_count}"
|
211
|
+
|
212
|
+
finally:
|
213
|
+
test_file.unlink(missing_ok=True)
|
214
|
+
|
215
|
+
def test_empty_list_compilation(self) -> None:
|
216
|
+
"""Test compiling an empty list."""
|
217
|
+
source = """
|
218
|
+
Define `empty_list` as unordered list.
|
219
|
+
Set `empty_list` to:
|
220
|
+
"""
|
221
|
+
config = CompilerConfig(verbose=False)
|
222
|
+
pipeline = CompilationPipeline(config)
|
223
|
+
|
224
|
+
test_file = Path("test_empty.md")
|
225
|
+
test_file.write_text(source)
|
226
|
+
|
227
|
+
try:
|
228
|
+
context = pipeline.compile_file(test_file)
|
229
|
+
|
230
|
+
# Empty list should compile successfully
|
231
|
+
assert not context.has_errors(), f"Compilation errors: {context.errors}"
|
232
|
+
assert context.mir_module is not None
|
233
|
+
|
234
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
235
|
+
serialized = bytecode_module.serialize()
|
236
|
+
|
237
|
+
# Should create array with size 0
|
238
|
+
assert b"\x21" in serialized, "No array creation"
|
239
|
+
|
240
|
+
finally:
|
241
|
+
test_file.unlink(missing_ok=True)
|
242
|
+
|
243
|
+
def test_list_type_mismatch_error(self) -> None:
|
244
|
+
"""Test that mismatched list types produce an error."""
|
245
|
+
source = """
|
246
|
+
Define `mylist` as unordered list.
|
247
|
+
Set `mylist` to:
|
248
|
+
1. _"This is ordered"_
|
249
|
+
2. _"Not unordered"_
|
250
|
+
"""
|
251
|
+
config = CompilerConfig(verbose=False)
|
252
|
+
pipeline = CompilationPipeline(config)
|
253
|
+
|
254
|
+
test_file = Path("test_mismatch.md")
|
255
|
+
test_file.write_text(source)
|
256
|
+
|
257
|
+
try:
|
258
|
+
context = pipeline.compile_file(test_file)
|
259
|
+
|
260
|
+
# Should have type mismatch error
|
261
|
+
assert context.has_errors(), "Should have type mismatch error"
|
262
|
+
error_messages = " ".join(context.errors)
|
263
|
+
assert "Ordered List" in error_messages or "type" in error_messages.lower()
|
264
|
+
|
265
|
+
finally:
|
266
|
+
test_file.unlink(missing_ok=True)
|
267
|
+
|
268
|
+
|
269
|
+
class TestListBytecodeStructure:
|
270
|
+
"""Test the structure of generated bytecode for lists."""
|
271
|
+
|
272
|
+
def test_bytecode_constants_for_list_elements(self) -> None:
|
273
|
+
"""Test that list elements are properly stored in constant pool."""
|
274
|
+
source = """
|
275
|
+
Define `nums` as ordered list.
|
276
|
+
Set `nums` to:
|
277
|
+
1. _100_.
|
278
|
+
2. _200_.
|
279
|
+
3. _300_.
|
280
|
+
"""
|
281
|
+
config = CompilerConfig(verbose=False)
|
282
|
+
pipeline = CompilationPipeline(config)
|
283
|
+
|
284
|
+
test_file = Path("test_constants.md")
|
285
|
+
test_file.write_text(source)
|
286
|
+
|
287
|
+
try:
|
288
|
+
context = pipeline.compile_file(test_file)
|
289
|
+
assert not context.has_errors()
|
290
|
+
assert context.mir_module is not None
|
291
|
+
|
292
|
+
# Generate bytecode
|
293
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
294
|
+
|
295
|
+
# Check constant pool contains our values
|
296
|
+
# Constants are stored as (tag, value) tuples
|
297
|
+
constants_values = [val for tag, val in bytecode_module.chunks[0].constants]
|
298
|
+
assert 100 in constants_values
|
299
|
+
assert 200 in constants_values
|
300
|
+
assert 300 in constants_values
|
301
|
+
|
302
|
+
# Also verify bytecode contains array operations
|
303
|
+
serialized = bytecode_module.serialize()
|
304
|
+
assert b"\x21" in serialized, "No array creation instruction"
|
305
|
+
assert b"\x23" in serialized, "No array set operations"
|
306
|
+
|
307
|
+
finally:
|
308
|
+
test_file.unlink(missing_ok=True)
|
309
|
+
|
310
|
+
def test_bytecode_constants_all_types(self) -> None:
|
311
|
+
"""Test that all data types are properly stored in constant pool."""
|
312
|
+
source = """
|
313
|
+
Define `mixed` as unordered list.
|
314
|
+
Set `mixed` to:
|
315
|
+
- _"hello world"_.
|
316
|
+
- _42_.
|
317
|
+
- _3.14_.
|
318
|
+
- _yes_.
|
319
|
+
- _no_.
|
320
|
+
"""
|
321
|
+
config = CompilerConfig(verbose=False)
|
322
|
+
pipeline = CompilationPipeline(config)
|
323
|
+
|
324
|
+
test_file = Path("test_all_types.md")
|
325
|
+
test_file.write_text(source)
|
326
|
+
|
327
|
+
try:
|
328
|
+
context = pipeline.compile_file(test_file)
|
329
|
+
assert not context.has_errors()
|
330
|
+
assert context.mir_module is not None
|
331
|
+
|
332
|
+
bytecode_module, _metadata = generate_bytecode_from_mir(context.mir_module)
|
333
|
+
|
334
|
+
# Check constant pool contains our values
|
335
|
+
from machine_dialect.codegen.bytecode_module import ConstantTag
|
336
|
+
|
337
|
+
constants = bytecode_module.chunks[0].constants
|
338
|
+
|
339
|
+
# Extract values by type
|
340
|
+
strings = [val for tag, val in constants if tag == ConstantTag.STRING]
|
341
|
+
ints = [val for tag, val in constants if tag == ConstantTag.INT]
|
342
|
+
floats = [val for tag, val in constants if tag == ConstantTag.FLOAT]
|
343
|
+
bools = [val for tag, val in constants if tag == ConstantTag.BOOL]
|
344
|
+
|
345
|
+
# Check all values are in the pool
|
346
|
+
assert "hello world" in strings, f"String not in pool. Strings: {strings}"
|
347
|
+
assert 42 in ints, f"Integer not in pool. Ints: {ints}"
|
348
|
+
assert 3.14 in floats, f"Float not in pool. Floats: {floats}"
|
349
|
+
assert True in bools, f"True not in pool. Bools: {bools}"
|
350
|
+
assert False in bools, f"False not in pool. Bools: {bools}"
|
351
|
+
|
352
|
+
finally:
|
353
|
+
test_file.unlink(missing_ok=True)
|
354
|
+
|
355
|
+
def test_bytecode_size_scaling(self) -> None:
|
356
|
+
"""Test that bytecode size scales with list size."""
|
357
|
+
# Small list
|
358
|
+
small_source = """
|
359
|
+
Define `small` as unordered list.
|
360
|
+
Set `small` to:
|
361
|
+
- _1_.
|
362
|
+
- _2_.
|
363
|
+
"""
|
364
|
+
# Large list
|
365
|
+
large_items = "\n".join([f"- _{i}_." for i in range(20)])
|
366
|
+
large_source = f"""
|
367
|
+
Define `large` as unordered list.
|
368
|
+
Set `large` to:
|
369
|
+
{large_items}
|
370
|
+
"""
|
371
|
+
|
372
|
+
config = CompilerConfig(verbose=False)
|
373
|
+
pipeline = CompilationPipeline(config)
|
374
|
+
|
375
|
+
# Compile small list
|
376
|
+
test_file = Path("test_size.md")
|
377
|
+
test_file.write_text(small_source)
|
378
|
+
context = pipeline.compile_file(test_file)
|
379
|
+
assert not context.has_errors()
|
380
|
+
assert context.mir_module is not None
|
381
|
+
small_bytecode, _ = generate_bytecode_from_mir(context.mir_module)
|
382
|
+
small_size = len(small_bytecode.serialize())
|
383
|
+
|
384
|
+
# Compile large list
|
385
|
+
test_file.write_text(large_source)
|
386
|
+
context = pipeline.compile_file(test_file)
|
387
|
+
assert not context.has_errors()
|
388
|
+
assert context.mir_module is not None
|
389
|
+
large_bytecode, _ = generate_bytecode_from_mir(context.mir_module)
|
390
|
+
large_size = len(large_bytecode.serialize())
|
391
|
+
|
392
|
+
test_file.unlink(missing_ok=True)
|
393
|
+
|
394
|
+
# Large list should generate more bytecode
|
395
|
+
assert large_size > small_size * 2, f"Large list ({large_size}) should be much bigger than small ({small_size})"
|