Skip to content

Commit 3619a6e

Browse files
oxe-iSleeplessByte
authored andcommitted
add test result for forth exercise
1 parent 7c04054 commit 3619a6e

4 files changed

Lines changed: 455 additions & 0 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"authors": [
3+
"matthewmorgan"
4+
],
5+
"contributors": [
6+
"brendanmckeown",
7+
"jagdish-15",
8+
"slaymance",
9+
"SleeplessByte",
10+
"tejasbubane",
11+
"tgujar",
12+
"xarxziux"
13+
],
14+
"files": {
15+
"solution": [
16+
"forth.js"
17+
],
18+
"test": [
19+
"forth.spec.js"
20+
],
21+
"example": [
22+
".meta/proof.ci.js"
23+
]
24+
},
25+
"blurb": "Implement an evaluator for a very simple subset of Forth.",
26+
"custom": {
27+
"version.tests.compatibility": "jest-27",
28+
"flag.tests.task-per-describe": false,
29+
"flag.tests.may-run-long": false,
30+
"flag.tests.includes-optional": false
31+
}
32+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"track":"javascript","exercise":"forth","id":"f0d2d690eaf54c2da812805c8d7201ae","url":"https://exercism.org/tracks/javascript/exercises/forth","handle":"oxe-b","is_requester":true,"auto_approve":false}

test/fixtures/forth/oxe-b/forth.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
export class Forth {
2+
#stack = [];
3+
#ops = [
4+
[/^\s?dup\s?/i, () => this.#unary((x) => [x, x])],
5+
[/^\s?over\s?/i, () => this.#binary((x, y) => [y, x, y])],
6+
[/^\s?drop\s?/i, () => this.#unary(() => [])],
7+
[/^\s?swap\s?/i, () => this.#binary((x, y) => [x, y])],
8+
[/^\s?-?\d+\s?/i, (x) => Number(x)],
9+
[/^\s?\+\s?/i, () => this.#binary((x, y) => y + x)],
10+
[/^\s?-\s?/i, () => this.#binary((x, y) => y - x)],
11+
[/^\s?\*\s?/i, () => this.#binary((x, y) => y * x)],
12+
[
13+
/^\s?\/\s?/i,
14+
() => {
15+
return this.#binary((x, y) => {
16+
if (x === 0) throw new Error("Division by zero");
17+
return (y / x) | 0;
18+
});
19+
},
20+
],
21+
[
22+
/\s?:\s(.*?)\s(.*)\s;\s?/i,
23+
(expression) => {
24+
const { key, ops } = this.#processUserOps(expression);
25+
const idx = this.#ops.findIndex((crt) => crt.source === key.source);
26+
if (idx !== -1) this.#ops.splice(idx, 1, [key, () => ops]);
27+
else this.#ops.unshift([key, () => ops]);
28+
return [];
29+
},
30+
],
31+
];
32+
33+
#unary = (callback) => (x) => {
34+
if (x === undefined) throw new Error("Stack empty");
35+
return callback(x);
36+
};
37+
38+
#binary = (callback) => {
39+
return this.#unary((y) => (z) => {
40+
if (z === undefined) throw new Error("Only one value on the stack");
41+
return callback(y, z);
42+
});
43+
};
44+
45+
#consumeOperation = (expression) => {
46+
for (const [pattern, callback] of this.#ops) {
47+
const match = expression.match(pattern);
48+
if (match) return { pattern: match[0], callback: callback };
49+
}
50+
throw new Error("Unknown command");
51+
};
52+
53+
#processUserOps = (pattern) => {
54+
const groups = pattern.match(/:\s(.*?)\s(.*)\s;\s?/i);
55+
if (/^\s*-?\d+\s*$/.test(groups[1])) throw new Error("Invalid definition");
56+
const key = new RegExp(`^\\s?${RegExp.escape(groups[1])}`, "i");
57+
const ops = groups[2].split(" ").map((opName) => {
58+
return this.#consumeOperation(opName).callback(opName);
59+
});
60+
return { key: key, ops: ops };
61+
};
62+
63+
evaluate(expressions) {
64+
this.#stack = expressions.split(/(:.*;|\s)/).reduce((acc, op) => {
65+
if (!op || op === " ") return acc;
66+
const { pattern, callback } = this.#consumeOperation(op);
67+
return [callback(pattern)].flat(Infinity).reduce((res, fn) => {
68+
while (typeof fn === "function") fn = fn(res.pop());
69+
return [...res, fn].flat(Infinity);
70+
}, acc);
71+
}, this.#stack);
72+
}
73+
74+
get stack() {
75+
return this.#stack;
76+
}
77+
}

0 commit comments

Comments
 (0)