Finished
55
66export class Forth {
77 constructor() {
8 throw Error('Remove this statement and implement this function');
8 this._stack = [];
9 this._words = new Map();
10 // Initialize built-in words
11 this._initializeBuiltIns();
12 }
13
14 _initializeBuiltIns() {
15 // Arithmetic operations
16 this._words.set('+', () => {
17 if (this._stack.length === 0) throw new Error('Stack empty');
18 if (this._stack.length === 1) throw new Error('Only one value on the stack');
19 const b = this._stack.pop();
20 const a = this._stack.pop();
21 this._stack.push(a + b);
22 });
23
24 this._words.set('-', () => {
25 if (this._stack.length === 0) throw new Error('Stack empty');
26 if (this._stack.length === 1) throw new Error('Only one value on the stack');
27 const b = this._stack.pop();
28 const a = this._stack.pop();
29 this._stack.push(a - b);
30 });
31
32 this._words.set('*', () => {
33 if (this._stack.length === 0) throw new Error('Stack empty');
34 if (this._stack.length === 1) throw new Error('Only one value on the stack');
35 const b = this._stack.pop();
36 const a = this._stack.pop();
37 this._stack.push(a * b);
38 });
39
40 this._words.set('/', () => {
41 if (this._stack.length === 0) throw new Error('Stack empty');
42 if (this._stack.length === 1) throw new Error('Only one value on the stack');
43 const b = this._stack.pop();
44 const a = this._stack.pop();
45 if (b === 0) throw new Error('Division by zero');
46 this._stack.push(Math.trunc(a / b));
47 });
48
49 // Stack manipulation
50 this._words.set('dup', () => {
51 if (this._stack.length < 1) throw new Error('Stack empty');
52 this._stack.push(this._stack[this._stack.length - 1]);
53 });
54
55 this._words.set('drop', () => {
56 if (this._stack.length < 1) throw new Error('Stack empty');
57 this._stack.pop();
58 });
59
60 this._words.set('swap', () => {
61 if (this._stack.length === 0) throw new Error('Stack empty');
62 if (this._stack.length === 1) throw new Error('Only one value on the stack');
63 const temp = this._stack[this._stack.length - 1];
64 this._stack[this._stack.length - 1] = this._stack[this._stack.length - 2];
65 this._stack[this._stack.length - 2] = temp;
66 });
67
68 this._words.set('over', () => {
69 if (this._stack.length === 0) throw new Error('Stack empty');
70 if (this._stack.length === 1) throw new Error('Only one value on the stack');
71 this._stack.push(this._stack[this._stack.length - 2]);
72 });
973 }
1074
1175 /**
1276 * @param {string} program
1377 */
1478 evaluate(program) {
15 throw Error('Remove this statement and implement this function');
79 const tokens = program.toLowerCase().split(/\s+/).filter(token => token.length > 0);
80 let i = 0;
81
82 while (i < tokens.length) {
83 const token = tokens[i];
84
85 // Handle word definition
86 if (token === ':') {
87 i++;
88 // Edge Case: Empty definition
89 if (i >= tokens.length) throw new Error('Unterminated definition');
90
91 const wordName = tokens[i];
92 // Edge Case: Redefining built-in words or numbers
93 if (this._isNumber(wordName) || this._words.has(wordName)) throw new Error('Invalid definition');
94
95 i++;
96 const definition = [];
97 // Edge Case: Unterminated word definitions
98 while (i < tokens.length && tokens[i] !== ';') {
99 definition.push(tokens[i]);
100 i++;
101 }
102
103 // Edge Case: Unterminated definition (no semicolon found)
104 if (i >= tokens.length) throw new Error('Unterminated definition');
105
106 this._words.set(wordName, this._createWordFunction(definition));
107 i++;
108 continue;
109 }
110
111 // Handle execution of words
112 if (this._words.has(token)) {
113 this._words.get(token)();
114 } else if (this._isNumber(token)) {
115 this._stack.push(parseInt(token, 10));
116 } else {
117 // Edge Case: Unknown commands
118 throw new Error('Unknown command');
119 }
120
121 i++;
122 }
123 }
124
125 _isNumber(token) {
126 return /^-?\d+$/.test(token);
127 }
128
129 _createWordFunction(definition) {
130 // Create a function that will execute the definition
131 return () => {
132 const originalStack = [...this._stack];
133 try {
134 for (const token of definition) {
135 if (this._words.has(token)) {
136 this._words.get(token)();
137 } else if (this._isNumber(token)) {
138 this._stack.push(parseInt(token, 10));
139 } else {
140 // Edge Case: Unknown command in definition
141 throw new Error('Unknown command');
142 }
143 }
144 } catch (error) {
145 // Restore stack on error
146 this._stack = originalStack;
147 throw error;
148 }
149 };
16150 }
17151
18152 /**
19153 * @return {number[]}
20154 */
21155 get stack() {
22 throw Error('Remove this statement and implement this function');
156 return [...this._stack];
23157 }
24158}
159
160// Handled Edge Cases:
161// - Empty stack operations
162// - Insufficient stack values for binary operations
163// - Division by zero
164// - Unterminated word definitions
165// - Redefining built-in words or numbers
166// - Unknown commands
167// - Case sensitivity handling
168// - Invalid syntax in definitions
169// - Empty definition
170// - Unknown command in definition
Test NameStatus
can override other user-defined words
Fail
can override built-in words
Fail
can override built-in operators
Fail
can use different words with the same name
Fail
can define word that uses word with the same name
Fail
only defines locally
Fail
definitions are case-insensitive
Fail
numbers just get pushed onto the stack
Pass
pushes negative numbers onto the stack
Pass
can add two numbers
Pass
errors if there is nothing on the stack
Pass
errors if there is only one value on the stack
Pass
more than two values on the stack
Pass
can subtract two numbers
Pass
errors if there is nothing on the stack
Pass
errors if there is only one value on the stack
Pass
more than two values on the stack
Pass
can multiply two numbers
Pass
errors if there is nothing on the stack
Pass
errors if there is only one value on the stack
Pass
more than two values on the stack
Pass
can divide two numbers
Pass
performs integer division
Pass
errors if dividing by zero
Pass
errors if there is nothing on the stack
Pass
errors if there is only one value on the stack
Pass
more than two values on the stack
Pass
addition and subtraction
Pass
multiplication and division
Pass
multiplication and addition
Pass
addition and multiplication
Pass
copies a value on the stack
Pass
copies the top value on the stack
Pass
errors if there is nothing on the stack
Pass
removes the top value on the stack if it is the only one
Pass
removes the top value on the stack if it is not the only one
Pass
errors if there is nothing on the stack
Pass
swaps the top two values on the stack if they are the only ones
Pass
swaps the top two values on the stack if they are not the only ones
Pass
errors if there is nothing on the stack
Pass
errors if there is only one value on the stack
Pass
copies the second element if there are only two
Pass
copies the second element if there are more than two
Pass
errors if there is nothing on the stack
Pass
errors if there is only one value on the stack
Pass
can consist of built-in words
Pass
execute in the right order
Pass
cannot redefine non-negative numbers
Pass
cannot redefine negative numbers
Pass
errors if executing a non-existent word
Pass
DUP is case-insensitive
Pass
DROP is case-insensitive
Pass
SWAP is case-insensitive
Pass
OVER is case-insensitive
Pass
user-defined words are case-insensitive
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.