Kaynağa Gözat

forth: add to track

Stuart Kent 9 yıl önce
ebeveyn
işleme
59b665de3c

+ 10
- 0
config.json Dosyayı Görüntüle

@@ -769,6 +769,16 @@
769 769
       ]
770 770
     },
771 771
     {
772
+      "uuid": "f0c0316d-3fb5-455e-952a-91161e7fb298",
773
+      "slug": "forth",
774
+      "core": false,
775
+      "unlocked_by": null,
776
+      "difficulty": 9,
777
+      "topics": [
778
+
779
+      ]
780
+    },
781
+    {
772 782
       "uuid": "377fe38b-08ad-4f3a-8118-a43c10f7b9b2",
773 783
       "slug": "custom-set",
774 784
       "core": false,

+ 17
- 0
exercises/forth/.meta/readme.go.tmpl Dosyayı Görüntüle

@@ -0,0 +1,17 @@
1
+# {{ .Spec.Name }}
2
+
3
+{{ .Spec.Description -}}
4
+{{- with .Hints }}
5
+{{ . }}
6
+{{ end }}
7
+{{- with .TrackInsert }}
8
+{{ . }}
9
+{{ end }}
10
+{{- with .Spec.Credits -}}
11
+## Source
12
+
13
+{{ . }}
14
+{{ end }}
15
+## Submitting Incomplete Solutions
16
+It's possible to submit an incomplete solution so you can see how others have completed the exercise.
17
+

+ 41
- 0
exercises/forth/README.md Dosyayı Görüntüle

@@ -0,0 +1,41 @@
1
+# Forth
2
+
3
+Implement an evaluator for a very simple subset of Forth.
4
+
5
+[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29)
6
+is a stack-based programming language. Implement a very basic evaluator
7
+for a small subset of Forth.
8
+
9
+Your evaluator has to support the following words:
10
+
11
+- `+`, `-`, `*`, `/` (integer arithmetic)
12
+- `DUP`, `DROP`, `SWAP`, `OVER` (stack manipulation)
13
+
14
+Your evaluator also has to support defining new words using the
15
+customary syntax: `: word-name definition ;`.
16
+
17
+To keep things simple the only data type you need to support is signed
18
+integers of at least 16 bits size.
19
+
20
+You should use the following rules for the syntax: a number is a
21
+sequence of one or more (ASCII) digits, a word is a sequence of one or
22
+more letters, digits, symbols or punctuation that is not a number.
23
+(Forth probably uses slightly different rules, but this is close
24
+enough.)
25
+
26
+Words are case-insensitive.
27
+
28
+
29
+To run the tests:
30
+
31
+```sh
32
+$ gradle test
33
+```
34
+
35
+For more detailed info about the Java track see the [help page](http://exercism.io/languages/java).
36
+
37
+
38
+
39
+## Submitting Incomplete Solutions
40
+It's possible to submit an incomplete solution so you can see how others have completed the exercise.
41
+

+ 18
- 0
exercises/forth/build.gradle Dosyayı Görüntüle

@@ -0,0 +1,18 @@
1
+apply plugin: "java"
2
+apply plugin: "eclipse"
3
+apply plugin: "idea"
4
+
5
+repositories {
6
+    mavenCentral()
7
+}
8
+
9
+dependencies {
10
+    testCompile "junit:junit:4.12"
11
+}
12
+
13
+test {
14
+    testLogging {
15
+        exceptionFormat = 'full'
16
+        events = ["passed", "failed", "skipped"]
17
+    }
18
+}

+ 154
- 0
exercises/forth/src/example/java/ForthEvaluator.java Dosyayı Görüntüle

@@ -0,0 +1,154 @@
1
+import java.util.*;
2
+import java.util.function.UnaryOperator;
3
+
4
+class ForthEvaluator {
5
+
6
+    private static final Map<String, UnaryOperator<Deque<Integer>>> BUILT_IN_OPS
7
+            = new HashMap<String, UnaryOperator<Deque<Integer>>>() {{
8
+
9
+                put("+", values -> {
10
+                    if (values.size() < 2) {
11
+                        throw new IllegalArgumentException(
12
+                                "Addition requires that the stack contain at least 2 values");
13
+                    }
14
+
15
+                    values.push(values.pop() + values.pop());
16
+                    return values;
17
+                });
18
+
19
+                put("-", values -> {
20
+                    if (values.size() < 2) {
21
+                        throw new IllegalArgumentException(
22
+                                "Subtraction requires that the stack contain at least 2 values");
23
+                    }
24
+
25
+                    int topValue = values.pop();
26
+                    int secondValue = values.pop();
27
+
28
+                    values.push(secondValue - topValue);
29
+                    return values;
30
+                });
31
+
32
+                put("*", values -> {
33
+                    if (values.size() < 2) {
34
+                        throw new IllegalArgumentException(
35
+                                "Multiplication requires that the stack contain at least 2 values");
36
+                    }
37
+
38
+                    values.push(values.pop() * values.pop());
39
+                    return values;
40
+                });
41
+
42
+                put("/", values -> {
43
+                    if (values.size() < 2) {
44
+                        throw new IllegalArgumentException(
45
+                                "Division requires that the stack contain at least 2 values");
46
+                    }
47
+
48
+                    int topValue = values.pop();
49
+                    int secondValue = values.pop();
50
+
51
+                    if (topValue == 0) {
52
+                        throw new IllegalArgumentException("Division by 0 is not allowed");
53
+                    }
54
+
55
+                    values.push(secondValue / topValue);
56
+                    return values;
57
+                });
58
+
59
+                put("dup", values -> {
60
+                    if (values.isEmpty()) {
61
+                        throw new IllegalArgumentException(
62
+                                "Duplicating requires that the stack contain at least 1 value");
63
+                    }
64
+
65
+                    values.push(values.peek());
66
+                    return values;
67
+                });
68
+
69
+                put("drop", values -> {
70
+                    if (values.isEmpty()) {
71
+                        throw new IllegalArgumentException(
72
+                                "Dropping requires that the stack contain at least 1 value");
73
+                    }
74
+
75
+                    values.pop();
76
+                    return values;
77
+                });
78
+
79
+                put("swap", values -> {
80
+                    if (values.size() < 2) {
81
+                        throw new IllegalArgumentException(
82
+                                "Swapping requires that the stack contain at least 2 values");
83
+                    }
84
+
85
+                    int topValue = values.pop();
86
+                    int secondValue = values.pop();
87
+                    values.push(topValue);
88
+                    values.push(secondValue);
89
+                    return values;
90
+                });
91
+
92
+                put("over", values -> {
93
+                    if (values.size() < 2) {
94
+                        throw new IllegalArgumentException(
95
+                                "Overing requires that the stack contain at least 2 values");
96
+                    }
97
+
98
+                    int topValue = values.pop();
99
+                    int secondValue = values.peek();
100
+                    values.push(topValue);
101
+                    values.push(secondValue);
102
+                    return values;
103
+                });
104
+    }};
105
+
106
+    private Deque<Integer> values = new ArrayDeque<>();
107
+
108
+    private List<Token> tokens = new ArrayList<>();
109
+
110
+    private Map<String, List<Token>> userOps = new HashMap<>();
111
+
112
+    List<Integer> evaluateProgram(final List<String> program) {
113
+        parse(program);
114
+        evaluate();
115
+
116
+        final List<Integer> result = new ArrayList<>(values);
117
+        Collections.reverse(result);
118
+        return result;
119
+    }
120
+
121
+    private void parse(final List<String> program) {
122
+        program.forEach(string -> tokens.addAll(Token.fromString(string)));
123
+    }
124
+
125
+    private void evaluate() {
126
+        while (!tokens.isEmpty()) {
127
+            final Token token = tokens.remove(0);
128
+
129
+            if (token instanceof Token.OpDefToken) {
130
+                final Token.OpDefToken opDefToken = (Token.OpDefToken) token;
131
+                userOps.put(opDefToken.getNewOp().toLowerCase(), opDefToken.getNewOpDefTokens());
132
+            } else if (token instanceof Token.OpToken) {
133
+                evaluateOpToken((Token.OpToken) token);
134
+            } else if (token instanceof Token.IntToken) {
135
+                values.push(((Token.IntToken) token).getRawValue());
136
+            }
137
+        }
138
+    }
139
+
140
+    private void evaluateOpToken(final Token.OpToken opToken) {
141
+        final String op = opToken.getOp();
142
+
143
+        if (userOps.containsKey(op)) {
144
+            final List<Token> replacementOps = userOps.get(op);
145
+            Collections.reverse(replacementOps);
146
+            replacementOps.forEach(token -> tokens.add(0, token));
147
+        } else if (BUILT_IN_OPS.containsKey(op)) {
148
+            values = BUILT_IN_OPS.get(op).apply(values);
149
+        } else {
150
+            throw new IllegalArgumentException("No definition available for operator \"" + op + "\"");
151
+        }
152
+    }
153
+
154
+}

+ 90
- 0
exercises/forth/src/example/java/Token.java Dosyayı Görüntüle

@@ -0,0 +1,90 @@
1
+import java.util.Arrays;
2
+import java.util.Collections;
3
+import java.util.List;
4
+import java.util.stream.Collectors;
5
+
6
+class Token {
7
+
8
+    static class OpDefToken extends Token {
9
+
10
+        static OpDefToken opDefTokenFromString(final String string) {
11
+            final String trimmedLine = string.substring(2, string.length() - 2);
12
+            final int newOpEnd = trimmedLine.indexOf(" ");
13
+
14
+            if (newOpEnd == -1) {
15
+                throw new IllegalArgumentException("Incomplete operation definition");
16
+            }
17
+
18
+            final Token newOpToken = Token.fromString(trimmedLine.substring(0, newOpEnd)).get(0);
19
+
20
+            if (!(newOpToken instanceof OpToken)) {
21
+                throw new IllegalArgumentException("Cannot redefine numbers");
22
+            }
23
+
24
+            final List<Token> newOpDefTokens = Token.fromString(trimmedLine.substring(newOpEnd + 1));
25
+            return new OpDefToken(((OpToken) newOpToken).getOp(), newOpDefTokens);
26
+        }
27
+
28
+        private final String newOp;
29
+
30
+        private final List<Token> newOpDefTokens;
31
+
32
+        private OpDefToken(final String newOp, final List<Token> newOpDefTokens) {
33
+            this.newOp = newOp;
34
+            this.newOpDefTokens = newOpDefTokens;
35
+        }
36
+
37
+        String getNewOp() {
38
+            return newOp;
39
+        }
40
+
41
+        List<Token> getNewOpDefTokens() {
42
+            return newOpDefTokens;
43
+        }
44
+
45
+    }
46
+
47
+    static class OpToken extends Token {
48
+
49
+        private final String op;
50
+
51
+        OpToken(final String op) {
52
+            this.op = op;
53
+        }
54
+
55
+        String getOp() {
56
+            return op;
57
+        }
58
+
59
+    }
60
+
61
+    static class IntToken extends Token {
62
+
63
+        private final int rawValue;
64
+
65
+        IntToken(final int rawValue) {
66
+            this.rawValue = rawValue;
67
+        }
68
+
69
+        int getRawValue() {
70
+            return rawValue;
71
+        }
72
+
73
+    }
74
+
75
+    static List<Token> fromString(final String string) {
76
+        if (string.startsWith(":")) {
77
+            return Collections.singletonList(OpDefToken.opDefTokenFromString(string));
78
+        } else if (string.matches("[A-z+/*\\-]+(?:-[A-z+/*\\-]+)*")) {
79
+            return Collections.singletonList(new OpToken(string.toLowerCase()));
80
+        } else if (string.matches("\\d+")) {
81
+            return Collections.singletonList(new IntToken(Integer.parseInt(string)));
82
+        } else {
83
+            return Arrays.stream(string.split(" "))
84
+                    .map(Token::fromString)
85
+                    .flatMap(List::stream)
86
+                    .collect(Collectors.toList());
87
+        }
88
+    }
89
+
90
+}

+ 0
- 0
exercises/forth/src/main/java/.keep Dosyayı Görüntüle


+ 355
- 0
exercises/forth/src/test/java/ForthEvaluatorTest.java Dosyayı Görüntüle

@@ -0,0 +1,355 @@
1
+import org.junit.Before;
2
+import org.junit.Ignore;
3
+import org.junit.Rule;
4
+import org.junit.Test;
5
+import org.junit.rules.ExpectedException;
6
+
7
+import java.util.Arrays;
8
+import java.util.Collections;
9
+
10
+import static org.junit.Assert.assertEquals;
11
+
12
+/*
13
+ * version: 1.2.0
14
+ */
15
+public class ForthEvaluatorTest {
16
+
17
+    @Rule
18
+    public ExpectedException expectedException = ExpectedException.none();
19
+
20
+    private ForthEvaluator forthEvaluator;
21
+
22
+    @Before
23
+    public void setUp() {
24
+        forthEvaluator = new ForthEvaluator();
25
+    }
26
+
27
+    @Test
28
+    public void testEmptyProgramResultsInEmptyStack() {
29
+        assertEquals(
30
+                Collections.emptyList(),
31
+                forthEvaluator.evaluateProgram(Collections.emptyList()));
32
+    }
33
+
34
+    @Ignore("Remove to run test")
35
+    @Test
36
+    public void testNumbersAreJustPushedOntoTheStack() {
37
+        assertEquals(
38
+                Arrays.asList(1, 2, 3, 4, 5),
39
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 4 5")));
40
+    }
41
+
42
+    @Ignore("Remove to run test")
43
+    @Test
44
+    public void testTwoNumbersCanBeAdded() {
45
+        assertEquals(
46
+                Collections.singletonList(3),
47
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 +")));
48
+    }
49
+
50
+    @Ignore("Remove to run test")
51
+    @Test
52
+    public void testErrorIfAdditionAttemptedWithNothingOnTheStack() {
53
+        expectedException.expect(IllegalArgumentException.class);
54
+        expectedException.expectMessage("Addition requires that the stack contain at least 2 values");
55
+
56
+        forthEvaluator.evaluateProgram(Collections.singletonList("+"));
57
+    }
58
+
59
+    @Ignore("Remove to run test")
60
+    @Test
61
+    public void testErrorIfAdditionAttemptedWithOneNumberOnTheStack() {
62
+        expectedException.expect(IllegalArgumentException.class);
63
+        expectedException.expectMessage("Addition requires that the stack contain at least 2 values");
64
+
65
+        forthEvaluator.evaluateProgram(Collections.singletonList("1 +"));
66
+    }
67
+
68
+    @Ignore("Remove to run test")
69
+    @Test
70
+    public void testTwoNumbersCanBeSubtracted() {
71
+        assertEquals(
72
+                Collections.singletonList(-1),
73
+                forthEvaluator.evaluateProgram(Collections.singletonList("3 4 -")));
74
+    }
75
+
76
+    @Ignore("Remove to run test")
77
+    @Test
78
+    public void testErrorIfSubtractionAttemptedWithNothingOnTheStack() {
79
+        expectedException.expect(IllegalArgumentException.class);
80
+        expectedException.expectMessage("Subtraction requires that the stack contain at least 2 values");
81
+
82
+        forthEvaluator.evaluateProgram(Collections.singletonList("-"));
83
+    }
84
+
85
+    @Ignore("Remove to run test")
86
+    @Test
87
+    public void testErrorIfSubtractionAttemptedWithOneNumberOnTheStack() {
88
+        expectedException.expect(IllegalArgumentException.class);
89
+        expectedException.expectMessage("Subtraction requires that the stack contain at least 2 values");
90
+
91
+        forthEvaluator.evaluateProgram(Collections.singletonList("1 -"));
92
+    }
93
+
94
+    @Ignore("Remove to run test")
95
+    @Test
96
+    public void testTwoNumbersCanBeMultiplied() {
97
+        assertEquals(
98
+                Collections.singletonList(8),
99
+                forthEvaluator.evaluateProgram(Collections.singletonList("2 4 *")));
100
+    }
101
+
102
+    @Ignore("Remove to run test")
103
+    @Test
104
+    public void testErrorIfMultiplicationAttemptedWithNothingOnTheStack() {
105
+        expectedException.expect(IllegalArgumentException.class);
106
+        expectedException.expectMessage("Multiplication requires that the stack contain at least 2 values");
107
+
108
+        forthEvaluator.evaluateProgram(Collections.singletonList("*"));
109
+    }
110
+
111
+    @Ignore("Remove to run test")
112
+    @Test
113
+    public void testErrorIfMultiplicationAttemptedWithOneNumberOnTheStack() {
114
+        expectedException.expect(IllegalArgumentException.class);
115
+        expectedException.expectMessage("Multiplication requires that the stack contain at least 2 values");
116
+
117
+        forthEvaluator.evaluateProgram(Collections.singletonList("1 *"));
118
+    }
119
+
120
+    @Ignore("Remove to run test")
121
+    @Test
122
+    public void testTwoNumbersCanBeDivided() {
123
+        assertEquals(
124
+                Collections.singletonList(4),
125
+                forthEvaluator.evaluateProgram(Collections.singletonList("12 3 /")));
126
+    }
127
+
128
+    @Ignore("Remove to run test")
129
+    @Test
130
+    public void testThatIntegerDivisionIsUsed() {
131
+        assertEquals(
132
+                Collections.singletonList(2),
133
+                forthEvaluator.evaluateProgram(Collections.singletonList("8 3 /")));
134
+    }
135
+
136
+    @Ignore("Remove to run test")
137
+    @Test
138
+    public void testErrorIfDividingByZero() {
139
+        expectedException.expect(IllegalArgumentException.class);
140
+        expectedException.expectMessage("Division by 0 is not allowed");
141
+
142
+        forthEvaluator.evaluateProgram(Collections.singletonList("4 0 /"));
143
+    }
144
+
145
+    @Ignore("Remove to run test")
146
+    @Test
147
+    public void testErrorIfDivisionAttemptedWithNothingOnTheStack() {
148
+        expectedException.expect(IllegalArgumentException.class);
149
+        expectedException.expectMessage("Division requires that the stack contain at least 2 values");
150
+
151
+        forthEvaluator.evaluateProgram(Collections.singletonList("/"));
152
+    }
153
+
154
+    @Ignore("Remove to run test")
155
+    @Test
156
+    public void testErrorIfDivisionAttemptedWithOneNumberOnTheStack() {
157
+        expectedException.expect(IllegalArgumentException.class);
158
+        expectedException.expectMessage("Division requires that the stack contain at least 2 values");
159
+
160
+        forthEvaluator.evaluateProgram(Collections.singletonList("1 /"));
161
+    }
162
+
163
+    @Ignore("Remove to run test")
164
+    @Test
165
+    public void testCombinedAdditionAndSubtraction() {
166
+        assertEquals(
167
+                Collections.singletonList(-1),
168
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 + 4 -")));
169
+    }
170
+
171
+    @Ignore("Remove to run test")
172
+    @Test
173
+    public void testCombinedMultiplicationAndDivision() {
174
+        assertEquals(
175
+                Collections.singletonList(2),
176
+                forthEvaluator.evaluateProgram(Collections.singletonList("2 4 * 3 /")));
177
+    }
178
+
179
+    @Ignore("Remove to run test")
180
+    @Test
181
+    public void testDupCopiesTheTopValueOnTheStack() {
182
+        assertEquals(
183
+                Arrays.asList(1, 1),
184
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 DUP")));
185
+    }
186
+
187
+    @Ignore("Remove to run test")
188
+    @Test
189
+    public void testDupParsingIsCaseInsensitive() {
190
+        assertEquals(
191
+                Arrays.asList(1, 2, 2),
192
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 Dup")));
193
+    }
194
+
195
+    @Ignore("Remove to run test")
196
+    @Test
197
+    public void testErrorIfDuplicatingAttemptedWithNothingOnTheStack() {
198
+        expectedException.expect(IllegalArgumentException.class);
199
+        expectedException.expectMessage("Duplicating requires that the stack contain at least 1 value");
200
+
201
+        forthEvaluator.evaluateProgram(Collections.singletonList("dup"));
202
+    }
203
+
204
+    @Ignore("Remove to run test")
205
+    @Test
206
+    public void testDropRemovesTheTopValueOnTheStackIfItIsTheOnlyOne() {
207
+        assertEquals(
208
+                Collections.emptyList(),
209
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 drop")));
210
+    }
211
+
212
+    @Ignore("Remove to run test")
213
+    @Test
214
+    public void testDropRemovesTheTopValueOnTheStackIfItIsNotTheOnlyOne() {
215
+        assertEquals(
216
+                Collections.singletonList(1),
217
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 drop")));
218
+    }
219
+
220
+    @Ignore("Remove to run test")
221
+    @Test
222
+    public void testErrorIfDroppingAttemptedWithNothingOnTheStack() {
223
+        expectedException.expect(IllegalArgumentException.class);
224
+        expectedException.expectMessage("Dropping requires that the stack contain at least 1 value");
225
+
226
+        forthEvaluator.evaluateProgram(Collections.singletonList("drop"));
227
+    }
228
+
229
+    @Ignore("Remove to run test")
230
+    @Test
231
+    public void testSwapSwapsTheTopTwosValueOnTheStackIfTheyAreTheOnlyOnes() {
232
+        assertEquals(
233
+                Arrays.asList(2, 1),
234
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 swap")));
235
+    }
236
+
237
+    @Ignore("Remove to run test")
238
+    @Test
239
+    public void testSwapSwapsTheTopTwosValueOnTheStackIfTheyAreNotTheOnlyOnes() {
240
+        assertEquals(
241
+                Arrays.asList(1, 3, 2),
242
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 swap")));
243
+    }
244
+
245
+    @Ignore("Remove to run test")
246
+    @Test
247
+    public void testErrorIfSwappingAttemptedWithNothingOnTheStack() {
248
+        expectedException.expect(IllegalArgumentException.class);
249
+        expectedException.expectMessage("Swapping requires that the stack contain at least 2 values");
250
+
251
+        forthEvaluator.evaluateProgram(Collections.singletonList("swap"));
252
+    }
253
+
254
+    @Ignore("Remove to run test")
255
+    @Test
256
+    public void testErrorIfSwappingAttemptedWithOneNumberOnTheStack() {
257
+        expectedException.expect(IllegalArgumentException.class);
258
+        expectedException.expectMessage("Swapping requires that the stack contain at least 2 values");
259
+
260
+        forthEvaluator.evaluateProgram(Collections.singletonList("1 swap"));
261
+    }
262
+
263
+    @Ignore("Remove to run test")
264
+    @Test
265
+    public void testOverCopiesTheSecondElementIfThereAreOnlyTwo() {
266
+        assertEquals(
267
+                Arrays.asList(1, 2, 1),
268
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 over")));
269
+    }
270
+
271
+    @Ignore("Remove to run test")
272
+    @Test
273
+    public void testOverCopiesTheSecondElementIfThereAreMoreThanTwo() {
274
+        assertEquals(
275
+                Arrays.asList(1, 2, 3, 2),
276
+                forthEvaluator.evaluateProgram(Collections.singletonList("1 2 3 over")));
277
+    }
278
+
279
+    @Ignore("Remove to run test")
280
+    @Test
281
+    public void testErrorIfOveringAttemptedWithNothingOnTheStack() {
282
+        expectedException.expect(IllegalArgumentException.class);
283
+        expectedException.expectMessage("Overing requires that the stack contain at least 2 values");
284
+
285
+        forthEvaluator.evaluateProgram(Collections.singletonList("over"));
286
+    }
287
+
288
+    @Ignore("Remove to run test")
289
+    @Test
290
+    public void testErrorIfOveringAttemptedWithOneNumberOnTheStack() {
291
+        expectedException.expect(IllegalArgumentException.class);
292
+        expectedException.expectMessage("Overing requires that the stack contain at least 2 values");
293
+
294
+        forthEvaluator.evaluateProgram(Collections.singletonList("1 over"));
295
+    }
296
+
297
+    @Ignore("Remove to run test")
298
+    @Test
299
+    public void testUserDefinedOperatorsCanConsistOfBuiltInOperators() {
300
+        assertEquals(
301
+                Arrays.asList(1, 1, 1),
302
+                forthEvaluator.evaluateProgram(Arrays.asList(": dup-twice dup dup ;", "1 dup-twice")));
303
+    }
304
+
305
+    @Ignore("Remove to run test")
306
+    @Test
307
+    public void testUserDefinedOperatorsAreEvaluatedInTheCorrectOrder() {
308
+        assertEquals(
309
+                Arrays.asList(1, 2, 3),
310
+                forthEvaluator.evaluateProgram(Arrays.asList(": countup 1 2 3 ;", "countup")));
311
+    }
312
+
313
+    @Ignore("Remove to run test")
314
+    @Test
315
+    public void testCanRedefineAUserDefinedOperator() {
316
+        assertEquals(
317
+                Arrays.asList(1, 1, 1),
318
+                forthEvaluator.evaluateProgram(Arrays.asList(": foo dup ;", ": foo dup dup ;", "1 foo")));
319
+    }
320
+
321
+    @Ignore("Remove to run test")
322
+    @Test
323
+    public void testCanOverrideBuiltInWordOperators() {
324
+        assertEquals(
325
+                Arrays.asList(1, 1),
326
+                forthEvaluator.evaluateProgram(Arrays.asList(": swap dup ;", "1 swap")));
327
+    }
328
+
329
+    @Ignore("Remove to run test")
330
+    @Test
331
+    public void testCanOverrideBuiltInArithmeticOperators() {
332
+        assertEquals(
333
+                Collections.singletonList(12),
334
+                forthEvaluator.evaluateProgram(Arrays.asList(": + * ;", "3 4 +")));
335
+    }
336
+
337
+    @Ignore("Remove to run test")
338
+    @Test
339
+    public void testCannotRedefineNumbers() {
340
+        expectedException.expect(IllegalArgumentException.class);
341
+        expectedException.expectMessage("Cannot redefine numbers");
342
+
343
+        forthEvaluator.evaluateProgram(Collections.singletonList(": 1 2 ;"));
344
+    }
345
+
346
+    @Ignore("Remove to run test")
347
+    @Test
348
+    public void testErrorIfEvaluatingAnUndefinedOperator() {
349
+        expectedException.expect(IllegalArgumentException.class);
350
+        expectedException.expectMessage("No definition available for operator \"foo\"");
351
+
352
+        forthEvaluator.evaluateProgram(Collections.singletonList("foo"));
353
+    }
354
+
355
+}

+ 1
- 0
exercises/settings.gradle Dosyayı Görüntüle

@@ -25,6 +25,7 @@ include 'difference-of-squares'
25 25
 include 'etl'
26 26
 include 'flatten-array'
27 27
 include 'food-chain'
28
+include 'forth'
28 29
 include 'gigasecond'
29 30
 include 'grade-school'
30 31
 include 'hamming'