mimo-lang 1.0.0

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 (38) hide show
  1. package/README.md +15 -0
  2. package/bun.lockb +0 -0
  3. package/cli.js +44 -0
  4. package/compiler/execute/interpreter.js +68 -0
  5. package/compiler/execute/interpreters/binary.js +12 -0
  6. package/compiler/execute/interpreters/call.js +10 -0
  7. package/compiler/execute/interpreters/if.js +10 -0
  8. package/compiler/execute/interpreters/try-catch.js +9 -0
  9. package/compiler/execute/interpreters/while.js +8 -0
  10. package/compiler/execute/utils/createfunction.js +11 -0
  11. package/compiler/execute/utils/evaluate.js +20 -0
  12. package/compiler/execute/utils/operate.js +23 -0
  13. package/compiler/lexer/processToken.js +40 -0
  14. package/compiler/lexer/tokenTypes.js +4 -0
  15. package/compiler/lexer/tokenizer.js +63 -0
  16. package/compiler/parser/expression/comparison.js +18 -0
  17. package/compiler/parser/expression/identifier.js +29 -0
  18. package/compiler/parser/expression/number.js +10 -0
  19. package/compiler/parser/expression/operator.js +21 -0
  20. package/compiler/parser/expression/punctuation.js +31 -0
  21. package/compiler/parser/expression/string.js +6 -0
  22. package/compiler/parser/parseExpression.js +27 -0
  23. package/compiler/parser/parseStatement.js +36 -0
  24. package/compiler/parser/parser.js +16 -0
  25. package/compiler/parser/statement/call.js +26 -0
  26. package/compiler/parser/statement/function.js +29 -0
  27. package/compiler/parser/statement/if.js +34 -0
  28. package/compiler/parser/statement/return.js +10 -0
  29. package/compiler/parser/statement/set.js +11 -0
  30. package/compiler/parser/statement/show.js +10 -0
  31. package/compiler/parser/statement/try-catch.js +25 -0
  32. package/compiler/parser/statement/while.js +22 -0
  33. package/converter/go/convert.js +100 -0
  34. package/converter/js/convert.js +106 -0
  35. package/index.js +48 -0
  36. package/jsconfig.json +27 -0
  37. package/package.json +33 -0
  38. package/test.js +1 -0
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # mimo
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.js
13
+ ```
14
+
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.
package/bun.lockb ADDED
Binary file
package/cli.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "fs";
4
+ import Mimo from "./index.js";
5
+ import { version } from "./package.json";
6
+
7
+ // Check if the user asked for the version
8
+ if (process.argv.includes("-v") || process.argv.includes("--version")) {
9
+ console.log(version);
10
+ process.exit(0);
11
+ }
12
+
13
+ // Check if a filename was provided
14
+ if (process.argv.length < 3) {
15
+ console.error("Error: No file name provided.");
16
+ console.log("Usage: mimo [FILENAME]");
17
+ process.exit(1);
18
+ }
19
+
20
+ const filename = process.argv[2];
21
+
22
+ // Check if the file exists
23
+ if (!fs.existsSync(filename)) {
24
+ console.error(`Error: File '${filename}' does not exist.`);
25
+ process.exit(1);
26
+ }
27
+
28
+ // Read the file
29
+ let code;
30
+ try {
31
+ code = fs.readFileSync(filename, "utf-8");
32
+ } catch (err) {
33
+ console.error(`Error reading file '${filename}':`, err.message);
34
+ process.exit(1);
35
+ }
36
+
37
+ // Run the code
38
+ const mimo = new Mimo();
39
+ try {
40
+ mimo.run(code);
41
+ } catch (err) {
42
+ console.error("Error running code:", err.message);
43
+ process.exit(1);
44
+ }
@@ -0,0 +1,68 @@
1
+ import { interpretBinary } from "./interpreters/binary";
2
+ import { interpretCall } from "./interpreters/call";
3
+ import { interpretIf } from "./interpreters/if";
4
+ import { interpretTryCatch } from "./interpreters/try-catch";
5
+ import { interpretWhile } from "./interpreters/while";
6
+ import { createFunction } from "./utils/createfunction";
7
+ import { evaluate } from "./utils/evaluate";
8
+
9
+ export async function interpretStatement(statement, env) {
10
+ if (Array.isArray(statement)) {
11
+ for (let i = 0; i < statement.length; i++) {
12
+ if (await interpretStatement(statement[i], env)) return true;
13
+ }
14
+ return;
15
+ }
16
+
17
+ if (typeof statement === "object") {
18
+ if (statement.type === "try-catch") {
19
+ await interpretTryCatch(statement, env);
20
+ } else {
21
+ await interpretObjectStatement(statement, env);
22
+ }
23
+ }
24
+ }
25
+
26
+ async function interpretObjectStatement(statement, env) {
27
+ switch (statement.type) {
28
+ case "assignment":
29
+ env[statement.target] = evaluate(statement.value, env);
30
+ break;
31
+ case "binary":
32
+ await interpretBinary(statement, env);
33
+ break;
34
+ case "if":
35
+ await interpretIf(statement, env);
36
+ break;
37
+ case "while":
38
+ await interpretWhile(statement, env);
39
+ break;
40
+ case "function":
41
+ env[statement.name] = createFunction(
42
+ statement.params,
43
+ statement.body,
44
+ env
45
+ );
46
+ break;
47
+ case "return":
48
+ env["return"] = evaluate(statement.expression, env);
49
+ return true;
50
+ case "call":
51
+ await interpretCall(statement, env);
52
+ break;
53
+ case "print":
54
+ console.log(evaluate(statement.value, env));
55
+ break;
56
+ default:
57
+ console.log("Unknown statement type", statement.type);
58
+ break;
59
+ }
60
+ }
61
+
62
+ export async function interpret(program, env = {}) {
63
+ let index = 0;
64
+ while (index < program.length) {
65
+ if (await interpretStatement(program[index++], env)) break;
66
+ }
67
+ return env;
68
+ }
@@ -0,0 +1,12 @@
1
+ import { evaluate } from "../utils/evaluate";
2
+
3
+ export async function interpretBinary(statement, env) {
4
+ if (env[statement.target] === undefined) {
5
+ env[statement.target] = null;
6
+ }
7
+ env[statement.target] = await operate(
8
+ statement.operator,
9
+ await evaluate(statement.left, env),
10
+ await evaluate(statement.right, env)
11
+ );
12
+ }
@@ -0,0 +1,10 @@
1
+ import { evaluate } from "../utils/evaluate";
2
+
3
+ export async function interpretCall(statement, env) {
4
+ const func = env[statement.name];
5
+ if (typeof func !== "function") {
6
+ throw new Error(`${statement.name} is not a function`);
7
+ }
8
+ const args = statement.args.map((arg) => evaluate(arg, env));
9
+ env[statement.target] = await func(...args);
10
+ }
@@ -0,0 +1,10 @@
1
+ import { interpretStatement } from "../interpreter";
2
+ import { evaluate } from "../utils/evaluate";
3
+
4
+ export async function interpretIf(statement, env) {
5
+ if (evaluate(statement.condition, env)) {
6
+ if (await interpretStatement(statement.consequent, env)) return true;
7
+ } else if (statement.alternate) {
8
+ if (await interpretStatement(statement.alternate, env)) return true;
9
+ }
10
+ }
@@ -0,0 +1,9 @@
1
+
2
+ export async function interpretTryCatch(statement, env) {
3
+ try {
4
+ await interpretStatement(statement.tryBlock, env);
5
+ } catch (error) {
6
+ env[statement.error] = error;
7
+ await interpretStatement(statement.catchBlock, env);
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ import { interpretStatement } from "../interpreter";
2
+ import { evaluate } from "../utils/evaluate";
3
+
4
+ export async function interpretWhile(statement, env) {
5
+ while (evaluate(statement.condition, env)) {
6
+ if (await interpretStatement(statement.body, env)) return true;
7
+ }
8
+ }
@@ -0,0 +1,11 @@
1
+ import { interpret } from "../interpreter";
2
+
3
+ export function createFunction(params, body, env) {
4
+ return async function (...args) {
5
+ const newEnv = { ...env };
6
+ params.forEach((param, index) => {
7
+ newEnv[param] = args[index] ?? undefined;
8
+ });
9
+ return (await interpret(body, newEnv))["return"];
10
+ };
11
+ }
@@ -0,0 +1,20 @@
1
+ import { operate } from "./operate";
2
+
3
+ export const evaluate = (expression, env) =>
4
+ expression.type === "literal"
5
+ ? expression.value
6
+ : expression.type === "variable"
7
+ ? env.hasOwnProperty(expression.name)
8
+ ? env[expression.name]
9
+ : null
10
+ : expression.type === "list"
11
+ ? expression.elements.map((element) => evaluate(element, env))
12
+ : expression.type === "indexAccess"
13
+ ? env[expression.name][evaluate(expression.index, env)]
14
+ : expression.type === "binary"
15
+ ? operate(
16
+ expression.operator,
17
+ evaluate(expression.left, env),
18
+ evaluate(expression.right, env)
19
+ )
20
+ : null;
@@ -0,0 +1,23 @@
1
+ const operations = new Map([
2
+ ["+", (left, right) => left + right],
3
+ ["-", (left, right) => left - right],
4
+ ["*", (left, right) => left * right],
5
+ ["/", (left, right) => left / right],
6
+ ["%", (left, right) => left % right],
7
+ ["**", (left, right) => left ** right],
8
+ [">", (left, right) => left > right],
9
+ ["<", (left, right) => left < right],
10
+ [">=", (left, right) => left >= right],
11
+ ["<=", (left, right) => left <= right],
12
+ ["==", (left, right) => left == right],
13
+ ["!=", (left, right) => left != right],
14
+ ["!", (left) => !left],
15
+ ]);
16
+
17
+ export const operate = (operator, left, right) => {
18
+ const operation = operations.get(operator);
19
+ if (!operation) {
20
+ throw new Error(`Invalid operator: ${operator}`);
21
+ }
22
+ return operation(left, right);
23
+ };
@@ -0,0 +1,40 @@
1
+ // processToken.js
2
+
3
+ import { OPERATORS } from "./tokenTypes";
4
+
5
+ export const isOperator = (char) => OPERATORS.includes(char);
6
+
7
+ export const processToken = (currentToken, currentType, tokens) => {
8
+ if (currentToken) {
9
+ tokens.push({ type: currentType, value: currentToken });
10
+ return { currentToken: "", currentType: null };
11
+ }
12
+ return { currentToken, currentType };
13
+ };
14
+
15
+ export const processStringToken = (inString, currentToken, tokens) => {
16
+ inString = !inString;
17
+ if (!inString) {
18
+ tokens.push({ type: "string", value: currentToken });
19
+ currentToken = "";
20
+ }
21
+ return { inString, currentToken };
22
+ };
23
+
24
+ export const processOperatorToken = (char, index, input, currentType, currentToken, tokens) => {
25
+ if (currentToken) {
26
+ ({ currentToken, currentType } = processToken(currentToken, currentType, tokens));
27
+ }
28
+
29
+
30
+ currentType = "operator";
31
+ currentToken += char;
32
+
33
+
34
+ if (index < input.length - 1 && isOperator(input[index + 1])) {
35
+ currentToken += input[index + 1];
36
+ index++; // Skip the next operator character
37
+ }
38
+ tokens.push({ type: currentType, value: currentToken });
39
+ return { currentToken: "", currentType: null, i:index };
40
+ };
@@ -0,0 +1,4 @@
1
+ // tokenTypes.js
2
+ export const OPERATORS = ["+", "-", "*", "/", ">", "<", "=", "!"];
3
+ export const KEYWORDS = ["let", "const", "if", "else", "for", "while", "function", "return"];
4
+ export const PUNCTUATION = ["(", ")", ",", "[", "]"];
@@ -0,0 +1,63 @@
1
+ import { processToken, processStringToken, processOperatorToken, isOperator } from './processToken.js';
2
+ import { PUNCTUATION } from './tokenTypes.js';
3
+
4
+ function generateTokens(input) {
5
+ const tokens = [];
6
+ let currentToken = "";
7
+ let currentType = null;
8
+ let inComment = false;
9
+ let inString = false;
10
+
11
+ for (let i = 0; i < input.length; i++) {
12
+ const char = input[i];
13
+
14
+ if (inComment) {
15
+ if (char === "\n") {
16
+ inComment = false;
17
+ }
18
+ continue;
19
+ }
20
+
21
+ if (char === "/" && input[i + 1] === "/") {
22
+ inComment = true;
23
+ i++; // Skip the second '/'
24
+ continue;
25
+ }
26
+
27
+ if (char === '"') {
28
+ ({ inString, currentToken } = processStringToken(inString, currentToken, tokens));
29
+ continue;
30
+ }
31
+
32
+ if (inString) {
33
+ currentToken += char;
34
+ continue;
35
+ }
36
+
37
+ if (/\s/.test(char)) {
38
+ ({ currentToken, currentType } = processToken(currentToken, currentType, tokens));
39
+ continue;
40
+ }
41
+
42
+ if (isOperator(char)) {
43
+ ({ currentToken, currentType, i } = processOperatorToken(char, i, input, currentType, currentToken, tokens));
44
+ }else if (PUNCTUATION.includes(char)) {
45
+ ({ currentToken, currentType } = processToken(currentToken, currentType, tokens));
46
+ tokens.push({ type: "punctuation", value: char });
47
+ } else {
48
+ currentToken += char;
49
+ if (!currentType) {
50
+ currentType = /[a-zA-Z]/.test(char)
51
+ ? "identifier"
52
+ : /[0-9]/.test(char)
53
+ ? "number"
54
+ : null;
55
+ }
56
+ }
57
+ }
58
+
59
+ ({ currentToken, currentType } = processToken(currentToken, currentType, tokens));
60
+ return tokens;
61
+ }
62
+
63
+ export { generateTokens };
@@ -0,0 +1,18 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export function comparisonExpression(tokens, index) {
4
+ const operator = tokens[index++].value;
5
+ let left = parseExpression(tokens, index);
6
+ index = left.index; // Update the index
7
+ let right = parseExpression(tokens, index);
8
+ index = right.index; // Update the index
9
+ return {
10
+ expression: {
11
+ type: "comparison",
12
+ operator,
13
+ left: left.expression,
14
+ right: right.expression,
15
+ },
16
+ index,
17
+ };
18
+ }
@@ -0,0 +1,29 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export function identifierExpression(tokens, index) {
4
+ if (
5
+ tokens[index + 1]?.value === "[" &&
6
+ tokens[index + 3]?.value === "]"
7
+ ) {
8
+ const name = tokens[index].value;
9
+ index += 2; // Skip identifier and '['
10
+ const indexExpression = parseExpression(tokens, index);
11
+ index = indexExpression.index; // Update the index
12
+ if (tokens[index]?.value === "]") {
13
+ index++; // Skip ']'
14
+ }
15
+ return {
16
+ expression: {
17
+ type: "indexAccess",
18
+ name,
19
+ index: indexExpression.expression,
20
+ },
21
+ index,
22
+ };
23
+ } else {
24
+ return {
25
+ expression: { type: "variable", name: tokens[index++].value },
26
+ index,
27
+ };
28
+ }
29
+ }
@@ -0,0 +1,10 @@
1
+
2
+ export function numberExpression(tokens, index){
3
+ return {
4
+ expression: {
5
+ type: "literal",
6
+ value: parseFloat(tokens[index++].value),
7
+ },
8
+ index,
9
+ };
10
+ }
@@ -0,0 +1,21 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export function operatorExpression(tokens, index) {
4
+ let operator = tokens[index++].value;
5
+ let left = parseExpression(tokens, index);
6
+ index = left.index; // Update the index
7
+ if (tokens[index]?.type === "operator") {
8
+ operator += tokens[index++].value; // Handle two-character operators like '=='
9
+ }
10
+ let right = parseExpression(tokens, index);
11
+ index = right.index; // Update the index
12
+ return {
13
+ expression: {
14
+ type: "binary",
15
+ operator,
16
+ left: left.expression,
17
+ right: right.expression,
18
+ },
19
+ index,
20
+ };
21
+ }
@@ -0,0 +1,31 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export function punctuationExpression(tokens, index) {
4
+ if (tokens[index].value === "[") {
5
+ index++; // Skip '['
6
+ const elements = [];
7
+ while (
8
+ tokens[index]?.type !== "punctuation" &&
9
+ tokens[index]?.value !== "]"
10
+ ) {
11
+ let result = parseExpression(tokens, index);
12
+ elements.push(result.expression);
13
+ index = result.index; // Update the index
14
+ if (
15
+ tokens[index]?.type === "punctuation" &&
16
+ tokens[index]?.value === ","
17
+ ) {
18
+ index++; // Skip ',' between elements
19
+ }
20
+ }
21
+ if (tokens[index]?.value === "]") {
22
+ index++; // Skip ']'
23
+ }
24
+ return { expression: { type: "list", elements }, index };
25
+ }
26
+
27
+ return {
28
+ expression: { type: "punctuation", value: tokens[index++].value },
29
+ index,
30
+ };
31
+ }
@@ -0,0 +1,6 @@
1
+ export function stringExpression(tokens, index){
2
+ return {
3
+ expression: { type: "literal", value: tokens[index++].value },
4
+ index,
5
+ };
6
+ }
@@ -0,0 +1,27 @@
1
+ import { comparisonExpression } from "./expression/comparison";
2
+ import { identifierExpression } from "./expression/identifier";
3
+ import { numberExpression } from "./expression/number";
4
+ import { operatorExpression } from "./expression/operator";
5
+ import { punctuationExpression } from "./expression/punctuation";
6
+ import { stringExpression } from "./expression/string";
7
+
8
+ export const parseExpression = (tokens, index) => {
9
+ // console.log("expression..", tokens[index].type, tokens[index].value);
10
+
11
+ switch (tokens[index].type) {
12
+ case "number":
13
+ return numberExpression(tokens, index);
14
+ case "string":
15
+ return stringExpression(tokens, index);
16
+ case "identifier":
17
+ return identifierExpression(tokens, index);
18
+ case "operator":
19
+ return operatorExpression(tokens, index);
20
+ case "punctuation":
21
+ return punctuationExpression(tokens, index);
22
+ default:
23
+ if (["<", ">", ">=", "<=", "==", "!="].includes(tokens[index].value)) {
24
+ return comparisonExpression(tokens, index);
25
+ }
26
+ }
27
+ };
@@ -0,0 +1,36 @@
1
+ import { parseExpression } from "./parseExpression";
2
+ import { ifStatement } from "./statement/if";
3
+ import { setStatement } from "./statement/set";
4
+ import { tryCatchStatement } from "./statement/try-catch";
5
+ import { whileStatement } from "./statement/while";
6
+ import { functionStatement } from "./statement/function";
7
+ import { callStatement } from "./statement/call";
8
+ import { returnStatement } from "./statement/return";
9
+ import { showStatement } from "./statement/show";
10
+
11
+ export const parseStatement = (tokens, index) => {
12
+ let statement = { type: "statement" };
13
+
14
+ // console.log("parsing..", tokens[index].type, tokens[index].value);
15
+ if (tokens[index].value === "set") {
16
+ ({ statement, index } = setStatement(tokens, index));
17
+ } else if (tokens[index].value === "if") {
18
+ ({ statement, index } = ifStatement(tokens, index));
19
+ } else if (tokens[index].value === "while") {
20
+ ({ statement, index } = whileStatement(tokens, index));
21
+ } else if (tokens[index].value === "try") {
22
+ ({ statement, index } = tryCatchStatement(tokens, index));
23
+ } else if (tokens[index].value === "function") {
24
+ ({ statement, index } = functionStatement(tokens, index));
25
+ } else if (tokens[index].value === "call") {
26
+ ({ statement, index } = callStatement(tokens, index));
27
+ } else if (tokens[index].value === "return") {
28
+ ({ statement, index } = returnStatement(tokens, index));
29
+ } else if (tokens[index].value === "show") {
30
+ ({ statement, index } = showStatement(tokens, index));
31
+ } else {
32
+ index++;
33
+ }
34
+
35
+ return { statement, index };
36
+ };
@@ -0,0 +1,16 @@
1
+ import { parseStatement } from "./parseStatement";
2
+
3
+ export function parseTokens(tokens) {
4
+ let index = 0;
5
+
6
+ const program = [];
7
+ while (index < tokens.length) {
8
+ let statement;
9
+ let result = parseStatement(tokens, index);
10
+ statement = result.statement;
11
+ index = result.index; // Update the index
12
+ program.push(statement);
13
+ }
14
+
15
+ return program;
16
+ }
@@ -0,0 +1,26 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export const callStatement = (tokens, index) => {
4
+ let statement = { type: "call" };
5
+ statement.name = tokens[index + 1]?.value;
6
+ index += 2; // Skip 'call' and function name
7
+ statement.args = [];
8
+ statement.target = null;
9
+ if (tokens[index].value === "(") {
10
+ index++; // Skip '('
11
+ while (tokens[index].value !== ")") {
12
+ if (tokens[index].value !== ",") {
13
+ let result = parseExpression(tokens, index);
14
+ statement.args.push(result.expression);
15
+ index = result.index; // Update the index
16
+ } else {
17
+ index++; // Skip ','
18
+ }
19
+ }
20
+ index++; // Skip ')'
21
+ }
22
+ if ((tokens[index++].value = "->")) {
23
+ statement.target = tokens[index++].value;
24
+ }
25
+ return { statement, index };
26
+ };
@@ -0,0 +1,29 @@
1
+ import { parseStatement } from "../parseStatement";
2
+
3
+ // #file:statement/function.js
4
+ export const functionStatement = (tokens, index) => {
5
+ index++; // Skip 'function'
6
+ let statement = { type: "function" };
7
+ statement.name = tokens[index++]?.value;
8
+ index++; // Skip 'function' and function name
9
+ statement.params = [];
10
+ while (tokens[index]?.value !== ")") {
11
+ statement.params.push(tokens[index]?.value);
12
+ index++; // Skip parameter
13
+ if (tokens[index]?.value === ",") {
14
+ index++; // Skip ','
15
+ }
16
+ }
17
+ index++; // Skip ')'
18
+ const body = [];
19
+ while (tokens[index] && tokens[index].value !== "endfunction") {
20
+ let result = parseStatement(tokens, index);
21
+ body.push(result.statement);
22
+ index = result.index; // Update the index
23
+ }
24
+ if (tokens[index].value === "endfunction") {
25
+ index++;
26
+ }
27
+ statement.body = body;
28
+ return { statement, index };
29
+ };
@@ -0,0 +1,34 @@
1
+ import { parseExpression } from "../parseExpression";
2
+ import { parseStatement } from "../parseStatement";
3
+
4
+ export function ifStatement(tokens, index) {
5
+ let statement = { type: "if" };
6
+ index++;
7
+ let result = parseExpression(tokens, index);
8
+ statement.condition = result.expression;
9
+ index = result.index; // Update the index
10
+ statement.consequent = [];
11
+
12
+ while (
13
+ tokens[index] &&
14
+ tokens[index].value !== "endif" &&
15
+ tokens[index].value !== "else"
16
+ ) {
17
+ let result = parseStatement(tokens, index);
18
+ statement.consequent.push(result.statement);
19
+ index = result.index; // Update the index
20
+ }
21
+ if (tokens[index].value === "else") {
22
+ index++;
23
+ statement.alternate = [];
24
+ while (tokens[index] && tokens[index].value !== "endif") {
25
+ let result = parseStatement(tokens, index);
26
+ statement.alternate.push(result.statement);
27
+ index = result.index; // Update the index
28
+ }
29
+ }
30
+ if (tokens[index].value === "endif") {
31
+ index++;
32
+ }
33
+ return { statement, index };
34
+ }
@@ -0,0 +1,10 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ // #file:statement/return.js
4
+ export const returnStatement = (tokens, index) => {
5
+ let statement = { type: "return" };
6
+ let result = parseExpression(tokens, index + 1);
7
+ statement.expression = result.expression;
8
+ index = result.index; // Update the index
9
+ return { statement, index };
10
+ };
@@ -0,0 +1,11 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export function setStatement(tokens, index) {
4
+ let statement = { type: "assignment" };
5
+ index++;
6
+ statement.target = tokens[index++].value;
7
+ let result = parseExpression(tokens, index);
8
+ statement.value = result.expression;
9
+ index = result.index; // Update the index
10
+ return { statement, index };
11
+ }
@@ -0,0 +1,10 @@
1
+ import { parseExpression } from "../parseExpression";
2
+
3
+ export const showStatement = (tokens, index) => {
4
+ let statement = { type: "print" };
5
+ index++; // Skip 'show'
6
+ let result = parseExpression(tokens, index);
7
+ statement.value = result.expression;
8
+ index = result.index; // Update the index
9
+ return { statement, index };
10
+ };
@@ -0,0 +1,25 @@
1
+ import { parseStatement } from "../parseStatement";
2
+
3
+ export const tryCatchStatement = (tokens, index) => {
4
+ let statement = { type: "try-catch" };
5
+ statement.tryBlock = [];
6
+ index++;
7
+ while (tokens[index] && tokens[index].value !== "catch") {
8
+ let result = parseStatement(tokens, index);
9
+ statement.tryBlock.push(result.statement);
10
+ index = result.index; // Update the index
11
+ }
12
+ if (tokens[index].value === "catch") {
13
+ index++;
14
+ statement.catchBlock = [];
15
+ while (tokens[index] && tokens[index].value !== "endtry") {
16
+ let result = parseStatement(tokens, index);
17
+ statement.catchBlock.push(result.statement);
18
+ index = result.index; // Update the index
19
+ }
20
+ }
21
+ if (tokens[index].value === "endtry") {
22
+ index++;
23
+ }
24
+ return { statement, index };
25
+ };
@@ -0,0 +1,22 @@
1
+ import { parseExpression } from "../parseExpression";
2
+ import { parseStatement } from "../parseStatement";
3
+
4
+
5
+ export const whileStatement = (tokens, index) => {
6
+ index++; // Skip 'while'
7
+ let statement = { type: "while" };
8
+ let result = parseExpression(tokens, index);
9
+ statement.condition = result.expression;
10
+ index = result.index; // Update the index
11
+ const body = [];
12
+ while (tokens[index] && tokens[index].value !== "endwhile") {
13
+ let result = parseStatement(tokens, index);
14
+ body.push(result.statement);
15
+ index = result.index; // Update the index
16
+ }
17
+ if (tokens[index].value === "endwhile") {
18
+ index++;
19
+ }
20
+ statement.body = body;
21
+ return { statement, index };
22
+ };
@@ -0,0 +1,100 @@
1
+ let declaredVariables = new Set();
2
+
3
+ function generateGoCodeFromAst(node) {
4
+ switch (node.type) {
5
+ case "function":
6
+ return generateFunction(node);
7
+ case "assignment":
8
+ return generateAssignment(node);
9
+ case "while":
10
+ return generateWhile(node);
11
+ case "if":
12
+ return generateIf(node);
13
+ case "return":
14
+ return generateReturn(node);
15
+ case "call":
16
+ return generateCall(node);
17
+ case "print":
18
+ return generatePrint(node);
19
+ case "literal":
20
+ return node.value;
21
+ case "variable":
22
+ return node.name;
23
+ case "binary":
24
+ return generateBinary(node);
25
+ default:
26
+ throw new Error(`Unknown node type: ${node.type}`);
27
+ }
28
+ }
29
+
30
+ export function generateGoCodeFromAstArray(ast) {
31
+ declaredVariables = new Set();
32
+ const generatedCode = ast.map(generateGoCodeFromAst).join("\n\n");
33
+ return formatGoCode(`
34
+ package main
35
+
36
+ import "fmt"
37
+
38
+ ${generatedCode}
39
+ `);
40
+ }
41
+
42
+ function generateFunction(node) {
43
+ const params = node.params.join(", ");
44
+ const body = node.body.map(generateGoCodeFromAst).join("\n");
45
+ return `func ${node.name}(${params}) int {\n${body}\n}`;
46
+ }
47
+
48
+ function generateAssignment(node) {
49
+ let prefix = "";
50
+ if (!declaredVariables.has(node.target)) {
51
+ prefix = "var ";
52
+ declaredVariables.add(node.target);
53
+ }
54
+ return `${prefix}${node.target} := ${generateGoCodeFromAst(node.value)}`;
55
+ }
56
+
57
+ function generateWhile(node) {
58
+ const condition = generateGoCodeFromAst(node.condition);
59
+ const body = node.body.map(generateGoCodeFromAst).join("\n");
60
+ return `for ${condition} {\n${body}\n}`;
61
+ }
62
+
63
+ function generateIf(node) {
64
+ const condition = generateGoCodeFromAst(node.condition);
65
+ const consequent = node.consequent.map(generateGoCodeFromAst).join("\n");
66
+ return `if ${condition} {\n${consequent}\n}`;
67
+ }
68
+
69
+ function generateReturn(node) {
70
+ return `return ${generateGoCodeFromAst(node.expression)}`;
71
+ }
72
+
73
+ function generateCall(node) {
74
+ const args = node.args.map(generateGoCodeFromAst).join(", ");
75
+ let callCode = `${node.name}(${args})`;
76
+ if (node.target) {
77
+ let prefix = "";
78
+ if (!declaredVariables.has(node.target)) {
79
+ prefix = "var ";
80
+ declaredVariables.add(node.target);
81
+ }
82
+ callCode = `${prefix}${node.target} := ${callCode}`;
83
+ }
84
+ return callCode;
85
+ }
86
+
87
+
88
+ function generatePrint(node) {
89
+ return `fmt.Println(${generateGoCodeFromAst(node.value)})`;
90
+ }
91
+
92
+ function generateBinary(node) {
93
+ const left = generateGoCodeFromAst(node.left);
94
+ const right = generateGoCodeFromAst(node.right);
95
+ return `${left} ${node.operator} ${right}`;
96
+ }
97
+
98
+ function formatGoCode(code) {
99
+ return code;
100
+ }
@@ -0,0 +1,106 @@
1
+ import esformatter from 'esformatter';
2
+
3
+
4
+ let declaredVariables = new Set();
5
+
6
+ export function generateCodeFromAst(node) {
7
+ switch (node.type) {
8
+ case "function":
9
+ return generateFunction(node);
10
+ case "assignment":
11
+ return generateAssignment(node);
12
+ case "while":
13
+ return generateWhile(node);
14
+ case "if":
15
+ return generateIf(node);
16
+ case "return":
17
+ return generateReturn(node);
18
+ case "call":
19
+ return generateCall(node);
20
+ case "print":
21
+ return generatePrint(node);
22
+ case "literal":
23
+ return node.value;
24
+ case "variable":
25
+ return node.name;
26
+ case "binary":
27
+ return generateBinary(node);
28
+ case "indexAccess":
29
+ return generateIndexAccess(node);
30
+ case "list":
31
+ return generateList(node);
32
+ default:
33
+ console.log(node);
34
+ throw new Error(`Unknown node type: ${node.type}`);
35
+ }
36
+ }
37
+
38
+ export function generateCodeJsFromAstArray(ast) {
39
+ const generatedCode = ast.map(generateCodeFromAst).join("\n");
40
+ return esformatter.format(generatedCode);
41
+ }
42
+
43
+ function generateFunction(node) {
44
+ const params = node.params.join(", ");
45
+ const body = node.body.map(generateCodeFromAst).join("\n");
46
+ return `function ${node.name}(${params}) {\n${body}\n}`;
47
+ }
48
+
49
+ function generateAssignment(node) {
50
+ let prefix = "";
51
+ if (!declaredVariables.has(node.target)) {
52
+ prefix = "let ";
53
+ declaredVariables.add(node.target);
54
+ }
55
+ return `${prefix}${node.target} = ${generateCodeFromAst(node.value)};`;
56
+ }
57
+
58
+ function generateWhile(node) {
59
+ const condition = generateCodeFromAst(node.condition);
60
+ const body = node.body.map(generateCodeFromAst).join("\n");
61
+ return `while (${condition}) {\n${body}\n}`;
62
+ }
63
+
64
+ function generateIf(node) {
65
+ const condition = generateCodeFromAst(node.condition);
66
+ const consequent = node.consequent.map(generateCodeFromAst).join("\n");
67
+ return `if (${condition}) {\n${consequent}\n}`;
68
+ }
69
+
70
+ function generateReturn(node) {
71
+ return `return ${generateCodeFromAst(node.expression)};`;
72
+ }
73
+
74
+ function generateCall(node) {
75
+ const args = node.args.map(generateCodeFromAst).join(", ");
76
+ let callCode = `${node.name}(${args})`;
77
+ if (node.target) {
78
+ let prefix = "";
79
+ if (!declaredVariables.has(node.target)) {
80
+ prefix = "let ";
81
+ declaredVariables.add(node.target);
82
+ }
83
+ callCode = `${prefix}${node.target} = ${callCode};`;
84
+ }
85
+ return callCode;
86
+ }
87
+
88
+ function generatePrint(node) {
89
+ return `console.log(${generateCodeFromAst(node.value)});`;
90
+ }
91
+
92
+ function generateBinary(node) {
93
+ const left = generateCodeFromAst(node.left);
94
+ const right = generateCodeFromAst(node.right);
95
+ return `${left} ${node.operator} ${right}`;
96
+ }
97
+
98
+ function generateIndexAccess(node) {
99
+ const index = generateCodeFromAst(node.index);
100
+ return `${node.name}[${index}]`;
101
+ }
102
+
103
+ function generateList(node) {
104
+ const elements = node.elements.map(generateCodeFromAst).join(", ");
105
+ return `[${elements}]`;
106
+ }
package/index.js ADDED
@@ -0,0 +1,48 @@
1
+ import { generateTokens } from "./compiler/lexer/tokenizer";
2
+ import { parseTokens } from "./compiler/parser/parser";
3
+ import { interpret } from "./compiler/execute/interpreter";
4
+ import { generateGoCodeFromAstArray } from "./converter/go/convert";
5
+ import { generateCodeJsFromAstArray } from "./converter/js/convert";
6
+ import fs from "fs";
7
+
8
+ // The main class for the Mimo language
9
+ export default class Mimo {
10
+ constructor() {
11
+ // Initialize the environment for variables
12
+ this.env = {};
13
+ }
14
+
15
+ // Tokenize the given code into a list of tokens
16
+ async tokenize(code) {
17
+ return generateTokens(code);
18
+ }
19
+
20
+ // Parse the list of tokens into an abstract syntax tree (AST)
21
+ async parse(tokens) {
22
+ return parseTokens(tokens);
23
+ }
24
+
25
+ // Interpret the AST and execute the code
26
+ async interpret(program) {
27
+ return interpret(program, this.env);
28
+ }
29
+
30
+ // Run the given code by tokenizing, parsing, and interpreting it
31
+ async run(code) {
32
+ const tokens = await this.tokenize(code);
33
+ const program = await this.parse(tokens);
34
+ return await this.interpret(program);
35
+ }
36
+
37
+ // Convert the AST to JavaScript code
38
+ toJS(ast) {
39
+ return generateCodeJsFromAstArray(ast);
40
+ }
41
+
42
+ // Convert the AST to Go code
43
+ toGO(ast) {
44
+ return generateGoCodeFromAstArray(ast);
45
+ }
46
+ }
47
+
48
+
package/jsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+
22
+ // Some stricter flags (disabled by default)
23
+ "noUnusedLocals": false,
24
+ "noUnusedParameters": false,
25
+ "noPropertyAccessFromIndexSignature": false
26
+ }
27
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "mimo-lang",
3
+ "version": "1.0.0",
4
+ "description": "A programming language made in javascript mostly for learning purposes.",
5
+ "keywords": [
6
+ "programing language"
7
+ ],
8
+ "author": "bethropolis",
9
+ "license": "MIT",
10
+ "main": "index.js",
11
+ "module": "index.js",
12
+ "type": "module",
13
+ "bin": {
14
+ "mimo": "./cli.js"
15
+ },
16
+ "scripts": {
17
+ "dev": "bun index.js"
18
+ },
19
+ "devDependencies": {
20
+ "@types/bun": "latest"
21
+ },
22
+ "dependencies": {
23
+ "esformatter": "^0.11.3"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/bethropolis/mimo.git"
28
+ },
29
+ "homepage": "https://bethropolis.github.io/mimo",
30
+ "bugs": {
31
+ "url": "https://github.com/bethropolis/mimo/issues"
32
+ }
33
+ }
package/test.js ADDED
@@ -0,0 +1 @@
1
+ console.log(a)