Finished
55
66export class Forth {
77 constructor() {
8 throw Error('Remove this statement and implement this function');
8 this._stack = [];
9 this.words = {};
910 }
1011
11 evaluate() {
12 throw Error('Remove this statement and implement this function');
12 evaluate(input) {
13 const tokens = input.split(/\s+/).filter(token => token !== '');
14
15 // Edge Case: Empty input
16 if (tokens.length === 0) {
17 return;
18 }
19
20 let i = 0;
21 while (i < tokens.length) {
22 const token = tokens[i].toUpperCase();
23
24 // Handle word definition
25 if (token === ':') {
26 // Edge Case: Malformed word definition (missing semicolon)
27 if (i + 1 >= tokens.length) {
28 throw new Error('Incomplete word definition');
29 }
30
31 const wordName = tokens[i + 1].toUpperCase();
32
33 // Edge Case: Invalid word name (numbers cannot be redefined)
34 if (/^-?\d+$/.test(wordName)) {
35 throw new Error('Invalid definition');
36 }
37
38 i += 2;
39 const definition = [];
40
41 // Edge Case: Empty word definition (has semicolon but no content)
42 if (i < tokens.length && tokens[i] === ';') {
43 throw new Error('Invalid definition');
44 }
45
46 // Edge Case: Incomplete word definition (no semicolon found)
47 if (i >= tokens.length) {
48 throw new Error('Incomplete word definition');
49 }
50
51 while (i < tokens.length && tokens[i] !== ';') {
52 definition.push(tokens[i]);
53 i++;
54 }
55
56 // Edge Case: Missing semicolon at end of definition
57 if (i >= tokens.length) {
58 throw new Error('Incomplete word definition');
59 }
60
61 const definitionText = definition.join(' ');
62
63 // Prevent direct self-reference in word definitions
64 if (definitionText.toLowerCase().includes(wordName.toLowerCase())) {
65 throw new Error('Invalid definition');
66 }
67
68 this.words[wordName] = definitionText;
69 i++;
70 continue;
71 }
72
73 // Handle numbers
74 if (/^-?\d+$/.test(token)) {
75 this._stack.push(parseInt(token, 10));
76 i++;
77 continue;
78 }
79
80 // Handle custom words
81 if (this.words[token]) {
82 this.evaluate(this.words[token]);
83 i++;
84 continue;
85 }
86
87 // Handle built-in words
88 if (this.handleBuiltin(token)) {
89 i++;
90 continue;
91 }
92
93 // Edge Case: Undefined word
94 throw new Error('Unknown command');
95 }
1396 }
14
97
98 handleBuiltin(token) {
99 switch (token) {
100 case '+':
101 // Edge Case: Insufficient stack elements
102 if (this._stack.length < 2) {
103 if (this._stack.length === 0) {
104 throw new Error('Stack empty');
105 } else {
106 throw new Error('Only one value on the stack');
107 }
108 }
109 this._stack.push(this._stack.pop() + this._stack.pop());
110 return true;
111
112 case '-':
113 // Edge Case: Insufficient stack elements
114 if (this._stack.length < 2) {
115 if (this._stack.length === 0) {
116 throw new Error('Stack empty');
117 } else {
118 throw new Error('Only one value on the stack');
119 }
120 }
121 const subtrahend = this._stack.pop();
122 const minuend = this._stack.pop();
123 this._stack.push(minuend - subtrahend);
124 return true;
125
126 case '*':
127 // Edge Case: Insufficient stack elements
128 if (this._stack.length < 2) {
129 if (this._stack.length === 0) {
130 throw new Error('Stack empty');
131 } else {
132 throw new Error('Only one value on the stack');
133 }
134 }
135 this._stack.push(this._stack.pop() * this._stack.pop());
136 return true;
137
138 case '/':
139 // Edge Case: Insufficient stack elements
140 if (this._stack.length < 2) {
141 if (this._stack.length === 0) {
142 throw new Error('Stack empty');
143 } else {
144 throw new Error('Only one value on the stack');
145 }
146 }
147 const divisor = this._stack.pop();
148 const dividend = this._stack.pop();
149 // Edge Case: Division by zero
150 if (divisor === 0) {
151 throw new Error('Division by zero');
152 }
153 this._stack.push(Math.trunc(dividend / divisor));
154 return true;
155
156 case 'DUP':
157 // Edge Case: Insufficient stack elements
158 if (this._stack.length < 1) {
159 throw new Error('Stack empty');
160 }
161 this._stack.push(this._stack[this._stack.length - 1]);
162 return true;
163
164 case 'DROP':
165 // Edge Case: Insufficient stack elements
166 if (this._stack.length < 1) {
167 throw new Error('Stack empty');
168 }
169 this._stack.pop();
170 return true;
171
172 case 'SWAP':
173 // Edge Case: Insufficient stack elements
174 if (this._stack.length < 2) {
175 if (this._stack.length === 0) {
176 throw new Error('Stack empty');
177 } else {
178 throw new Error('Only one value on the stack');
179 }
180 }
181 const top = this._stack.pop();
182 const second = this._stack.pop();
183 this._stack.push(top);
184 this._stack.push(second);
185 return true;
186
187 case 'OVER':
188 // Edge Case: Insufficient stack elements
189 if (this._stack.length < 2) {
190 if (this._stack.length === 0) {
191 throw new Error('Stack empty');
192 } else {
193 throw new Error('Only one value on the stack');
194 }
195 }
196 this._stack.push(this._stack[this._stack.length - 2]);
197 return true;
198
199 default:
200 return false;
201 }
202 }
203
15204 get stack() {
16 throw Error('Remove this statement and implement this function');
205 return this._stack;
17206 }
18207}
208// Handled Edge Cases: Empty input, Malformed word definition (missing semicolon), Invalid word name (starts with digit), Empty word definition, Missing semicolon at end of definition, Insufficient stack elements, Division by zero, Undefined word
Test NameStatus
can use different words with the same name
Fail
can define word that uses word with the same name
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
can override other user-defined words
Pass
can override built-in words
Pass
can override built-in operators
Pass
cannot redefine non-negative numbers
Pass
cannot redefine negative numbers
Pass
errors if executing a non-existent word
Pass
only defines locally
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
definitions are case-insensitive
Pass

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