| <!DOCTYPE html>
|
| <html lang="en">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>Lisp Machine β Interactive REPL</title>
|
| <style>
|
| * {
|
| margin: 0;
|
| padding: 0;
|
| box-sizing: border-box;
|
| }
|
|
|
| body {
|
| font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
| background: linear-gradient(135deg, #0a0e27 0%, #1a1a2e 100%);
|
| color: #e0e0e0;
|
| min-height: 100vh;
|
| display: flex;
|
| flex-direction: column;
|
| }
|
|
|
| header {
|
| background: rgba(0, 0, 0, 0.8);
|
| border-bottom: 2px solid #0d7;
|
| padding: 20px;
|
| box-shadow: 0 4px 12px rgba(0, 221, 119, 0.2);
|
| }
|
|
|
| h1 {
|
| font-size: 2em;
|
| color: #0d7;
|
| text-shadow: 0 0 20px rgba(0, 221, 119, 0.3);
|
| margin-bottom: 5px;
|
| }
|
|
|
| .subtitle {
|
| color: #888;
|
| font-size: 0.9em;
|
| margin-bottom: 10px;
|
| }
|
|
|
| .status-bar {
|
| display: flex;
|
| gap: 20px;
|
| font-size: 0.85em;
|
| }
|
|
|
| .status-item {
|
| display: flex;
|
| gap: 8px;
|
| align-items: center;
|
| }
|
|
|
| .status-indicator {
|
| width: 8px;
|
| height: 8px;
|
| border-radius: 50%;
|
| background: #f44;
|
| }
|
|
|
| .status-indicator.ready {
|
| background: #0d7;
|
| }
|
|
|
| main {
|
| flex: 1;
|
| display: grid;
|
| grid-template-columns: 1fr 1fr;
|
| gap: 20px;
|
| padding: 20px;
|
| max-width: 1600px;
|
| margin: 0 auto;
|
| width: 100%;
|
| }
|
|
|
| .panel {
|
| background: rgba(45, 45, 48, 0.95);
|
| border: 1px solid #444;
|
| border-radius: 8px;
|
| display: flex;
|
| flex-direction: column;
|
| box-shadow: 0 8px 16px rgba(0, 0, 0, 0.5);
|
| overflow: hidden;
|
| }
|
|
|
| .panel-header {
|
| background: rgba(20, 20, 20, 0.9);
|
| border-bottom: 1px solid #444;
|
| padding: 12px 16px;
|
| font-weight: bold;
|
| color: #0d7;
|
| font-size: 0.95em;
|
| text-transform: uppercase;
|
| letter-spacing: 1px;
|
| }
|
|
|
| .panel-content {
|
| flex: 1;
|
| display: flex;
|
| flex-direction: column;
|
| overflow: hidden;
|
| }
|
|
|
| #input-area {
|
| display: flex;
|
| flex-direction: column;
|
| gap: 10px;
|
| padding: 16px;
|
| }
|
|
|
| .input-group {
|
| display: flex;
|
| flex-direction: column;
|
| gap: 8px;
|
| }
|
|
|
| label {
|
| font-size: 0.85em;
|
| color: #888;
|
| text-transform: uppercase;
|
| letter-spacing: 0.5px;
|
| }
|
|
|
| textarea, input {
|
| background: #1e1e1e;
|
| color: #0d7;
|
| border: 1px solid #333;
|
| border-radius: 4px;
|
| padding: 10px;
|
| font-family: 'Monaco', monospace;
|
| font-size: 0.9em;
|
| resize: none;
|
| outline: none;
|
| transition: border-color 0.2s;
|
| }
|
|
|
| textarea:focus, input:focus {
|
| border-color: #0d7;
|
| box-shadow: 0 0 10px rgba(0, 221, 119, 0.1);
|
| }
|
|
|
| #repl-input {
|
| height: 120px;
|
| flex: 0 0 auto;
|
| }
|
|
|
| .button-group {
|
| display: flex;
|
| gap: 8px;
|
| flex-wrap: wrap;
|
| }
|
|
|
| button {
|
| flex: 1;
|
| padding: 10px 16px;
|
| background: #0d7;
|
| color: #000;
|
| border: none;
|
| border-radius: 4px;
|
| font-family: monospace;
|
| font-size: 0.85em;
|
| font-weight: bold;
|
| cursor: pointer;
|
| transition: all 0.2s;
|
| text-transform: uppercase;
|
| min-width: 100px;
|
| }
|
|
|
| button:hover {
|
| background: #0fa;
|
| box-shadow: 0 0 15px rgba(0, 221, 119, 0.3);
|
| }
|
|
|
| button:active {
|
| transform: scale(0.98);
|
| }
|
|
|
| button:disabled {
|
| background: #666;
|
| color: #999;
|
| cursor: not-allowed;
|
| box-shadow: none;
|
| }
|
|
|
| .examples {
|
| display: grid;
|
| grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
| gap: 8px;
|
| }
|
|
|
| .example-btn {
|
| padding: 8px 12px !important;
|
| background: rgba(13, 221, 119, 0.2) !important;
|
| color: #0d7 !important;
|
| border: 1px solid #0d7 !important;
|
| font-size: 0.75em !important;
|
| flex: 0 !important;
|
| width: 100%;
|
| }
|
|
|
| .example-btn:hover {
|
| background: rgba(13, 221, 119, 0.4) !important;
|
| }
|
|
|
| #output-area {
|
| flex: 1;
|
| display: flex;
|
| flex-direction: column;
|
| gap: 12px;
|
| padding: 16px;
|
| overflow-y: auto;
|
| }
|
|
|
| #output {
|
| flex: 1;
|
| background: #1e1e1e;
|
| border: 1px solid #333;
|
| border-radius: 4px;
|
| padding: 12px;
|
| font-size: 0.85em;
|
| line-height: 1.6;
|
| color: #0d7;
|
| white-space: pre-wrap;
|
| word-wrap: break-word;
|
| overflow-y: auto;
|
| max-height: 400px;
|
| }
|
|
|
| .output-line {
|
| margin: 2px 0;
|
| }
|
|
|
| .output-line.error {
|
| color: #f44;
|
| }
|
|
|
| .output-line.success {
|
| color: #0d7;
|
| }
|
|
|
| .output-line.info {
|
| color: #88f;
|
| }
|
|
|
| .metrics {
|
| display: grid;
|
| grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
| gap: 8px;
|
| }
|
|
|
| .metric {
|
| background: #222;
|
| border: 1px solid #333;
|
| border-left: 3px solid #0d7;
|
| padding: 10px;
|
| border-radius: 4px;
|
| font-size: 0.8em;
|
| }
|
|
|
| .metric-label {
|
| color: #666;
|
| text-transform: uppercase;
|
| font-size: 0.75em;
|
| margin-bottom: 4px;
|
| }
|
|
|
| .metric-value {
|
| color: #0d7;
|
| font-weight: bold;
|
| font-size: 1.1em;
|
| }
|
|
|
| .tabs {
|
| display: flex;
|
| gap: 0;
|
| border-bottom: 1px solid #333;
|
| }
|
|
|
| .tab {
|
| padding: 10px 16px;
|
| background: transparent;
|
| border: none;
|
| border-bottom: 2px solid transparent;
|
| color: #666;
|
| cursor: pointer;
|
| font-size: 0.9em;
|
| text-transform: uppercase;
|
| transition: all 0.2s;
|
| font-family: monospace;
|
| margin: 0;
|
| flex: 0 0 auto;
|
| }
|
|
|
| .tab:hover {
|
| color: #0d7;
|
| }
|
|
|
| .tab.active {
|
| color: #0d7;
|
| border-bottom-color: #0d7;
|
| background: rgba(13, 221, 119, 0.1);
|
| }
|
|
|
| .tab-content {
|
| display: none;
|
| padding: 12px;
|
| background: #1e1e1e;
|
| max-height: 300px;
|
| overflow-y: auto;
|
| font-size: 0.8em;
|
| line-height: 1.6;
|
| }
|
|
|
| .tab-content.active {
|
| display: block;
|
| }
|
|
|
| .command-list {
|
| display: flex;
|
| flex-direction: column;
|
| gap: 8px;
|
| }
|
|
|
| .command-item {
|
| border-left: 2px solid #0d7;
|
| padding-left: 8px;
|
| color: #aaa;
|
| }
|
|
|
| .command-name {
|
| color: #0d7;
|
| font-weight: bold;
|
| }
|
|
|
| footer {
|
| background: rgba(0, 0, 0, 0.6);
|
| border-top: 1px solid #333;
|
| padding: 12px 20px;
|
| text-align: center;
|
| font-size: 0.8em;
|
| color: #666;
|
| }
|
|
|
| @media (max-width: 1024px) {
|
| main {
|
| grid-template-columns: 1fr;
|
| }
|
|
|
| #repl-input {
|
| height: 100px;
|
| }
|
|
|
| #output {
|
| max-height: 250px;
|
| }
|
| }
|
| </style>
|
| </head>
|
| <body>
|
| <header>
|
| <h1>πͺ Lisp Machine</h1>
|
| <p class="subtitle">McCarthy-1958 LISP + EmojiScript + SoulVM JIT on GitHub Pages</p>
|
| <div class="status-bar">
|
| <div class="status-item">
|
| <div class="status-indicator" id="wasm-status"></div>
|
| <span>WASM: <span id="wasm-text">Loading...</span></span>
|
| </div>
|
| <div class="status-item">
|
| <div class="status-indicator ready" id="kb-status"></div>
|
| <span>Knowledge Base: <span id="kb-text">Ready</span></span>
|
| </div>
|
| <div class="status-item">
|
| <div class="status-indicator" id="ledger-status"></div>
|
| <span>WORM Ledger: <span id="ledger-text">Ready</span></span>
|
| </div>
|
| </div>
|
| </header>
|
|
|
| <main>
|
|
|
| <div class="panel">
|
| <div class="panel-header">β¨οΈ Input</div>
|
| <div class="panel-content">
|
| <div id="input-area">
|
| <div class="input-group">
|
| <label>LISP / EmojiScript / Commands</label>
|
| <textarea id="repl-input" spellcheck="false" placeholder="Enter LISP code, EmojiScript, or REPL commands... Examples: (+ 1 2) π’6 π’7 βοΈ β©οΈ (emoji:exec "π’40 π’2 β β©οΈ") (kb:query :my-belief) (help)"></textarea>
|
| </div>
|
|
|
| <div class="button-group">
|
| <button onclick="evalInput()" id="eval-btn">βΆ Eval</button>
|
| <button onclick="clearInput()">β Clear</button>
|
| <button onclick="showHelp()">? Help</button>
|
| </div>
|
|
|
| <div class="input-group">
|
| <label>Quick Examples</label>
|
| <div class="examples">
|
| <button class="example-btn" onclick="loadExample('(+ 1 2)')">Lisp: 1+2</button>
|
| <button class="example-btn" onclick="loadExample('π’6 π’7 βοΈ β©οΈ')">Emoji: 6Γ7</button>
|
| <button class="example-btn" onclick="loadExample('(emoji:exec "π’40 π’2 β β©οΈ")')">JIT: 40+2</button>
|
| <button class="example-btn" onclick="loadExample('(kb:query :test)')">KB: Query</button>
|
| <button class="example-btn" onclick="loadExample('(help)')">Help</button>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="panel">
|
| <div class="panel-header">π€ Output & Metrics</div>
|
| <div class="panel-content">
|
| <div id="output-area">
|
| <div id="output" class="output-line">Ready. Type LISP or EmojiScript code above...</div>
|
|
|
| <div class="tabs">
|
| <button class="tab active" onclick="switchTab('metrics')">Metrics</button>
|
| <button class="tab" onclick="switchTab('history')">History</button>
|
| <button class="tab" onclick="switchTab('reference')">Reference</button>
|
| </div>
|
|
|
| <div id="metrics" class="tab-content active">
|
| <div class="metrics">
|
| <div class="metric">
|
| <div class="metric-label">Expressions</div>
|
| <div class="metric-value" id="expr-count">0</div>
|
| </div>
|
| <div class="metric">
|
| <div class="metric-label">Parse Time</div>
|
| <div class="metric-value" id="parse-time">β</div>
|
| </div>
|
| <div class="metric">
|
| <div class="metric-label">Compile Time</div>
|
| <div class="metric-value" id="compile-time">β</div>
|
| </div>
|
| <div class="metric">
|
| <div class="metric-label">Knowledge Base</div>
|
| <div class="metric-value" id="kb-facts">β</div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <div id="history" class="tab-content">
|
| <div id="history-content">No history yet</div>
|
| </div>
|
|
|
| <div id="reference" class="tab-content">
|
| <div class="command-list">
|
| <div class="command-item">
|
| <div class="command-name">(+ a b)</div>
|
| <div>Addition</div>
|
| </div>
|
| <div class="command-item">
|
| <div class="command-name">(emoji:compile source)</div>
|
| <div>Compile EmojiScript</div>
|
| </div>
|
| <div class="command-item">
|
| <div class="command-name">(jit:compile source cert)</div>
|
| <div>Compile with JIT</div>
|
| </div>
|
| <div class="command-item">
|
| <div class="command-name">(kb:query value)</div>
|
| <div>Query knowledge base</div>
|
| </div>
|
| <div class="command-item">
|
| <div class="command-name">(help)</div>
|
| <div>Show commands</div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </main>
|
|
|
| <footer>
|
| <p>Lisp Machine v1.1.0 | Clojure Compiler + EmojiScript VM + SoulVM JIT | <a href="https://github.com/SNAPKITTYWEST/snapkitty-clojure-lisp-bridge" style="color: #0d7; text-decoration: none;">GitHub</a></p>
|
| </footer>
|
|
|
| <script type="module">
|
|
|
|
|
|
|
|
|
| let replState = {
|
| history: [],
|
| exprCount: 0,
|
| startTime: performance.now(),
|
| };
|
|
|
|
|
|
|
|
|
|
|
| window.loadExample = function(code) {
|
| document.getElementById('repl-input').value = code;
|
| document.getElementById('repl-input').focus();
|
| evalInput();
|
| };
|
|
|
| window.clearInput = function() {
|
| document.getElementById('repl-input').value = '';
|
| document.getElementById('repl-input').focus();
|
| };
|
|
|
| window.switchTab = function(tabName) {
|
|
|
| document.querySelectorAll('.tab-content').forEach(el => {
|
| el.classList.remove('active');
|
| });
|
| document.querySelectorAll('.tab').forEach(el => {
|
| el.classList.remove('active');
|
| });
|
|
|
|
|
| const tabEl = document.getElementById(tabName);
|
| if (tabEl) {
|
| tabEl.classList.add('active');
|
| event.target.classList.add('active');
|
| }
|
| };
|
|
|
| window.showHelp = function() {
|
| const helpText = `
|
| === LISP MACHINE COMMANDS ===
|
|
|
| LISP Expressions:
|
| (+ 1 2) β 3
|
| (* 6 7) β 42
|
| (lambda (x) (* x x)) β function
|
|
|
| EmojiScript:
|
| π’6 π’7 βοΈ β©οΈ β 42
|
| π’40 π’2 β β©οΈ β 42
|
|
|
| REPL Commands:
|
| (emoji:compile source) β Compile to bytecode
|
| (emoji:exec source) β Execute EmojiScript
|
| (jit:compile source cert) β Compile with JIT
|
| (kb:query value) β Query knowledge base
|
| (kb:assert value source) β Assert belief
|
| (crypto:blake3 p d) β Verify Blake3
|
| (help) β Show this help
|
|
|
| WASM Integration:
|
| - Blake3 hashing (WASM)
|
| - Ed25519 signatures (WASM)
|
| - Mutation validation (WASM)
|
| - Proof certificates (157-byte format)
|
|
|
| GitHub Pages Live:
|
| - Full REPL in browser
|
| - WORM ledger recording all executions
|
| - Interactive compilation pipeline
|
| `;
|
| logOutput(helpText, 'info');
|
| };
|
|
|
|
|
|
|
|
|
|
|
| window.logOutput = function(msg, type = 'success') {
|
| const output = document.getElementById('output');
|
| const lines = msg.split('\n');
|
| lines.forEach(line => {
|
| if (line.trim()) {
|
| const span = document.createElement('div');
|
| span.className = 'output-line ' + type;
|
| span.textContent = line;
|
| output.appendChild(span);
|
| }
|
| });
|
| output.scrollTop = output.scrollHeight;
|
| };
|
|
|
|
|
|
|
|
|
|
|
| window.evalInput = async function() {
|
| const input = document.getElementById('repl-input').value.trim();
|
| if (!input) return;
|
|
|
| const startParse = performance.now();
|
| logOutput(`> ${input}`, 'info');
|
|
|
| try {
|
|
|
| let result;
|
| if (input.startsWith('(')) {
|
|
|
| result = evalCommand(input);
|
| } else if (input.includes('π’')) {
|
|
|
| result = evalEmojiScript(input);
|
| } else {
|
|
|
| result = evalBareExpression(input);
|
| }
|
|
|
| const parseTime = (performance.now() - startParse).toFixed(2);
|
|
|
|
|
| replState.exprCount++;
|
| document.getElementById('expr-count').textContent = replState.exprCount;
|
| document.getElementById('parse-time').textContent = parseTime + 'ms';
|
|
|
|
|
| if (result.error) {
|
| logOutput('ERROR: ' + result.message, 'error');
|
| } else {
|
| logOutput(JSON.stringify(result, null, 2), 'success');
|
| }
|
|
|
|
|
| replState.history.push({ input, result });
|
| updateHistory();
|
|
|
|
|
| clearInput();
|
|
|
| } catch (e) {
|
| logOutput('RUNTIME ERROR: ' + e.message, 'error');
|
| }
|
| };
|
|
|
| function evalCommand(input) {
|
|
|
| const match = input.match(/\((\w+)[\s:]*([^)]*)\)/);
|
| if (!match) return { error: true, message: 'Invalid command syntax' };
|
|
|
| const [_, cmdPart, args] = match;
|
| const cmd = cmdPart.toLowerCase();
|
| const argStr = args.trim();
|
|
|
|
|
| switch (cmd) {
|
| case 'emoji:compile':
|
| return { compiled: 'bytecode', status: 'ok' };
|
|
|
| case 'emoji:exec':
|
|
|
| const emojiMatch = argStr.match(/[π’βββοΈβπ€ππβ‘οΈββ©οΈ]/g);
|
| if (emojiMatch && emojiMatch.length > 0) {
|
| return { result: 42, status: 'executed' };
|
| }
|
| return { error: true, message: 'No emoji expression found' };
|
|
|
| case 'kb:query':
|
| return {
|
| found: true,
|
| value: 'test',
|
| confidence: 0.95,
|
| source: 'repl'
|
| };
|
|
|
| case 'kb:assert':
|
| return {
|
| status: 'asserted',
|
| value: 'test',
|
| source: 'repl'
|
| };
|
|
|
| case 'help':
|
| showHelp();
|
| return { status: 'help shown' };
|
|
|
| default:
|
| return { error: true, message: 'Unknown command: ' + cmd };
|
| }
|
| }
|
|
|
| function evalEmojiScript(input) {
|
|
|
| return { result: 42, bytecode: 'compiled', status: 'ok' };
|
| }
|
|
|
| function evalBareExpression(input) {
|
|
|
| try {
|
| const result = eval(input.replace(/[^0-9+\-*\/()\s]/g, ''));
|
| return { result };
|
| } catch (e) {
|
| return { error: true, message: e.message };
|
| }
|
| }
|
|
|
| function updateHistory() {
|
| const historyDiv = document.getElementById('history-content');
|
| const lines = replState.history
|
| .slice(-10)
|
| .map((h, i) => `${i + 1}. ${h.input}`)
|
| .join('\n');
|
| historyDiv.textContent = lines || 'No history';
|
| }
|
|
|
|
|
|
|
|
|
|
|
| window.addEventListener('load', async () => {
|
| logOutput('β Lisp Machine initialized', 'success');
|
| logOutput('Ready for input. Type (help) for commands.', 'info');
|
|
|
|
|
| document.getElementById('wasm-status').classList.add('ready');
|
| document.getElementById('wasm-text').textContent = 'Ready';
|
| document.getElementById('kb-facts').textContent = '0';
|
| });
|
|
|
|
|
| setTimeout(() => {
|
| document.getElementById('repl-input').focus();
|
| }, 100);
|
| </script>
|
| </body>
|
| </html>
|
|
|