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/bun.lock ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 0,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "mimo-next",
7
+ "devDependencies": {
8
+ "@types/bun": "latest",
9
+ "esbuild": "^0.25.5",
10
+ },
11
+ },
12
+ },
13
+ "packages": {
14
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="],
15
+
16
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="],
17
+
18
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.5", "", { "os": "android", "cpu": "arm64" }, "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg=="],
19
+
20
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.25.5", "", { "os": "android", "cpu": "x64" }, "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw=="],
21
+
22
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ=="],
23
+
24
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ=="],
25
+
26
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw=="],
27
+
28
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw=="],
29
+
30
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.5", "", { "os": "linux", "cpu": "arm" }, "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw=="],
31
+
32
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg=="],
33
+
34
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA=="],
35
+
36
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg=="],
37
+
38
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg=="],
39
+
40
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ=="],
41
+
42
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA=="],
43
+
44
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="],
45
+
46
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, ""],
47
+
48
+ "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="],
49
+
50
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.5", "", { "os": "none", "cpu": "x64" }, "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ=="],
51
+
52
+ "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.5", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw=="],
53
+
54
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg=="],
55
+
56
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA=="],
57
+
58
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw=="],
59
+
60
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ=="],
61
+
62
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="],
63
+
64
+ "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
65
+
66
+ "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
67
+
68
+ "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
69
+
70
+ "esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": "bin/esbuild" }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="],
71
+
72
+ "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
73
+ }
74
+ }
package/index.js CHANGED
@@ -1,41 +1,51 @@
1
- import { generateTokens } from "./compiler/lexer/tokenizer.js";
2
- import { parseTokens } from "./compiler/parser/parser.js";
3
- import { interpret } from "./compiler/execute/interpreter.js";
4
- import { generateCodeJsFromAstArray } from "./converter/js/convert.js";
5
-
6
- // The main class for the Mimo language
7
- export default class Mimo {
8
- constructor() {
9
- // Initialize the environment for variables
10
- this.env = {};
11
- }
12
-
13
- // Tokenize the given code into a list of tokens
14
- async tokenize(code) {
15
- return generateTokens(code);
16
- }
17
-
18
- // Parse the list of tokens into an abstract syntax tree (AST)
19
- async parse(tokens) {
20
- return parseTokens(tokens);
21
- }
22
-
23
- // Interpret the AST and execute the code
24
- async interpret(program) {
25
- return interpret(program, this.env);
26
- }
27
-
28
- // Run the given code by tokenizing, parsing, and interpreting it
29
- async run(code) {
30
- const tokens = await this.tokenize(code);
31
- const program = await this.parse(tokens);
32
- const env = await this.interpret(program);
33
- return { program, env };
34
- }
35
-
36
- // Convert the AST to JavaScript code
37
- toJS(ast) {
38
- return generateCodeJsFromAstArray(ast);
39
- }
1
+ /**
2
+ * @file The Mimo library entry point for NODE.JS environments.
3
+ * Exports the Mimo class and Node.js-specific helpers.
4
+ */
5
+
6
+ import { Interpreter } from './interpreter/index.js';
7
+ import { Lexer } from './lexer/Lexer.js';
8
+ import { Parser } from './parser/Parser.js';
9
+ import { MimoError } from './interpreter/MimoError.js';
10
+ import { nodeAdapter } from './adapters/nodeAdapter.js';
11
+
12
+ export class Mimo {
13
+ constructor(adapter = nodeAdapter) {
14
+ this.interpreter = new Interpreter(adapter);
15
+ }
16
+
17
+ run(source, filePath) {
18
+ if (!filePath) {
19
+ throw new Error("Mimo.run() requires a filePath argument in a Node.js environment for module resolution.");
20
+ }
21
+
22
+ try {
23
+ const lexer = new Lexer(source, filePath);
24
+ const tokens = [];
25
+ let token;
26
+ while ((token = lexer.nextToken()) !== null) {
27
+ tokens.push(token);
28
+ }
29
+
30
+ const parser = new Parser(tokens, filePath);
31
+ this.interpreter.errorHandler.addSourceFile(filePath, source);
32
+ parser.setErrorHandler(this.interpreter.errorHandler);
33
+ const ast = parser.parse();
34
+
35
+ const result = this.interpreter.interpret(ast, filePath);
36
+
37
+ return result;
38
+
39
+ } catch (error) {
40
+ if (error instanceof MimoError) {
41
+ throw error.format(this.interpreter.errorHandler.getLine(error.location.file, error.location.line));
42
+ } else {
43
+ throw error;
44
+ }
45
+ }
46
+ }
40
47
  }
41
48
 
49
+
50
+ // Export Node.js specific helpers and other components
51
+ export { Interpreter, Lexer, Parser, MimoError, nodeAdapter };
package/index.web.js ADDED
@@ -0,0 +1,364 @@
1
+ /**
2
+ * @file The Mimo library entry point for BROWSER environments.
3
+ * It exports the Mimo class but avoids importing any Node.js-specific modules.
4
+ */
5
+
6
+ import { Interpreter } from './interpreter/index.js';
7
+ import { Lexer } from './lexer/Lexer.js';
8
+ import { Parser } from './parser/Parser.js';
9
+ import { MimoError } from './interpreter/MimoError.js';
10
+ import { Linter } from './tools/lint/Linter.js';
11
+ import { PrettyPrinter } from './tools/PrettyPrinter.js';
12
+ import { extractComments } from './tools/format/CommentLexer.js';
13
+ import { attachComments } from './tools/format/CommentAttacher.js';
14
+
15
+ /**
16
+ * Tokenizer module - handles lexical analysis
17
+ */
18
+ export class MimoTokenizer {
19
+ constructor(source, filePath = '/playground.mimo') {
20
+ this.source = source;
21
+ this.filePath = filePath;
22
+ this.lexer = new Lexer(source, filePath);
23
+ }
24
+
25
+ tokenize() {
26
+ const tokens = [];
27
+ let token;
28
+ while ((token = this.lexer.nextToken()) !== null) {
29
+ tokens.push(token);
30
+ }
31
+ return tokens;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Parser module - handles syntax analysis
37
+ */
38
+ export class MimoParser {
39
+ constructor(tokens, filePath = '/playground.mimo', errorHandler = null) {
40
+ this.tokens = tokens;
41
+ this.filePath = filePath;
42
+ this.parser = new Parser(tokens, filePath);
43
+ if (errorHandler) {
44
+ this.parser.setErrorHandler(errorHandler);
45
+ }
46
+ }
47
+
48
+ parse() {
49
+ return this.parser.parse();
50
+ }
51
+ }
52
+
53
+ /**
54
+ * AST Hook Manager - manages AST interception callbacks
55
+ */
56
+ export class ASTHookManager {
57
+ constructor() {
58
+ this.hooks = [];
59
+ }
60
+
61
+ /**
62
+ * Register a callback to receive the AST
63
+ * @param {Function} callback - Function that receives (ast, filePath) as parameters
64
+ * @param {string} [name] - Optional name for the hook
65
+ */
66
+ registerHook(callback, name = null) {
67
+ if (typeof callback !== 'function') {
68
+ throw new Error('AST hook must be a function');
69
+ }
70
+
71
+ const hook = {
72
+ callback,
73
+ name: name || `hook_${this.hooks.length}`,
74
+ id: Date.now() + Math.random()
75
+ };
76
+
77
+ this.hooks.push(hook);
78
+ return hook.id;
79
+ }
80
+
81
+ /**
82
+ * Unregister a hook by ID
83
+ * @param {string|number} hookId - The ID returned by registerHook
84
+ */
85
+ unregisterHook(hookId) {
86
+ this.hooks = this.hooks.filter(hook => hook.id !== hookId);
87
+ }
88
+
89
+ /**
90
+ * Unregister all hooks with a specific name
91
+ * @param {string} name - The name of hooks to remove
92
+ */
93
+ unregisterHooksByName(name) {
94
+ this.hooks = this.hooks.filter(hook => hook.name !== name);
95
+ }
96
+
97
+ /**
98
+ * Clear all registered hooks
99
+ */
100
+ clearHooks() {
101
+ this.hooks = [];
102
+ }
103
+
104
+ /**
105
+ * Execute all registered hooks with the AST
106
+ * @param {Object} ast - The parsed AST
107
+ * @param {string} filePath - The file path
108
+ */
109
+ executeHooks(ast, filePath) {
110
+ for (const hook of this.hooks) {
111
+ try {
112
+ hook.callback(ast, filePath);
113
+ } catch (error) {
114
+ console.error(`Error in AST hook '${hook.name}':`, error);
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Get list of registered hooks
121
+ */
122
+ getHooks() {
123
+ return this.hooks.map(hook => ({
124
+ id: hook.id,
125
+ name: hook.name
126
+ }));
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Main Mimo class with modular design and AST interception
132
+ */
133
+ export class Mimo {
134
+ constructor(adapter, options = {}) {
135
+ if (!adapter) {
136
+ throw new Error("Mimo constructor requires an adapter object.");
137
+ }
138
+
139
+ this.interpreter = new Interpreter(adapter);
140
+ this.astHookManager = new ASTHookManager();
141
+
142
+ // Configuration options
143
+ this.options = {
144
+ enableASTHooks: options.enableASTHooks !== false,
145
+ throwOnHookError: options.throwOnHookError || false,
146
+ ...options
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Register an AST hook
152
+ * @param {Function} callback - Function that receives (ast, filePath)
153
+ * @param {string} [name] - Optional name for the hook
154
+ * @returns {string|number} Hook ID for later removal
155
+ */
156
+ onAST(callback, name) {
157
+ return this.astHookManager.registerHook(callback, name);
158
+ }
159
+
160
+ /**
161
+ * Remove an AST hook by ID
162
+ * @param {string|number} hookId - The hook ID
163
+ */
164
+ offAST(hookId) {
165
+ this.astHookManager.unregisterHook(hookId);
166
+ }
167
+
168
+ /**
169
+ * Get the AST hook manager for advanced hook management
170
+ */
171
+ getASTHookManager() {
172
+ return this.astHookManager;
173
+ }
174
+
175
+ /**
176
+ * Tokenize source code
177
+ * @param {string} source - The source code
178
+ * @param {string} [filePath] - Optional file path
179
+ * @returns {Array} Array of tokens
180
+ */
181
+ tokenize(source, filePath = '/playground.mimo') {
182
+ const tokenizer = new MimoTokenizer(source, filePath);
183
+ return tokenizer.tokenize();
184
+ }
185
+
186
+ /**
187
+ * Parse tokens into an AST
188
+ * @param {Array} tokens - Array of tokens
189
+ * @param {string} [filePath] - Optional file path
190
+ * @returns {Object} The parsed AST
191
+ */
192
+ parse(tokens, filePath = '/playground.mimo') {
193
+ const parser = new MimoParser(tokens, filePath, this.interpreter.errorHandler);
194
+ this.interpreter.errorHandler.addSourceFile(filePath, ''); // Add empty source for now
195
+ return parser.parse();
196
+ }
197
+
198
+ /**
199
+ * Parse source code directly into an AST
200
+ * @param {string} source - The source code
201
+ * @param {string} [filePath] - Optional file path
202
+ * @returns {Object} The parsed AST
203
+ */
204
+ parseSource(source, filePath = '/playground.mimo') {
205
+ const tokens = this.tokenize(source, filePath);
206
+ this.interpreter.errorHandler.addSourceFile(filePath, source);
207
+ const parser = new MimoParser(tokens, filePath, this.interpreter.errorHandler);
208
+ const ast = parser.parse();
209
+
210
+ // Execute AST hooks if enabled
211
+ if (this.options.enableASTHooks) {
212
+ this.astHookManager.executeHooks(ast, filePath);
213
+ }
214
+
215
+ return ast;
216
+ }
217
+
218
+ /**
219
+ * Run source code with full pipeline
220
+ * @param {string} source - The source code
221
+ * @param {string} [filePath] - Optional file path
222
+ * @returns {*} The execution result
223
+ */
224
+ run(source, filePath = '/playground.mimo') {
225
+ const effectivePath = filePath;
226
+
227
+ try {
228
+ // Tokenize
229
+ const tokens = this.tokenize(source, effectivePath);
230
+
231
+ // Parse and get AST
232
+ const ast = this.parseSource(source, effectivePath);
233
+
234
+ // Interpret
235
+ const result = this.interpreter.interpret(ast, effectivePath);
236
+
237
+ return result;
238
+
239
+ } catch (error) {
240
+ if (error instanceof MimoError) {
241
+ throw error.format(this.interpreter.errorHandler.getLine(error.location.file, error.location.line));
242
+ } else {
243
+ throw error;
244
+ }
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Run pre-parsed AST
250
+ * @param {Object} ast - The parsed AST
251
+ * @param {string} [filePath] - Optional file path
252
+ * @returns {*} The execution result
253
+ */
254
+ runAST(ast, filePath = '/playground.mimo') {
255
+ try {
256
+ return this.interpreter.interpret(ast, filePath);
257
+ } catch (error) {
258
+ if (error instanceof MimoError) {
259
+ throw error.format(this.interpreter.errorHandler.getLine(error.location.file, error.location.line));
260
+ } else {
261
+ throw error;
262
+ }
263
+ }
264
+ }
265
+ }
266
+
267
+ // Export all classes and modules
268
+ export { Interpreter } from './interpreter/index.js';
269
+ export { Lexer } from './lexer/Lexer.js';
270
+ export { Parser } from './parser/Parser.js';
271
+ export { MimoError } from './interpreter/MimoError.js';
272
+ export { Linter } from './tools/lint/Linter.js';
273
+ export { PrettyPrinter } from './tools/PrettyPrinter.js';
274
+
275
+ const DEFAULT_LINT_RULES = {
276
+ 'no-unused-vars': true,
277
+ 'prefer-const': true,
278
+ 'no-magic-numbers': false
279
+ };
280
+
281
+ export function lintSource(source, filePath = '/playground.mimo', rules = {}) {
282
+ const enabledRules = { ...DEFAULT_LINT_RULES, ...rules };
283
+
284
+ try {
285
+ const lexer = new Lexer(source, filePath);
286
+ const tokens = [];
287
+ let token;
288
+ while ((token = lexer.nextToken()) !== null) {
289
+ tokens.push(token);
290
+ }
291
+
292
+ const parser = new Parser(tokens, filePath);
293
+ const ast = parser.parse();
294
+
295
+ const linter = new Linter({ rules: enabledRules });
296
+ const messages = linter.verify(ast, source, filePath);
297
+
298
+ return {
299
+ ok: true,
300
+ file: filePath,
301
+ messages: messages.map(msg => ({
302
+ line: msg.line,
303
+ column: msg.column,
304
+ endColumn: msg.endColumn,
305
+ message: msg.message,
306
+ ruleId: msg.ruleId,
307
+ severity: 'warning'
308
+ }))
309
+ };
310
+ } catch (err) {
311
+ // Convert syntax/parse errors into lint diagnostics
312
+ return {
313
+ ok: false,
314
+ file: filePath,
315
+ error: {
316
+ message: err.message,
317
+ line: err.location?.line || 1,
318
+ column: err.location?.column || 1
319
+ },
320
+ messages: [{
321
+ line: err.location?.line || 1,
322
+ column: err.location?.column || 1,
323
+ endColumn: (err.location?.column || 1) + 1,
324
+ message: err.message,
325
+ ruleId: 'syntax-error',
326
+ severity: 'error'
327
+ }]
328
+ };
329
+ }
330
+ }
331
+
332
+ export function formatSource(source) {
333
+ try {
334
+ // Extract comments from raw source (formatter-only path)
335
+ const { comments } = extractComments(source);
336
+
337
+ const lexer = new Lexer(source, '/format.mimo');
338
+ const tokens = [];
339
+ let token;
340
+ while ((token = lexer.nextToken()) !== null) {
341
+ tokens.push(token);
342
+ }
343
+
344
+ const parser = new Parser(tokens, '/format.mimo');
345
+ const ast = parser.parse();
346
+
347
+ // Attach extracted comments to AST nodes
348
+ attachComments(ast, comments);
349
+
350
+ const printer = new PrettyPrinter();
351
+ // A8: format() already normalises the trailing newline
352
+ const formatted = printer.format(ast);
353
+
354
+ return {
355
+ ok: true,
356
+ formatted,
357
+ };
358
+ } catch (err) {
359
+ return {
360
+ ok: false,
361
+ error: err.message,
362
+ };
363
+ }
364
+ }
@@ -0,0 +1,32 @@
1
+ export class BuiltinFunction {
2
+ constructor(name, implementation, arity) {
3
+ this.name = name;
4
+ this.implementation = implementation;
5
+ this.arity = arity;
6
+ }
7
+
8
+ call(interpreter, args, callNode) { // Add callNode parameter
9
+ // Handle variable arity functions (arity can be an array [min, max])
10
+ if (Array.isArray(this.arity)) {
11
+ const [min, max] = this.arity;
12
+ if (args.length < min || args.length > max) {
13
+ throw interpreter.errorHandler.createRuntimeError(
14
+ `Built-in function '${this.name}' expects ${min}-${max} arguments but received ${args.length}.`,
15
+ callNode,
16
+ 'BUILTIN001',
17
+ `Check the arguments provided to built-in function '${this.name}'.`
18
+ );
19
+ }
20
+ } else {
21
+ if (args.length !== this.arity) {
22
+ throw interpreter.errorHandler.createRuntimeError(
23
+ `Built-in function '${this.name}' expects ${this.arity} arguments but received ${args.length}.`,
24
+ callNode,
25
+ 'BUILTIN001',
26
+ `Check the arguments provided to built-in function '${this.name}'.`
27
+ );
28
+ }
29
+ }
30
+ return this.implementation(args, interpreter, callNode); // Pass callNode to implementation
31
+ }
32
+ }