diff --git a/demo/test-cases.html b/demo/test-cases.html
index 4348358..df780a0 100644
--- a/demo/test-cases.html
+++ b/demo/test-cases.html
@@ -92,6 +92,7 @@
Operators
ı.^\^
x.^ \(n)
<<< [] >>>
+ a o. b
\`lim sup`._(n -> oo)
diff --git a/src/compiler/tokenizer/scanners/alpha.js b/src/compiler/tokenizer/scanners/alpha.js
index 37f561e..d45a60f 100644
--- a/src/compiler/tokenizer/scanners/alpha.js
+++ b/src/compiler/tokenizer/scanners/alpha.js
@@ -30,8 +30,8 @@ export default function alphaScanner(char, input, { start, grouping }) {
[nextChar] = input.slice(i);
}
- // alpha may contain a period, but not never end with one.
- if (value.endsWith(".")) {
+ // alpha may contain a period, but only known ops can end with one.
+ if (value.endsWith(".") && !KNOWN_OPS.has(value)) {
value = value.slice(0, -1);
}
diff --git a/src/compiler/tokenizer/scanners/alpha.test.js b/src/compiler/tokenizer/scanners/alpha.test.js
index e92485c..1926f44 100644
--- a/src/compiler/tokenizer/scanners/alpha.test.js
+++ b/src/compiler/tokenizer/scanners/alpha.test.js
@@ -138,6 +138,24 @@ test("can’t end with a period", (t) => {
t.is(token?.split, true);
});
+test("unless it is a known operator", (t) => {
+ const token = alpha("o", "o.", { start: 0, grouping: false });
+
+ t.is(token?.type, "operator");
+ t.is(token?.value, "⊙");
+ t.is(token?.end, 2);
+ t.falsy(token?.split);
+});
+
+test("known operator ends in period cannot be followed by an alphanum", (t) => {
+ const token = alpha("o", "o.o", { start: 0, grouping: false });
+
+ t.is(token?.type, "ident");
+ t.is(token?.value, "o");
+ t.is(token?.end, 1);
+ t.is(token?.split, true);
+});
+
test("known prefix", (t) => {
const token = alpha("h", "hat a", { start: 0, grouping: false });
diff --git a/src/compiler/tokenizer/scanners/operator.test.js b/src/compiler/tokenizer/scanners/operator.test.js
index acb37cf..b67e08a 100644
--- a/src/compiler/tokenizer/scanners/operator.test.js
+++ b/src/compiler/tokenizer/scanners/operator.test.js
@@ -30,6 +30,14 @@ test("known operator", (t) => {
t.is(token?.end, 3);
});
+test("known operator that ends with a period", (t) => {
+ const token = operator("o.", " o. b", { start: 1, grouping: false });
+
+ t.is(token?.type, "operator");
+ t.is(token?.value, "⊙");
+ t.is(token?.end, 3);
+});
+
test("emits the longest possible known operator", (t) => {
const token = operator("^", "^^^ 1", { start: 0, grouping: false });
diff --git a/test/operators.js b/test/operators.js
index 39b9996..7bc7044 100644
--- a/test/operators.js
+++ b/test/operators.js
@@ -33,6 +33,12 @@ test("i hat", (t) => {
t.snapshot(render("ı.^\\^"));
});
+test("circumpunct", (t) => {
+ t.is(render("o."), "");
+ t.snapshot(render("a o. b"));
+ t.snapshot(render("a o.b"));
+});
+
test("Norm of two parallel lines", (t) => {
t.snapshot(render("||a || b||"));
});
diff --git a/test/snapshots/operators.js.md b/test/snapshots/operators.js.md
index 271c68e..f7440dd 100644
--- a/test/snapshots/operators.js.md
+++ b/test/snapshots/operators.js.md
@@ -36,6 +36,16 @@ Generated by [AVA](https://avajs.dev).
''
+## circumpunct
+
+> Snapshot 1
+
+ ''
+
+> Snapshot 2
+
+ ''
+
## Norm of two parallel lines
> Snapshot 1
diff --git a/test/snapshots/operators.js.snap b/test/snapshots/operators.js.snap
index 63dab0c..1858c05 100644
Binary files a/test/snapshots/operators.js.snap and b/test/snapshots/operators.js.snap differ