about summary refs log tree commit diff stats
path: root/js/scripting-lang/web
diff options
context:
space:
mode:
Diffstat (limited to 'js/scripting-lang/web')
-rw-r--r--js/scripting-lang/web/README-AST.md67
-rw-r--r--js/scripting-lang/web/ast-viewer.html150
-rw-r--r--js/scripting-lang/web/simple.html2
-rw-r--r--js/scripting-lang/web/src/ast.js161
-rw-r--r--js/scripting-lang/web/src/view.js4
-rw-r--r--js/scripting-lang/web/style.css36
6 files changed, 417 insertions, 3 deletions
diff --git a/js/scripting-lang/web/README-AST.md b/js/scripting-lang/web/README-AST.md
new file mode 100644
index 0000000..194aeec
--- /dev/null
+++ b/js/scripting-lang/web/README-AST.md
@@ -0,0 +1,67 @@
+# Baba Yaga AST Visualizer
+
+A web-based tool for visualizing the Abstract Syntax Tree (AST) of Baba Yaga code.
+
+## Features
+
+- **Real-time AST Generation**: Enter Baba Yaga code and see its AST instantly
+- **Token Visualization**: View the tokenized representation of your code
+- **Error Display**: Clear error messages for invalid syntax
+- **Example Code**: Pre-loaded examples demonstrating different language features
+- **Copy to Clipboard**: One-click copying of AST and tokens for easy sharing
+- **Clean Interface**: Simple, focused design following the project's design patterns
+
+## Usage
+
+1. Open `ast-viewer.html` in your browser
+2. Enter Baba Yaga code in the text area
+3. Click "Generate AST" or use Ctrl+Enter
+4. View the AST and tokens in the output sections below
+5. Use the "Copy AST" or "Copy Tokens" buttons to copy the content to your clipboard
+
+## Examples Included
+
+- **Simple Assignment**: Basic variable assignment
+- **When Expression**: Pattern matching with when/is/then
+- **Function Definition**: Arrow function with pattern matching
+- **Table Literal**: Creating and accessing table structures
+- **Arithmetic Expression**: Mathematical operations and function composition
+- **Complex When Expression**: Multi-pattern matching
+
+## Technical Details
+
+- Uses the same `lexer.js` and `parser.js` modules as the main language
+- No modifications to core language files required
+- Pure client-side JavaScript with ES6 modules
+- Responsive design that works on desktop and mobile
+
+## File Structure
+
+```
+web/
+├── ast.html          # Main AST visualization interface
+├── src/
+│   └── ast.js        # AST generation logic
+├── style.css         # Shared styling
+└── README-AST.md     # This file
+```
+
+## Browser Compatibility
+
+Requires a modern browser with ES6 module support:
+- Chrome 61+
+- Firefox 60+
+- Safari 10.1+
+- Edge 16+
+
+## Development
+
+To run locally:
+```bash
+cd web
+python3 -m http.server 8000
+# or
+npx serve .
+```
+
+Then open `http://localhost:8000/ast.html` 
\ No newline at end of file
diff --git a/js/scripting-lang/web/ast-viewer.html b/js/scripting-lang/web/ast-viewer.html
new file mode 100644
index 0000000..269504f
--- /dev/null
+++ b/js/scripting-lang/web/ast-viewer.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Baba Yaga AST Viewer</title>
+  <link rel="stylesheet" href="style.css">
+  <style>
+    textarea {
+      width: 100%;
+      min-height: 200px;
+      padding: 0.6em;
+      font-size: 1em;
+      font-family: 'Courier New', monospace;
+      border: 2px solid var(--color-input-border);
+      border-radius: 0.2em;
+      margin-bottom: 1em;
+      box-sizing: border-box;
+      resize: vertical;
+    }
+
+    .output {
+      white-space: pre-wrap;
+      font-family: 'Courier New', monospace;
+      font-size: 0.9em;
+      background: var(--color-code-bg);
+      padding: 1em;
+      border-radius: 0.2em;
+      border: 1px solid var(--color-result-border);
+      max-height: 400px;
+      overflow-y: auto;
+      resize: vertical;
+      min-height: 200px;
+    }
+
+    .error {
+      color: var(--color-error);
+      background: #ffeef0;
+      border-left: 4px solid var(--color-error);
+      padding: 1em;
+      margin-bottom: 1em;
+    }
+
+    .example-selector {
+      margin-bottom: 1em;
+    }
+
+    .example-selector select {
+      padding: 0.6em;
+      font-size: 1em;
+      border: 2px solid var(--color-input-border);
+      border-radius: 0.2em;
+      background: white;
+      margin-left: 0.5em;
+    }
+
+    .example-selector select:focus {
+      outline: none;
+      border-color: #007acc;
+    }
+
+    .output-section {
+      margin-top: 1.5em;
+    }
+
+    .output-section h3 {
+      margin-bottom: 0.5em;
+      color: var(--color-label);
+      text-transform: uppercase;
+      font-size: 0.9em;
+    }
+
+    .output-container {
+      position: relative;
+    }
+
+    .copy-btn {
+      position: absolute;
+      top: 0.5em;
+      right: 0.5em;
+      background: var(--color-button-bg);
+      color: var(--color-button-text);
+      border: none;
+      border-radius: 0.2em;
+      padding: 0.3em 0.6em;
+      font-size: 0.8em;
+      font-weight: bold;
+      cursor: pointer;
+      z-index: 10;
+    }
+
+    .copy-btn:hover {
+      background: #005a9e;
+    }
+
+    .copy-btn:active {
+      transform: translateY(1px);
+    }
+  </style>
+</head>
+<body>
+  <main>
+    <h1>Baba Yaga AST Visualizer</h1>
+    
+    <div class="example-selector">
+      <label for="examples">Load Example:</label>
+      <select id="examples">
+        <option value="">Choose an example...</option>
+        <option value="simple">Simple Assignment</option>
+        <option value="when">When Expression</option>
+        <option value="function">Function Definition</option>
+        <option value="table">Table Literal</option>
+        <option value="arithmetic">Arithmetic Expression</option>
+        <option value="complex">Complex When Expression</option>
+      </select>
+    </div>
+    
+    <label for="code-input">Code:</label>
+    <textarea 
+      id="code-input" 
+      placeholder="Enter Baba Yaga code here...
+Example:
+x : 42;
+result : when x is 42 then &quot;correct&quot; _ then &quot;wrong&quot;;"
+    ></textarea>
+    
+    <button id="generate-btn">Generate AST</button>
+    
+    <div class="output-section">
+      <h3>AST Output:</h3>
+      <div class="output-container">
+        <textarea id="ast-output" class="output" readonly placeholder="AST will appear here..."></textarea>
+        <button id="copy-ast-btn" class="copy-btn">Copy AST</button>
+      </div>
+    </div>
+    
+    <div class="output-section">
+      <h3>Tokens:</h3>
+      <div class="output-container">
+        <textarea id="tokens-output" class="output" readonly placeholder="Tokens will appear here..."></textarea>
+        <button id="copy-tokens-btn" class="copy-btn">Copy Tokens</button>
+      </div>
+    </div>
+    
+    <div id="error-output" class="error" style="display: none;"></div>
+  </main>
+  
+  <script type="module" src="src/ast.js"></script>
+</body>
+</html> 
\ No newline at end of file
diff --git a/js/scripting-lang/web/simple.html b/js/scripting-lang/web/simple.html
index 2aa5dac..9b8fd19 100644
--- a/js/scripting-lang/web/simple.html
+++ b/js/scripting-lang/web/simple.html
@@ -39,7 +39,7 @@
 <body>
     <main>
         <h1>Baba Yaga</h1>
-        
+
         <div class="result" id="result" style="display: none;">
             <div class="output" id="output"></div>
         </div>
diff --git a/js/scripting-lang/web/src/ast.js b/js/scripting-lang/web/src/ast.js
new file mode 100644
index 0000000..522d026
--- /dev/null
+++ b/js/scripting-lang/web/src/ast.js
@@ -0,0 +1,161 @@
+// 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}`);
+  }
+} 
\ No newline at end of file
diff --git a/js/scripting-lang/web/src/view.js b/js/scripting-lang/web/src/view.js
index 6d591cf..ab64910 100644
--- a/js/scripting-lang/web/src/view.js
+++ b/js/scripting-lang/web/src/view.js
@@ -22,7 +22,9 @@
  */
 export function view(state) {
   return `
-    <h1>Baba Yaga's PokéDex</h1>
+    <header class="app-header">
+      <h1>Baba Yaga's PokéDex</h1>
+    </header>
     <container>
       <form id="search-form" autocomplete="off">
         <label for="pokemon-query">Pokémon Name (or number)</label>
diff --git a/js/scripting-lang/web/style.css b/js/scripting-lang/web/style.css
index fea1820..4cd5c33 100644
--- a/js/scripting-lang/web/style.css
+++ b/js/scripting-lang/web/style.css
@@ -23,9 +23,43 @@ body {
   margin: 0;
   padding: 0;
 }
+.app-header {
+  max-width: 800px;
+  margin: 2rem auto 1rem;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0 1.5rem;
+}
+
+.app-header h1 {
+  margin: 0;
+  font-size: 1.8rem;
+}
+
+.app-nav {
+  display: flex;
+  gap: 1rem;
+}
+
+.nav-link {
+  color: var(--color-text);
+  text-decoration: none;
+  padding: 0.5rem 1rem;
+  border: 2px solid var(--color-main-border);
+  border-radius: 6px;
+  font-weight: 600;
+  transition: all 0.2s;
+}
+
+.nav-link:hover {
+  background: var(--color-main-border);
+  color: var(--color-button-text);
+}
+
 main {
   max-width: 800px;
-  margin: 3rem auto;
+  margin: 0 auto 3rem;
   background: var(--color-main-bg);
   border: 2px solid var(--color-main-border);
   border-radius: 8px;