1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file. 4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @fileoverview An interface definition of a speech rule. 7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * A speech rule is a data structure along with supporting methods that 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * stipulates how to transform a tree structure such as XML, a browser DOM, or 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * HTML into a format (usually strings) suitable for rendering by a 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * text-to-speech engine. 12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Speech rules consists of a variable number of speech rule components. Each 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * component describes how to construct a single utterance. Text-to-speech 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * renders the components in order. 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.SpeechRule'); 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.SpeechRule.Action'); 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.SpeechRule.Component'); 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.SpeechRule.DynamicCstr'); 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.SpeechRule.Precondition'); 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.SpeechRule.Type'); 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Creates a speech rule with precondition, actions and admin information. 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} name The name of the rule. 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {cvox.SpeechRule.DynamicCstr} dynamic Dynamic constraint annotations 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * of the rule. 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {cvox.SpeechRule.Precondition} prec Precondition of the rule. 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {cvox.SpeechRule.Action} action Action of the speech rule. 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule = function(name, dynamic, prec, action) { 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {string} */ 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.name = name; 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {cvox.SpeechRule.DynamicCstr} */ 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.dynamicCstr = dynamic; 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {cvox.SpeechRule.Precondition} */ 41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.precondition = prec; 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {cvox.SpeechRule.Action} */ 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.action = action; 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @override 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.prototype.toString = function() { 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var cstrStrings = []; 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (var key in this.dynamicCstr) { 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) cstrStrings.push(this.dynamicCstr[key]); 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return this.name + ' | ' + cstrStrings.join('.') + ' | ' + 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.precondition.toString() + ' ==> ' + 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.action.toString(); 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Mapping for types of speech rule components. 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @enum {string} 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Type = { 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NODE: 'NODE', 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MULTI: 'MULTI', 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) TEXT: 'TEXT', 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PERSONALITY: 'PERSONALITY' 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Maps a string to a valid speech rule type. 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} str Input string. 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {cvox.SpeechRule.Type} 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Type.fromString = function(str) { 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (str) { 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case '[n]': return cvox.SpeechRule.Type.NODE; 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case '[m]': return cvox.SpeechRule.Type.MULTI; 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case '[t]': return cvox.SpeechRule.Type.TEXT; 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case '[p]': return cvox.SpeechRule.Type.PERSONALITY; 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: throw 'Parse error: ' + str; 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Maps a speech rule type to a human-readable string. 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {cvox.SpeechRule.Type} speechType 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {string} Output string. 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Type.toString = function(speechType) { 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (speechType) { 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.NODE: return '[n]'; 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.MULTI: return '[m]'; 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.TEXT: return '[t]'; 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.PERSONALITY: return '[p]'; 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: throw 'Unknown type error: ' + speechType; 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Defines a component within a speech rule. 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {{type: cvox.SpeechRule.Type, content: string}} kwargs The input 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * component in JSON format. 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Component = function(kwargs) { 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {cvox.SpeechRule.Type} */ 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.type = kwargs.type; 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {string} */ 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.content = kwargs.content; 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Parses a valid string representation of a speech component into a Component 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * object. 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} input The input string. 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {cvox.SpeechRule.Component} The resulting component. 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Component.fromString = function(input) { 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The output JSON. 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var output = {}; 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Parse the type. 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output.type = cvox.SpeechRule.Type.fromString(input.substring(0, 3)); 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Prep the rest of the parsing. 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var rest = input.slice(3).trimLeft(); 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!rest) { 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) throw new cvox.SpeechRule.OutputError('Missing content.'); 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (output.type) { 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.TEXT: 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rest[0] == '"') { 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var quotedString = cvox.SpeechRule.splitString_(rest, '\\(')[0].trim(); 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (quotedString.slice(-1) != '"') { 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) throw new cvox.SpeechRule.OutputError('Invalid string syntax.'); 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output.content = quotedString; 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rest = rest.slice(quotedString.length).trim(); 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rest.indexOf('(') == -1) { 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rest = ''; 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This break is conditional. If the content is not an explicit string, 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // it can be treated like node and multi type. 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.NODE: 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case cvox.SpeechRule.Type.MULTI: 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var bracket = rest.indexOf(' ('); 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (bracket == -1) { 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output.content = rest.trim(); 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rest = ''; 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output.content = rest.substring(0, bracket).trim(); 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rest = rest.slice(bracket).trimLeft(); 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output = new cvox.SpeechRule.Component(output); 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rest) { 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output.addAttributes(rest); 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return output; 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @override 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Component.prototype.toString = function() { 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var strs = ''; 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strs += cvox.SpeechRule.Type.toString(this.type); 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strs += this.content ? ' ' + this.content : ''; 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var attribs = this.getAttributes(); 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (attribs.length > 0) { 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strs += ' (' + attribs.join(', ') + ')'; 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return strs; 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Adds a single attribute to the component. 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} attr String representation of an attribute. 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Component.prototype.addAttribute = function(attr) { 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var colon = attr.indexOf(':'); 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (colon == -1) { 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this[attr.trim()] = 'true'; 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this[attr.substring(0, colon).trim()] = attr.slice(colon + 1).trim(); 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Adds a list of attributes to the component. 207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} attrs String representation of attribute list. 208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Component.prototype.addAttributes = function(attrs) { 210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (attrs[0] != '(' || attrs.slice(-1) != ')') { 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) throw new cvox.SpeechRule.OutputError( 212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'Invalid attribute expression: ' + attrs); 213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var attribs = cvox.SpeechRule.splitString_(attrs.slice(1, -1), ','); 215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (var i = 0; i < attribs.length; i++) { 216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.addAttribute(attribs[i]); 217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Transforms the attributes of an object into a list of strings. 223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {Array.<string>} List of translated attribute:value strings. 224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Component.prototype.getAttributes = function() { 226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var attribs = []; 227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (var key in this) { 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (key != 'content' && key != 'type' && typeof(this[key]) != 'function') { 229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) attribs.push(key + ':' + this[key]); 230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return attribs; 233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * A speech rule is a collection of speech components. 238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Array.<cvox.SpeechRule.Component>} components The input rule. 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor 240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Action = function(components) { 242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {Array.<cvox.SpeechRule.Component>} */ 243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.components = components; 244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Parses an input string into a speech rule class object. 249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} input The input string. 250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {cvox.SpeechRule.Action} The resulting object. 251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Action.fromString = function(input) { 253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var comps = cvox.SpeechRule.splitString_(input, ';') 254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) .filter(function(x) {return x.match(/\S/);}) 255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) .map(function(x) {return x.trim();}); 256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var newComps = []; 257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (var i = 0; i < comps.length; i++) { 258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var comp = cvox.SpeechRule.Component.fromString(comps[i]); 259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (comp) { 260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) newComps.push(comp); 261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)return new cvox.SpeechRule.Action(newComps); 264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @override 269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Action.prototype.toString = function() { 271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var comps = this.components.map(function(c) { return c.toString(); }); 272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return comps.join('; '); 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// TODO (sorge) Separatation of xpath expressions and custom functions. 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Also test validity of xpath expressions. 278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Constructs a valid precondition for a speech rule. 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} query A node selector function or xpath expression. 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Array.<string>=} opt_constraints A list of constraint functions. 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Precondition = function(query, opt_constraints) { 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {string} */ 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.query = query; 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** @type {!Array.<string>} */ 289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.constraints = opt_constraints || []; 290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @override 295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.Precondition.prototype.toString = function() { 297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var constrs = this.constraints.join(', '); 298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return this.query + ', ' + constrs; 299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Split a string wrt. a given separator symbol while not splitting inside of a 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * double quoted string. For example, splitting 305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * '[t] "matrix; 3 by 3"; [n] ./*[1]' with separators ';' would yield 306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * ['[t] "matrix; 3 by 3"', ' [n] ./*[1]']. 307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} str String to be split. 308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} sep Separator symbol. 309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {Array.<string>} A list of single component strings. 310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private 311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.splitString_ = function(str, sep) { 313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var strList = []; 314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var prefix = ''; 315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) while (str != '') { 317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var sepPos = str.search(sep); 318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (sepPos == -1) { 319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if ((str.match(/"/g) || []).length % 2 != 0) { 320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) throw new cvox.SpeechRule.OutputError( 321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'Invalid string in expression: ' + str); 322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strList.push(prefix + str); 324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) prefix = ''; 325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) str = ''; 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if ( 327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (str.substring(0, sepPos).match(/"/g) || []).length % 2 == 0) { 328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strList.push(prefix + str.substring(0, sepPos)); 329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) prefix = ''; 330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) str = str.substring(sepPos + 1); 331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var nextQuot = str.substring(sepPos).search('"'); 333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (nextQuot == -1) { 334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) throw new cvox.SpeechRule.OutputError( 335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'Invalid string in expression: ' + str); 336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) prefix = prefix + str.substring(0, sepPos + nextQuot + 1); 338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) str = str.substring(sepPos + nextQuot + 1); 339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (prefix) { 343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strList.push(prefix); 344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return strList; 346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Attributes for dynamic constraints. 351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * We define one default attribute as style. Speech rule stores can add other 352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * attributes later. 353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @enum {string} 354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.DynamicCstrAttrib = 356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles){ 357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) STYLE: 'style' 358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Dynamic constraints are a means to specialize rules that can be changed 363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * dynamically by the user, for example by choosing different styles, etc. 364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @typedef {!Object.<cvox.SpeechRule.DynamicCstrAttrib, string>} 365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.DynamicCstr; 367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Error object for signaling parsing errors. 371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} msg The error message. 372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor 373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @extends {Error} 374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.SpeechRule.OutputError = function(msg) { 376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.name = 'RuleError'; 377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.message = msg || ''; 378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.inherits(cvox.SpeechRule.OutputError, Error); 380