From ba1aece66eadc83614fa0f693b2c57cb7556260d Mon Sep 17 00:00:00 2001 From: Dmytro <30444137+swarty@users.noreply.github.com> Date: Wed, 17 Jan 2024 16:02:11 +0200 Subject: [PATCH] Support for ? symbol and questioned equal operator (#160) --- src/functions.ts | 6 +++--- src/parser.ts | 2 +- src/symbols.ts | 4 +++- test/parsing-test.ts | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) 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(); });