Skip to content

Commit 028b3ff

Browse files
authored
Reject invalid moshscript characters (#5)
1 parent 35df05f commit 028b3ff

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
},
99
"scripts": {
1010
"start": "node bin/moshcode.mjs",
11-
"demo": "node bin/moshcode.mjs run examples/alive.mosh"
11+
"demo": "node bin/moshcode.mjs run examples/alive.mosh",
12+
"test": "node --test"
1213
},
1314
"files": ["bin", "src", "examples", "install.sh", "README.md"],
1415
"license": "MIT"

src/interpreter.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@ export function tokenize(src) {
1515
const re = /("(?:[^"\\]|\\.)*")|(\/\/[^\n]*)|(\d+(?:\.\d+)?)|([A-Za-z_]\w*)|([(){};,])|(\s+)/g;
1616
const tokens = [];
1717
let m;
18+
let lastIndex = 0;
1819
while ((m = re.exec(src)) !== null) {
20+
if (m.index !== lastIndex) {
21+
throw new Error(`moshscript: unexpected character near "${src.slice(lastIndex, lastIndex + 12)}"`);
22+
}
23+
lastIndex = re.lastIndex;
1924
if (m[2] || m[6]) continue; // comment or whitespace
2025
if (m[1]) tokens.push({ t: "str", v: JSON.parse(m[1]) });
2126
else if (m[3]) tokens.push({ t: "num", v: Number(m[3]) });
2227
else if (m[4]) tokens.push({ t: "id", v: m[4] });
2328
else if (m[5]) tokens.push({ t: "punc", v: m[5] });
2429
else throw new Error(`moshscript: unexpected character near "${src.slice(m.index, m.index + 12)}"`);
2530
}
31+
if (lastIndex !== src.length) {
32+
throw new Error(`moshscript: unexpected character near "${src.slice(lastIndex, lastIndex + 12)}"`);
33+
}
2634
return tokens;
2735
}
2836

test/interpreter.test.mjs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import assert from "node:assert/strict";
2+
import test from "node:test";
3+
import { compile, tokenize } from "../src/interpreter.mjs";
4+
5+
test("tokenize rejects unexpected characters between valid tokens", () => {
6+
assert.throws(() => tokenize("say(@);"), /unexpected character/);
7+
assert.throws(() => tokenize("say(\"ok\") @"), /unexpected character/);
8+
});
9+
10+
test("compile preserves valid moshscript behavior", () => {
11+
assert.deepEqual(compile("say(\"hi\");").body[0], {
12+
type: "call",
13+
name: "say",
14+
args: ["hi"],
15+
});
16+
});

0 commit comments

Comments
 (0)