1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Rule store for math syntax tree nodes.
9 goog
.provide('cvox.MathStore');
11 goog
.require('cvox.AbstractTts');
12 goog
.require('cvox.BaseRuleStore');
13 goog
.require('cvox.ChromeVox');
14 goog
.require('cvox.NavMathDescription');
15 goog
.require('cvox.SpeechRule');
16 goog
.require('cvox.TraverseMath');
20 * A store for Math rules.
22 * @extends {cvox.BaseRuleStore}
24 cvox
.MathStore = function() {
30 this.dynamicCstrAttribs
= [
31 cvox
.SpeechRule
.DynamicCstrAttrib
.DOMAIN
,
32 cvox
.SpeechRule
.DynamicCstrAttrib
.STYLE
38 this.defaultTtsProps
= [cvox
.AbstractTts
.PITCH
];
40 goog
.inherits(cvox
.MathStore
, cvox
.BaseRuleStore
);
42 /** This adds domain to dynamic constraint annotation. */
43 cvox
.SpeechRule
.DynamicCstrAttrib
.DOMAIN
= 'domain';
49 cvox
.MathStore
.prototype.defineRule = function(
50 name
, dynamic
, action
, query
, cstr
) {
51 var dynamicCstr
= this.parseDynamicConstraint(dynamic
);
52 var cstrList
= Array
.prototype.slice
.call(arguments
, 4);
53 // We can not use goog.base due to variable number of constraint arguments.
54 var rule
= cvox
.MathStore
.superClass_
.defineRule
.apply(
55 this, [name
, dynamicCstr
[cvox
.SpeechRule
.DynamicCstrAttrib
.STYLE
],
56 action
, query
].concat(cstrList
));
57 // In the superclass the dynamic constraint only contains style annotations.
58 // We now set the proper dynamic constraint that contains in addition a
59 // a domain attribute/value pair.
60 rule
.dynamicCstr
= dynamicCstr
;
61 this.removeDuplicates(rule
);
67 * Parses the dynamic constraint for math rules, consisting of a domain and
68 * style information, given as 'domain.style'.
69 * @param {string} cstr A string representation of the dynamic constraint.
70 * @return {!cvox.SpeechRule.DynamicCstr} The dynamic constraint.
72 cvox
.MathStore
.prototype.parseDynamicConstraint = function(cstr
) {
73 var domainStyle
= cstr
.split('.');
74 if (!domainStyle
[0] || !domainStyle
[1]) {
75 throw new cvox
.SpeechRule
.OutputError('Invalid domain assignment:' + cstr
);
77 return cvox
.MathStore
.createDynamicConstraint(domainStyle
[0], domainStyle
[1]);
82 * Creates a dynamic constraint annotation for math rules from domain and style
84 * @param {string} domain Domain annotation.
85 * @param {string} style Style annotation.
86 * @return {!cvox.SpeechRule.DynamicCstr}
88 cvox
.MathStore
.createDynamicConstraint = function(domain
, style
) {
90 dynamicCstr
[cvox
.SpeechRule
.DynamicCstrAttrib
.DOMAIN
] = domain
;
91 dynamicCstr
[cvox
.SpeechRule
.DynamicCstrAttrib
.STYLE
] = style
;
97 * Adds an alias for an existing rule.
98 * @param {string} name The name of the rule.
99 * @param {string} dynamic A math domain and style assignment.
100 * @param {string} query Precondition query of the rule.
101 * @param {...string} cstr Additional static precondition constraints.
103 cvox
.MathStore
.prototype.defineUniqueRuleAlias = function(
104 name
, dynamic
, query
, cstr
) {
105 var dynamicCstr
= this.parseDynamicConstraint(dynamic
);
106 var rule
= this.findRule(
109 return rule
.name
== name
&&
110 this.testDynamicConstraints(dynamicCstr
, rule
);},
113 throw new cvox
.SpeechRule
.OutputError(
114 'Rule named ' + name
+ ' with style ' + dynamic
+ ' does not exist.');
116 this.addAlias_(rule
, query
, Array
.prototype.slice
.call(arguments
, 3));
121 * Adds an alias for an existing rule.
122 * @param {string} name The name of the rule.
123 * @param {string} query Precondition query of the rule.
124 * @param {...string} cstr Additional static precondition constraints.
126 cvox
.MathStore
.prototype.defineRuleAlias = function(name
, query
, cstr
) {
127 var rule
= this.findRule(function(rule
) {
128 return rule
.name
== name
;});
130 throw new cvox
.SpeechRule
.OutputError(
131 'Rule with named ' + name
+ ' does not exist.');
133 this.addAlias_(rule
, query
, Array
.prototype.slice
.call(arguments
, 2));
138 * Adds an alias for an existing rule.
139 * @param {string} name The name of the rule.
140 * @param {string} query Precondition query of the rule.
141 * @param {...string} cstr Additional static precondition constraints.
143 cvox
.MathStore
.prototype.defineRulesAlias = function(name
, query
, cstr
) {
144 var rules
= this.findAllRules(function(rule
) {return rule
.name
== name
;});
145 if (rules
.length
== 0) {
146 throw new cvox
.SpeechRule
.OutputError(
147 'Rule with name ' + name
+ ' does not exist.');
149 var cstrList
= Array
.prototype.slice
.call(arguments
, 2);
150 rules
.forEach(goog
.bind(
152 this.addAlias_(rule
, query
, cstrList
);
159 * Adds a new speech rule as alias of the given rule.
160 * @param {cvox.SpeechRule} rule The existing rule.
161 * @param {string} query Precondition query of the rule.
162 * @param {Array<string>} cstrList List of additional constraints.
165 cvox
.MathStore
.prototype.addAlias_ = function(rule
, query
, cstrList
) {
166 var prec
= new cvox
.SpeechRule
.Precondition(query
, cstrList
);
167 var newRule
= new cvox
.SpeechRule(
168 rule
.name
, rule
.dynamicCstr
, prec
, rule
.action
);
169 newRule
.name
= rule
.name
;
170 this.addRule(newRule
);
178 cvox
.MathStore
.prototype.evaluateDefault = function(node
) {
179 return this.evaluateString_(node
.textContent
);
184 * Evaluates a single string of a math expressions. The method splits the given
185 * string into components such as single characters, function names or words,
186 * numbers, etc. and creates the appropriate navigation descriptions.
187 * @param {string} str A string.
188 * @return {!Array<cvox.NavDescription>} Messages for the math expression.
191 cvox
.MathStore
.prototype.evaluateString_ = function(str
) {
192 var descs
= new Array();
193 if (str
.match(/^\s+$/)) {
194 // Nothing but whitespace: Ignore.
197 var split
= cvox
.MathStore
.removeEmpty_(str
.replace(/\s/g, ' ').split(' '));
198 for (var i
= 0, s
; s
= split
[i
]; i
++) {
200 descs
.push(this.evaluate_(s
));
201 } else if (s
.match(/^[a-zA-Z]+$/)) {
202 descs
.push(this.evaluate_(s
));
204 // Break up string even further wrt. symbols vs alphanum substrings.
208 var num
= rest
.match(/^\d+/);
209 var alpha
= rest
.match(/^[a-zA-Z]+/);
211 descs
.push(this.evaluate_(num
[0]));
212 rest
= rest
.substring(num
[0].length
);
214 descs
.push(this.evaluate_(alpha
[0]));
215 rest
= rest
.substring(alpha
[0].length
);
217 // Dealing with surrogate pairs.
219 var code
= chr
.charCodeAt(0);
220 if (0xD800 <= code
&& code
<= 0xDBFF &&
221 rest
.length
> 1 && !isNaN(rest
.charCodeAt(1))) {
222 descs
.push(this.evaluate_(rest
.slice(0, 2)));
223 rest
= rest
.substring(2);
225 descs
.push(this.evaluate_(rest
[0]));
226 rest
= rest
.substring(1);
237 * Creates a new Navigation Description for a math expression that be used by
238 * the background tts.
239 * @param {string} text to be translated.
240 * @return {cvox.NavDescription} Navigation description for the
244 cvox
.MathStore
.prototype.evaluate_ = function(text
) {
245 if (cvox
.ChromeVox
.host
['mathMap']) {
246 // VS: Change this for android!
247 return cvox
.ChromeVox
.host
['mathMap'].evaluate(
249 cvox
.TraverseMath
.getInstance().domain
,
250 cvox
.TraverseMath
.getInstance().style
);
252 return new cvox
.NavMathDescription(
254 'domain': cvox
.TraverseMath
.getInstance().domain
,
255 'style': cvox
.TraverseMath
.getInstance().style
261 * Removes all empty strings from an array of strings.
262 * @param {Array<string>} strs An array of strings.
263 * @return {Array<string>} The cleaned array.
266 cvox
.MathStore
.removeEmpty_ = function(strs
) {
267 return strs
.filter(function(str
) {return str
;});