mlog-py 0.8.1__tar.gz

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.
Files changed (115) hide show
  1. mlog_py-0.8.1/LICENSE +21 -0
  2. mlog_py-0.8.1/MANIFEST.in +4 -0
  3. mlog_py-0.8.1/PKG-INFO +388 -0
  4. mlog_py-0.8.1/README.md +359 -0
  5. mlog_py-0.8.1/mlog/__init__.py +664 -0
  6. mlog_py-0.8.1/mlog/__init__.pyi +2002 -0
  7. mlog_py-0.8.1/mlog/__main__.py +6 -0
  8. mlog_py-0.8.1/mlog/allocator.py +108 -0
  9. mlog_py-0.8.1/mlog/clipboard.py +223 -0
  10. mlog_py-0.8.1/mlog/comments.py +165 -0
  11. mlog_py-0.8.1/mlog/compiler.py +4505 -0
  12. mlog_py-0.8.1/mlog/constants.py +313 -0
  13. mlog_py-0.8.1/mlog/decompiler/__init__.py +240 -0
  14. mlog_py-0.8.1/mlog/decompiler/cfg.py +363 -0
  15. mlog_py-0.8.1/mlog/decompiler/dataflow.py +994 -0
  16. mlog_py-0.8.1/mlog/decompiler/dsl_symbols.py +245 -0
  17. mlog_py-0.8.1/mlog/decompiler/errors.py +24 -0
  18. mlog_py-0.8.1/mlog/decompiler/expression.py +417 -0
  19. mlog_py-0.8.1/mlog/decompiler/function_analyzer.py +841 -0
  20. mlog_py-0.8.1/mlog/decompiler/function_ir.py +147 -0
  21. mlog_py-0.8.1/mlog/decompiler/instruction.py +117 -0
  22. mlog_py-0.8.1/mlog/decompiler/naming.py +303 -0
  23. mlog_py-0.8.1/mlog/decompiler/parser.py +197 -0
  24. mlog_py-0.8.1/mlog/decompiler/semantics.py +422 -0
  25. mlog_py-0.8.1/mlog/decompiler/sourcemap.py +473 -0
  26. mlog_py-0.8.1/mlog/decompiler/structured_ir.py +776 -0
  27. mlog_py-0.8.1/mlog/decompiler/structurer.py +879 -0
  28. mlog_py-0.8.1/mlog/emitter.py +92 -0
  29. mlog_py-0.8.1/mlog/errors.py +25 -0
  30. mlog_py-0.8.1/mlog/extract_registry.py +286 -0
  31. mlog_py-0.8.1/mlog/ir.py +87 -0
  32. mlog_py-0.8.1/mlog/metadata.py +3551 -0
  33. mlog_py-0.8.1/mlog/mindustry_discovery.py +748 -0
  34. mlog_py-0.8.1/mlog/mindustry_validator.py +744 -0
  35. mlog_py-0.8.1/mlog/mlog.py +3 -0
  36. mlog_py-0.8.1/mlog/mlog_registry.py +768 -0
  37. mlog_py-0.8.1/mlog/mlog_registry_data.py +65 -0
  38. mlog_py-0.8.1/mlog/optimizer.py +32 -0
  39. mlog_py-0.8.1/mlog/parser.py +661 -0
  40. mlog_py-0.8.1/mlog/py.typed +0 -0
  41. mlog_py-0.8.1/mlog/validator.py +218 -0
  42. mlog_py-0.8.1/mlog.pyi +2002 -0
  43. mlog_py-0.8.1/mlog_py.egg-info/PKG-INFO +388 -0
  44. mlog_py-0.8.1/mlog_py.egg-info/SOURCES.txt +113 -0
  45. mlog_py-0.8.1/mlog_py.egg-info/dependency_links.txt +1 -0
  46. mlog_py-0.8.1/mlog_py.egg-info/entry_points.txt +3 -0
  47. mlog_py-0.8.1/mlog_py.egg-info/top_level.txt +1 -0
  48. mlog_py-0.8.1/pyproject.toml +48 -0
  49. mlog_py-0.8.1/setup.cfg +4 -0
  50. mlog_py-0.8.1/src/mlog.pyi +2002 -0
  51. mlog_py-0.8.1/tests/test_agent_memory.py +103 -0
  52. mlog_py-0.8.1/tests/test_array.py +1068 -0
  53. mlog_py-0.8.1/tests/test_aug_assign.py +697 -0
  54. mlog_py-0.8.1/tests/test_bitwise_support.py +456 -0
  55. mlog_py-0.8.1/tests/test_builtins_and_properties.py +374 -0
  56. mlog_py-0.8.1/tests/test_cli_clipboard.py +447 -0
  57. mlog_py-0.8.1/tests/test_cli_decompile_stdin.py +250 -0
  58. mlog_py-0.8.1/tests/test_cli_functions.py +176 -0
  59. mlog_py-0.8.1/tests/test_comment_features.py +356 -0
  60. mlog_py-0.8.1/tests/test_comment_to_print.py +230 -0
  61. mlog_py-0.8.1/tests/test_compiler_examples.py +100 -0
  62. mlog_py-0.8.1/tests/test_constant_folding.py +562 -0
  63. mlog_py-0.8.1/tests/test_control_namespace.py +327 -0
  64. mlog_py-0.8.1/tests/test_corpus_hardening.py +312 -0
  65. mlog_py-0.8.1/tests/test_decompiler_control_flow_realworld.py +201 -0
  66. mlog_py-0.8.1/tests/test_decompiler_dataflow_alias.py +189 -0
  67. mlog_py-0.8.1/tests/test_decompiler_dest_var_recovery.py +326 -0
  68. mlog_py-0.8.1/tests/test_decompiler_examples.py +121 -0
  69. mlog_py-0.8.1/tests/test_decompiler_full_coverage.py +212 -0
  70. mlog_py-0.8.1/tests/test_decompiler_imports.py +233 -0
  71. mlog_py-0.8.1/tests/test_decompiler_loops.py +575 -0
  72. mlog_py-0.8.1/tests/test_decompiler_phase1.py +416 -0
  73. mlog_py-0.8.1/tests/test_decompiler_phase2.py +558 -0
  74. mlog_py-0.8.1/tests/test_decompiler_phase3.py +334 -0
  75. mlog_py-0.8.1/tests/test_decompiler_phase4.py +480 -0
  76. mlog_py-0.8.1/tests/test_decompiler_temporaries.py +385 -0
  77. mlog_py-0.8.1/tests/test_decompiler_ucontrol_aliases.py +115 -0
  78. mlog_py-0.8.1/tests/test_draw_clear.py +104 -0
  79. mlog_py-0.8.1/tests/test_draw_namespace.py +259 -0
  80. mlog_py-0.8.1/tests/test_for_loop.py +291 -0
  81. mlog_py-0.8.1/tests/test_fstring_formatting.py +289 -0
  82. mlog_py-0.8.1/tests/test_harness_classpath.py +807 -0
  83. mlog_py-0.8.1/tests/test_imports_and_stub.py +370 -0
  84. mlog_py-0.8.1/tests/test_int_enum.py +394 -0
  85. mlog_py-0.8.1/tests/test_memory_bank_header_protocol.py +330 -0
  86. mlog_py-0.8.1/tests/test_min_max_support.py +232 -0
  87. mlog_py-0.8.1/tests/test_modulo_semantics.py +405 -0
  88. mlog_py-0.8.1/tests/test_noop.py +309 -0
  89. mlog_py-0.8.1/tests/test_op_namespace.py +378 -0
  90. mlog_py-0.8.1/tests/test_packaging_and_wheel.py +359 -0
  91. mlog_py-0.8.1/tests/test_phase1a.py +113 -0
  92. mlog_py-0.8.1/tests/test_phase1b.py +81 -0
  93. mlog_py-0.8.1/tests/test_phase1c.py +137 -0
  94. mlog_py-0.8.1/tests/test_phase1d.py +118 -0
  95. mlog_py-0.8.1/tests/test_phase1e.py +133 -0
  96. mlog_py-0.8.1/tests/test_phase1f.py +393 -0
  97. mlog_py-0.8.1/tests/test_phase2_control_flow.py +248 -0
  98. mlog_py-0.8.1/tests/test_phase2_golden.py +126 -0
  99. mlog_py-0.8.1/tests/test_phase2_semantics.py +238 -0
  100. mlog_py-0.8.1/tests/test_print_buffer_semantics.py +614 -0
  101. mlog_py-0.8.1/tests/test_registry.py +421 -0
  102. mlog_py-0.8.1/tests/test_select_and_ternary.py +813 -0
  103. mlog_py-0.8.1/tests/test_semantic_argument_recovery.py +261 -0
  104. mlog_py-0.8.1/tests/test_source_mapping.py +596 -0
  105. mlog_py-0.8.1/tests/test_tier3_runtime.py +2649 -0
  106. mlog_py-0.8.1/tests/test_tier4_audio_markers_and_final.py +270 -0
  107. mlog_py-0.8.1/tests/test_tier4_combat_spawning.py +220 -0
  108. mlog_py-0.8.1/tests/test_tier4_messaging_and_cutscene.py +272 -0
  109. mlog_py-0.8.1/tests/test_tier4_rules_and_queries.py +279 -0
  110. mlog_py-0.8.1/tests/test_tier4_weather_and_effects.py +195 -0
  111. mlog_py-0.8.1/tests/test_tier4_world_state.py +218 -0
  112. mlog_py-0.8.1/tests/test_unit_namespace.py +504 -0
  113. mlog_py-0.8.1/tests/test_unpackcolor.py +313 -0
  114. mlog_py-0.8.1/tests/test_ux_and_cli_compile_stdin.py +353 -0
  115. mlog_py-0.8.1/tests/test_vars_api.py +425 -0
mlog_py-0.8.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anzuno
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include mlog/py.typed
2
+ recursive-include mlog *.pyi
3
+ include mlog.pyi
4
+ include src/mlog.pyi
mlog_py-0.8.1/PKG-INFO ADDED
@@ -0,0 +1,388 @@
1
+ Metadata-Version: 2.4
2
+ Name: mlog-py
3
+ Version: 0.8.1
4
+ Summary: Verified Python-to-Mindustry Logic (mlog) Compiler and Decompiler
5
+ Author-email: Anzuno <anzunonguyen@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/annguyen2k8/mlog-py
8
+ Project-URL: Repository, https://github.com/annguyen2k8/mlog-py
9
+ Project-URL: Issues, https://github.com/annguyen2k8/mlog-py/issues
10
+ Keywords: mindustry,mlog,compiler,decompiler,dsl
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Software Development :: Compilers
23
+ Classifier: Topic :: Software Development :: Code Generators
24
+ Classifier: Topic :: Software Development :: Disassemblers
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ # mlog-py: Python-to-Mindustry Logic (mlog) Compiler & Decompiler
31
+
32
+ A robust, verified compiler and decompiler suite connecting a strongly-typed subset of Python with vanilla Mindustry Logic (mlog).
33
+
34
+ ---
35
+
36
+ ## What is mlog-py?
37
+
38
+ In the strategy game **Mindustry**, logic processors execute low-level assembly-like instructions (`.mlog`) to automate factories, defense units, and reactors. Writing logic by hand in the in-game editor is tedious and prone to errors.
39
+
40
+ `mlog-py` bridges Python and Mindustry Logic in both directions:
41
+
42
+ - **Compile (Python DSL → MLog)**: Write loops, conditionals, expressions, and hardware controls in Python; compile directly to vanilla `.mlog` instructions ready to paste into any processor.
43
+ - **Decompile (MLog → Python DSL)**: Reverse-engineer existing in-game logic into clean, readable Python code with structured `if`/`while` blocks, math expressions, and functions.
44
+ - **Round-Trip Verification**: Decompiled Python code recompiles cleanly into valid, functionally identical MLog bytecode.
45
+ - **Strong Typing & IDE Stubs**: Full autocomplete, signature help, and inline documentation in VS Code and Pylance via `mlog.pyi`.
46
+
47
+ ---
48
+
49
+ ## Quick Start
50
+
51
+ ### Installation
52
+
53
+ From PyPI:
54
+
55
+ ```bash
56
+ pip install mlog-py
57
+ ```
58
+
59
+ From GitHub:
60
+
61
+ ```bash
62
+ pip install git+https://github.com/annguyen2k8/mlog-py.git
63
+ ```
64
+
65
+ From source:
66
+
67
+ ```bash
68
+ git clone https://github.com/annguyen2k8/mlog-py.git
69
+ cd mlog-py
70
+ pip install .
71
+ ```
72
+
73
+ ### 1. Compile Python to MLog
74
+
75
+ Use the `mlog compile` CLI (or `mlog-py compile` / `python -m mlog compile`):
76
+
77
+ ```bash
78
+ # Compile to stdout (auto-copies to clipboard by default)
79
+ mlog compile input.py
80
+
81
+ # Compile and save to file
82
+ mlog compile input.py -o output.mlog
83
+
84
+ # Shorthand (defaults to compile command)
85
+ mlog input.py -o output.mlog
86
+ ```
87
+
88
+ **Common Compiler Flags**:
89
+ - `-o, --output <file>`: Save compiled bytecode to a file instead of stdout.
90
+ - `--no-clipboard`: Disable automatic copying of compiled MLog to clipboard (auto-copy is enabled by default; overridable via `MLOG_NO_CLIPBOARD=1`).
91
+ - `--comments-to-print`: Convert Python `# comments` into runtime Mindustry `print` instructions.
92
+ - `--no-functions`: Reject `def` function definitions and `return` statements (functions are allowed by default).
93
+ - `--debug`: Print IR instructions, source locations, and resolved label addresses.
94
+
95
+ Or via Python API:
96
+
97
+ ```python
98
+ from mlog import compile_py
99
+
100
+ result = compile_py("set(x, 10)\nwait(1.0)\n")
101
+ print(result.mlog)
102
+ ```
103
+
104
+ ### 2. Decompile MLog to Python DSL
105
+
106
+ Use the `mlog decompile` CLI (or `mlog-py decompile` / `python -m mlog decompile`):
107
+
108
+ ```bash
109
+ # Decompile from file (prints to stdout, or use -o to save)
110
+ mlog decompile input.mlog -o output.py
111
+
112
+ # Stream / piped input from stdin
113
+ cat input.mlog | mlog decompile
114
+ mlog decompile - < input.mlog
115
+
116
+ # Interactive paste in terminal (finish with Ctrl+D or type 'EOF' on an empty line)
117
+ mlog decompile
118
+ ```
119
+
120
+ **Common Decompiler Flags**:
121
+ - `-o, --output <file>`: Output Python file path (`.py`). Prints to stdout if omitted (or prompts interactively in paste mode).
122
+ - `--debug`: Include instruction provenance comments (`# mlog[<addr>]`).
123
+ - **Dataflow Simplification** *(built-in)*: Expression inlining, constant folding, and alias elimination are performed automatically by default.
124
+
125
+ Or via Python API:
126
+
127
+ ```python
128
+ from mlog import decompile, decompile_with_source_map
129
+
130
+ mlog_code = """
131
+ sensor heat reactor1 @heat
132
+ jump 4 lessThanEq heat 0.5
133
+ control enabled reactor1 0 0 0 0
134
+ jump 5 always 0 0
135
+ control enabled reactor1 1 0 0 0
136
+ wait 0.5
137
+ """
138
+
139
+ # Decompile to structured Python DSL
140
+ py_code = decompile(mlog_code)
141
+ print(py_code)
142
+
143
+ # Decompile with debug comments showing bytecode provenance addresses
144
+ debug_code = decompile(mlog_code, debug=True)
145
+ print(debug_code)
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Example: Reactor Safety Controller
151
+
152
+ A complete round-trip example protecting a Thorium reactor from overheating:
153
+
154
+ ### 1. Python Source (`examples/compiler/reactor_safety.py`)
155
+
156
+ ```python
157
+ from mlog import sensor, control, wait, SensorProperty, ControlProperty
158
+
159
+ heat = sensor("reactor1", SensorProperty.HEAT)
160
+
161
+ if heat > 0.5:
162
+ control(ControlProperty.ENABLED, "reactor1", 0)
163
+ else:
164
+ control(ControlProperty.ENABLED, "reactor1", 1)
165
+
166
+ wait(0.5)
167
+ ```
168
+
169
+ ### 2. Compile to MLog
170
+
171
+ ```bash
172
+ mlog-py compile examples/compiler/reactor_safety.py
173
+ ```
174
+
175
+ Resulting MLog bytecode (`examples/compiler/reactor_safety.mlog`):
176
+
177
+ ```text
178
+ sensor heat reactor1 @heat
179
+ jump 4 lessThanEq heat 0.5
180
+ control enabled reactor1 0 0 0 0
181
+ jump 5 always 0 0
182
+ control enabled reactor1 1 0 0 0
183
+ wait 0.5
184
+ ```
185
+
186
+ ### 3. Decompile Back to Python DSL
187
+
188
+ ```bash
189
+ mlog-py decompile examples/compiler/reactor_safety.mlog
190
+ ```
191
+
192
+ Resulting decompiled Python DSL (`examples/decompiler/reactor_safety.py`):
193
+
194
+ ```python
195
+ from mlog import control, sensor, wait
196
+
197
+ heat = sensor("reactor1", '@heat')
198
+ if heat > 0.5:
199
+ control.enabled("reactor1", 0)
200
+ else:
201
+ control.enabled("reactor1", 1)
202
+ wait(0.5)
203
+ ```
204
+
205
+ > [!NOTE]
206
+ > Decompilation recovers a **semantically equivalent** structured program rather than an exact character-for-character reconstruction of the original source. For instance, the decompiler automatically discovers minimal imports and recovers idiomatic method aliases such as `control.enabled(...)`.
207
+
208
+ ### 4. Load into Mindustry
209
+
210
+ 1. Copy the compiled `.mlog` content to your clipboard.
211
+ 2. In Mindustry, build a logic processor (Micro, Logic, or Hyper Processor) and link it to the reactor (`reactor1`).
212
+ 3. Click the processor, choose **Edit**, then select **Import from clipboard**.
213
+
214
+ ---
215
+
216
+ ## Example Catalog
217
+
218
+ Explore complete paired examples in [`examples/`](examples/README.md):
219
+
220
+ - **Arithmetic & Bitwise**: [`arithmetic.py`](examples/compiler/arithmetic.py), [`bitwise.py`](examples/compiler/bitwise.py), [`min_max.py`](examples/compiler/min_max.py)
221
+ - **Control Flow**: [`for_loop.py`](examples/compiler/for_loop.py), [`while_loop.py`](examples/compiler/while_loop.py), [`conditionals.py`](examples/compiler/conditionals.py), [`nested_loops.py`](examples/compiler/nested_loops.py)
222
+ - **Hardware Interaction**: [`reactor_safety.py`](examples/compiler/reactor_safety.py), [`display_graphics.py`](examples/compiler/display_graphics.py), [`print_message.py`](examples/compiler/print_message.py), [`memory_cell.py`](examples/compiler/memory_cell.py), [`array_memory.py`](examples/compiler/array_memory.py)
223
+ - **Unit Operations (Canonical Unit APIs)**: [`unit_operations.py`](examples/compiler/unit_operations.py)
224
+ - **Interactive Demos**: [`roundtrip_demo.py`](examples/compiler/roundtrip_demo.py), [`roundtrip_verify.py`](examples/decompiler/roundtrip_verify.py)
225
+
226
+ ---
227
+
228
+ ## Key Features
229
+
230
+ - **Structured Control Flow**: Full support for `for` loops with `range(...)`, `while`, `break`, `continue`, `if`, `elif`, and `else` with automatic label and instruction address resolution.
231
+ - **Arithmetic, Bitwise & Math**: Full expression support (`+`, `-`, `*`, `/`, `//`, `%`, bitwise `&`, `|`, `^`, `~`, `<<`, `>>`, built-in `min` and `max`) lowered with deterministic temporary variable management and strict 64-bit integer hardening.
232
+ - **Compile-Time Constant Folding**: Recursively folds pure constant expressions (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `&`, `|`, `^`, `<<`, `>>`, comparisons, boolean logic, and string concatenation) at compile time while preserving Mindustry IEEE-754 runtime semantics, eliminating runtime temporaries, and statically resolving `Array` allocation sizes and subscript bounds checks.
233
+ - **Conditional Selection & Python Ternary**: Pure ternary expressions (`a if cond else b`) lower directly to the Mindustry `select dest op comp0 comp1 a b` opcode (zero jumps). Expressions with side effects, division, or memory access safely fall back to short-circuiting jump ladders. Full intrinsic `select()` supports 3, 4, 5, and 6-argument conventions.
234
+ - **Color Operations (`packcolor`, `unpackcolor`)**: Pack 4 RGBA channels in `[0, 1]` into a 64-bit double color (`packcolor(r, g, b, a)` with full expression nesting), and unpack double colors into 4 destination variables (`unpackcolor(r, g, b, a, color)` or the equivalent tuple form `r, g, b, a = unpackcolor(color)`).
235
+ - **Character Output, Print Formatting & f-Strings**: Low-level character/emoji output via `printchar(val)`, print buffer placeholder substitution via `format(val)`, and native Python f-strings (`f"..."`) automatically compiled into optimized template print and format sequences with strict evaluation order preservation.
236
+ - **Processor Execution Rate (`setrate`)**: Direct configuration of processor instructions per tick (IPT) via `setrate(ipt)`.
237
+ - **Memory Arrays & Static Allocation**: High-level `Array("cell1", size=10, dtype=...)` abstraction supporting `int`, `float`, and `bool` dtypes with compile-time contiguous layout tracking, capacity validation (64 for cells, 512 for banks), base offset calculations, and static index bounds checking.
238
+ - **Augmented Assignment**: In-place assignment operators (`+=`, `-=`, `*=`, `/=`, `//=`, `%=`, `**=`, `&=`, `|=`, `^=`, `<<=`, `>>=`) for both scalar variables and memory arrays (`arr[i] += val`), featuring atomic single-offset address evaluation without redundant reads.
239
+ - **Short-Circuit Boolean Logic**: Full support for `and`, `or`, and `not` with standard Python short-circuit evaluation.
240
+ - **Mindustry Compiler Intrinsics**: Direct access to Mindustry instructions (`sensor`, `control`, `ucontrol`, `draw`, `read`, `write`, `print`, `ubind`, `lookup`, `packcolor`, `unpackcolor`, `printchar`, `format`, `setrate`, `select`, etc.).
241
+ - **Display & Graphics API**: Complete support for `draw` instructions, including `draw.clear(r=0, g=0, b=0, a=0)` (DSL accepts 0 to 4 arguments for color compatibility; compiles to canonical Mindustry RGB `draw clear r g b 0 0 0`), shape drawing, affine transforms, and `drawflush`.
242
+ - **Advanced Decompiler Control Flow**: Deterministic reconstruction of top-tested while loops with inlined temporaries, bottom-tested loops (`do-while`), nested loops, loop-scoped `break`/`continue`, loop invariant protection, and canonical method aliases (`ucontrol.<method>`, `draw.<method>`).
243
+ - **Comments to Print Buffer**: Compile-time `--comments-to-print` flag converting Python `# comments` directly into Mindustry `print` instructions.
244
+ - **Verified Registry & Enums**: Enums (`SensorProperty`, `ControlProperty`, `UnitControl`, `DrawType`, `LogicOp`, `Condition`, `Units`, etc.) verified against vanilla Mindustry source.
245
+ - **Source Mapping**: Bi-directional provenance tracking between Python statements and mlog instruction addresses.
246
+ - **Semantic Argument Recovery**: Disambiguates named hardware links (quoted strings like `"reactor1"`) from program variables during decompilation.
247
+ - **Safe Zero Guessing Fallback**: Unstructured jumps, computed jump counters, and irreducible loops fall back safely to `UnstructuredNode` comments rather than speculative loops.
248
+ - **VS Code / Pylance Stubs**: Official `from mlog import ...` entry point backed by comprehensive typing stubs (`mlog.pyi`).
249
+
250
+ ---
251
+
252
+ ## Architecture
253
+
254
+ ```text
255
+ Compilation: Python DSL ──► AST Lowering ──► IR ──► Address Resolution ──► MLog Bytecode
256
+ Decompilation: MLog Bytecode ──► CFG Rebuild ──► Structurer & Dataflow ──► Python DSL
257
+ ```
258
+
259
+ Detailed architectural specifications:
260
+
261
+ - [Unified System Architecture](docs/architecture.md)
262
+ - [Compiler Pipeline & Lowering](docs/compiler.md)
263
+ - [Decompiler Pipeline & Structuring](docs/decompiler.md)
264
+
265
+ ---
266
+
267
+ ## Project Structure
268
+
269
+ ```text
270
+ mlog-py/
271
+ ├── AGENTS.md # Shared agent instructions and memory protocol
272
+ ├── .agents/memory/ # Project context and task handoff
273
+ ├── compiler.py # Standalone CLI entry point
274
+ ├── mlog/ # Canonical package (PEP 561, DSL, compiler, decompiler)
275
+ │ ├── __init__.py # Public API exports (compile_py, decompile, intrinsics)
276
+ │ ├── __main__.py # CLI runner (python -m mlog)
277
+ │ ├── py.typed # PEP 561 typing marker
278
+ │ ├── compiler.py # AST -> IR lowering
279
+ │ ├── emitter.py # Two-pass address resolution
280
+ │ ├── metadata.py # Single Source of Truth (SSOT)
281
+ │ └── decompiler/ # Decompiler pipeline (CFG, structurer, dataflow)
282
+ ├── src/ # Backward-compatibility import shim
283
+ ├── pyproject.toml # Package metadata and build configuration
284
+ ├── docs/ # Technical documentation and specifications
285
+ ├── examples/ # Paired compiler and decompiler examples
286
+ └── tests/ # Automated test suite and corpus
287
+ ```
288
+
289
+ ---
290
+
291
+ ## Testing & Verification
292
+
293
+ The project maintains a comprehensive automated test suite verifying both compiler and decompiler across a 3-tier verification architecture:
294
+
295
+ - **Tier 1 (AST & Semantics)**: Python AST parsing, type constraints, and semantic argument validation.
296
+ - **Tier 2 (Bytecode & Round-Trip)**: Assembler/disassembler equivalence and invariance under the `MLog → Python → MLog` round-trip.
297
+ - **Tier 3 (Runtime JVM Mindustry v160.7)**: Direct execution on official Mindustry bytecode engine (`LExecutor` + `LAssembler`), verifying variable registers, print buffer states, hardware interactions, and edge cases.
298
+
299
+ ```bash
300
+ # Run entire test suite (using persistent Mindustry JVM daemon ~50-80s)
301
+ python3 run_tests.py --all
302
+
303
+ # Run fast tier (Pure Python: AST, Compiler, Decompiler, IR ~13s)
304
+ python3 run_tests.py --fast
305
+
306
+ # Run JVM tier (Real Mindustry runtime ~70s)
307
+ python3 run_tests.py --jvm
308
+
309
+ # Standard unittest command is also fully supported
310
+ python3 -m unittest discover -s tests -p "test_*.py"
311
+ ```
312
+
313
+ The JVM harness is auto-discovered from `Mindustry`/`Mindustry-source` and `Arc` checkouts (including local `build/libs` and the Gradle cache). Build it once with `python3 tools/build_harness.py --test`; explicit paths can be supplied through `MINDUSTRY_CORE_PATH`, `ARC_JARS_PATH`, `MINDUSTRY_HARNESS_BUILD`, and `MINDUSTRY_ASSETS_PATH`, or through a `.mindustry.json` config file. When a dependency is missing, JVM tests skip with the specific reason.
314
+
315
+ Agents working in this repository should read [`AGENTS.md`](AGENTS.md) and [`.agents/memory/handoff.md`](.agents/memory/handoff.md) before starting. See [Shared Agent Memory and Handoff](docs/agent-memory.md) for the workflow.
316
+
317
+ - **1,300+ Automated Tests**: 100% passing baseline across compiler, decompiler, registry, CFG, structuring, dataflow, function recovery, bitwise operators, min/max, for loops, memory arrays (int, float, bool), Memory Bank Header Protocol (inter-processor communication layout), Callable Namespace Objects (`draw.<method>`, `ucontrol.<method>`, `ulocate.<method>`, `op.<method>`), augmented assignment, constant folding, system clipboard, built-in variables (Vars API), Mindustry v8 modulo semantics, color packing/unpacking, printchar, format & f-strings, setrate, select & ternary expressions, comprehensive `is`/`is not` semantics, all 25 World Processor privileged statements, CLI stdin/paste decompile, user-defined `enum.IntEnum` named constants, source mapping, and real JVM runtime verification.
318
+ - **Real-World Test Corpus**: 32 representative programs across handwritten scripts, compiler-generated programs, control flow patterns, and pathological edge cases.
319
+ - **Round-Trip Verification**: Guarantees that `MLog → Decompiler → Compiler` produces valid, functionally equivalent instructions.
320
+
321
+ ### Mindustry v160.7 Tier 3 Runtime Scorecard (28/28 Opcodes — 100%)
322
+
323
+ | Group | Opcode List | Tier 3 Status | Runtime Semantics Verified in Real Engine |
324
+ | :--- | :--- | :---: | :--- |
325
+ | **A: Core & Control** (9) | `select`, `packcolor`, `unpackcolor`, `noop`, `set`, `op`, `jump`, `stop`, `end` | **VERIFIED** | Conditional branching, RGBA color pack/unpack, cycle halt (`stop`), cycle reset (`end`), division by zero propagation (`null`), all arithmetic and comparison operators |
326
+ | **B: Text & Buffer** (4) | `print`, `printchar`, `format`, `printflush` | **VERIFIED** | String concatenation, 400-char buffer limit, unicode/surrogate characters, template format placeholder substitution, message block flush and buffer reset |
327
+ | **C: Timing & Rate** (2) | `wait`, `setrate` | **VERIFIED** | Virtual Clock tick scheduler, IPT execution rate clamping ([1, 120] micro/logic, [1, 1500] hyper, [1, 8000] world), zero/negative duration yield |
328
+ | **D: Hardware & Data** (6) | `read`, `write`, `getlink`, `sensor`, `radar`, `lookup` | **VERIFIED** | Memory Cell (64) & Bank (512) read/write, string character code extraction, game content table lookup, turret radar unit scanning, building property sensing, null/dead target safety |
329
+ | **E: Graphics & Units** (7) | `draw`, `drawflush`, `control`, `ubind`, `ucontrol`, `uradar`, `ulocate` | **VERIFIED** | Display draw command buffer, building enable/disable toggle via control, round-robin unit cycling, coordinate distance check (`within`), unit radar target acquisition, core/ore locating |
330
+
331
+ ---
332
+
333
+ ## Limitations
334
+
335
+ ### Mindustry Platform Constraints
336
+
337
+ - **Flat Memory Model**: Mindustry processors operate on flat registers and hardware memory blocks (Cell/Bank), with no heap, dynamic memory allocation, or garbage collector. Arbitrary Python objects, dynamic classes, and heap collections (`list`, `dict`, `set`) cannot be instantiated at runtime; use fixed-size hardware `Array` instances instead.
338
+ - **Identity Semantics (`is` vs `strictEqual`)**: Python `is` compares heap identity (`id(a) == id(b)`), whereas Mindustry Logic has no heap object model. The compiler maps `is` to Mindustry `strictEqual` (`===`), which checks runtime type category (double vs object) and exact value without float epsilon tolerance. Because Mindustry represents booleans as numeric `1.0`/`0.0`, `True is 1` evaluates to true in compiled logic, whereas Python treats `True` and `1` as distinct types. For `is not`, the compiler uses inverted `strictEqual` checks to avoid Mindustry's engine quirk where `0 != null` evaluates to false.
339
+ - **World Processor Privilege Requirements**: All 25 World Processor privileged statements (`query`, `getblock`, `setblock`, `spawn`, `bullet`, `status`, `explosion`, `setrule`, `getflag`, `setflag`, `setprop`, `fetch`, `sync`, `weathersense`, `weatherset`, `spawnwave`, `effect`, `message`, `cutscene`, `playsound`, `playmusic`, `makemarker`, `setmarker`, `localeprint`, `clientdata`) are supported for custom map scripting. However, standard survival processors (Micro, Logic, Hyper) reject them as `InvalidStatement` at runtime; they require a World Processor (`#processor: world`).
340
+
341
+ ### Compiler & Decompiler Constraints
342
+
343
+ - **Irreducible Control Flow**: Non-natural loops, computed jumps, and indirect counter manipulation (`set @counter ...`) cannot be restructured into natural Python `while` loops. The decompiler preserves these via explicit `jump(...)` fallback nodes to guarantee execution equivalence.
344
+ - **Multi-Use Temporaries**: Compiler temporaries that are read multiple times or cross side-effecting operations (such as memory `read` feeding `write`) are not inlined into compound expressions. They are retained as explicit assignments (`tmp_val_N = ...`) to prevent reordering or duplicate side effects.
345
+
346
+ ---
347
+
348
+ ## Technical Documentation
349
+
350
+ Detailed architecture specifications are available in [`docs/`](docs/):
351
+
352
+ - [Architecture Overview](docs/architecture.md): End-to-end compiler and decompiler architecture.
353
+ - [Compiler Specification](docs/compiler.md): AST lowering, IR instructions, and label resolution.
354
+ - [Decompiler Specification](docs/decompiler.md): CFG reconstruction, structuring, and function recovery.
355
+ - [Semantic Argument Recovery](docs/semantic-arguments.md): Hardware link detection and quoting rules.
356
+ - [Source Mapping](docs/source-mapping.md): Provenance tracking, debug comments, and JSON export.
357
+ - [Mindustry Logic Command Coverage](docs/mlog-command-coverage.md): Comprehensive mapping of 53 in-game UI commands and 28 standard opcodes in Mindustry v160.7.
358
+ - [ADR-001: Modulo Operator Semantics](docs/adr/0001-modulo-semantics.md): Architectural decision on lowering `%` to `emod`.
359
+ - [ADR-002: Shared Agent Memory](docs/adr/0002-shared-agent-memory.md): Filesystem Markdown memory and handoff for Antigravity and OpenCode.
360
+ - [Shared Agent Memory and Handoff](docs/agent-memory.md): Setup, workflow, and verified limits for the shared memory files.
361
+ - [Upstream Mindustry Sync Guide](docs/mindustry-updates.md): Guide for updating and syncing mlog-py when new Mindustry versions release.
362
+
363
+ ---
364
+
365
+ ## Release & Publishing
366
+
367
+ The project uses GitHub Actions with **PyPI Trusted Publishing (OIDC)** to automatically build, verify, and publish packages when a GitHub Release is published (`release: published`).
368
+
369
+ ### PyPI Trusted Publisher Configuration
370
+
371
+ To configure Trusted Publishing on PyPI:
372
+
373
+ 1. Log in to [PyPI](https://pypi.org/) and navigate to **Publishing** -> **Add a publisher** (or project settings if already registered).
374
+ 2. Select **GitHub**.
375
+ 3. Set the following publisher details:
376
+ - **PyPI Project Name**: `mlog-py`
377
+ - **Owner / Organization**: `annguyen2k8`
378
+ - **Repository name**: `mlog-py`
379
+ - **Workflow name**: `publish.yml`
380
+ - **Environment name**: `pypi`
381
+ 4. On GitHub, navigate to **Settings** -> **Environments** and create an environment named `pypi` (matching the environment configured on PyPI).
382
+ 5. When creating a GitHub Release, the `.github/workflows/publish.yml` workflow will automatically trigger, build the sdist/wheel, verify package integrity with `twine` and `check-wheel-contents`, and publish to PyPI using short-lived OIDC tokens without storing API keys or passwords in repository secrets.
383
+
384
+ ---
385
+
386
+ ## License
387
+
388
+ This project is licensed under the [MIT License](LICENSE).