diff --git a/src/functions.ts b/src/functions.ts
index 3d0651b9..4a03767d 100644
--- a/src/functions.ts
+++ b/src/functions.ts
@@ -8,7 +8,7 @@ import {flatten, isOneOf, join, repeat, unique, words} from '@mathigon/core';
import {evaluate, interval, Interval} from './eval';
import {collapseTerm} from './parser';
import {BRACKETS, escape, isSpecialFunction, VOICE_STRINGS} from './symbols';
-import {CustomFunction, ExprElement, ExprMap, ExprNumber, MathMLMap, VarMap} from './elements';
+import {ExprElement, ExprMap, ExprNumber, MathMLMap, VarMap} from './elements';
import {ExprError} from './errors';
@@ -119,7 +119,7 @@ export class ExprFunction extends ExprElement {
if (this.fn === 'sub') return args.join('_');
if (this.fn === 'subsup') return `${args[0]}_${args[1]}^${args[2]}`;
- if (words('+ * × · / = < > ≤ ≥ ≈').includes(this.fn)) {
+ if (words('+ * × · / = < > ≤ ≥ ≈ ≟ ≠').includes(this.fn)) {
return args.join(` ${this.fn} `);
}
@@ -149,7 +149,7 @@ export class ExprFunction extends ExprElement {
return argsF.length > 1 ? argsF.join('−') : `−${argsF[0]}`;
}
- if (isOneOf(this.fn, '+', '=', '<', '>', '≤', '≥', '≈')) {
+ if (isOneOf(this.fn, '+', '=', '<', '>', '≤', '≥', '≈', '≟', '≠')) {
const fn = escape(this.fn);
return argsF.join(`${fn}`);
}
diff --git a/src/parser.ts b/src/parser.ts
index e2c65fe3..43b62708 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -262,7 +262,7 @@ export function collapseTerm(tokens: ExprElement[]): ExprElement {
if (!tokens.length) throw ExprError.invalidExpression();
// Match comparison operators first
- const comp = tokens.findIndex(t => isOperator(t, '= < > ≤ ≥'));
+ const comp = tokens.findIndex(t => isOperator(t, '= < > ≤ ≥ ≟ ≠'));
if (comp === 0) throw ExprError.startOperator(tokens[0]);
if (comp === tokens.length - 1) throw ExprError.endOperator(tokens[0]);
if (comp > 0) {
diff --git a/src/symbols.ts b/src/symbols.ts
index 7c5f5523..abc4a9c4 100644
--- a/src/symbols.ts
+++ b/src/symbols.ts
@@ -39,6 +39,7 @@ export const SPECIAL_OPERATORS: Obj = {
'\'': '’',
'!=': '≠',
+ '?=': '≟',
'<=': '≤',
'>=': '≥',
'in': '∈',
@@ -112,7 +113,7 @@ const UPPERCASE = ALPHABET.toUpperCase().split('');
const GREEK = Object.values(SPECIAL_IDENTIFIERS);
export const IDENTIFIER_SYMBOLS = [...LOWERCASE, ...UPPERCASE, ...GREEK, '$'];
-const SIMPLE_SYMBOLS = '|()[]{}÷,!<>=*/+-–−~^_…°•∥⊥\'∠:%∼△';
+const SIMPLE_SYMBOLS = '|()[]{}÷,!?<>=*/+-–−~^_…°•∥⊥\'∠:%∼△';
const COMPLEX_SYMBOLS = Object.values(SPECIAL_OPERATORS);
export const OPERATOR_SYMBOLS = [...SIMPLE_SYMBOLS, ...COMPLEX_SYMBOLS];
@@ -154,6 +155,7 @@ export const VOICE_STRINGS: Obj = {
'±': 'plus-minus',
'=': 'equals',
'≠': 'does not equal',
+ '≟': 'is it equal?',
'<': 'is less than',
'>': 'is greater than',
'≤': 'is less than or equal to',
diff --git a/test/parsing-test.ts b/test/parsing-test.ts
index 736e082c..a3447aff 100644
--- a/test/parsing-test.ts
+++ b/test/parsing-test.ts
@@ -73,6 +73,7 @@ tape('symbols', (test) => {
test.equal(str('x cup y'), 'x ∪ y');
test.equal(str('x ∩ y'), 'x ∩ y');
test.equal(str('a != b'), 'a ≠ b');
+ test.equal(str('a ?= b'), 'a ≟ b');
test.end();
});