lumos-language 1.0.5 → 1.0.7
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.
- package/README.md +13 -0
- package/index.cjs +157 -0
- package/package.json +11 -8
- package/index.js +0 -153
package/README.md
CHANGED
|
@@ -44,11 +44,24 @@ Lumos is influenced by
|
|
|
44
44
|
<li><code>break</code></li>
|
|
45
45
|
<li><code>continue</code></li>
|
|
46
46
|
</ul>
|
|
47
|
+
- Launch from your terminal:
|
|
48
|
+
<ol>
|
|
49
|
+
<li><code>cd path/to/lumos-language</code></li>
|
|
50
|
+
<li><code>node index.cjs</code></li>
|
|
51
|
+
</ol>
|
|
52
|
+
- Compile on your terminal:
|
|
53
|
+
<ol>
|
|
54
|
+
<li><code>cd path/to/lumos-language</code></li>
|
|
55
|
+
<li><code>node index.cjs main.lumos</code></li>
|
|
56
|
+
</ol>
|
|
47
57
|
|
|
48
58
|
## Caution
|
|
49
59
|
|
|
50
60
|
- Please write the code in a single line and don't execute it while writing.
|
|
51
61
|
|
|
62
|
+
## Change
|
|
63
|
+
- You can refer to [npm](https://www.npmjs.com/package/lumos-language) or [GitHub Releases](https://github.com/Uchida16104/Lumos-Language/releases).
|
|
64
|
+
|
|
52
65
|
## More Info
|
|
53
66
|
Get from <strong><a href="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.pdf?v=1748869028196">pdf</a></strong>.
|
|
54
67
|
|
package/index.cjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const readline = require("readline");
|
|
5
|
+
|
|
6
|
+
const vars = {};
|
|
7
|
+
const functions = {};
|
|
8
|
+
|
|
9
|
+
function evaluateExpression(expr, scope = vars) {
|
|
10
|
+
expr = expr.trim();
|
|
11
|
+
if (/^".*"$/.test(expr)) return expr.slice(1, -1);
|
|
12
|
+
if (expr in scope) return scope[expr];
|
|
13
|
+
if (!isNaN(expr)) return Number(expr);
|
|
14
|
+
|
|
15
|
+
let m;
|
|
16
|
+
|
|
17
|
+
if ((m = expr.match(/^(.+?)\s*(==|!=|<=|>=|<|>)\s*(.+)$/))) {
|
|
18
|
+
const a = evaluateExpression(m[1], scope);
|
|
19
|
+
const b = evaluateExpression(m[3], scope);
|
|
20
|
+
switch (m[2]) {
|
|
21
|
+
case "==": return a == b;
|
|
22
|
+
case "!=": return a != b;
|
|
23
|
+
case "<=": return a <= b;
|
|
24
|
+
case ">=": return a >= b;
|
|
25
|
+
case "<": return a < b;
|
|
26
|
+
case ">": return a > b;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if ((m = expr.match(/^(.+?)\s*([+\-*/%])\s*(.+)$/))) {
|
|
31
|
+
const a = evaluateExpression(m[1], scope);
|
|
32
|
+
const b = evaluateExpression(m[3], scope);
|
|
33
|
+
switch (m[2]) {
|
|
34
|
+
case "+": return a + b;
|
|
35
|
+
case "-": return a - b;
|
|
36
|
+
case "*": return a * b;
|
|
37
|
+
case "/": return a / b;
|
|
38
|
+
case "%": return a % b;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
throw new Error("Invalid expression: " + expr);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function interpret(cmd) {
|
|
46
|
+
let m;
|
|
47
|
+
|
|
48
|
+
if ((m = cmd.match(/^let\s+(\w+)\s*=\s*(.+)$/))) {
|
|
49
|
+
const name = m[1], value = evaluateExpression(m[2]);
|
|
50
|
+
vars[name] = value;
|
|
51
|
+
return `${name} = ${value}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if ((m = cmd.match(/^def\s+(\w+)\(([^)]*)\)\s*{([\s\S]+)}$/))) {
|
|
55
|
+
const name = m[1];
|
|
56
|
+
const params = m[2].split(",").map(s => s.trim()).filter(Boolean);
|
|
57
|
+
const body = m[3].trim();
|
|
58
|
+
functions[name] = { params, body };
|
|
59
|
+
return `Function ${name} defined.`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if ((m = cmd.match(/^(\w+)\((.*)\)$/)) && functions[m[1]]) {
|
|
63
|
+
const func = functions[m[1]];
|
|
64
|
+
const args = m[2] ? m[2].split(",").map(s => s.trim()) : [];
|
|
65
|
+
const localScope = { ...vars };
|
|
66
|
+
func.params.forEach((p, i) => {
|
|
67
|
+
localScope[p] = evaluateExpression(args[i], vars);
|
|
68
|
+
});
|
|
69
|
+
const letm = func.body.match(/^let\s+(\w+)\s*=\s*(.+)$/);
|
|
70
|
+
if (!letm) throw new Error("Invalid function body");
|
|
71
|
+
const res = evaluateExpression(letm[2], localScope);
|
|
72
|
+
vars[letm[1]] = res;
|
|
73
|
+
return `${letm[1]} = ${res}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if ((m = cmd.match(/^for\s+(\w+)\s*=\s*(\d+)\s+to\s+(\d+)\s*{([\s\S]+)}$/))) {
|
|
77
|
+
const [_, v, s, e, body] = m;
|
|
78
|
+
for (let i = +s; i <= +e; i++) {
|
|
79
|
+
vars[v] = i;
|
|
80
|
+
interpret(body.trim());
|
|
81
|
+
}
|
|
82
|
+
return `Looped ${v} from ${s} to ${e}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if ((m = cmd.match(/^while\s*\((.+?)\)\s*{([\s\S]+)}$/))) {
|
|
86
|
+
const cond = m[1], body = m[2].trim();
|
|
87
|
+
let count = 0;
|
|
88
|
+
while (evaluateExpression(cond)) {
|
|
89
|
+
interpret(body);
|
|
90
|
+
if (++count > 10000) throw new Error("Infinite loop detected");
|
|
91
|
+
}
|
|
92
|
+
return "While loop executed.";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if ((m = cmd.match(/^if\s*\((.+?)\)\s*{([\s\S]+?)}(?:\s*elsif\s*\((.+?)\)\s*{([\s\S]+?)})?(?:\s*else\s*{([\s\S]+?)})?$/))) {
|
|
96
|
+
if (evaluateExpression(m[1])) return interpret(m[2].trim());
|
|
97
|
+
else if (m[3] && evaluateExpression(m[3])) return interpret(m[4].trim());
|
|
98
|
+
else if (m[5]) return interpret(m[5].trim());
|
|
99
|
+
return "If condition was false.";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if ((m = cmd.match(/^(\d+)\.times\s+do\s+\|(\w+)\|\s*{([\s\S]+)}\s*end$/))) {
|
|
103
|
+
const [_, n, v, body] = m;
|
|
104
|
+
let out = [];
|
|
105
|
+
for (let i = 0; i < +n; i++) {
|
|
106
|
+
vars[v] = i;
|
|
107
|
+
out.push(interpret(body.trim()));
|
|
108
|
+
}
|
|
109
|
+
return out.join("\n");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (vars.hasOwnProperty(cmd)) {
|
|
113
|
+
return vars[cmd];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
throw new Error("Unrecognized command: " + cmd);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function runFile(fn) {
|
|
120
|
+
const lines = fs.readFileSync(fn, "utf8").split(/\r?\n/);
|
|
121
|
+
lines.filter(line => line.trim()).forEach(line => {
|
|
122
|
+
const res = interpret(line.trim());
|
|
123
|
+
console.log("> " + res);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function startREPL() {
|
|
128
|
+
const rl = readline.createInterface({
|
|
129
|
+
input: process.stdin,
|
|
130
|
+
output: process.stdout,
|
|
131
|
+
prompt: "Lumos> ",
|
|
132
|
+
});
|
|
133
|
+
console.log("Welcome to Lumos CLI (type exit)");
|
|
134
|
+
rl.prompt();
|
|
135
|
+
|
|
136
|
+
rl.on("line", line => {
|
|
137
|
+
if (line.trim() === "exit") return rl.close();
|
|
138
|
+
if (line.trim()) {
|
|
139
|
+
try {
|
|
140
|
+
const res = interpret(line.trim());
|
|
141
|
+
console.log("> " + res);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.error("! " + e.message);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
rl.prompt();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
rl.on("close", () => {
|
|
150
|
+
console.log("Goodbye!");
|
|
151
|
+
process.exit(0);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const args = process.argv.slice(2);
|
|
156
|
+
if (args.length) runFile(args[0]);
|
|
157
|
+
else startREPL();
|
package/package.json
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lumos-language",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Lumos - Interactive CLI",
|
|
5
|
-
"main": "index.
|
|
5
|
+
"main": "index.cjs",
|
|
6
6
|
"bin": {
|
|
7
|
-
"lumos": "index.
|
|
7
|
+
"lumos": "./index.cjs"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/Uchida16104/Lumos.git"
|
|
11
|
+
"url": "git+https://github.com/Uchida16104/Lumos-Language.git"
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
|
-
|
|
14
|
+
"@Uchida16104:registry": "https://npm.pkg.github.com"
|
|
15
15
|
},
|
|
16
16
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/Uchida16104/Lumos/issues"
|
|
17
|
+
"url": "https://github.com/Uchida16104/Lumos-Language/issues"
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://lumos-language.glitch.me",
|
|
20
20
|
"author": "Hirotoshi Uchida",
|
|
21
21
|
"license": "MIT",
|
|
22
|
-
"type": "
|
|
22
|
+
"type": "commonjs",
|
|
23
23
|
"scripts": {
|
|
24
24
|
"test": "lumos"
|
|
25
25
|
},
|
|
26
26
|
"keywords": [
|
|
27
27
|
"programming-language"
|
|
28
|
-
]
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"lumos-language": "^1.0.7"
|
|
31
|
+
}
|
|
29
32
|
}
|
package/index.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const readline = require("readline");
|
|
4
|
-
|
|
5
|
-
class BreakException {}
|
|
6
|
-
class ContinueException {}
|
|
7
|
-
|
|
8
|
-
const vars = {};
|
|
9
|
-
const functions = {};
|
|
10
|
-
|
|
11
|
-
function evaluateExpression(expr) {
|
|
12
|
-
try {
|
|
13
|
-
return Function(...Object.keys(vars), `return (${expr})`)(...Object.values(vars));
|
|
14
|
-
} catch (e) {
|
|
15
|
-
throw new Error("Invalid expression: " + expr);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function preprocessCommand(command) {
|
|
20
|
-
command = command.replace(/\r\n/g, "\n");
|
|
21
|
-
|
|
22
|
-
const timesRegex = /^(\d+)\.times\s+do\s+\|([a-zA-Z_][a-zA-Z0-9_]*)\|([\s\S]+?)end$/;
|
|
23
|
-
const timesMatch = command.match(timesRegex);
|
|
24
|
-
if (timesMatch) {
|
|
25
|
-
const count = parseInt(timesMatch[1]);
|
|
26
|
-
const varName = timesMatch[2];
|
|
27
|
-
const body = timesMatch[3].trim();
|
|
28
|
-
let result = "";
|
|
29
|
-
for (let i = 0; i < count; i++) {
|
|
30
|
-
vars[varName] = i;
|
|
31
|
-
result += interpret(body) + "\n";
|
|
32
|
-
}
|
|
33
|
-
return result.trim();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const ifElseRegex = /^if\s*\((.+?)\)\s*\{([\s\S]+?)\}(?:\s*elsif\s*\((.+?)\)\s*\{([\s\S]+?)\})?(?:\s*else\s*\{([\s\S]+?)\})?$/;
|
|
37
|
-
const ifElseMatch = command.match(ifElseRegex);
|
|
38
|
-
if (ifElseMatch) {
|
|
39
|
-
const [, cond1, body1, cond2, body2, body3] = ifElseMatch;
|
|
40
|
-
if (evaluateExpression(cond1)) return interpret(body1.trim());
|
|
41
|
-
if (cond2 && evaluateExpression(cond2)) return interpret(body2.trim());
|
|
42
|
-
if (body3) return interpret(body3.trim());
|
|
43
|
-
return "If condition was false.";
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function interpret(command) {
|
|
50
|
-
const preprocessed = preprocessCommand(command);
|
|
51
|
-
if (preprocessed !== null) return preprocessed;
|
|
52
|
-
|
|
53
|
-
command = command.trim();
|
|
54
|
-
|
|
55
|
-
if (/^let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/.test(command)) {
|
|
56
|
-
const [, name, value] = command.match(/^let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/);
|
|
57
|
-
vars[name] = evaluateExpression(value);
|
|
58
|
-
return `${name} = ${vars[name]}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (/^def\s+([a-zA-Z_][a-zA-Z0-9_]*)\(([^)]*)\)\s*\{([\s\S]*)\}$/.test(command)) {
|
|
62
|
-
const [, name, args, body] = command.match(/^def\s+([a-zA-Z_][a-zA-Z0-9_]*)\(([^)]*)\)\s*\{([\s\S]*)\}$/);
|
|
63
|
-
functions[name] = {
|
|
64
|
-
args: args.split(",").map((s) => s.trim()).filter((s) => s),
|
|
65
|
-
body: body.trim(),
|
|
66
|
-
};
|
|
67
|
-
return `Function ${name} defined.`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (/^([a-zA-Z_][a-zA-Z0-9_]*)\((.*)\)$/.test(command)) {
|
|
71
|
-
const [, name, argstr] = command.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\((.*)\)$/);
|
|
72
|
-
if (!functions[name]) throw new Error("Undefined function: " + name);
|
|
73
|
-
const func = functions[name];
|
|
74
|
-
const argValues = argstr.split(",").map((s) => evaluateExpression(s.trim()));
|
|
75
|
-
const localVars = {};
|
|
76
|
-
func.args.forEach((arg, i) => (localVars[arg] = argValues[i]));
|
|
77
|
-
|
|
78
|
-
const prevVars = Object.assign({}, vars);
|
|
79
|
-
Object.assign(vars, localVars);
|
|
80
|
-
|
|
81
|
-
let result;
|
|
82
|
-
try {
|
|
83
|
-
result = interpret(func.body);
|
|
84
|
-
} finally {
|
|
85
|
-
Object.assign(vars, prevVars);
|
|
86
|
-
}
|
|
87
|
-
return result;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
let loopMatch = command.match(/^for\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+?)\s+to\s+(.+?)\s*\{([\s\S]+)\}$/);
|
|
91
|
-
if (loopMatch) {
|
|
92
|
-
const vname = loopMatch[1];
|
|
93
|
-
const start = evaluateExpression(loopMatch[2]);
|
|
94
|
-
const end = evaluateExpression(loopMatch[3]);
|
|
95
|
-
const body = loopMatch[4];
|
|
96
|
-
|
|
97
|
-
for (let i = start; i <= end; i++) {
|
|
98
|
-
vars[vname] = i;
|
|
99
|
-
try {
|
|
100
|
-
interpret(body.trim());
|
|
101
|
-
} catch (e) {
|
|
102
|
-
if (e instanceof BreakException) break;
|
|
103
|
-
if (e instanceof ContinueException) continue;
|
|
104
|
-
throw e;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return `Looped ${vname} from ${start} to ${end}`;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
let whileMatch = command.match(/^while\s*\((.+?)\)\s*\{([\s\S]+)\}$/);
|
|
111
|
-
if (whileMatch) {
|
|
112
|
-
const condition = whileMatch[1];
|
|
113
|
-
const body = whileMatch[2];
|
|
114
|
-
|
|
115
|
-
while (evaluateExpression(condition)) {
|
|
116
|
-
try {
|
|
117
|
-
interpret(body.trim());
|
|
118
|
-
} catch (e) {
|
|
119
|
-
if (e instanceof BreakException) break;
|
|
120
|
-
if (e instanceof ContinueException) continue;
|
|
121
|
-
throw e;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return "While loop executed.";
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (command === "break") throw new BreakException();
|
|
128
|
-
if (command === "continue") throw new ContinueException();
|
|
129
|
-
|
|
130
|
-
return evaluateExpression(command);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// CLI 入力受付
|
|
134
|
-
const rl = readline.createInterface({
|
|
135
|
-
input: process.stdin,
|
|
136
|
-
output: process.stdout,
|
|
137
|
-
prompt: "Lumos> ",
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
console.log("Welcome to Lumos CLI!");
|
|
141
|
-
rl.prompt();
|
|
142
|
-
|
|
143
|
-
rl.on("line", (line) => {
|
|
144
|
-
const command = line.trim();
|
|
145
|
-
try {
|
|
146
|
-
const result = interpret(command);
|
|
147
|
-
console.log("> " + result);
|
|
148
|
-
} catch (err) {
|
|
149
|
-
console.error("! " + err.message);
|
|
150
|
-
}
|
|
151
|
-
rl.prompt();
|
|
152
|
-
});
|
|
153
|
-
|