lumos-language 1.0.4 → 1.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.
@@ -0,0 +1,33 @@
1
+ name: Release lumos-language
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-node@v4
13
+ with:
14
+ node-version: 20
15
+ - run: npm ci
16
+ - run: npm test
17
+
18
+ publish-gpr:
19
+ needs: build
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ packages: write
23
+ contents: read
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-node@v4
27
+ with:
28
+ node-version: 20
29
+ registry-url: https://npm.pkg.github.com/
30
+ - run: npm ci
31
+ - run: npm publish
32
+ env:
33
+ NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
package/LICENSE CHANGED
@@ -1,21 +1,13 @@
1
- The LICENSE file for any project gives credit to the creator/author of the
2
- project, copyright information for the project, and the legal terms under
3
- which it's being shared. In other words, this is us using an MIT license to
4
- say "we wrote this and you can do whatever you want with it."
5
-
6
- ******************************************************************************
7
- ~glitch-hello-website
8
- ******************************************************************************
9
1
  MIT License
10
2
 
11
- Copyright (c) 2021, Glitch, Inc.
3
+ Copyright (c) 2025 Hirotoshi Uchida
12
4
 
13
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
14
- of this software and associated documentation files (the "Software"), to deal
15
- in the Software without restriction, including without limitation the rights
16
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- copies of the Software, and to permit persons to whom the Software is
18
- furnished to do so, subject to the following conditions:
6
+ of the "lumos-language" software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including without
8
+ limitation the rights to use, copy, modify, merge, publish, distribute,
9
+ sublicense, and/or sell copies of the Software, and to permit persons to whom
10
+ the Software is furnished to do so, subject to the following conditions:
19
11
 
20
12
  The above copyright notice and this permission notice shall be included in all
21
13
  copies or substantial portions of the Software.
@@ -28,27 +20,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
21
  SOFTWARE.
30
22
 
23
+ ---
31
24
 
25
+ Third-Party Component:
32
26
 
33
-
34
- ******************************************************************************
35
-
36
- THIRD-PARTY SOFTWARE
37
- This is all the software we used to build this starter project. All of these
38
- licenses are compatible with the license above. We've included links so you
39
- can learn more if you want.
40
-
41
- 1. HK Grotesk: The font we're using.
42
-
43
-
44
- ******************************************************************************
45
- 1. HK Grotesk
46
- URL: https://hanken.co/products/hk-grotesk
47
- ******************************************************************************
48
- HK Grotesk was designed by Hanken Design Co. It is shared using a SIL OFL
49
- license. Full license text can be found at:
50
-
27
+ The font “HK Grotesk” used in this project is designed by Hanken Design Co.
28
+ and is licensed separately under the SIL Open Font License (OFL). Complete
29
+ terms for HK Grotesk can be found here:
51
30
  https://hanken.co/pages/web-fonts-eula
52
- ******************************************************************************
53
- END, HK Grotesk
54
- ******************************************************************************
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Lumos
1
+ # Lumos Language
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/lumos-language.svg)](https://www.npmjs.com/package/lumos-language)
4
4
 
@@ -37,7 +37,7 @@ Lumos is influenced by
37
37
  - Conditional branch:
38
38
  <ul>
39
39
  <li><code>if (x == 10) { let status = "Done" } else { let status = "Not yet" }</code></li>
40
- <li><code>if (let x == 10) { let status = "Done" } elsif (let x == 20) { let status = "Already" } else { let status = "Not yet" }</code></li>
40
+ <li><code>if (x == 10) { let status = "Done" } elsif (x == 20) { let status = "Already" } else { let status = "Not yet" }</code></li>
41
41
  </ul>
42
42
  - Break and Continue:
43
43
  <ul>
@@ -49,6 +49,9 @@ Lumos is influenced by
49
49
 
50
50
  - Please write the code in a single line and don't execute it while writing.
51
51
 
52
+ ## Change
53
+ - You can refer to [npm](https://www.npmjs.com/package/lumos-language) or [GitHub Releases](https://github.com/Uchida16104/Lumos-Language/releases).
54
+
52
55
  ## More Info
53
56
  Get from <strong><a href="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.pdf?v=1748869028196">pdf</a></strong>.
54
57
 
package/index.html CHANGED
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
  <head>
3
3
  <meta charset="UTF-8" />
4
- <title>Lumos</title>
4
+ <title>Lumos Language</title>
5
5
  <link rel="apple-touch-icon" sizes="180x180" href="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.png" />
6
6
  <link rel="icon" type="image/x-icon" href="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.ico" />
7
7
  <style>
@@ -57,15 +57,25 @@
57
57
  #compileButton:hover {
58
58
  background: #005f9e;
59
59
  }
60
- h5 {
60
+ h5, #logo {
61
61
  text-align: center;
62
62
  }
63
+ .github {
64
+ mix-blend-mode: darken;
65
+ }
66
+ .npm {
67
+ mix-blend-mode: color;
68
+ }
69
+ .github, .npm {
70
+ width: 100px;
71
+ height: 100px;
72
+ }
63
73
  </style>
64
74
  </head>
65
75
  <body>
66
76
  <div class="header">
67
77
  <img src="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.png?v=1748865997035" />
68
- <h1>Lumos</h1>
78
+ <h1>Lumos Language</h1>
69
79
  </div>
70
80
  <input type="text" id="input" placeholder="Enter command..." />
71
81
  <button id="compileButton">Compile</button>
@@ -265,6 +275,10 @@
265
275
  });
266
276
  </script>
267
277
  <footer>
278
+ <div id="logo">
279
+ <a href="https://github.com/Uchida16104/Lumos-Language"><img class="github" src="https://icon2.cleanpng.com/20180530/ywr/kisspng-github-computer-icons-directory-5b0ec64b102792.7107546015276949230662.jpg" /></a>
280
+ <a href="https://www.npmjs.com/package/lumos-language"><img class="npm" src="https://icon2.cleanpng.com/20180618/hxa/aa6nx3pxr.webp" /></a>
281
+ </div>
268
282
  <h5>2025 © Hirotoshi Uchida</h5>
269
283
  </footer>
270
284
  </body>
package/index.js CHANGED
@@ -1,153 +1,157 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const fs = require("fs");
3
4
  const readline = require("readline");
4
5
 
5
- class BreakException {}
6
- class ContinueException {}
7
-
8
6
  const vars = {};
9
7
  const functions = {};
10
8
 
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";
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;
32
27
  }
33
- return result.trim();
34
28
  }
35
29
 
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.";
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
+ }
44
40
  }
45
41
 
46
- return null;
42
+ throw new Error("Invalid expression: " + expr);
47
43
  }
48
44
 
49
- function interpret(command) {
50
- const preprocessed = preprocessCommand(command);
51
- if (preprocessed !== null) return preprocessed;
45
+ function interpret(cmd) {
46
+ let m;
52
47
 
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]}`;
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}`;
59
52
  }
60
53
 
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
- };
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 };
67
59
  return `Function ${name} defined.`;
68
60
  }
69
61
 
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;
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}`;
88
74
  }
89
75
 
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];
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
+ }
96
84
 
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
- }
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");
106
91
  }
107
- return `Looped ${vname} from ${start} to ${end}`;
92
+ return "While loop executed.";
108
93
  }
109
94
 
110
- let whileMatch = command.match(/^while\s*\((.+?)\)\s*\{([\s\S]+)\}$/);
111
- if (whileMatch) {
112
- const condition = whileMatch[1];
113
- const body = whileMatch[2];
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
+ }
114
101
 
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
- }
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()));
123
108
  }
124
- return "While loop executed.";
109
+ return out.join("\n");
125
110
  }
126
111
 
127
- if (command === "break") throw new BreakException();
128
- if (command === "continue") throw new ContinueException();
112
+ if (vars.hasOwnProperty(cmd)) {
113
+ return vars[cmd];
114
+ }
129
115
 
130
- return evaluateExpression(command);
116
+ throw new Error("Unrecognized command: " + cmd);
131
117
  }
132
118
 
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
- }
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)");
151
134
  rl.prompt();
152
- });
153
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,6 +1,6 @@
1
1
  {
2
2
  "name": "lumos-language",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Lumos - Interactive CLI",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -8,13 +8,13 @@
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
- "@Uchida16104:registry": "https://npm.pkg.github.com"
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",
@@ -25,5 +25,8 @@
25
25
  },
26
26
  "keywords": [
27
27
  "programming-language"
28
- ]
28
+ ],
29
+ "dependencies": {
30
+ "lumos-language": "^1.0.6"
31
+ }
29
32
  }