diff options
Diffstat (limited to 'forth/foreforthfourth')
-rw-r--r-- | forth/foreforthfourth/README.md | 108 | ||||
-rw-r--r-- | forth/foreforthfourth/forth.js | 177 |
2 files changed, 213 insertions, 72 deletions
diff --git a/forth/foreforthfourth/README.md b/forth/foreforthfourth/README.md index 3e8579b..29c3b5e 100644 --- a/forth/foreforthfourth/README.md +++ b/forth/foreforthfourth/README.md @@ -25,9 +25,10 @@ This Forth interpreter features **4 separate stacks** that users can juggle betw ### Multi-Stack Operations - **Stack Focus System**: `focus.red`, `focus.teal`, `focus.blue`, `focus.yellow` (or `focus.1`, `focus.2`, `focus.3`, `focus.4`) -- **Push Operations**: `push.red`, `push.teal`, `push.blue`, `push.yellow` (or `push.1`, `push.2`, `push.3`, `push.4`) +- **Move Operations**: `move.red`, `move.teal`, `move.blue`, `move.yellow` (or `move.1`, `move.2`, `move.3`, `move.4`) - **Pop Operations**: `pop.red`, `pop.teal`, `pop.blue`, `pop.yellow` (or `pop.1`, `pop.2`, `pop.3`, `pop.4`) -- **Move Operations**: `move` (interactive stack-to-stack movement), `push.red`, `push.teal`, `push.blue`, `push.yellow` (or `push.1`, `push.2`, `push.3`, `push.4`) +- **Copy Operations**: `copy.red`, `copy.teal`, `copy.blue`, `copy.yellow` (or `copy.1`, `copy.2`, `copy.3`, `copy.4`) +- **Move Operations**: `move` (interactive stack-to-stack movement), `move.red`, `move.teal`, `move.blue`, `move.yellow` (or `move.1`, `move.2`, `move.3`, `move.4`) - **Clear Operations**: `clear.all` (clear all stacks), `clear.focused` (clear focused stack) - **Cross-Stack Operations**: `dup.stacks`, `over.stacks`, `swap.stacks`, `nip.stacks`, `tuck.stacks`, `rot.stacks`, `2dup.stacks`, `2over.stacks`, `2swap.stacks` @@ -98,8 +99,8 @@ dup over # Duplicate top, copy second over top ### Multi-Stack Juggling ```forth 5 3 2 # Push to red stack -push.teal # Move top of red to teal stack -push.blue # Move top of red to blue stack +move.teal # Move top of red to teal stack +move.blue # Move top of red to blue stack ``` ### Stack Focus System @@ -130,11 +131,17 @@ focus.2 # Same as focus.teal focus.3 # Same as focus.blue focus.4 # Same as focus.yellow -# Push commands -push.1 # Same as push.red -push.2 # Same as push.teal -push.3 # Same as push.blue -push.4 # Same as push.yellow +# Move commands +move.1 # Same as move.red +move.2 # Same as move.teal +move.3 # Same as move.blue +move.4 # Same as move.yellow + +# Copy commands +copy.1 # Same as copy.red +copy.2 # Same as copy.teal +copy.3 # Same as copy.blue +copy.4 # Same as copy.yellow # Pop commands pop.1 # Same as pop.red @@ -258,36 +265,47 @@ move # Start move operation 3. Enter the **destination stack number** (1-4) 4. The item is **removed** from source and **added** to destination -#### **Push Commands with Focus System** -Use `push.` commands to move items from the focused stack to a specific target stack: +#### **Move Commands with Focus System** +Use `move.` commands to move items from the focused stack to a specific target stack: ```forth focus.red # Focus on Red stack (1) 42 # Add item to Red stack -push.3 # Move top item to Blue stack (3) +move.3 # Move top item to Blue stack (3) # Result: 42 moved from Red to Blue stack focus.teal # Focus on Teal stack (2) 100 # Add item to Teal stack -push.yellow # Move top item to Yellow stack (4) +move.yellow # Move top item to Yellow stack (4) # Result: 100 moved from Teal to Yellow stack ``` #### **Number and Color Aliases** -All push commands support both number and color naming: +All move and copy commands support both number and color naming: ```forth -# Number aliases -push.1 # Move to Red stack (1) -push.2 # Move to Teal stack (2) -push.3 # Move to Blue stack (3) -push.4 # Move to Yellow stack (4) +# Move commands (remove from source) +move.1 # Move to Red stack (1) +move.2 # Move to Teal stack (2) +move.3 # Move to Blue stack (3) +move.4 # Move to Yellow stack (4) + +# Copy commands (keep in source) +copy.1 # Copy to Red stack (1) +copy.2 # Copy to Teal stack (2) +copy.3 # Copy to Blue stack (3) +copy.4 # Copy to Yellow stack (4) # Color aliases -push.red # Move to Red stack (1) -push.teal # Move to Teal stack (2) -push.blue # Move to Blue stack (3) -push.yellow # Move to Yellow stack (4) +move.red # Move to Red stack (1) +move.teal # Move to Teal stack (2) +move.blue # Move to Blue stack (3) +move.yellow # Move to Yellow stack (4) + +copy.red # Copy to Red stack (1) +copy.teal # Copy to Teal stack (2) +copy.blue # Copy to Blue stack (3) +copy.yellow # Copy to Yellow stack (4) ``` #### **Comparison: Move vs Copy Operations** @@ -295,19 +313,24 @@ push.yellow # Move to Yellow stack (4) | Operation | Effect | Duplication | Use Case | |-----------|--------|-------------|----------| | `move` | **Moves** item from source to destination | ❌ No | Relocate items between stacks | -| `push.` | **Moves** item from focused stack to target | ❌ No | Move from focused stack to specific stack | +| `move.{stack}` | **Moves** item from focused stack to target | ❌ No | Move from focused stack to specific stack | +| `copy.{stack}` | **Copies** item from focused stack to target | ✅ Yes | Keep item on source, copy to target | | `dup.stacks` | **Copies** item from focused stack to target | ✅ Yes | Keep item on source, copy to target | | `over.stacks` | **Copies** second item from focused stack to target | ✅ Yes | Copy second item without affecting top | -#### **Quick Reference: All Move Operations** +#### **Quick Reference: All Move and Copy Operations** | Command | From | To | Effect | |---------|------|----|---------| | `move` + source + dest | Any stack | Any stack | Move top item between specified stacks | -| `push.red` / `push.1` | Focused stack | Red stack (1) | Move top item to Red stack | -| `push.teal` / `push.2` | Focused stack | Teal stack (2) | Move top item to Teal stack | -| `push.blue` / `push.3` | Focused stack | Blue stack (3) | Move top item to Blue stack | -| `push.yellow` / `push.4` | Focused stack | Yellow stack (4) | Move top item to Yellow stack | +| `move.red` / `move.1` | Focused stack | Red stack (1) | Move top item to Red stack | +| `move.teal` / `move.2` | Focused stack | Teal stack (2) | Move top item to Teal stack | +| `move.blue` / `move.3` | Focused stack | Blue stack (3) | Move top item to Blue stack | +| `move.yellow` / `move.4` | Focused stack | Yellow stack (4) | Move top item to Yellow stack | +| `copy.red` / `copy.1` | Focused stack | Red stack (1) | Copy top item to Red stack | +| `copy.teal` / `copy.2` | Focused stack | Teal stack (2) | Copy top item to Teal stack | +| `copy.blue` / `copy.3` | Focused stack | Blue stack (3) | Copy top item to Blue stack | +| `copy.yellow` / `copy.4` | Focused stack | Yellow stack (4) | Copy top item to Yellow stack | #### **Complete Move Example** ```forth @@ -321,11 +344,11 @@ focus.blue # Move items between stacks focus.red -push.2 # Move 42 from Red to Teal +move.2 # Move 42 from Red to Teal # Red stack: [], Teal stack: [100, 42] focus.teal -push.3 # Move 100 from Teal to Blue +move.3 # Move 100 from Teal to Blue # Teal stack: [42], Blue stack: [200, 100] # Use interactive move for complex operations @@ -376,7 +399,7 @@ words # List all available words ## Current Status -### ✅ **Fully Implemented Features** +### **Fully Implemented Features** - **Control Flow**: `IF ... THEN`, `IF ... ELSE ... THEN`, `BEGIN ... UNTIL` constructs - **String Operations**: String literals (`."` and `s"`), manipulation (`strlen`, `strcat`, `char+`, `type`, `count`) - **Stack Focus System**: Operate on any of the 4 stacks using focus commands @@ -384,25 +407,14 @@ words # List all available words - **Help System**: Comprehensive help (`help`) and word documentation (`doc`) - **Multi-Stack Operations**: Full support for all 4 stacks with focus system - **Enhanced Clear Operations**: `clear.all` and `clear.focused` commands -- **Move Operations**: Interactive `move` command and `push.` commands for moving items between stacks -- **Number Aliases**: All focus, push, and pop commands support both color names and numbers (1-4) +- **Move Operations**: Interactive `move` command and `move.{stack}` commands for moving items between stacks +- **Copy Operations**: `copy.{stack}` commands for copying items between stacks without removal +- **Number Aliases**: All focus, move, copy, and pop commands support both color names and numbers (1-4) - **Math Utilities**: `abs`, `negate`, `min`, `max` operations -### 🚀 **Advanced Capabilities** +### **Advanced Capabilities** - **Universal Stack Operations**: All built-in words work on any focused stack - **Dual Naming System**: Both color names and numbers work for all commands - **Professional Error Handling**: Context-aware error messages with solutions - **Visual Focus Indicators**: UI shows which stack is currently focused -- **Complete Test Coverage**: 100% test coverage of all features - -### Potential Extensions -- **Graphics**: Simple drawing operations -- **Networking**: HTTP requests and responses -- **Persistence**: Save state between sessions -- **Modules**: Import/export word definitions - -## Known Issues - -- The `move` operation requires two separate command inputs -- Some edge cases in error handling may need refinement -- Performance optimization for large programs +- **Complete Test Coverage**: 100% test coverage of all features \ No newline at end of file diff --git a/forth/foreforthfourth/forth.js b/forth/foreforthfourth/forth.js index 3a654d1..af133ea 100644 --- a/forth/foreforthfourth/forth.js +++ b/forth/foreforthfourth/forth.js @@ -933,11 +933,11 @@ const builtinWords = { }, // Multi-stack operations - 'push.red': { + 'move.red': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.red - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.red - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -945,15 +945,15 @@ const builtinWords = { stacks: pushToStack(stacks, 0, value) }); }, - doc: 'Move top item from focused stack to red stack', + doc: 'Move top item from focused stack to red stack (removes from focused stack)', stack: '( x -- )' }, - 'push.1': { + 'move.1': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.1 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.1 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -961,15 +961,15 @@ const builtinWords = { stacks: pushToStack(stacks, 0, value) }); }, - doc: 'Move top item from focused stack to red stack (Stack 1)', + doc: 'Move top item from focused stack to red stack (Stack 1) (removes from focused stack)', stack: '( x -- )' }, - 'push.teal': { + 'move.teal': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.teal - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.teal - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -977,15 +977,15 @@ const builtinWords = { stacks: pushToStack(stacks, 1, value) }); }, - doc: 'Move top item from focused stack to teal stack', + doc: 'Move top item from focused stack to teal stack (removes from focused stack)', stack: '( x -- )' }, - 'push.2': { + 'move.2': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.2 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.2 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -993,15 +993,15 @@ const builtinWords = { stacks: pushToStack(stacks, 1, value) }); }, - doc: 'Move top item from focused stack to teal stack (Stack 2)', + doc: 'Move top item from focused stack to teal stack (Stack 2) (removes from focused stack)', stack: '( x -- )' }, - 'push.blue': { + 'move.blue': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.blue - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.blue - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -1009,15 +1009,15 @@ const builtinWords = { stacks: pushToStack(stacks, 2, value) }); }, - doc: 'Move top item from focused stack to blue stack', + doc: 'Move top item from focused stack to blue stack (removes from focused stack)', stack: '( x -- )' }, - 'push.3': { + 'move.3': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.3 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.3 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -1025,15 +1025,15 @@ const builtinWords = { stacks: pushToStack(stacks, 2, value) }); }, - doc: 'Move top item from focused stack to blue stack (Stack 3)', + doc: 'Move top item from focused stack to blue stack (Stack 3) (removes from focused stack)', stack: '( x -- )' }, - 'push.yellow': { + 'move.yellow': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.yellow - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.yellow - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -1041,15 +1041,15 @@ const builtinWords = { stacks: pushToStack(stacks, 3, value) }); }, - doc: 'Move top item from focused stack to yellow stack', + doc: 'Move top item from focused stack to yellow stack (removes from focused stack)', stack: '( x -- )' }, - 'push.4': { + 'move.4': { fn: (state) => { if (state.stacks[state.focusedStack].length === 0) { return updateState(state, { - output: [...state.output, `Error: Stack underflow on push.4 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] + output: [...state.output, `Error: Stack underflow on move.4 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to move.`] }); } const { stacks, value } = popFromStack(state.stacks, state.focusedStack); @@ -1057,10 +1057,139 @@ const builtinWords = { stacks: pushToStack(stacks, 3, value) }); }, - doc: 'Move top item from focused stack to yellow stack (Stack 4)', + doc: 'Move top item from focused stack to yellow stack (Stack 4) (removes from focused stack)', stack: '( x -- )' }, + // Copy operations (keep item in source stack) + 'copy.red': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.red - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 0, top) + }); + }, + doc: 'Copy top item from focused stack to red stack (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.1': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.1 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 0, top) + }); + }, + doc: 'Copy top item from focused stack to red stack (Stack 1) (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.teal': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.teal - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 1, top) + }); + }, + doc: 'Copy top item from focused stack to teal stack (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.2': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.2 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 1, top) + }); + }, + doc: 'Copy top item from focused stack to teal stack (Stack 2) (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.blue': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.blue - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 2, top) + }); + }, + doc: 'Copy top item from focused stack to blue stack (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.3': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.3 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 2, top) + }); + }, + doc: 'Copy top item from focused stack to blue stack (Stack 3) (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.yellow': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.yellow - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 3, top) + }); + }, + doc: 'Copy top item from focused stack to yellow stack (keeps item on focused stack)', + stack: '( x -- x )' + }, + + 'copy.4': { + fn: (state) => { + if (state.stacks[state.focusedStack].length === 0) { + return updateState(state, { + output: [...state.output, `Error: Stack underflow on copy.4 - ${getFocusedStackName(state.focusedStack)} is empty. Nothing to copy.`] + }); + } + const top = state.stacks[state.focusedStack][state.stacks[state.focusedStack].length - 1]; + return updateState(state, { + stacks: pushToStack(state.stacks, 3, top) + }); + }, + doc: 'Copy top item from focused stack to yellow stack (Stack 4) (keeps item on focused stack)', + stack: '( x -- x )' + }, + 'pop.red': { fn: (state) => popAndPrint(state, 0), doc: 'Pop and print top item from red stack', |