| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Rule store for math syntax tree nodes. |
| */ |
| |
| goog.provide('cvox.MathStore'); |
| |
| goog.require('cvox.AbstractTts'); |
| goog.require('cvox.BaseRuleStore'); |
| goog.require('cvox.ChromeVox'); |
| goog.require('cvox.NavMathDescription'); |
| goog.require('cvox.SpeechRule'); |
| goog.require('cvox.TraverseMath'); |
| |
| |
| /** |
| * A store for Math rules. |
| * @constructor |
| * @extends {cvox.BaseRuleStore} |
| */ |
| cvox.MathStore = function() { |
| goog.base(this); |
| |
| /** |
| * @override |
| */ |
| this.dynamicCstrAttribs = [ |
| cvox.SpeechRule.DynamicCstrAttrib.DOMAIN, |
| cvox.SpeechRule.DynamicCstrAttrib.STYLE |
| ]; |
| |
| /** |
| * @override |
| */ |
| this.defaultTtsProps = [cvox.AbstractTts.PITCH, cvox.AbstractTts.RATE]; |
| }; |
| goog.inherits(cvox.MathStore, cvox.BaseRuleStore); |
| |
| /** This adds domain to dynamic constraint annotation. */ |
| cvox.SpeechRule.DynamicCstrAttrib.DOMAIN = 'domain'; |
| |
| |
| /** |
| * @override |
| */ |
| cvox.MathStore.prototype.defineRule = function( |
| name, dynamic, action, query, cstr) { |
| var dynamicCstr = this.parseDynamicConstraint(dynamic); |
| var cstrList = Array.prototype.slice.call(arguments, 4); |
| // We can not use goog.base due to variable number of constraint arguments. |
| var rule = cvox.MathStore.superClass_.defineRule.apply( |
| this, [name, dynamicCstr[cvox.SpeechRule.DynamicCstrAttrib.STYLE], |
| action, query].concat(cstrList)); |
| // In the superclass the dynamic constraint only contains style annotations. |
| // We now set the proper dynamic constraint that contains in addition a |
| // a domain attribute/value pair. |
| rule.dynamicCstr = dynamicCstr; |
| this.removeDuplicates(rule); |
| return rule; |
| }; |
| |
| |
| /** |
| * Parses the dynamic constraint for math rules, consisting of a domain and |
| * style information, given as 'domain.style'. |
| * @param {string} cstr A string representation of the dynamic constraint. |
| * @return {!cvox.SpeechRule.DynamicCstr} The dynamic constraint. |
| */ |
| cvox.MathStore.prototype.parseDynamicConstraint = function(cstr) { |
| var domainStyle = cstr.split('.'); |
| if (!domainStyle[0] || !domainStyle[1]) { |
| throw new cvox.SpeechRule.OutputError('Invalid domain assignment:' + cstr); |
| } |
| return cvox.MathStore.createDynamicConstraint(domainStyle[0], domainStyle[1]); |
| }; |
| |
| |
| /** |
| * Creates a dynamic constraint annotation for math rules from domain and style |
| * values. |
| * @param {string} domain Domain annotation. |
| * @param {string} style Style annotation. |
| * @return {!cvox.SpeechRule.DynamicCstr} |
| */ |
| cvox.MathStore.createDynamicConstraint = function(domain, style) { |
| var dynamicCstr = {}; |
| dynamicCstr[cvox.SpeechRule.DynamicCstrAttrib.DOMAIN] = domain; |
| dynamicCstr[cvox.SpeechRule.DynamicCstrAttrib.STYLE] = style; |
| return dynamicCstr; |
| }; |
| |
| |
| /** |
| * Adds an alias for an existing rule. |
| * @param {string} name The name of the rule. |
| * @param {string} dynamic A math domain and style assignment. |
| * @param {string} query Precondition query of the rule. |
| * @param {...string} cstr Additional static precondition constraints. |
| */ |
| cvox.MathStore.prototype.defineUniqueRuleAlias = function( |
| name, dynamic, query, cstr) { |
| var dynamicCstr = this.parseDynamicConstraint(dynamic); |
| var rule = this.findRule( |
| goog.bind( |
| function(rule) { |
| return rule.name == name && |
| this.testDynamicConstraints(dynamicCstr, rule);}, |
| this)); |
| if (!rule) { |
| throw new cvox.SpeechRule.OutputError( |
| 'Rule named ' + name + ' with style ' + dynamic + ' does not exist.'); |
| } |
| this.addAlias_(rule, query, Array.prototype.slice.call(arguments, 3)); |
| }; |
| |
| |
| /** |
| * Adds an alias for an existing rule. |
| * @param {string} name The name of the rule. |
| * @param {string} query Precondition query of the rule. |
| * @param {...string} cstr Additional static precondition constraints. |
| */ |
| cvox.MathStore.prototype.defineRuleAlias = function(name, query, cstr) { |
| var rule = this.findRule(function(rule) { |
| return rule.name == name;}); |
| if (!rule) { |
| throw new cvox.SpeechRule.OutputError( |
| 'Rule with named ' + name + ' does not exist.'); |
| } |
| this.addAlias_(rule, query, Array.prototype.slice.call(arguments, 2)); |
| }; |
| |
| |
| /** |
| * Adds an alias for an existing rule. |
| * @param {string} name The name of the rule. |
| * @param {string} query Precondition query of the rule. |
| * @param {...string} cstr Additional static precondition constraints. |
| */ |
| cvox.MathStore.prototype.defineRulesAlias = function(name, query, cstr) { |
| var rules = this.findAllRules(function(rule) {return rule.name == name;}); |
| if (rules.length == 0) { |
| throw new cvox.SpeechRule.OutputError( |
| 'Rule with name ' + name + ' does not exist.'); |
| } |
| var cstrList = Array.prototype.slice.call(arguments, 2); |
| rules.forEach(goog.bind( |
| function(rule) { |
| this.addAlias_(rule, query, cstrList); |
| }, |
| this)); |
| }; |
| |
| |
| /** |
| * Adds a new speech rule as alias of the given rule. |
| * @param {cvox.SpeechRule} rule The existing rule. |
| * @param {string} query Precondition query of the rule. |
| * @param {Array.<string>} cstrList List of additional constraints. |
| * @private |
| */ |
| cvox.MathStore.prototype.addAlias_ = function(rule, query, cstrList) { |
| var prec = new cvox.SpeechRule.Precondition(query, cstrList); |
| var newRule = new cvox.SpeechRule( |
| rule.name, rule.dynamicCstr, prec, rule.action); |
| newRule.name = rule.name; |
| this.addRule(newRule); |
| }; |
| |
| |
| // Evaluator |
| /** |
| * @override |
| */ |
| cvox.MathStore.prototype.evaluateDefault = function(node) { |
| return this.evaluateString_(node.textContent); |
| }; |
| |
| |
| /** |
| * Evaluates a single string of a math expressions. The method splits the given |
| * string into components such as single characters, function names or words, |
| * numbers, etc. and creates the appropriate navigation descriptions. |
| * @param {string} str A string. |
| * @return {!Array.<cvox.NavDescription>} Messages for the math expression. |
| * @private |
| */ |
| cvox.MathStore.prototype.evaluateString_ = function(str) { |
| var descs = new Array(); |
| if (str.match(/^\s+$/)) { |
| // Nothing but whitespace: Ignore. |
| return descs; |
| } |
| var split = cvox.MathStore.removeEmpty_(str.replace(/\s/g, ' ').split(' ')); |
| for (var i = 0, s; s = split[i]; i++) { |
| if (s.length == 1) { |
| descs.push(this.evaluate_(s)); |
| } else if (s.match(/^[a-zA-Z]+$/)) { |
| descs.push(this.evaluate_(s)); |
| } else { |
| // Break up string even further wrt. symbols vs alphanum substrings. |
| var rest = s; |
| var count = 0; |
| while (rest) { |
| var num = rest.match(/^\d+/); |
| var alpha = rest.match(/^[a-zA-Z]+/); |
| if (num) { |
| descs.push(this.evaluate_(num[0])); |
| rest = rest.substring(num[0].length); |
| } else if (alpha) { |
| descs.push(this.evaluate_(alpha[0])); |
| rest = rest.substring(alpha[0].length); |
| } else { |
| // Dealing with surrogate pairs. |
| var chr = rest[0]; |
| var code = chr.charCodeAt(0); |
| if (0xD800 <= code && code <= 0xDBFF && |
| rest.length > 1 && !isNaN(rest.charCodeAt(1))) { |
| descs.push(this.evaluate_(rest.slice(0, 2))); |
| rest = rest.substring(2); |
| } else { |
| descs.push(this.evaluate_(rest[0])); |
| rest = rest.substring(1); |
| } |
| } |
| } |
| } |
| } |
| return descs; |
| }; |
| |
| |
| /** |
| * Creates a new Navigation Description for a math expression that be used by |
| * the background tts. |
| * @param {string} text to be translated. |
| * @return {cvox.NavDescription} Navigation description for the |
| * math expression. |
| * @private |
| */ |
| cvox.MathStore.prototype.evaluate_ = function(text) { |
| if (cvox.ChromeVox.host['mathMap']) { |
| // VS: Change this for android! |
| return cvox.ChromeVox.host['mathMap'].evaluate( |
| text, |
| cvox.TraverseMath.getInstance().domain, |
| cvox.TraverseMath.getInstance().style); |
| } |
| return new cvox.NavMathDescription( |
| {'text': text, |
| 'domain': cvox.TraverseMath.getInstance().domain, |
| 'style': cvox.TraverseMath.getInstance().style |
| }); |
| }; |
| |
| |
| /** |
| * Removes all empty strings from an array of strings. |
| * @param {Array.<string>} strs An array of strings. |
| * @return {Array.<string>} The cleaned array. |
| * @private |
| */ |
| cvox.MathStore.removeEmpty_ = function(strs) { |
| return strs.filter(function(str) {return str;}); |
| }; |