// ast.js // AST visualization tool for Baba Yaga language import { lexer, parser } from '../../lang.js'; const examples = { simple: `x : 42;`, when: `result : when x is 42 then "correct" _ then "wrong";`, function: `factorial : n -> when n is 0 then 1 _ then n * (factorial (n - 1));`, table: `person : {name: "Baba Yaga", age: 99, active: true}; numbers : {1, 2, 3, 4, 5};`, arithmetic: `result : 5 + 3 * 2; composed : compose @double @increment 5;`, complex: `classify : x y -> when x y is 0 0 then "both zero" 0 _ then "x is zero" _ 0 then "y is zero" _ _ then "neither zero";` }; // DOM elements - will be initialized when DOM is ready let codeInput, generateBtn, examplesSelect, astOutput, tokensOutput, errorOutput, copyAstBtn, copyTokensBtn; // Initialize when DOM is ready document.addEventListener('DOMContentLoaded', () => { // Initialize DOM elements codeInput = document.getElementById('code-input'); generateBtn = document.getElementById('generate-btn'); examplesSelect = document.getElementById('examples'); astOutput = document.getElementById('ast-output'); tokensOutput = document.getElementById('tokens-output'); errorOutput = document.getElementById('error-output'); copyAstBtn = document.getElementById('copy-ast-btn'); copyTokensBtn = document.getElementById('copy-tokens-btn'); // Example selector functionality examplesSelect.addEventListener('change', () => { const selectedExample = examplesSelect.value; if (selectedExample && examples[selectedExample]) { codeInput.value = examples[selectedExample]; generateAST(); } }); // Generate button click handler generateBtn.addEventListener('click', generateAST); // Copy button click handlers copyAstBtn.addEventListener('click', () => copyToClipboard(astOutput, 'AST')); copyTokensBtn.addEventListener('click', () => copyToClipboard(tokensOutput, 'Tokens')); // Auto-generate on Enter key (but not in textarea) document.addEventListener('keydown', (e) => { if (e.key === 'Enter' && e.ctrlKey && document.activeElement !== codeInput) { generateAST(); } }); // Initialize with a default example codeInput.value = examples.when; generateAST(); }); // Generate AST from code function generateAST() { if (!codeInput) return; // DOM not ready yet const code = codeInput.value.trim(); if (!code) { showError('Please enter some code to analyze.'); return; } try { // Generate tokens const tokens = lexer(code); showTokens(tokens); // Generate AST const ast = parser(tokens); showAST(ast); // Clear any previous errors showError(''); } catch (error) { showError(`Parsing Error: ${error.message}`); showAST(null); showTokens(null); } } // Display AST in formatted JSON function showAST(ast) { if (!astOutput) return; // DOM not ready yet if (ast) { astOutput.value = JSON.stringify(ast, null, 2); } else { astOutput.value = 'No AST available due to parsing error.'; } } // Display tokens in formatted JSON function showTokens(tokens) { if (!tokensOutput) return; // DOM not ready yet if (tokens) { tokensOutput.value = JSON.stringify(tokens, null, 2); } else { tokensOutput.value = 'No tokens available due to parsing error.'; } } // Display error message function showError(message) { if (!errorOutput) return; // DOM not ready yet if (message) { errorOutput.textContent = message; errorOutput.style.display = 'block'; } else { errorOutput.style.display = 'none'; } } // Copy text to clipboard async function copyToClipboard(textarea, label) { if (!textarea || !textarea.value) { showError(`No ${label} content to copy.`); return; } try { await navigator.clipboard.writeText(textarea.value); // Show temporary success message const originalText = errorOutput.textContent; showError(`${label} copied to clipboard!`); // Clear success message after 2 seconds setTimeout(() => { if (errorOutput.textContent === `${label} copied to clipboard!`) { showError(''); } }, 2000); } catch (error) { showError(`Failed to copy ${label}: ${error.message}`); } }