UNPKG

lumos-language

Version:
287 lines (257 loc) 9.47 kB
<html> <head> <meta charset="UTF-8" /> <title>Lumos Language</title> <link rel="apple-touch-icon" sizes="180x180" href="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.png" /> <link rel="icon" type="image/x-icon" href="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.ico" /> <style> body { font-family: monospace; background: #1e1e1e; color: #d4d4d4; padding: 1em; } .header { display: flex; } h1 { font-size: 4em; display: inline-block; vertical-align: middle; } h3 { font-size: 2em; } iframe { display: block; margin: 0 auto; } img { width: 10%; height: 10%; } #output { white-space: pre-wrap; margin-top: 1em; } input[type="text"] { width: 100%; padding: 0.5em; background: #2e2e2e; color: white; border: none; } .history-item { cursor: pointer; color: #9cdcfe; } #compileButton { margin-top: 1em; background: #007acc; color: white; border: none; padding: 0.5em 1em; cursor: pointer; font-weight: bold; } #compileButton:hover { background: #005f9e; } h5, #logo { text-align: center; } .github { mix-blend-mode: darken; } .npm { mix-blend-mode: color; } .github, .npm { width: 100px; height: 100px; } </style> </head> <body> <div class="header"> <img src="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.png?v=1748865997035" /> <h1>Lumos Language</h1> </div> <h4>Press Enter / Return to execute your code.</h4> <input type="text" id="input" placeholder="Enter command..." /> <button id="compileButton">Compile</button> <br /> <h3>Usage</h3> <iframe src="https://cdn.glitch.global/a6e15949-0cae-4ce8-a653-5883a6d0adc5/Lumos.pdf?v=1748869028196" width="80%" height="50%"></iframe> <div id="output"></div> <script> class BreakException {} class ContinueException {} const vars = {}; const functions = {}; const history = []; function evaluateExpression(expr) { try { return Function(...Object.keys(vars), `return (${expr})`)(...Object.values(vars)); } catch (e) { throw new Error("Invalid expression: " + expr); } } function preprocessCommand(command) { command = command.replace(/\r\n/g, "\n"); const timesRegex = /^(\d+)\.times\s+do\s+\|([a-zA-Z_][a-zA-Z0-9_]*)\|([\s\S]+?)end$/; const timesMatch = command.match(timesRegex); if (timesMatch) { const count = parseInt(timesMatch[1]); const varName = timesMatch[2]; const body = timesMatch[3].trim(); let result = ""; for (let i = 0; i < count; i++) { vars[varName] = i; result += interpret(body) + "\n"; } return result.trim(); } const ifElseRegex = /^if\s*\((.+?)\)\s*\{([\s\S]+?)\}(?:\s*elsif\s*\((.+?)\)\s*\{([\s\S]+?)\})?(?:\s*else\s*\{([\s\S]+?)\})?$/; const ifElseMatch = command.match(ifElseRegex); if (ifElseMatch) { const [, cond1, body1, cond2, body2, body3] = ifElseMatch; if (evaluateExpression(cond1)) return interpret(body1.trim()); if (cond2 && evaluateExpression(cond2)) return interpret(body2.trim()); if (body3) return interpret(body3.trim()); return "If condition was false."; } return null; } function interpret(command) { const preprocessed = preprocessCommand(command); if (preprocessed !== null) return preprocessed; command = command.trim(); if (/^let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/.test(command)) { const [, name, value] = command.match(/^let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/); vars[name] = evaluateExpression(value); return `${name} = ${vars[name]}`; } if (/^def\s+([a-zA-Z_][a-zA-Z0-9_]*)\(([^)]*)\)\s*\{([\s\S]*)\}$/.test(command)) { const [, name, args, body] = command.match(/^def\s+([a-zA-Z_][a-zA-Z0-9_]*)\(([^)]*)\)\s*\{([\s\S]*)\}$/); functions[name] = { args: args.split(",").map((s) => s.trim()).filter((s) => s), body: body.trim(), }; return `Function ${name} defined.`; } if (/^([a-zA-Z_][a-zA-Z0-9_]*)\((.*)\)$/.test(command)) { const [, name, argstr] = command.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\((.*)\)$/); if (!functions[name]) throw new Error("Undefined function: " + name); const func = functions[name]; const argValues = argstr.split(",").map((s) => evaluateExpression(s.trim())); const localVars = {}; func.args.forEach((arg, i) => (localVars[arg] = argValues[i])); const prevVars = Object.assign({}, vars); Object.assign(vars, localVars); let result; try { result = interpret(func.body); } finally { Object.assign(vars, prevVars); } return result; } let loopMatch = command.match(/^for\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+?)\s+to\s+(.+?)\s*\{([\s\S]+)\}$/); if (loopMatch) { const vname = loopMatch[1]; const start = evaluateExpression(loopMatch[2]); const end = evaluateExpression(loopMatch[3]); const body = loopMatch[4]; for (let i = start; i <= end; i++) { vars[vname] = i; try { interpret(body.trim()); } catch (e) { if (e instanceof BreakException) break; if (e instanceof ContinueException) continue; throw e; } } return `Looped ${vname} from ${start} to ${end}`; } let whileMatch = command.match(/^while\s*\((.+?)\)\s*\{([\s\S]+)\}$/); if (whileMatch) { const condition = whileMatch[1]; const body = whileMatch[2]; while (evaluateExpression(condition)) { try { interpret(body.trim()); } catch (e) { if (e instanceof BreakException) break; if (e instanceof ContinueException) continue; throw e; } } return "While loop executed."; } if (command === "break") throw new BreakException(); if (command === "continue") throw new ContinueException(); return evaluateExpression(command); } const input = document.getElementById("input"); const output = document.getElementById("output"); input.addEventListener("keydown", function (e) { if (e.key === "Enter") { const command = input.value.trim(); if (command === "") return; history.push(command); const historyItem = document.createElement("div"); historyItem.className = "history-item"; historyItem.textContent = command; historyItem.onclick = () => { input.value = command; input.focus(); }; output.appendChild(historyItem); try { const result = interpret(command); const resultDiv = document.createElement("div"); resultDiv.textContent = `> ${result}`; output.appendChild(resultDiv); } catch (err) { const errorDiv = document.createElement("div"); errorDiv.textContent = `! ${err.message}`; errorDiv.style.color = "red"; output.appendChild(errorDiv); } input.value = ""; } }); document.getElementById("compileButton").addEventListener("click", () => { output.appendChild(document.createElement("hr")); for (let i = 0; i < history.length; i++) { const command = history[i]; const lineHeader = `Line ${i + 1}: `; const historyLine = document.createElement("div"); historyLine.className = "history-item"; historyLine.textContent = lineHeader + command; output.appendChild(historyLine); try { const result = interpret(command); const resultDiv = document.createElement("div"); resultDiv.textContent = `> ${result}`; output.appendChild(resultDiv); } catch (err) { const errorDiv = document.createElement("div"); errorDiv.textContent = `! ${err.message}`; errorDiv.style.color = "red"; output.appendChild(errorDiv); } } }); </script> <footer> <div id="logo"> <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> <a href="https://www.npmjs.com/package/lumos-language"><img class="npm" src="https://icon2.cleanpng.com/20180618/hxa/aa6nx3pxr.webp" /></a> </div> <h5>2025 © Hirotoshi Uchida</h5> </footer> </body> </html>