mimo-lang 1.1.1 → 2.0.6

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 (165) hide show
  1. package/.gitattributes +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +71 -39
  4. package/adapters/browserAdapter.js +86 -0
  5. package/adapters/nodeAdapter.js +101 -0
  6. package/bin/cli.js +80 -0
  7. package/bin/commands/convert.js +27 -0
  8. package/bin/commands/doctor.js +139 -0
  9. package/bin/commands/eval.js +39 -0
  10. package/bin/commands/fmt.js +109 -0
  11. package/bin/commands/help.js +72 -0
  12. package/bin/commands/lint.js +117 -0
  13. package/bin/commands/repl.js +24 -0
  14. package/bin/commands/run.js +64 -0
  15. package/bin/commands/test.js +126 -0
  16. package/bin/utils/colors.js +38 -0
  17. package/bin/utils/formatError.js +47 -0
  18. package/bin/utils/fs.js +57 -0
  19. package/bin/utils/version.js +8 -0
  20. package/build.js +18 -0
  21. package/bun.lock +74 -0
  22. package/index.js +48 -77
  23. package/index.web.js +364 -0
  24. package/interpreter/BuiltinFunction.js +32 -0
  25. package/interpreter/ErrorHandler.js +120 -0
  26. package/interpreter/ExpressionEvaluator.js +106 -0
  27. package/interpreter/Interpreter.js +172 -0
  28. package/interpreter/MimoError.js +112 -0
  29. package/interpreter/ModuleLoader.js +236 -0
  30. package/interpreter/StatementExecutor.js +107 -0
  31. package/interpreter/Utils.js +82 -0
  32. package/interpreter/Values.js +87 -0
  33. package/interpreter/coreBuiltins.js +490 -0
  34. package/interpreter/environment.js +99 -0
  35. package/interpreter/evaluators/binaryExpressionEvaluator.js +111 -0
  36. package/interpreter/evaluators/collectionEvaluator.js +151 -0
  37. package/interpreter/evaluators/functionCallEvaluator.js +76 -0
  38. package/interpreter/evaluators/literalEvaluator.js +27 -0
  39. package/interpreter/evaluators/moduleAccessEvaluator.js +25 -0
  40. package/interpreter/evaluators/templateLiteralEvaluator.js +20 -0
  41. package/interpreter/executors/BaseExecutor.js +37 -0
  42. package/interpreter/executors/ControlFlowExecutor.js +206 -0
  43. package/interpreter/executors/FunctionExecutor.js +126 -0
  44. package/interpreter/executors/PatternMatchExecutor.js +93 -0
  45. package/interpreter/executors/VariableExecutor.js +144 -0
  46. package/interpreter/index.js +8 -0
  47. package/interpreter/stdlib/array/accessFunctions.js +61 -0
  48. package/interpreter/stdlib/array/arrayUtils.js +36 -0
  49. package/interpreter/stdlib/array/higherOrderFunctions.js +285 -0
  50. package/interpreter/stdlib/array/searchFunctions.js +77 -0
  51. package/interpreter/stdlib/array/setFunctions.js +49 -0
  52. package/interpreter/stdlib/array/transformationFunctions.js +68 -0
  53. package/interpreter/stdlib/array.js +85 -0
  54. package/interpreter/stdlib/assert.js +143 -0
  55. package/interpreter/stdlib/datetime.js +170 -0
  56. package/interpreter/stdlib/env.js +54 -0
  57. package/interpreter/stdlib/fs.js +161 -0
  58. package/interpreter/stdlib/http.js +92 -0
  59. package/interpreter/stdlib/json.js +70 -0
  60. package/interpreter/stdlib/math.js +309 -0
  61. package/interpreter/stdlib/object.js +142 -0
  62. package/interpreter/stdlib/path.js +69 -0
  63. package/interpreter/stdlib/regex.js +134 -0
  64. package/interpreter/stdlib/string.js +260 -0
  65. package/interpreter/suggestions.js +46 -0
  66. package/lexer/Lexer.js +245 -0
  67. package/lexer/TokenTypes.js +131 -0
  68. package/lexer/createToken.js +11 -0
  69. package/lexer/tokenizers/commentTokenizer.js +45 -0
  70. package/lexer/tokenizers/literalTokenizer.js +163 -0
  71. package/lexer/tokenizers/symbolTokenizer.js +69 -0
  72. package/lexer/tokenizers/whitespaceTokenizer.js +36 -0
  73. package/package.json +29 -13
  74. package/parser/ASTNodes.js +448 -0
  75. package/parser/Parser.js +188 -0
  76. package/parser/expressions/atomicExpressions.js +165 -0
  77. package/parser/expressions/conditionalExpressions.js +0 -0
  78. package/parser/expressions/operatorExpressions.js +79 -0
  79. package/parser/expressions/primaryExpressions.js +77 -0
  80. package/parser/parseStatement.js +184 -0
  81. package/parser/parserExpressions.js +115 -0
  82. package/parser/parserUtils.js +19 -0
  83. package/parser/statements/controlFlowParsers.js +106 -0
  84. package/parser/statements/functionParsers.js +314 -0
  85. package/parser/statements/moduleParsers.js +57 -0
  86. package/parser/statements/patternMatchParsers.js +124 -0
  87. package/parser/statements/variableParsers.js +155 -0
  88. package/repl.js +325 -0
  89. package/test.js +47 -0
  90. package/tools/PrettyPrinter.js +3 -0
  91. package/tools/convert/Args.js +46 -0
  92. package/tools/convert/Registry.js +91 -0
  93. package/tools/convert/Transpiler.js +78 -0
  94. package/tools/convert/plugins/README.md +66 -0
  95. package/tools/convert/plugins/alya/index.js +10 -0
  96. package/tools/convert/plugins/alya/to_alya.js +289 -0
  97. package/tools/convert/plugins/alya/visitors/expressions.js +257 -0
  98. package/tools/convert/plugins/alya/visitors/statements.js +403 -0
  99. package/tools/convert/plugins/base_converter.js +228 -0
  100. package/tools/convert/plugins/javascript/index.js +10 -0
  101. package/tools/convert/plugins/javascript/mimo_runtime.js +265 -0
  102. package/tools/convert/plugins/javascript/to_js.js +155 -0
  103. package/tools/convert/plugins/javascript/visitors/expressions.js +197 -0
  104. package/tools/convert/plugins/javascript/visitors/patterns.js +102 -0
  105. package/tools/convert/plugins/javascript/visitors/statements.js +236 -0
  106. package/tools/convert/plugins/python/index.js +10 -0
  107. package/tools/convert/plugins/python/mimo_runtime.py +811 -0
  108. package/tools/convert/plugins/python/to_py.js +329 -0
  109. package/tools/convert/plugins/python/visitors/expressions.js +272 -0
  110. package/tools/convert/plugins/python/visitors/patterns.js +100 -0
  111. package/tools/convert/plugins/python/visitors/statements.js +257 -0
  112. package/tools/convert.js +102 -0
  113. package/tools/format/CommentAttacher.js +190 -0
  114. package/tools/format/CommentLexer.js +152 -0
  115. package/tools/format/Printer.js +849 -0
  116. package/tools/format/config.js +107 -0
  117. package/tools/formatter.js +169 -0
  118. package/tools/lint/Linter.js +391 -0
  119. package/tools/lint/config.js +114 -0
  120. package/tools/lint/rules/consistent-return.js +62 -0
  121. package/tools/lint/rules/max-depth.js +56 -0
  122. package/tools/lint/rules/no-empty-function.js +45 -0
  123. package/tools/lint/rules/no-magic-numbers.js +46 -0
  124. package/tools/lint/rules/no-shadow.js +113 -0
  125. package/tools/lint/rules/no-unused-vars.js +26 -0
  126. package/tools/lint/rules/prefer-const.js +19 -0
  127. package/tools/linter.js +261 -0
  128. package/tools/replFormatter.js +93 -0
  129. package/tools/stamp-version.js +32 -0
  130. package/web/index.js +9 -0
  131. package/bun.lockb +0 -0
  132. package/cli.js +0 -84
  133. package/compiler/execute/interpreter.js +0 -68
  134. package/compiler/execute/interpreters/binary.js +0 -12
  135. package/compiler/execute/interpreters/call.js +0 -10
  136. package/compiler/execute/interpreters/if.js +0 -10
  137. package/compiler/execute/interpreters/try-catch.js +0 -10
  138. package/compiler/execute/interpreters/while.js +0 -8
  139. package/compiler/execute/utils/createfunction.js +0 -11
  140. package/compiler/execute/utils/evaluate.js +0 -20
  141. package/compiler/execute/utils/operate.js +0 -23
  142. package/compiler/lexer/processToken.js +0 -40
  143. package/compiler/lexer/tokenTypes.js +0 -4
  144. package/compiler/lexer/tokenizer.js +0 -74
  145. package/compiler/parser/expression/comparison.js +0 -18
  146. package/compiler/parser/expression/identifier.js +0 -29
  147. package/compiler/parser/expression/number.js +0 -10
  148. package/compiler/parser/expression/operator.js +0 -21
  149. package/compiler/parser/expression/punctuation.js +0 -31
  150. package/compiler/parser/expression/string.js +0 -6
  151. package/compiler/parser/parseExpression.js +0 -27
  152. package/compiler/parser/parseStatement.js +0 -34
  153. package/compiler/parser/parser.js +0 -45
  154. package/compiler/parser/statement/call.js +0 -26
  155. package/compiler/parser/statement/function.js +0 -29
  156. package/compiler/parser/statement/if.js +0 -34
  157. package/compiler/parser/statement/return.js +0 -10
  158. package/compiler/parser/statement/set.js +0 -11
  159. package/compiler/parser/statement/show.js +0 -10
  160. package/compiler/parser/statement/try-catch.js +0 -25
  161. package/compiler/parser/statement/while.js +0 -22
  162. package/converter/go/convert.js +0 -110
  163. package/converter/js/convert.js +0 -107
  164. package/jsconfig.json +0 -27
  165. package/vite.config.js +0 -17
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Expression visitors for the Mimo → JavaScript converter.
3
+ * Mixed into MimoToJsConverter via Object.assign.
4
+ */
5
+ export const expressionVisitors = {
6
+ visitBinaryExpression(node) {
7
+ const opMap = { '=': '===', '!=': '!==', '!': '!==', and: '&&', or: '||' };
8
+ const jsOp = opMap[node.operator] || node.operator;
9
+ this.write('(');
10
+ this.visitNode(node.left);
11
+ this.write(` ${jsOp} `);
12
+ this.visitNode(node.right);
13
+ this.write(')');
14
+ },
15
+
16
+ visitUnaryExpression(node) {
17
+ const opMap = { not: '!' };
18
+ const jsOp = opMap[node.operator] || node.operator;
19
+ this.write(`(${jsOp}`);
20
+ this.visitNode(node.argument);
21
+ this.write(')');
22
+ },
23
+
24
+ visitInlineIfExpression(node) {
25
+ // if cond then a else b → (cond ? a : b)
26
+ this.write('(');
27
+ this.visitNode(node.condition);
28
+ this.write(' ? ');
29
+ this.visitNode(node.consequent);
30
+ this.write(' : ');
31
+ this.visitNode(node.alternate);
32
+ this.write(')');
33
+ },
34
+
35
+ visitPipeExpression(node) {
36
+ // value |> callee(extraArgs) → callee(value, extraArgs)
37
+ // value |> if cond then f else g → (cond ? f : g)(value)
38
+ const callee = node.callee;
39
+ const extraArgs = node.args || [];
40
+
41
+ if (!callee) {
42
+ this.visitNode(node.left);
43
+ return;
44
+ }
45
+
46
+ if (callee.type === 'InlineIfExpression') {
47
+ this.write('(');
48
+ this.visitNode(callee.condition);
49
+ this.write(' ? ');
50
+ this.visitNode(callee.consequent);
51
+ this.write(' : ');
52
+ this.visitNode(callee.alternate);
53
+ this.write(')(');
54
+ this.visitNode(node.left);
55
+ this.write(')');
56
+ } else {
57
+ this.visitNode(callee);
58
+ this.write('(');
59
+ this.visitNode(node.left);
60
+ if (extraArgs.length > 0) {
61
+ this.write(', ');
62
+ this.emitArgs(extraArgs);
63
+ }
64
+ this.write(')');
65
+ }
66
+ },
67
+
68
+ visitIdentifier(node) {
69
+ this.write(node.name);
70
+ },
71
+
72
+ visitLiteral(node) {
73
+ this.write(JSON.stringify(node.value));
74
+ },
75
+
76
+ visitArrayLiteral(node) {
77
+ this.write('[');
78
+ node.elements.forEach((el, i) => {
79
+ if (el.type === 'SpreadElement') {
80
+ this.emitSpread(el);
81
+ } else {
82
+ this.visitNode(el);
83
+ }
84
+ if (i < node.elements.length - 1) this.write(', ');
85
+ });
86
+ this.write(']');
87
+ },
88
+
89
+ visitObjectLiteral(node) {
90
+ this.write('({');
91
+ node.properties.forEach((prop, i) => {
92
+ if (prop.type === 'SpreadElement') {
93
+ this.write('...');
94
+ this.visitNode(prop.argument);
95
+ } else {
96
+ this.write(`${JSON.stringify(prop.key)}: `);
97
+ this.visitNode(prop.value);
98
+ }
99
+ if (i < node.properties.length - 1) this.write(', ');
100
+ });
101
+ this.write('})');
102
+ },
103
+
104
+ visitTemplateLiteral(node) {
105
+ this.write('`');
106
+ node.parts.forEach((part) => {
107
+ if (part.type === 'Literal') {
108
+ this.write(this.escapeForTemplateLiteral(String(part.value)));
109
+ } else {
110
+ this.write('${');
111
+ this.visitNode(part);
112
+ this.write('}');
113
+ }
114
+ });
115
+ this.write('`');
116
+ },
117
+
118
+ visitRangeLiteral(node) {
119
+ this.write('mimo.range(');
120
+ this.visitNode(node.start);
121
+ this.write(', ');
122
+ this.visitNode(node.end);
123
+ this.write(')');
124
+ },
125
+
126
+ visitAnonymousFunction(node) {
127
+ this.enterScope();
128
+
129
+ const defaults = node.defaults || {};
130
+ const paramParts = (node.params || []).map((p) => {
131
+ this.declareVariable(p.name);
132
+ const defaultNode = defaults[p.name];
133
+ if (defaultNode !== undefined && defaultNode !== null) {
134
+ return `${p.name} = ${this._exprToString(defaultNode)}`;
135
+ }
136
+ return p.name;
137
+ });
138
+ if (node.restParam) {
139
+ this.declareVariable(node.restParam.name);
140
+ paramParts.push(`...${node.restParam.name}`);
141
+ }
142
+
143
+ this.write(`(${paramParts.join(', ')}) => {\n`);
144
+ this.visitBlock(node.body);
145
+ this.write(`${this.currentIndent}}`);
146
+
147
+ this.exitScope();
148
+ },
149
+
150
+ visitCallExpression(node) {
151
+ this.visitCallee(node.callee);
152
+ this.write('(');
153
+ this.emitArgs(node.arguments);
154
+ this.write(')');
155
+ },
156
+
157
+ visitSafeCallExpression(node) {
158
+ // func?.(...args) — wrap in ?? null to match Mimo semantics (undefined → null)
159
+ this.write('(');
160
+ this.visitNode(node.callee);
161
+ this.write('?.(');
162
+ this.emitArgs(node.arguments || []);
163
+ this.write(') ?? null)');
164
+ },
165
+
166
+ visitModuleAccess(node) {
167
+ this.write(`${node.module}.${node.property}`);
168
+ },
169
+
170
+ visitPropertyAccess(node) {
171
+ this.visitNode(node.object);
172
+ this.write(`.${node.property}`);
173
+ },
174
+
175
+ visitSafePropertyAccess(node) {
176
+ // Wrap in ?? null to match Mimo semantics (undefined → null)
177
+ this.write('(');
178
+ this.visitNode(node.object);
179
+ this.write(`?.${node.property} ?? null)`);
180
+ },
181
+
182
+ visitArrayAccess(node) {
183
+ this.visitNode(node.object);
184
+ this.write('[');
185
+ this.visitNode(node.index);
186
+ this.write(']');
187
+ },
188
+
189
+ visitSafeArrayAccess(node) {
190
+ // arr?.[index] — wrap in ?? null to match Mimo semantics (undefined → null)
191
+ this.write('(');
192
+ this.visitNode(node.object);
193
+ this.write('?.[');
194
+ this.visitNode(node.index);
195
+ this.write('] ?? null)');
196
+ },
197
+ };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Pattern matching visitors for the Mimo → JavaScript converter.
3
+ * Mixed into MimoToJsConverter via Object.assign.
4
+ */
5
+ export const patternVisitors = {
6
+ visitArrayPattern(node) {
7
+ this.write(`[${node.elements.map((e) => e.name).join(', ')}]`);
8
+ },
9
+
10
+ visitObjectPattern(node) {
11
+ this.write(`{ ${node.properties.map((p) => p.name).join(', ')} }`);
12
+ },
13
+
14
+ visitDecorator(_node) {
15
+ // Decorators are handled inside visitFunctionDeclaration.
16
+ },
17
+
18
+ visitMatchStatement(node) {
19
+ const tempVar = `__match_${this._matchCounter++}`;
20
+ this.write(`${this.currentIndent}const ${tempVar} = `);
21
+ this.visitNode(node.discriminant);
22
+ this.write(';\n');
23
+ this.writeLine(`switch (true) {`);
24
+ this.indent();
25
+ node.cases.forEach((caseNode) => this._visitCaseClause(caseNode, tempVar));
26
+ this.dedent();
27
+ this.writeLine('}');
28
+ },
29
+
30
+ _visitCaseClause(node, matchVar) {
31
+ if (!node.pattern) {
32
+ // default case
33
+ this.writeLine('default: {');
34
+ } else {
35
+ this.write(`${this.currentIndent}case (`);
36
+ this._emitMatchCondition(node.pattern, matchVar);
37
+ // Handle `when` guard
38
+ if (node.guard) {
39
+ this.write(' && (');
40
+ this._emitMatchBindingsInline(node.pattern, matchVar);
41
+ this.visitNode(node.guard);
42
+ this.write(')');
43
+ }
44
+ this.write('): {\n');
45
+ this.indent();
46
+ this._emitMatchBindings(node.pattern, matchVar);
47
+ this.dedent();
48
+ }
49
+ this.visitBlock(node.consequent);
50
+ this.writeLine('break;');
51
+ this.writeLine('}');
52
+ },
53
+
54
+ _emitMatchCondition(pattern, matchVar) {
55
+ if (!pattern) { this.write('true'); return; }
56
+ switch (pattern.type) {
57
+ case 'Literal':
58
+ this.write(`mimo.eq(${matchVar}, `);
59
+ this.visitNode(pattern);
60
+ this.write(')');
61
+ break;
62
+ case 'Identifier':
63
+ this.write('true');
64
+ break;
65
+ case 'ArrayPattern':
66
+ this.write(`Array.isArray(${matchVar}) && ${matchVar}.length === ${pattern.elements.length}`);
67
+ pattern.elements.forEach((el, i) => {
68
+ this.write(' && ');
69
+ this._emitMatchCondition(el, `${matchVar}[${i}]`);
70
+ });
71
+ break;
72
+ case 'ObjectPattern':
73
+ this.write(`(${matchVar} !== null && typeof ${matchVar} === 'object')`);
74
+ break;
75
+ default:
76
+ this.write('true');
77
+ }
78
+ },
79
+
80
+ /** Emit bindings as part of a `when` guard expression (no-op; bindings run after the case label). */
81
+ _emitMatchBindingsInline(_pattern, _matchVar) {},
82
+
83
+ _emitMatchBindings(pattern, matchVar) {
84
+ if (!pattern) return;
85
+ switch (pattern.type) {
86
+ case 'Identifier':
87
+ this.writeLine(`const ${pattern.name} = ${matchVar};`);
88
+ break;
89
+ case 'ArrayPattern':
90
+ pattern.elements.forEach((el, i) =>
91
+ this._emitMatchBindings(el, `${matchVar}[${i}]`)
92
+ );
93
+ break;
94
+ case 'ObjectPattern':
95
+ pattern.properties.forEach((prop) => {
96
+ const key = prop.key || prop.name;
97
+ this.writeLine(`const ${prop.name} = ${matchVar}["${key}"];`);
98
+ });
99
+ break;
100
+ }
101
+ },
102
+ };
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Statement visitors for the Mimo → JavaScript converter.
3
+ * Mixed into MimoToJsConverter via Object.assign.
4
+ */
5
+ export const statementVisitors = {
6
+ visitShowStatement(node) {
7
+ this.write(`${this.currentIndent}mimo.show(`);
8
+ this.visitNode(node.expression);
9
+ this.write(');\n');
10
+ },
11
+
12
+ visitVariableDeclaration(node) {
13
+ let keyword = 'let';
14
+ if (node.kind === 'const') keyword = 'const';
15
+ // Mimo's `set` is mutable and function-scoped (not block-scoped).
16
+ // Use `var` to match this: declared once with `var`, subsequent uses are bare assignments.
17
+ if (node.kind === 'set') keyword = 'var';
18
+
19
+ let prefix;
20
+ if (this.isVariableDeclared(node.identifier)) {
21
+ prefix = '';
22
+ } else {
23
+ prefix = node.isExported ? `export ${keyword} ` : `${keyword} `;
24
+ this.declareVariable(node.identifier);
25
+ }
26
+
27
+ this.write(`${this.currentIndent}${prefix}${node.identifier} = `);
28
+ this.visitNode(node.value);
29
+ this.write(';\n');
30
+ },
31
+
32
+ visitFunctionDeclaration(node) {
33
+ this.declareVariable(node.name);
34
+ const exportPrefix = node.isExported ? 'export ' : '';
35
+
36
+ // Handle decorators (bottom-up application order)
37
+ const decorators = node.decorators || [];
38
+
39
+ this.enterScope();
40
+
41
+ // Build parameter list with defaults and rest params
42
+ const defaults = node.defaults || {};
43
+ const paramParts = (node.params || []).map((p) => {
44
+ this.declareVariable(p.name);
45
+ const defaultNode = defaults[p.name];
46
+ if (defaultNode !== undefined && defaultNode !== null) {
47
+ return `${p.name} = ${this._exprToString(defaultNode)}`;
48
+ }
49
+ return p.name;
50
+ });
51
+ if (node.restParam) {
52
+ this.declareVariable(node.restParam.name);
53
+ paramParts.push(`...${node.restParam.name}`);
54
+ }
55
+
56
+ this.write(`${this.currentIndent}${exportPrefix}function ${node.name}(${paramParts.join(', ')}) {\n`);
57
+ this.visitBlock(node.body);
58
+ this.writeLine('}');
59
+
60
+ this.exitScope();
61
+
62
+ // Apply decorators: fn = decorator(fn)
63
+ // Mimo applies decorators in reverse order (innermost/last decorator first),
64
+ // matching Python's @decorator stacking semantics.
65
+ for (const dec of [...decorators].reverse()) {
66
+ const decName = typeof dec.name === 'string' ? dec.name : dec.name?.name;
67
+ const decArgs = dec.arguments || dec.args || [];
68
+ const decCall = decArgs.length > 0
69
+ ? `${decName}(${decArgs.map(a => this._exprToString(a)).join(', ')})(${node.name})`
70
+ : `${decName}(${node.name})`;
71
+ this.writeLine(`${node.name} = ${decCall};`);
72
+ }
73
+ },
74
+
75
+ visitCallStatement(node) {
76
+ if (node.destination) {
77
+ const destName = node.destination.name;
78
+ const keyword = this.isVariableDeclared(destName) ? '' : 'let ';
79
+ this.write(`${this.currentIndent}${keyword}${destName} = `);
80
+ this.declareVariable(destName);
81
+ } else {
82
+ this.write(this.currentIndent);
83
+ }
84
+
85
+ this.visitCallee(node.callee);
86
+ this.write('(');
87
+ this.emitArgs(node.arguments);
88
+ this.write(');\n');
89
+ },
90
+
91
+ visitReturnStatement(node) {
92
+ this.write(`${this.currentIndent}return`);
93
+ if (node.argument) {
94
+ this.write(' ');
95
+ this.visitNode(node.argument);
96
+ }
97
+ this.write(';\n');
98
+ },
99
+
100
+ visitIfStatement(node) {
101
+ this.write(`${this.currentIndent}if (`);
102
+ this.visitNode(node.condition);
103
+ this.write(') {\n');
104
+ this.visitBlock(node.consequent);
105
+ if (node.alternate) {
106
+ this.write(`${this.currentIndent}} else `);
107
+ if (node.alternate.type === 'IfStatement') {
108
+ this.visitNode(node.alternate);
109
+ } else {
110
+ this.write('{\n');
111
+ this.visitBlock(node.alternate);
112
+ this.writeLine('}');
113
+ }
114
+ } else {
115
+ this.writeLine('}');
116
+ }
117
+ },
118
+
119
+ visitGuardStatement(node) {
120
+ // guard cond else ... end → if (!cond) { <alternate-block> }
121
+ this.write(`${this.currentIndent}if (!(`);
122
+ this.visitNode(node.condition);
123
+ this.write(')) {\n');
124
+ this.visitBlock(node.alternate || node.elseBlock || []);
125
+ this.writeLine('}');
126
+ },
127
+
128
+ visitWhileStatement(node) {
129
+ this.write(`${this.currentIndent}while (`);
130
+ this.visitNode(node.condition);
131
+ this.write(') {\n');
132
+ this.visitBlock(node.body);
133
+ this.writeLine('}');
134
+ },
135
+
136
+ visitForStatement(node) {
137
+ this.write(`${this.currentIndent}for (const ${node.variable.name} of `);
138
+ this.visitNode(node.iterable);
139
+ this.write(') {\n');
140
+ this.visitBlock(node.body);
141
+ this.writeLine('}');
142
+ },
143
+
144
+ visitLoopStatement(node) {
145
+ if (node.label) this.writeLine(`${node.label}:`);
146
+ this.writeLine('while (true) {');
147
+ this.visitBlock(node.body);
148
+ this.writeLine('}');
149
+ },
150
+
151
+ visitLabeledStatement(node) {
152
+ this.writeLine(`${node.label}:`);
153
+ this.visitNode(node.statement);
154
+ },
155
+
156
+ visitBreakStatement(node) {
157
+ this.write(`${this.currentIndent}break`);
158
+ if (node.label) this.write(` ${node.label}`);
159
+ this.write(';\n');
160
+ },
161
+
162
+ visitContinueStatement(node) {
163
+ this.write(`${this.currentIndent}continue`);
164
+ if (node.label) this.write(` ${node.label}`);
165
+ this.write(';\n');
166
+ },
167
+
168
+ visitTryStatement(node) {
169
+ this.writeLine('try {');
170
+ this.visitBlock(node.tryBlock);
171
+ if (node.catchBlock) {
172
+ const errName = node.catchVar?.name || '_err';
173
+ this.write(`${this.currentIndent}} catch (${errName}) {\n`);
174
+ this.visitBlock(node.catchBlock);
175
+ }
176
+ this.writeLine('}');
177
+ },
178
+
179
+ visitThrowStatement(node) {
180
+ this.write(`${this.currentIndent}throw `);
181
+ this.visitNode(node.argument);
182
+ this.write(';\n');
183
+ },
184
+
185
+ visitImportStatement(node) {
186
+ this.moduleAliases.set(node.alias, node.path);
187
+ if (this.isStdlibModule(node.path)) {
188
+ this.writeLine(`const ${node.alias} = mimo.${node.path};`);
189
+ } else {
190
+ const importPath = node.path.endsWith('.mimo')
191
+ ? node.path.replace('.mimo', '.js')
192
+ : `${node.path}.js`;
193
+ this.writeLine(`import * as ${node.alias} from './${importPath}';`);
194
+ }
195
+ },
196
+
197
+ visitDestructuringAssignment(node) {
198
+ const patternVars = this._collectPatternVars(node.pattern);
199
+ const isReassignment = patternVars.some((v) => this.isVariableDeclared(v));
200
+
201
+ this.write(this.currentIndent);
202
+
203
+ if (isReassignment) {
204
+ if (node.pattern.type === 'ObjectPattern') this.write('(');
205
+ } else {
206
+ this.write('let ');
207
+ }
208
+
209
+ this.visitNode(node.pattern);
210
+ this.write(' = ');
211
+ this.visitNode(node.expression);
212
+
213
+ if (isReassignment && node.pattern.type === 'ObjectPattern') this.write(')');
214
+ this.write(';\n');
215
+
216
+ patternVars.forEach((v) => this.declareVariable(v));
217
+ },
218
+
219
+ visitPropertyAssignment(node) {
220
+ this.write(this.currentIndent);
221
+ this.visitNode(node.object);
222
+ this.write(`.${node.property} = `);
223
+ this.visitNode(node.value);
224
+ this.write(';\n');
225
+ },
226
+
227
+ visitBracketAssignment(node) {
228
+ this.write(this.currentIndent);
229
+ this.visitNode(node.object);
230
+ this.write('[');
231
+ this.visitNode(node.index);
232
+ this.write('] = ');
233
+ this.visitNode(node.value);
234
+ this.write(';\n');
235
+ },
236
+ };
@@ -0,0 +1,10 @@
1
+ import { MimoToPyConverter } from './to_py.js';
2
+
3
+ export const config = {
4
+ name: 'python',
5
+ aliases: ['py', 'python'],
6
+ extension: '.py',
7
+ runtimeFile: 'mimo_runtime.py'
8
+ };
9
+
10
+ export { MimoToPyConverter as Converter };