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,415 @@
|
|
1
|
+
"""Tests for parsing prefix expressions.
|
2
|
+
|
3
|
+
This module tests the parser's ability to handle prefix expressions including:
|
4
|
+
- Negative numbers (-42, -3.14)
|
5
|
+
- Boolean negation (not True, not False)
|
6
|
+
"""
|
7
|
+
|
8
|
+
import pytest
|
9
|
+
|
10
|
+
from machine_dialect.ast import ExpressionStatement, Identifier, PrefixExpression
|
11
|
+
from machine_dialect.parser import Parser
|
12
|
+
from machine_dialect.parser.tests.helper_functions import (
|
13
|
+
assert_literal_expression,
|
14
|
+
assert_program_statements,
|
15
|
+
)
|
16
|
+
|
17
|
+
|
18
|
+
class TestPrefixExpressions:
|
19
|
+
"""Test parsing of prefix expressions."""
|
20
|
+
|
21
|
+
@pytest.mark.parametrize(
|
22
|
+
"source,operator,value",
|
23
|
+
[
|
24
|
+
# Negative integers
|
25
|
+
("-5", "-", 5),
|
26
|
+
("-42", "-", 42),
|
27
|
+
("-123", "-", 123),
|
28
|
+
("-0", "-", 0),
|
29
|
+
("-999", "-", 999),
|
30
|
+
# Negative integers with underscores wrapping the positive number
|
31
|
+
("-_5_", "-", 5),
|
32
|
+
("-_42_", "-", 42),
|
33
|
+
("-_123_", "-", 123),
|
34
|
+
# Underscore-wrapped negative integers (entire expression)
|
35
|
+
# ("_-5_", "-", 5),
|
36
|
+
# ("_-42_", "-", 42),
|
37
|
+
# ("_-123_", "-", 123),
|
38
|
+
],
|
39
|
+
)
|
40
|
+
def test_negative_integer_expressions(self, source: str, operator: str, value: int) -> None:
|
41
|
+
"""Test parsing negative integer expressions.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
source: The source code containing a negative integer.
|
45
|
+
operator: The expected operator (should be "-").
|
46
|
+
value: The expected positive integer value.
|
47
|
+
"""
|
48
|
+
parser = Parser()
|
49
|
+
|
50
|
+
program = parser.parse(source)
|
51
|
+
|
52
|
+
assert len(parser.errors) == 0
|
53
|
+
assert_program_statements(parser, program)
|
54
|
+
|
55
|
+
statement = program.statements[0]
|
56
|
+
assert isinstance(statement, ExpressionStatement)
|
57
|
+
assert statement.expression is not None
|
58
|
+
|
59
|
+
# Check that it's a prefix expression
|
60
|
+
assert isinstance(statement.expression, PrefixExpression)
|
61
|
+
prefix_exp = statement.expression
|
62
|
+
|
63
|
+
# Check the operator
|
64
|
+
assert prefix_exp.operator == operator
|
65
|
+
|
66
|
+
# Check the right expression (should be the positive number)
|
67
|
+
assert prefix_exp.right is not None
|
68
|
+
assert_literal_expression(prefix_exp.right, value)
|
69
|
+
|
70
|
+
@pytest.mark.parametrize(
|
71
|
+
"source,operator,value",
|
72
|
+
[
|
73
|
+
# Negative floats
|
74
|
+
("-3.14", "-", 3.14),
|
75
|
+
("-0.5", "-", 0.5),
|
76
|
+
("-123.456", "-", 123.456),
|
77
|
+
("-0.0", "-", 0.0),
|
78
|
+
("-.5", "-", 0.5),
|
79
|
+
("-.25", "-", 0.25),
|
80
|
+
# Negative floats with underscores wrapping the positive number
|
81
|
+
("-_3.14_", "-", 3.14),
|
82
|
+
("-_0.5_", "-", 0.5),
|
83
|
+
("-_.25_", "-", 0.25),
|
84
|
+
# Underscore-wrapped negative floats (entire expression)
|
85
|
+
# ("_-3.14_", "-", 3.14),
|
86
|
+
# ("_-0.5_", "-", 0.5),
|
87
|
+
# ("_-.25_", "-", 0.25),
|
88
|
+
],
|
89
|
+
)
|
90
|
+
def test_negative_float_expressions(self, source: str, operator: str, value: float) -> None:
|
91
|
+
"""Test parsing negative float expressions.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
source: The source code containing a negative float.
|
95
|
+
operator: The expected operator (should be "-").
|
96
|
+
value: The expected positive float value.
|
97
|
+
"""
|
98
|
+
parser = Parser()
|
99
|
+
|
100
|
+
program = parser.parse(source)
|
101
|
+
|
102
|
+
assert len(parser.errors) == 0
|
103
|
+
assert_program_statements(parser, program)
|
104
|
+
|
105
|
+
statement = program.statements[0]
|
106
|
+
assert isinstance(statement, ExpressionStatement)
|
107
|
+
assert statement.expression is not None
|
108
|
+
|
109
|
+
# Check that it's a prefix expression
|
110
|
+
assert isinstance(statement.expression, PrefixExpression)
|
111
|
+
prefix_exp = statement.expression
|
112
|
+
|
113
|
+
# Check the operator
|
114
|
+
assert prefix_exp.operator == operator
|
115
|
+
|
116
|
+
# Check the right expression (should be the positive number)
|
117
|
+
assert prefix_exp.right is not None
|
118
|
+
assert_literal_expression(prefix_exp.right, value)
|
119
|
+
|
120
|
+
@pytest.mark.parametrize(
|
121
|
+
"source,operator,value",
|
122
|
+
[
|
123
|
+
# Boolean negation
|
124
|
+
("not Yes", "not", True),
|
125
|
+
("not No", "not", False),
|
126
|
+
# Boolean negation with underscores
|
127
|
+
("not _Yes_", "not", True),
|
128
|
+
("not _No_", "not", False),
|
129
|
+
# Underscore-wrapped entire negation expression
|
130
|
+
# ("_not True_", "not", True),
|
131
|
+
# ("_not False_", "not", False),
|
132
|
+
# Case insensitive NOT
|
133
|
+
("NOT Yes", "not", True),
|
134
|
+
("NOT No", "not", False),
|
135
|
+
("Not Yes", "not", True),
|
136
|
+
("Not No", "not", False),
|
137
|
+
("nOt Yes", "not", True),
|
138
|
+
("nOt No", "not", False),
|
139
|
+
# Case insensitive boolean values with negation
|
140
|
+
("not yes", "not", True),
|
141
|
+
("not no", "not", False),
|
142
|
+
("NOT YES", "not", True),
|
143
|
+
("NOT NO", "not", False),
|
144
|
+
],
|
145
|
+
)
|
146
|
+
def test_boolean_negation_expressions(self, source: str, operator: str, value: bool) -> None:
|
147
|
+
"""Test parsing boolean negation expressions.
|
148
|
+
|
149
|
+
Args:
|
150
|
+
source: The source code containing a negated boolean.
|
151
|
+
operator: The expected operator (should be "not").
|
152
|
+
value: The expected boolean value being negated.
|
153
|
+
"""
|
154
|
+
parser = Parser()
|
155
|
+
|
156
|
+
program = parser.parse(source)
|
157
|
+
|
158
|
+
assert len(parser.errors) == 0
|
159
|
+
assert_program_statements(parser, program)
|
160
|
+
|
161
|
+
statement = program.statements[0]
|
162
|
+
assert isinstance(statement, ExpressionStatement)
|
163
|
+
assert statement.expression is not None
|
164
|
+
|
165
|
+
# Check that it's a prefix expression
|
166
|
+
assert isinstance(statement.expression, PrefixExpression)
|
167
|
+
prefix_exp = statement.expression
|
168
|
+
|
169
|
+
# Check the operator (should be lowercase "not")
|
170
|
+
assert prefix_exp.operator == operator
|
171
|
+
|
172
|
+
# Check the right expression (should be the boolean value)
|
173
|
+
assert prefix_exp.right is not None
|
174
|
+
assert_literal_expression(prefix_exp.right, value)
|
175
|
+
|
176
|
+
def test_multiple_prefix_expressions(self) -> None:
|
177
|
+
"""Test parsing multiple prefix expressions in sequence."""
|
178
|
+
source = "-42. not Yes. -3.14. not No."
|
179
|
+
parser = Parser()
|
180
|
+
|
181
|
+
program = parser.parse(source)
|
182
|
+
|
183
|
+
assert len(parser.errors) == 0
|
184
|
+
assert len(program.statements) == 4
|
185
|
+
|
186
|
+
# First statement: -42
|
187
|
+
statement = program.statements[0]
|
188
|
+
assert isinstance(statement, ExpressionStatement)
|
189
|
+
assert statement.expression is not None
|
190
|
+
assert isinstance(statement.expression, PrefixExpression)
|
191
|
+
assert statement.expression.operator == "-"
|
192
|
+
assert statement.expression.right is not None
|
193
|
+
assert_literal_expression(statement.expression.right, 42)
|
194
|
+
|
195
|
+
# Second statement: not True
|
196
|
+
statement = program.statements[1]
|
197
|
+
assert isinstance(statement, ExpressionStatement)
|
198
|
+
assert statement.expression is not None
|
199
|
+
assert isinstance(statement.expression, PrefixExpression)
|
200
|
+
assert statement.expression.operator == "not"
|
201
|
+
assert statement.expression.right is not None
|
202
|
+
assert_literal_expression(statement.expression.right, True)
|
203
|
+
|
204
|
+
# Third statement: -3.14
|
205
|
+
statement = program.statements[2]
|
206
|
+
assert isinstance(statement, ExpressionStatement)
|
207
|
+
assert statement.expression is not None
|
208
|
+
assert isinstance(statement.expression, PrefixExpression)
|
209
|
+
assert statement.expression.operator == "-"
|
210
|
+
assert statement.expression.right is not None
|
211
|
+
assert_literal_expression(statement.expression.right, 3.14)
|
212
|
+
|
213
|
+
# Fourth statement: not False
|
214
|
+
statement = program.statements[3]
|
215
|
+
assert isinstance(statement, ExpressionStatement)
|
216
|
+
assert statement.expression is not None
|
217
|
+
assert isinstance(statement.expression, PrefixExpression)
|
218
|
+
assert statement.expression.operator == "not"
|
219
|
+
assert statement.expression.right is not None
|
220
|
+
assert_literal_expression(statement.expression.right, False)
|
221
|
+
|
222
|
+
def test_prefix_expression_with_identifier(self) -> None:
|
223
|
+
"""Test prefix expressions with identifiers."""
|
224
|
+
source = "-x. not `is valid`."
|
225
|
+
parser = Parser()
|
226
|
+
|
227
|
+
program = parser.parse(source)
|
228
|
+
|
229
|
+
assert len(parser.errors) == 0
|
230
|
+
assert len(program.statements) == 2
|
231
|
+
|
232
|
+
# First statement: -x
|
233
|
+
statement = program.statements[0]
|
234
|
+
assert isinstance(statement, ExpressionStatement)
|
235
|
+
assert statement.expression is not None
|
236
|
+
assert isinstance(statement.expression, PrefixExpression)
|
237
|
+
assert statement.expression.operator == "-"
|
238
|
+
assert statement.expression.right is not None
|
239
|
+
assert_literal_expression(statement.expression.right, "x")
|
240
|
+
|
241
|
+
# Second statement: not `is valid`
|
242
|
+
statement = program.statements[1]
|
243
|
+
assert isinstance(statement, ExpressionStatement)
|
244
|
+
assert statement.expression is not None
|
245
|
+
assert isinstance(statement.expression, PrefixExpression)
|
246
|
+
assert statement.expression.operator == "not"
|
247
|
+
assert statement.expression.right is not None
|
248
|
+
assert_literal_expression(statement.expression.right, "is valid")
|
249
|
+
|
250
|
+
def test_double_negation(self) -> None:
|
251
|
+
"""Test parsing double negation expressions."""
|
252
|
+
source = "--42. not not Yes."
|
253
|
+
parser = Parser()
|
254
|
+
|
255
|
+
program = parser.parse(source)
|
256
|
+
|
257
|
+
assert len(parser.errors) == 0
|
258
|
+
assert len(program.statements) == 2
|
259
|
+
|
260
|
+
# First statement: --42 (negative of negative 42)
|
261
|
+
statement = program.statements[0]
|
262
|
+
assert isinstance(statement, ExpressionStatement)
|
263
|
+
assert statement.expression is not None
|
264
|
+
assert isinstance(statement.expression, PrefixExpression)
|
265
|
+
assert statement.expression.operator == "-"
|
266
|
+
|
267
|
+
# The right side should be another prefix expression
|
268
|
+
assert statement.expression.right is not None
|
269
|
+
assert isinstance(statement.expression.right, PrefixExpression)
|
270
|
+
assert statement.expression.right.operator == "-"
|
271
|
+
assert statement.expression.right.right is not None
|
272
|
+
assert_literal_expression(statement.expression.right.right, 42)
|
273
|
+
|
274
|
+
# Second statement: not not True
|
275
|
+
statement = program.statements[1]
|
276
|
+
assert isinstance(statement, ExpressionStatement)
|
277
|
+
assert statement.expression is not None
|
278
|
+
assert isinstance(statement.expression, PrefixExpression)
|
279
|
+
assert statement.expression.operator == "not"
|
280
|
+
|
281
|
+
# The right side should be another prefix expression
|
282
|
+
assert statement.expression.right is not None
|
283
|
+
assert isinstance(statement.expression.right, PrefixExpression)
|
284
|
+
assert statement.expression.right.operator == "not"
|
285
|
+
assert statement.expression.right.right is not None
|
286
|
+
assert_literal_expression(statement.expression.right.right, True)
|
287
|
+
|
288
|
+
def test_boolean_negation_with_identifiers(self) -> None:
|
289
|
+
"""Test parsing boolean negation with identifier expressions."""
|
290
|
+
test_cases = [
|
291
|
+
("not x", "not", "x"),
|
292
|
+
("not isValid", "not", "isValid"),
|
293
|
+
("not `is valid`", "not", "is valid"),
|
294
|
+
("not foo", "not", "foo"),
|
295
|
+
("NOT bar", "not", "bar"),
|
296
|
+
]
|
297
|
+
|
298
|
+
for source, expected_operator, expected_identifier in test_cases:
|
299
|
+
parser = Parser()
|
300
|
+
|
301
|
+
program = parser.parse(source)
|
302
|
+
|
303
|
+
assert len(parser.errors) == 0, f"Parser errors for '{source}': {parser.errors}"
|
304
|
+
assert_program_statements(parser, program)
|
305
|
+
|
306
|
+
statement = program.statements[0]
|
307
|
+
assert isinstance(statement, ExpressionStatement)
|
308
|
+
assert statement.expression is not None
|
309
|
+
|
310
|
+
# Check it's a prefix expression
|
311
|
+
prefix_exp = statement.expression
|
312
|
+
assert isinstance(prefix_exp, PrefixExpression)
|
313
|
+
assert prefix_exp.operator == expected_operator
|
314
|
+
|
315
|
+
# Check the right side is an identifier
|
316
|
+
assert prefix_exp.right is not None
|
317
|
+
assert isinstance(prefix_exp.right, Identifier)
|
318
|
+
assert prefix_exp.right.value == expected_identifier
|
319
|
+
|
320
|
+
def test_boolean_negation_with_non_boolean_literals(self) -> None:
|
321
|
+
"""Test that using 'not' with non-boolean literals parses successfully.
|
322
|
+
|
323
|
+
Note: Since this language follows Java's approach where 'not' only accepts
|
324
|
+
boolean values, type checking would happen at a later semantic analysis stage,
|
325
|
+
not during parsing. The parser accepts these syntactically valid constructs.
|
326
|
+
"""
|
327
|
+
test_cases = [
|
328
|
+
("not 42", "not", 42),
|
329
|
+
("not 0", "not", 0),
|
330
|
+
("not 3.14", "not", 3.14),
|
331
|
+
("not 0.0", "not", 0.0),
|
332
|
+
# ("not -5", "not", -5), # This creates nested prefix expressions: not (- 5)
|
333
|
+
("NOT 123", "not", 123),
|
334
|
+
# String literals - uncomment when string parsing is implemented
|
335
|
+
# ("not \"hello\"", "not", "hello"),
|
336
|
+
# ("not 'world'", "not", "world"),
|
337
|
+
# ("not \"\"", "not", ""),
|
338
|
+
]
|
339
|
+
|
340
|
+
for source, expected_operator, expected_value in test_cases:
|
341
|
+
parser = Parser()
|
342
|
+
|
343
|
+
program = parser.parse(source)
|
344
|
+
|
345
|
+
# These should parse successfully - type errors would be caught in semantic analysis
|
346
|
+
assert len(parser.errors) == 0, f"Parser errors for '{source}': {parser.errors}"
|
347
|
+
assert_program_statements(parser, program)
|
348
|
+
|
349
|
+
statement = program.statements[0]
|
350
|
+
assert isinstance(statement, ExpressionStatement)
|
351
|
+
assert statement.expression is not None
|
352
|
+
|
353
|
+
# Check it's a prefix expression
|
354
|
+
prefix_exp = statement.expression
|
355
|
+
assert isinstance(prefix_exp, PrefixExpression)
|
356
|
+
assert prefix_exp.operator == expected_operator
|
357
|
+
|
358
|
+
# The right side should be parsed as the appropriate literal
|
359
|
+
assert prefix_exp.right is not None
|
360
|
+
assert_literal_expression(prefix_exp.right, expected_value)
|
361
|
+
|
362
|
+
def test_boolean_negation_with_nested_prefix(self) -> None:
|
363
|
+
"""Test that 'not -5' creates nested prefix expressions."""
|
364
|
+
source = "not -5"
|
365
|
+
parser = Parser()
|
366
|
+
|
367
|
+
program = parser.parse(source)
|
368
|
+
|
369
|
+
assert len(parser.errors) == 0, f"Parser errors: {parser.errors}"
|
370
|
+
assert_program_statements(parser, program)
|
371
|
+
|
372
|
+
statement = program.statements[0]
|
373
|
+
assert isinstance(statement, ExpressionStatement)
|
374
|
+
assert statement.expression is not None
|
375
|
+
|
376
|
+
# Check outer prefix expression (not)
|
377
|
+
outer_prefix = statement.expression
|
378
|
+
assert isinstance(outer_prefix, PrefixExpression)
|
379
|
+
assert outer_prefix.operator == "not"
|
380
|
+
|
381
|
+
# Check inner prefix expression (-)
|
382
|
+
assert outer_prefix.right is not None
|
383
|
+
inner_prefix = outer_prefix.right
|
384
|
+
assert isinstance(inner_prefix, PrefixExpression)
|
385
|
+
assert inner_prefix.operator == "-"
|
386
|
+
|
387
|
+
# Check the innermost literal (5)
|
388
|
+
assert inner_prefix.right is not None
|
389
|
+
assert_literal_expression(inner_prefix.right, 5)
|
390
|
+
|
391
|
+
def test_prefix_expression_string_representation(self) -> None:
|
392
|
+
"""Test the string representation of prefix expressions."""
|
393
|
+
# Test cases with expected string representations
|
394
|
+
test_cases = [
|
395
|
+
("-42", "(-_42_)"),
|
396
|
+
("not Yes", "(not _Yes_)"),
|
397
|
+
("-3.14", "(-_3.14_)"),
|
398
|
+
("not No", "(not _No_)"),
|
399
|
+
("--5", "(-(-_5_))"),
|
400
|
+
("not not Yes", "(not (not _Yes_))"),
|
401
|
+
]
|
402
|
+
|
403
|
+
for source, expected in test_cases:
|
404
|
+
parser = Parser()
|
405
|
+
program = parser.parse(source)
|
406
|
+
|
407
|
+
assert len(parser.errors) == 0
|
408
|
+
assert len(program.statements) == 1
|
409
|
+
|
410
|
+
statement = program.statements[0]
|
411
|
+
assert isinstance(statement, ExpressionStatement)
|
412
|
+
assert statement.expression is not None
|
413
|
+
|
414
|
+
# Check string representation
|
415
|
+
assert str(statement.expression) == expected
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from machine_dialect.ast import Program
|
2
|
+
from machine_dialect.parser import Parser
|
3
|
+
|
4
|
+
|
5
|
+
class TestParser:
|
6
|
+
def test_parse_program(self) -> None:
|
7
|
+
source: str = "Set `X` to 5."
|
8
|
+
parser: Parser = Parser()
|
9
|
+
|
10
|
+
program: Program = parser.parse(source)
|
11
|
+
|
12
|
+
assert program is not None
|
13
|
+
assert isinstance(program, Program)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
"""Tests for return statement parsing."""
|
2
|
+
|
3
|
+
from machine_dialect.ast import ReturnStatement
|
4
|
+
from machine_dialect.parser import Parser
|
5
|
+
|
6
|
+
|
7
|
+
class TestReturnStatements:
|
8
|
+
"""Test parsing of return statements."""
|
9
|
+
|
10
|
+
def test_give_back_statement(self) -> None:
|
11
|
+
"""Test parsing 'give back' return statement."""
|
12
|
+
source = "give back 42"
|
13
|
+
parser = Parser()
|
14
|
+
|
15
|
+
program = parser.parse(source, check_semantics=False)
|
16
|
+
|
17
|
+
assert len(parser.errors) == 0, f"Parser had errors: {parser.errors}"
|
18
|
+
assert len(program.statements) == 1
|
19
|
+
|
20
|
+
statement = program.statements[0]
|
21
|
+
assert isinstance(statement, ReturnStatement)
|
22
|
+
assert statement.token.literal == "give back"
|
23
|
+
|
24
|
+
def test_gives_back_statement(self) -> None:
|
25
|
+
"""Test parsing 'gives back' return statement."""
|
26
|
+
source = "gives back true"
|
27
|
+
parser = Parser()
|
28
|
+
|
29
|
+
program = parser.parse(source, check_semantics=False)
|
30
|
+
|
31
|
+
assert len(parser.errors) == 0, f"Parser had errors: {parser.errors}"
|
32
|
+
assert len(program.statements) == 1
|
33
|
+
|
34
|
+
statement = program.statements[0]
|
35
|
+
assert isinstance(statement, ReturnStatement)
|
36
|
+
assert statement.token.literal == "gives back"
|
37
|
+
|
38
|
+
def test_multiple_return_statements(self) -> None:
|
39
|
+
"""Test parsing multiple return statements."""
|
40
|
+
source = """
|
41
|
+
give back 1.
|
42
|
+
gives back 2.
|
43
|
+
"""
|
44
|
+
parser = Parser()
|
45
|
+
|
46
|
+
program = parser.parse(source, check_semantics=False)
|
47
|
+
|
48
|
+
assert len(parser.errors) == 0, f"Parser had errors: {parser.errors}"
|
49
|
+
assert len(program.statements) == 2
|
50
|
+
|
51
|
+
# First statement
|
52
|
+
statement1 = program.statements[0]
|
53
|
+
assert isinstance(statement1, ReturnStatement)
|
54
|
+
assert statement1.token.literal == "give back"
|
55
|
+
|
56
|
+
# Second statement
|
57
|
+
statement2 = program.statements[1]
|
58
|
+
assert isinstance(statement2, ReturnStatement)
|
59
|
+
assert statement2.token.literal == "gives back"
|
60
|
+
|
61
|
+
def test_return_with_set_statement(self) -> None:
|
62
|
+
"""Test parsing return statement followed by set statement."""
|
63
|
+
source = """
|
64
|
+
Define `x` as Whole Number.
|
65
|
+
give back 42.
|
66
|
+
Set `x` to 10
|
67
|
+
"""
|
68
|
+
parser = Parser()
|
69
|
+
|
70
|
+
program = parser.parse(source, check_semantics=False)
|
71
|
+
|
72
|
+
assert len(parser.errors) == 0, f"Parser had errors: {parser.errors}"
|
73
|
+
assert len(program.statements) == 3
|
74
|
+
|
75
|
+
# First statement should be define
|
76
|
+
from machine_dialect.ast import DefineStatement, SetStatement
|
77
|
+
|
78
|
+
statement1 = program.statements[0]
|
79
|
+
assert isinstance(statement1, DefineStatement)
|
80
|
+
|
81
|
+
# Second statement should be return
|
82
|
+
statement2 = program.statements[1]
|
83
|
+
assert isinstance(statement2, ReturnStatement)
|
84
|
+
assert statement2.token.literal == "give back"
|
85
|
+
|
86
|
+
# Third statement should be set
|
87
|
+
statement3 = program.statements[2]
|
88
|
+
assert isinstance(statement3, SetStatement)
|
89
|
+
assert statement3.token.literal == "Set"
|
@@ -0,0 +1,152 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from machine_dialect.ast import Identifier, Program, SetStatement
|
4
|
+
from machine_dialect.lexer import TokenType
|
5
|
+
from machine_dialect.parser import Parser
|
6
|
+
|
7
|
+
|
8
|
+
class TestSetStatements:
|
9
|
+
def test_parse_set_integer(self) -> None:
|
10
|
+
source: str = "Set `X` to 1"
|
11
|
+
parser: Parser = Parser()
|
12
|
+
|
13
|
+
program: Program = parser.parse(source)
|
14
|
+
|
15
|
+
assert program is not None
|
16
|
+
assert len(program.statements) == 1
|
17
|
+
|
18
|
+
statement = program.statements[0]
|
19
|
+
assert isinstance(statement, SetStatement)
|
20
|
+
assert statement.token.literal == "Set"
|
21
|
+
|
22
|
+
assert statement.name is not None
|
23
|
+
assert isinstance(statement.name, Identifier)
|
24
|
+
assert statement.name.value == "X"
|
25
|
+
assert statement.name.token.literal == "X"
|
26
|
+
|
27
|
+
def test_parse_set_float(self) -> None:
|
28
|
+
source: str = "Set `price` to 3.14"
|
29
|
+
parser: Parser = Parser()
|
30
|
+
|
31
|
+
program: Program = parser.parse(source)
|
32
|
+
|
33
|
+
assert program is not None
|
34
|
+
assert len(program.statements) == 1
|
35
|
+
|
36
|
+
statement = program.statements[0]
|
37
|
+
assert isinstance(statement, SetStatement)
|
38
|
+
assert statement.token.literal == "Set"
|
39
|
+
|
40
|
+
assert statement.name is not None
|
41
|
+
assert isinstance(statement.name, Identifier)
|
42
|
+
assert statement.name.value == "price"
|
43
|
+
assert statement.name.token.literal == "price"
|
44
|
+
|
45
|
+
def test_parse_set_string(self) -> None:
|
46
|
+
source: str = 'Set `Z` to "Hello, World!"'
|
47
|
+
parser: Parser = Parser()
|
48
|
+
|
49
|
+
program: Program = parser.parse(source)
|
50
|
+
|
51
|
+
assert program is not None
|
52
|
+
assert len(program.statements) == 1
|
53
|
+
|
54
|
+
statement = program.statements[0]
|
55
|
+
assert isinstance(statement, SetStatement)
|
56
|
+
assert statement.token.literal == "Set"
|
57
|
+
|
58
|
+
assert statement.name is not None
|
59
|
+
assert isinstance(statement.name, Identifier)
|
60
|
+
assert statement.name.value == "Z"
|
61
|
+
assert statement.name.token.literal == "Z"
|
62
|
+
|
63
|
+
def test_parse_multiple_set_statements(self) -> None:
|
64
|
+
source: str = "\n".join(
|
65
|
+
[
|
66
|
+
"Set `X` to 1.",
|
67
|
+
"Set `price` to 3.14.",
|
68
|
+
'Set `Z` to "Hello, World!".',
|
69
|
+
]
|
70
|
+
)
|
71
|
+
|
72
|
+
parser: Parser = Parser()
|
73
|
+
|
74
|
+
program: Program = parser.parse(source)
|
75
|
+
|
76
|
+
assert program is not None
|
77
|
+
assert len(program.statements) == 3
|
78
|
+
|
79
|
+
# Check first statement
|
80
|
+
statement1 = program.statements[0]
|
81
|
+
assert isinstance(statement1, SetStatement)
|
82
|
+
assert statement1.name is not None
|
83
|
+
assert statement1.name.value == "X"
|
84
|
+
assert statement1.name.token.type == TokenType.MISC_IDENT
|
85
|
+
assert statement1.name.token.literal == "X"
|
86
|
+
|
87
|
+
# Check second statement
|
88
|
+
statement2 = program.statements[1]
|
89
|
+
assert isinstance(statement2, SetStatement)
|
90
|
+
assert statement2.name is not None
|
91
|
+
assert statement2.name.value == "price"
|
92
|
+
assert statement2.name.token.type == TokenType.MISC_IDENT
|
93
|
+
assert statement2.name.token.literal == "price"
|
94
|
+
|
95
|
+
# Check third statement
|
96
|
+
statement3 = program.statements[2]
|
97
|
+
assert isinstance(statement3, SetStatement)
|
98
|
+
assert statement3.name is not None
|
99
|
+
assert statement3.name.value == "Z"
|
100
|
+
assert statement3.name.token.type == TokenType.MISC_IDENT
|
101
|
+
assert statement3.name.token.literal == "Z"
|
102
|
+
|
103
|
+
def test_set_statement_string_representation(self) -> None:
|
104
|
+
source: str = "Set `X` to 1"
|
105
|
+
parser: Parser = Parser()
|
106
|
+
|
107
|
+
program: Program = parser.parse(source)
|
108
|
+
|
109
|
+
assert program is not None
|
110
|
+
statement = program.statements[0]
|
111
|
+
assert isinstance(statement, SetStatement)
|
112
|
+
|
113
|
+
# Test the string representation
|
114
|
+
program_str = str(program)
|
115
|
+
assert program_str is not None # Should have some string representation
|
116
|
+
|
117
|
+
@pytest.mark.parametrize(
|
118
|
+
"source",
|
119
|
+
[
|
120
|
+
"Set `foo` to 1 if `certain_condition`, else 0",
|
121
|
+
"Set `foo` to 1 if `certain_condition`, otherwise 0",
|
122
|
+
"Set `foo` to 1 when `certain_condition`, else 0",
|
123
|
+
"Set `foo` to 1 when `certain_condition`, otherwise 0",
|
124
|
+
"Set `foo` to 1 whenever `certain_condition`, else 0",
|
125
|
+
"Set `foo` to 1 whenever `certain_condition`, otherwise 0",
|
126
|
+
"Set `foo` to 1 if `certain_condition`; else 0",
|
127
|
+
"Set `foo` to 1 if `certain_condition`; otherwise 0",
|
128
|
+
"Set `foo` to 1 when `certain_condition`; else 0",
|
129
|
+
"Set `foo` to 1 when `certain_condition`; otherwise 0",
|
130
|
+
"Set `foo` to 1 whenever `certain_condition`; else 0",
|
131
|
+
"Set `foo` to 1 whenever `certain_condition`; otherwise 0",
|
132
|
+
],
|
133
|
+
)
|
134
|
+
def test_parse_ternary_expressions(self, source: str) -> None:
|
135
|
+
parser: Parser = Parser()
|
136
|
+
|
137
|
+
program: Program = parser.parse(source)
|
138
|
+
|
139
|
+
assert program is not None
|
140
|
+
assert len(program.statements) == 1
|
141
|
+
|
142
|
+
statement = program.statements[0]
|
143
|
+
assert isinstance(statement, SetStatement)
|
144
|
+
assert statement.token.literal == "Set"
|
145
|
+
|
146
|
+
assert statement.name is not None
|
147
|
+
assert isinstance(statement.name, Identifier)
|
148
|
+
assert statement.name.value == "foo"
|
149
|
+
assert statement.name.token.literal == "foo"
|
150
|
+
|
151
|
+
# The value should be a ternary/conditional expression
|
152
|
+
assert statement.value is not None
|