mimo-lang 1.1.0 → 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 (166) hide show
  1. package/.gitattributes +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +91 -6
  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 +49 -39
  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 -11
  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 -1
  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 -63
  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 -35
  153. package/compiler/parser/parser.js +0 -16
  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/i.js +0 -30
  165. package/jsconfig.json +0 -27
  166. package/webpack.config.js +0 -9
package/.gitattributes ADDED
@@ -0,0 +1,24 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
3
+
4
+ # Source code
5
+ *.js text eol=lf
6
+ *.mimo text eol=lf linguist-language=Mimo
7
+
8
+ # Config files
9
+ *.json text eol=lf
10
+ *.md text eol=lf
11
+ *.yml text eol=lf
12
+ *.yaml text eol=lf
13
+
14
+ # Shell scripts
15
+ *.sh text eol=lf
16
+
17
+ # Binary files
18
+ *.png binary
19
+ *.jpg binary
20
+ *.jpeg binary
21
+ *.gif binary
22
+ *.ico binary
23
+ *.woff binary
24
+ *.woff2 binary
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 bethropolis
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.
package/README.md CHANGED
@@ -1,15 +1,100 @@
1
- # mimo
1
+ <p align="center">
2
+ <img src="playground/src/lib/assets/mascot.png" alt="Mimo mascot" width="120">
3
+ </p>
2
4
 
3
- To install dependencies:
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/mimo-lang">
7
+ <img src="https://img.shields.io/npm/v/mimo-lang?color=%23a855f7&label=npm&logo=npm" alt="npm version">
8
+ </a>
9
+ <a href="https://github.com/bethropolis/mimo/releases">
10
+ <img src="https://img.shields.io/github/v/release/bethropolis/mimo?color=%236366f1&label=github&logo=github" alt="GitHub release">
11
+ </a>
12
+ <a href="https://github.com/bethropolis/mimo/blob/main/LICENSE">
13
+ <img src="https://img.shields.io/github/license/bethropolis/mimo?color=%2310b981" alt="License">
14
+ </a>
15
+ <a href="https://bethropolis.github.io/mimo/">
16
+ <img src="https://img.shields.io/badge/docs-online-%23f59e0b?logo=book" alt="Documentation">
17
+ </a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <strong>A minimal prefix-notation programming language</strong>
22
+ </p>
23
+
24
+ ---
25
+
26
+ ## Installation
4
27
 
5
28
  ```bash
6
- bun install
29
+ bun install -g mimo-lang
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Run Programs
35
+
36
+ ```bash
37
+ mimo path/to/program.mimo
38
+ mimo -e "+ 1 2"
39
+ echo "+ 1 2" | mimo
40
+ ```
41
+
42
+ ### REPL
43
+
44
+ ```bash
45
+ mimo repl
7
46
  ```
8
47
 
9
- To run:
48
+ ### CLI Commands
10
49
 
11
50
  ```bash
12
- bun run index.js
51
+ mimo run <file> # Run a file
52
+ mimo repl # Start REPL
53
+ mimo fmt <path> --write # Format files
54
+ mimo lint <path> # Lint files
55
+ mimo test <path> # Run tests
13
56
  ```
14
57
 
15
- This project was created using `bun init` in bun v1.0.35. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
58
+ ## Syntax
59
+
60
+ ```mimo
61
+ function add(a, b)
62
+ return + a b
63
+ end
64
+
65
+ call add(4, 8) -> result
66
+ show result
67
+ ```
68
+
69
+ More examples in [`test/source/`](./test/source).
70
+
71
+ ## Development
72
+
73
+ ```bash
74
+ bun install
75
+ bun run check
76
+ ```
77
+
78
+ ## Playground
79
+
80
+ <p>
81
+ <img src="docs/assets/playground.jpg" alt="Mimo playground" width="600">
82
+ </p>
83
+
84
+ The playground is a web application that allows you to run Mimo code in your browser.
85
+
86
+ ## About
87
+ this is just a simple language i created to learn more about how programing languages work.
88
+ contributions are welcome.
89
+
90
+ ## Links
91
+
92
+ - [Documentation](https://bethropolis.github.io/mimo/)
93
+ - [Playground](https://bethropolis.github.io/mimo/playground)
94
+ - [GitHub](https://github.com/bethropolis/mimo)
95
+
96
+ ## License
97
+
98
+ Released under [MIT](./LICENSE)
99
+
100
+ <p align="center">happy coding 💜</p>
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @file An adapter for running Mimo in a web browser environment.
3
+ * It provides browser-compatible implementations for system interactions.
4
+ * File system operations are disabled and will throw errors.
5
+ */
6
+
7
+ function fsUnavailable() {
8
+ throw new Error(
9
+ "File system access is not available in the browser environment.",
10
+ );
11
+ }
12
+
13
+ const baseBrowserAdapter = {
14
+ // --- File System (Disabled by default) ---
15
+ readFileSync: fsUnavailable,
16
+ readdirSync: fsUnavailable,
17
+ existsSync: () => false, // Always return false, as no real file system exists
18
+ writeFileSync: fsUnavailable,
19
+ mkdirSync: fsUnavailable,
20
+ unlinkSync: fsUnavailable,
21
+ rmdirSync: fsUnavailable,
22
+ rmSync: fsUnavailable,
23
+
24
+ // --- Path (Simplified for URL/string-based paths) ---
25
+ resolvePath: (...segments) => segments.join("/").replace(/\/+/g, "/"),
26
+ dirname: (filePath) => {
27
+ const lastSlash = filePath.lastIndexOf("/");
28
+ return lastSlash === -1 ? "." : filePath.substring(0, lastSlash);
29
+ },
30
+ isAbsolutePath: (filePath) => filePath.startsWith("/"),
31
+ joinPath: (...segments) => segments.join("/"),
32
+ basename: (filePath) => {
33
+ const lastSlash = filePath.lastIndexOf("/");
34
+ return filePath.substring(lastSlash + 1);
35
+ },
36
+ extname: (filePath) => {
37
+ const base = filePath.substring(filePath.lastIndexOf("/") + 1);
38
+ const dot = base.lastIndexOf(".");
39
+ return dot > 0 ? base.substring(dot) : "";
40
+ },
41
+
42
+ // http
43
+ fetchSync: (url, options = {}) => {
44
+ try {
45
+ const xhr = new XMLHttpRequest();
46
+ // The 3rd argument 'false' makes the request Synchronous
47
+ xhr.open(options.method || "GET", url, false);
48
+
49
+ if (options.headers) {
50
+ for (const [key, value] of Object.entries(options.headers)) {
51
+ xhr.setRequestHeader(key, value);
52
+ }
53
+ }
54
+
55
+ xhr.send(options.body || null);
56
+
57
+ return {
58
+ status: xhr.status,
59
+ body: xhr.responseText,
60
+ };
61
+ } catch (e) {
62
+ throw new Error("HTTP request failed: " + e.message);
63
+ }
64
+ },
65
+
66
+ // --- Process (Mocked) ---
67
+ getArguments: () => [], // No command-line arguments in the browser
68
+ getEnvVariable: () => null, // No environment variables
69
+ getEnvAll: () => ({}),
70
+ exit: (code) => {
71
+ console.warn(
72
+ `Mimo script called exit(${code}), but exit is disabled in the browser.`,
73
+ );
74
+ },
75
+ cwd: () => "/", // The "root" in a browser context
76
+
77
+ // --- Console (Direct Mapping) ---
78
+ log: (...args) => console.log(...args),
79
+ error: (...args) => console.error(...args),
80
+ };
81
+
82
+ export function createBrowserAdapter(overrides = {}) {
83
+ return { ...baseBrowserAdapter, ...overrides };
84
+ }
85
+
86
+ export const browserAdapter = createBrowserAdapter();
@@ -0,0 +1,101 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ export const nodeAdapter = {
6
+ readFileSync: (filePath, encoding = "utf-8") =>
7
+ fs.readFileSync(filePath, encoding),
8
+
9
+ readdirSync: (filePath) => fs.readdirSync(filePath),
10
+
11
+ existsSync: (filePath) => fs.existsSync(filePath),
12
+
13
+ writeFileSync: (filePath, data, encoding = "utf-8") =>
14
+ fs.writeFileSync(filePath, data, encoding),
15
+
16
+ mkdirSync: (filePath, options) => {
17
+ if (!fs.existsSync(filePath)) {
18
+ fs.mkdirSync(filePath, options);
19
+ }
20
+ },
21
+ unlinkSync: (filePath) => fs.unlinkSync(filePath),
22
+ rmdirSync: (filePath) => fs.rmdirSync(filePath),
23
+
24
+ rmSync: (filePath, options) => fs.rmSync(filePath, options),
25
+
26
+ resolvePath: (...segments) => path.resolve(...segments),
27
+
28
+ dirname: (filePath) => path.dirname(filePath),
29
+
30
+ isAbsolutePath: (filePath) => path.isAbsolute(filePath),
31
+
32
+ joinPath: (...segments) => path.join(...segments),
33
+
34
+ basename: (filePath, ext) => path.basename(filePath, ext),
35
+ extname: (filePath) => path.extname(filePath),
36
+
37
+ getArguments: () => process.argv.slice(2),
38
+
39
+ getEnvVariable: (variableName) => process.env[variableName],
40
+ getEnvAll: () => ({ ...process.env }),
41
+
42
+ exit: (code) => process.exit(code),
43
+
44
+ cwd: () => process.cwd(),
45
+
46
+ log: (...args) => console.log(...args),
47
+ error: (...args) => console.error(...args),
48
+
49
+ // --- HTTP Implementation ---
50
+ fetchSync: (url, options = {}) => {
51
+ const method = options.method || "GET";
52
+ const headers = options.headers || {};
53
+ const body = options.body || null;
54
+
55
+ const args = ["-s", "-i", "-X", method];
56
+
57
+ for (const [key, value] of Object.entries(headers)) {
58
+ args.push("-H", `${key}: ${value}`);
59
+ }
60
+
61
+ if (body) {
62
+ args.push("-d", body);
63
+ }
64
+
65
+ args.push(url);
66
+
67
+ const result = spawnSync("curl", args, { encoding: "utf-8" });
68
+
69
+ if (result.error) {
70
+ throw new Error(
71
+ `HTTP Request failed: ${result.error.message}. Ensure 'curl' is installed.`,
72
+ );
73
+ }
74
+
75
+ if (result.status !== 0) {
76
+ throw new Error(
77
+ `HTTP Connection failed: ${result.stderr || "Unknown error"}`,
78
+ );
79
+ }
80
+
81
+ const output = result.stdout;
82
+ const separator = "\r\n\r\n";
83
+ let splitIndex = output.indexOf(separator);
84
+ if (splitIndex === -1) splitIndex = output.indexOf("\n\n");
85
+
86
+ const headerPart = splitIndex !== -1 ? output.substring(0, splitIndex) : "";
87
+ const bodyPart =
88
+ splitIndex !== -1
89
+ ? output.substring(splitIndex + separator.length)
90
+ : output;
91
+
92
+ const statusLine = headerPart.split("\n")[0] || "";
93
+ const statusMatch = statusLine.match(/HTTP\/\d(\.\d)?\s+(\d+)/);
94
+ const statusCode = statusMatch ? parseInt(statusMatch[2], 10) : 0;
95
+
96
+ return {
97
+ status: statusCode,
98
+ body: bodyPart,
99
+ };
100
+ },
101
+ };
package/bin/cli.js ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bun
2
+ // bin/cli.js — Mimo Language Toolkit entry point
3
+ // This file is intentionally thin: it parses the top-level command and
4
+ // delegates to the appropriate module in bin/commands/.
5
+
6
+ import { c } from './utils/colors.js';
7
+ import { getVersion } from './utils/version.js';
8
+
9
+ // ── Command registry ──────────────────────────────────────────────────────────
10
+
11
+ const COMMANDS = {
12
+ help: () => import('./commands/help.js'),
13
+ run: () => import('./commands/run.js'),
14
+ repl: () => import('./commands/repl.js'),
15
+ fmt: () => import('./commands/fmt.js'),
16
+ lint: () => import('./commands/lint.js'),
17
+ test: () => import('./commands/test.js'),
18
+ convert: () => import('./commands/convert.js'),
19
+ doctor: () => import('./commands/doctor.js'),
20
+ };
21
+
22
+ // ── Main ──────────────────────────────────────────────────────────────────────
23
+
24
+ async function main() {
25
+ const args = process.argv.slice(2);
26
+ const command = args[0];
27
+ const rest = args.slice(1);
28
+
29
+ // No args → global help
30
+ if (!command) {
31
+ const { run } = await import('./commands/help.js');
32
+ await run([]);
33
+ return;
34
+ }
35
+
36
+ // Version
37
+ if (command === '--version' || command === '-v') {
38
+ console.log(getVersion());
39
+ return;
40
+ }
41
+
42
+ // Help flags → same as `mimo help`
43
+ if (command === '--help' || command === '-h' || command === 'help') {
44
+ const { run } = await import('./commands/help.js');
45
+ await run(rest);
46
+ return;
47
+ }
48
+
49
+ // --eval / -e
50
+ if (command === '--eval' || command === '-e') {
51
+ const { run, help } = await import('./commands/eval.js');
52
+ if (rest.includes('--help')) { help(); return; }
53
+ await run(rest);
54
+ return;
55
+ }
56
+
57
+ // STDIN shorthand: `mimo -`
58
+ if (command === '-') {
59
+ const { run } = await import('./commands/run.js');
60
+ await run(['-']);
61
+ return;
62
+ }
63
+
64
+ // Named commands
65
+ if (command in COMMANDS) {
66
+ const { run, help } = await COMMANDS[command]();
67
+ if (rest.includes('--help')) { help(); return; }
68
+ await run(rest);
69
+ return;
70
+ }
71
+
72
+ // Default: treat the argument as a file path
73
+ const { run } = await import('./commands/run.js');
74
+ await run(args);
75
+ }
76
+
77
+ main().catch((err) => {
78
+ console.error(c.error('Unexpected error: ') + (err?.message ?? String(err)));
79
+ process.exit(1);
80
+ });
@@ -0,0 +1,27 @@
1
+ // bin/commands/convert.js
2
+ // Converts Mimo source to another language (JavaScript, Python, Alya, …).
3
+
4
+ import { runConverter } from '../../tools/convert.js';
5
+ import { c } from '../utils/colors.js';
6
+
7
+ export function help() {
8
+ console.log(`
9
+ ${c.bold('mimo convert')} — Transpile Mimo code to another language
10
+
11
+ ${c.bold('Usage:')}
12
+ mimo convert --in <file> --out <file> --to <target>
13
+
14
+ ${c.bold('Options:')}
15
+ --in <file> Input .mimo file
16
+ --out <file> Output file path
17
+ --to <target> Target language: javascript, python, alya
18
+
19
+ ${c.bold('Examples:')}
20
+ mimo convert --in app.mimo --out app.js --to javascript
21
+ mimo convert --in app.mimo --out app.py --to python
22
+ `);
23
+ }
24
+
25
+ export async function run(args) {
26
+ await runConverter(args);
27
+ }
@@ -0,0 +1,139 @@
1
+ // bin/commands/doctor.js
2
+ // Validates the Mimo runtime environment, adapter API, and stdlib availability.
3
+
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { spawnSync } from 'node:child_process';
7
+ import { Mimo } from '../../index.js';
8
+ import { nodeAdapter } from '../../adapters/nodeAdapter.js';
9
+ import { c } from '../utils/colors.js';
10
+
11
+ const REQUIRED_ADAPTER_METHODS = [
12
+ 'readFileSync',
13
+ 'writeFileSync',
14
+ 'existsSync',
15
+ 'dirname',
16
+ 'resolvePath',
17
+ 'joinPath',
18
+ 'basename',
19
+ 'extname',
20
+ 'getEnvVariable',
21
+ 'getEnvAll',
22
+ 'fetchSync',
23
+ ];
24
+
25
+ const STDLIB_MODULES = [
26
+ 'array', 'assert', 'datetime', 'env', 'fs',
27
+ 'http', 'json', 'math', 'object', 'path', 'regex', 'string',
28
+ ];
29
+
30
+ export function help() {
31
+ console.log(`
32
+ ${c.bold('mimo doctor')} — Validate the Mimo runtime environment
33
+
34
+ ${c.bold('Usage:')}
35
+ mimo doctor
36
+
37
+ ${c.bold('Checks performed:')}
38
+ - Node adapter API completeness
39
+ - Bun runtime detection
40
+ - Filesystem read/write access in current directory
41
+ - curl availability (required by the http stdlib module)
42
+ - Interpreter smoke test (evaluates \`+ 1 2\`)
43
+ - Stdlib module registry (all built-in modules resolve)
44
+ `);
45
+ }
46
+
47
+ export function run(_args) {
48
+ const checks = [];
49
+ const pass = (name, detail) => checks.push({ status: 'PASS', name, detail });
50
+ const warn = (name, detail) => checks.push({ status: 'WARN', name, detail });
51
+ const fail = (name, detail) => checks.push({ status: 'FAIL', name, detail });
52
+
53
+ // 1. Adapter API
54
+ const missing = REQUIRED_ADAPTER_METHODS.filter((m) => typeof nodeAdapter[m] !== 'function');
55
+ if (missing.length === 0) {
56
+ pass('Adapter API', 'All required adapter methods are present.');
57
+ } else {
58
+ fail('Adapter API', `Missing: ${missing.join(', ')}. Add them to adapters/nodeAdapter.js.`);
59
+ }
60
+
61
+ // 2. Bun runtime
62
+ if (process.versions?.bun) {
63
+ pass('Bun runtime', `Detected Bun ${process.versions.bun}.`);
64
+ } else {
65
+ warn('Bun runtime', 'Bun version could not be detected.');
66
+ }
67
+
68
+ // 3. Filesystem access
69
+ try {
70
+ const probe = path.join(process.cwd(), '.mimo_doctor_tmp');
71
+ fs.writeFileSync(probe, 'ok', 'utf-8');
72
+ fs.unlinkSync(probe);
73
+ pass('Filesystem access', 'Read/write operations in current directory work.');
74
+ } catch (err) {
75
+ fail('Filesystem access', `Failed RW check in cwd: ${err.message}`);
76
+ }
77
+
78
+ // 4. curl (needed by http stdlib)
79
+ {
80
+ const curl = spawnSync('curl', ['--version'], { encoding: 'utf-8' });
81
+ if (curl.status === 0) {
82
+ pass('HTTP dependency', 'curl is installed (required by http module).');
83
+ } else {
84
+ warn('HTTP dependency', 'curl not found — `http.get/post` will fail until curl is installed.');
85
+ }
86
+ }
87
+
88
+ // 5. Interpreter smoke test
89
+ {
90
+ const mimo = new Mimo(nodeAdapter);
91
+ try {
92
+ const result = mimo.run('+ 1 2', '/doctor_smoke.mimo');
93
+ pass('Interpreter smoke test', `Basic evaluation works (result: ${result}).`);
94
+ } catch (err) {
95
+ fail('Interpreter smoke test', String(err));
96
+ }
97
+ }
98
+
99
+ // 6. Stdlib module registry
100
+ {
101
+ const mimo = new Mimo(nodeAdapter);
102
+ const unresolved = [];
103
+ for (const mod of STDLIB_MODULES) {
104
+ try {
105
+ mimo.interpreter.moduleLoader.loadModule(mod, process.cwd());
106
+ } catch {
107
+ unresolved.push(mod);
108
+ }
109
+ }
110
+ if (unresolved.length === 0) {
111
+ pass('Stdlib module registry', 'All built-in stdlib modules resolved.');
112
+ } else {
113
+ fail('Stdlib module registry', `Failed to resolve: ${unresolved.join(', ')}.`);
114
+ }
115
+ }
116
+
117
+ // ── Report ────────────────────────────────────────────────────────────────
118
+
119
+ const statusColor = { PASS: c.green, WARN: c.yellow, FAIL: c.red };
120
+
121
+ console.log(`\n${c.bold('Mimo Doctor Report')} ${c.dim(`(${new Date().toISOString()})`)}\n`);
122
+ for (const item of checks) {
123
+ const badge = statusColor[item.status](`[${item.status}]`);
124
+ console.log(`${badge} ${c.bold(item.name)}: ${item.detail}`);
125
+ }
126
+
127
+ const hasFail = checks.some((ch) => ch.status === 'FAIL');
128
+ const hasWarn = checks.some((ch) => ch.status === 'WARN');
129
+
130
+ if (hasFail) {
131
+ console.log(`\n${c.red(c.bold('Doctor result: FAILED'))}`);
132
+ process.exit(1);
133
+ }
134
+ if (hasWarn) {
135
+ console.log(`\n${c.yellow(c.bold('Doctor result: PASS WITH WARNINGS'))}`);
136
+ return;
137
+ }
138
+ console.log(`\n${c.green(c.bold('Doctor result: PASS'))}`);
139
+ }
@@ -0,0 +1,39 @@
1
+ // bin/commands/eval.js
2
+ // Evaluates a string of Mimo code passed directly on the command line.
3
+
4
+ import { Mimo } from '../../index.js';
5
+ import { nodeAdapter } from '../../adapters/nodeAdapter.js';
6
+ import { formatError } from '../utils/formatError.js';
7
+ import { c } from '../utils/colors.js';
8
+
9
+ export function help() {
10
+ console.log(`
11
+ ${c.bold('mimo --eval')} — Evaluate a string of Mimo code
12
+
13
+ ${c.bold('Usage:')}
14
+ mimo --eval <code>
15
+ mimo -e <code>
16
+
17
+ ${c.bold('Examples:')}
18
+ mimo -e "show + 1 2"
19
+ mimo -e 'set x 10 \\n show * x 2'
20
+ `);
21
+ }
22
+
23
+ export async function run(args) {
24
+ const code = args[0];
25
+ if (!code) {
26
+ console.error(c.error('Error: No code provided to --eval.'));
27
+ process.exit(1);
28
+ }
29
+ const mimo = new Mimo(nodeAdapter);
30
+ try {
31
+ const result = mimo.run(code, '/eval');
32
+ if (result !== undefined && result !== null) {
33
+ console.log(result);
34
+ }
35
+ } catch (err) {
36
+ console.error(formatError(err, code));
37
+ process.exit(1);
38
+ }
39
+ }