UNPKG

speech-rule-engine

Version:

A standalone speech rule engine for XML structures, based on the original engine from ChromeVox.

193 lines 7.17 kB
import { Engine } from '../common/engine.js'; import { SemanticRole, SemanticType } from '../semantic_tree/semantic_meaning.js'; import { register, activate } from '../semantic_tree/semantic_annotations.js'; import { SemanticAnnotator, SemanticVisitor } from '../semantic_tree/semantic_annotator.js'; function isSimpleExpression(node) { return (isSimpleNumber_(node) || isSimpleLetters_(node) || isSimpleDegree_(node) || isSimpleNegative_(node) || isSimpleFunction_(node)); } function isSimpleFunction_(node) { return (node.type === SemanticType.APPL && (node.childNodes[0].role === SemanticRole.PREFIXFUNC || node.childNodes[0].role === SemanticRole.SIMPLEFUNC) && (isSimple_(node.childNodes[1]) || (node.childNodes[1].type === SemanticType.FENCED && isSimple_(node.childNodes[1].childNodes[0])))); } function isSimpleNegative_(node) { return (node.type === SemanticType.PREFIXOP && node.role === SemanticRole.NEGATIVE && isSimple_(node.childNodes[0]) && node.childNodes[0].type !== SemanticType.PREFIXOP && node.childNodes[0].type !== SemanticType.APPL && node.childNodes[0].type !== SemanticType.PUNCTUATED); } function isSimpleDegree_(node) { return (node.type === SemanticType.PUNCTUATED && node.role === SemanticRole.ENDPUNCT && node.childNodes.length === 2 && node.childNodes[1].role === SemanticRole.DEGREE && (isLetter_(node.childNodes[0]) || isNumber_(node.childNodes[0]) || (node.childNodes[0].type === SemanticType.PREFIXOP && node.childNodes[0].role === SemanticRole.NEGATIVE && (isLetter_(node.childNodes[0].childNodes[0]) || isNumber_(node.childNodes[0].childNodes[0]))))); } function isSimpleLetters_(node) { return (isLetter_(node) || (node.type === SemanticType.INFIXOP && node.role === SemanticRole.IMPLICIT && ((node.childNodes.length === 2 && (isLetter_(node.childNodes[0]) || isSimpleNumber_(node.childNodes[0])) && isLetter_(node.childNodes[1])) || (node.childNodes.length === 3 && isSimpleNumber_(node.childNodes[0]) && isLetter_(node.childNodes[1]) && isLetter_(node.childNodes[2]))))); } function isSimple_(node) { return node.hasAnnotation('clearspeak', 'simple'); } function isLetter_(node) { return (node.type === SemanticType.IDENTIFIER && (node.role === SemanticRole.LATINLETTER || node.role === SemanticRole.GREEKLETTER || node.role === SemanticRole.OTHERLETTER || node.role === SemanticRole.SIMPLEFUNC)); } function isNumber_(node) { return (node.type === SemanticType.NUMBER && (node.role === SemanticRole.INTEGER || node.role === SemanticRole.FLOAT)); } function isSimpleNumber_(node) { return isNumber_(node) || isSimpleFraction_(node); } function isSimpleFraction_(node) { if (hasPreference('Fraction_Over') || hasPreference('Fraction_FracOver')) { return false; } if (node.type !== SemanticType.FRACTION || node.role !== SemanticRole.VULGAR) { return false; } if (hasPreference('Fraction_Ordinal')) { return true; } const enumerator = parseInt(node.childNodes[0].textContent, 10); const denominator = parseInt(node.childNodes[1].textContent, 10); return (enumerator > 0 && enumerator < 20 && denominator > 0 && denominator < 11); } function hasPreference(pref) { return Engine.getInstance().options.style === pref; } register(new SemanticAnnotator('clearspeak', 'simple', function (node) { return isSimpleExpression(node) ? 'simple' : ''; })); activate('clearspeak', 'simple'); function isUnitExpression(node) { return ((node.type === SemanticType.TEXT && node.role !== SemanticRole.LABEL) || (node.type === SemanticType.PUNCTUATED && node.role === SemanticRole.TEXT && isNumber_(node.childNodes[0]) && allTextLastContent_(node.childNodes.slice(1))) || (node.type === SemanticType.IDENTIFIER && node.role === SemanticRole.UNIT) || (node.type === SemanticType.INFIXOP && (node.role === SemanticRole.IMPLICIT || node.role === SemanticRole.UNIT))); } function allTextLastContent_(nodes) { for (let i = 0; i < nodes.length - 1; i++) { if (!(nodes[i].type === SemanticType.TEXT && nodes[i].textContent === '')) { return false; } } return nodes[nodes.length - 1].type === SemanticType.TEXT; } register(new SemanticAnnotator('clearspeak', 'unit', function (node) { return isUnitExpression(node) ? 'unit' : ''; })); activate('clearspeak', 'unit'); const NUMBER_PROPAGATORS = [ SemanticType.MULTIREL, SemanticType.RELSEQ, SemanticType.APPL, SemanticType.ROW, SemanticType.LINE ]; const NUMBER_INHIBITORS = [ SemanticType.SUBSCRIPT, SemanticType.SUPERSCRIPT, SemanticType.OVERSCORE, SemanticType.UNDERSCORE ]; function checkParent(node, info) { const parent = node.parent; if (!parent) { return false; } const type = parent.type; if (NUMBER_PROPAGATORS.indexOf(type) !== -1 || (type === SemanticType.PREFIXOP && parent.role === SemanticRole.NEGATIVE && !info.script && !info.enclosed) || (type === SemanticType.PREFIXOP && parent.role === SemanticRole.GEOMETRY)) { return true; } if (type === SemanticType.PUNCTUATED) { if (!info.enclosed || parent.role === SemanticRole.TEXT) { return true; } } return false; } function propagateNumber(node, info) { if (!node.childNodes.length) { if (checkParent(node, info)) { info.number = true; info.script = false; info.enclosed = false; } return [ info['number'] ? 'number' : '', { number: false, enclosed: info.enclosed, script: info.script } ]; } if (NUMBER_INHIBITORS.indexOf(node.type) !== -1) { info.script = true; } if (node.type === SemanticType.FENCED) { info.number = false; info.enclosed = true; return ['', info]; } if (node.type === SemanticType.PREFIXOP && node.role !== SemanticRole.GEOMETRY && node.role !== SemanticRole.NEGATIVE) { info.number = false; return ['', info]; } if (checkParent(node, info)) { info.number = true; info.enclosed = false; } return ['', info]; } register(new SemanticVisitor('nemeth', 'number', propagateNumber, { number: true })); activate('nemeth', 'number'); function annotateDepth(node) { if (!node.parent) { return [1]; } const depth = parseInt(node.parent.annotation['depth'][0]); return [depth + 1]; } register(new SemanticVisitor('depth', 'depth', annotateDepth)); activate('depth', 'depth'); //# sourceMappingURL=special_annotators.js.map