base_rule_store.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.BaseRuleStore = void 0;
  4. const auditory_description_js_1 = require("../audio/auditory_description.js");
  5. const dynamic_cstr_js_1 = require("./dynamic_cstr.js");
  6. const speech_rule_js_1 = require("./speech_rule.js");
  7. const speech_rule_context_js_1 = require("./speech_rule_context.js");
  8. class BaseRuleStore {
  9. static compareStaticConstraints_(cstr1, cstr2) {
  10. if (cstr1.length !== cstr2.length) {
  11. return false;
  12. }
  13. for (let i = 0, cstr; (cstr = cstr1[i]); i++) {
  14. if (cstr2.indexOf(cstr) === -1) {
  15. return false;
  16. }
  17. }
  18. return true;
  19. }
  20. static comparePreconditions_(rule1, rule2) {
  21. const prec1 = rule1.precondition;
  22. const prec2 = rule2.precondition;
  23. if (prec1.query !== prec2.query) {
  24. return false;
  25. }
  26. return BaseRuleStore.compareStaticConstraints_(prec1.constraints, prec2.constraints);
  27. }
  28. constructor() {
  29. this.context = new speech_rule_context_js_1.SpeechRuleContext();
  30. this.parseOrder = dynamic_cstr_js_1.DynamicCstr.DEFAULT_ORDER;
  31. this.parser = new dynamic_cstr_js_1.DynamicCstrParser(this.parseOrder);
  32. this.locale = dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.LOCALE];
  33. this.modality = dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.MODALITY];
  34. this.domain = '';
  35. this.initialized = false;
  36. this.inherits = null;
  37. this.kind = 'standard';
  38. this.customTranscriptions = {};
  39. this.preconditions = new Map();
  40. this.speechRules_ = [];
  41. this.rank = 0;
  42. this.parseMethods = {
  43. Rule: this.defineRule,
  44. Generator: this.generateRules,
  45. Action: this.defineAction,
  46. Precondition: this.definePrecondition,
  47. Ignore: this.ignoreRules
  48. };
  49. }
  50. defineRule(name, dynamic, action, prec, ...args) {
  51. const postc = this.parseAction(action);
  52. const fullPrec = this.parsePrecondition(prec, args);
  53. const dynamicCstr = this.parseCstr(dynamic);
  54. if (!(postc && fullPrec && dynamicCstr)) {
  55. console.error(`Rule Error: ${prec}, (${dynamic}): ${action}`);
  56. return null;
  57. }
  58. const rule = new speech_rule_js_1.SpeechRule(name, dynamicCstr, fullPrec, postc);
  59. rule.precondition.rank = this.rank++;
  60. this.addRule(rule);
  61. return rule;
  62. }
  63. addRule(rule) {
  64. rule.context = this.context;
  65. this.speechRules_.unshift(rule);
  66. }
  67. deleteRule(rule) {
  68. const index = this.speechRules_.indexOf(rule);
  69. if (index !== -1) {
  70. this.speechRules_.splice(index, 1);
  71. }
  72. }
  73. findRule(pred) {
  74. for (let i = 0, rule; (rule = this.speechRules_[i]); i++) {
  75. if (pred(rule)) {
  76. return rule;
  77. }
  78. }
  79. return null;
  80. }
  81. findAllRules(pred) {
  82. return this.speechRules_.filter(pred);
  83. }
  84. evaluateDefault(node) {
  85. const rest = node.textContent.slice(0);
  86. if (rest.match(/^\s+$/)) {
  87. return this.evaluateWhitespace(rest);
  88. }
  89. return this.evaluateString(rest);
  90. }
  91. evaluateWhitespace(_str) {
  92. return [];
  93. }
  94. evaluateCustom(str) {
  95. const trans = this.customTranscriptions[str];
  96. return trans !== undefined
  97. ? auditory_description_js_1.AuditoryDescription.create({ text: trans }, { adjust: true, translate: false })
  98. : null;
  99. }
  100. evaluateCharacter(str) {
  101. return (this.evaluateCustom(str) ||
  102. auditory_description_js_1.AuditoryDescription.create({ text: str }, { adjust: true, translate: true }));
  103. }
  104. removeDuplicates(rule) {
  105. for (let i = this.speechRules_.length - 1, oldRule; (oldRule = this.speechRules_[i]); i--) {
  106. if (oldRule !== rule &&
  107. rule.dynamicCstr.equal(oldRule.dynamicCstr) &&
  108. BaseRuleStore.comparePreconditions_(oldRule, rule)) {
  109. this.speechRules_.splice(i, 1);
  110. }
  111. }
  112. }
  113. getSpeechRules() {
  114. return this.speechRules_;
  115. }
  116. setSpeechRules(rules) {
  117. this.speechRules_ = rules;
  118. }
  119. getPreconditions() {
  120. return this.preconditions;
  121. }
  122. parseCstr(cstr) {
  123. try {
  124. return this.parser.parse(this.locale +
  125. '.' +
  126. this.modality +
  127. (this.domain ? '.' + this.domain : '') +
  128. '.' +
  129. cstr);
  130. }
  131. catch (err) {
  132. if (err.name === 'RuleError') {
  133. console.error('Rule Error ', `Illegal Dynamic Constraint: ${cstr}.`, err.message);
  134. return null;
  135. }
  136. else {
  137. throw err;
  138. }
  139. }
  140. }
  141. parsePrecondition(query, rest) {
  142. try {
  143. const queryCstr = this.parsePrecondition_(query);
  144. query = queryCstr[0];
  145. let restCstr = queryCstr.slice(1);
  146. for (const cstr of rest) {
  147. restCstr = restCstr.concat(this.parsePrecondition_(cstr));
  148. }
  149. return new speech_rule_js_1.Precondition(query, ...restCstr);
  150. }
  151. catch (err) {
  152. if (err.name === 'RuleError') {
  153. console.error('Rule Error ', `Illegal preconditions: ${query}, ${rest}.`, err.message);
  154. return null;
  155. }
  156. else {
  157. throw err;
  158. }
  159. }
  160. }
  161. parseAction(action) {
  162. try {
  163. return speech_rule_js_1.Action.fromString(action);
  164. }
  165. catch (err) {
  166. if (err.name === 'RuleError') {
  167. console.error('Rule Error ', `Illegal action: ${action}.`, err.message);
  168. return null;
  169. }
  170. else {
  171. throw err;
  172. }
  173. }
  174. }
  175. parse(ruleSet) {
  176. this.modality = ruleSet.modality || this.modality;
  177. this.locale = ruleSet.locale || this.locale;
  178. this.domain = ruleSet.domain || this.domain;
  179. this.context.parse(ruleSet.functions || []);
  180. if (ruleSet.kind !== 'actions') {
  181. this.kind = ruleSet.kind || this.kind;
  182. this.inheritRules();
  183. }
  184. this.parseRules(ruleSet.rules || []);
  185. }
  186. parseRules(rules) {
  187. for (let i = 0, rule; (rule = rules[i]); i++) {
  188. const type = rule[0];
  189. const method = this.parseMethods[type];
  190. if (type && method) {
  191. method.apply(this, rule.slice(1));
  192. }
  193. }
  194. }
  195. generateRules(generator) {
  196. const method = this.context.customGenerators.lookup(generator);
  197. if (method) {
  198. method(this);
  199. }
  200. }
  201. defineAction(name, action) {
  202. let postc;
  203. try {
  204. postc = speech_rule_js_1.Action.fromString(action);
  205. }
  206. catch (err) {
  207. if (err.name === 'RuleError') {
  208. console.error('Action Error ', action, err.message);
  209. return;
  210. }
  211. else {
  212. throw err;
  213. }
  214. }
  215. const prec = this.getFullPreconditions(name);
  216. if (!prec) {
  217. console.error(`Action Error: No precondition for action ${name}`);
  218. return;
  219. }
  220. this.ignoreRules(name);
  221. const regexp = new RegExp('^\\w+\\.\\w+\\.' + (this.domain ? '\\w+\\.' : ''));
  222. prec.conditions.forEach(([dynamic, prec]) => {
  223. const newDynamic = this.parseCstr(dynamic.toString().replace(regexp, ''));
  224. this.addRule(new speech_rule_js_1.SpeechRule(name, newDynamic, prec, postc));
  225. });
  226. }
  227. getFullPreconditions(name) {
  228. const prec = this.preconditions.get(name);
  229. if (prec || !this.inherits) {
  230. return prec;
  231. }
  232. return this.inherits.getFullPreconditions(name);
  233. }
  234. definePrecondition(name, dynamic, prec, ...args) {
  235. const fullPrec = this.parsePrecondition(prec, args);
  236. const dynamicCstr = this.parseCstr(dynamic);
  237. if (!(fullPrec && dynamicCstr)) {
  238. console.error(`Precondition Error: ${prec}, (${dynamic})`);
  239. return;
  240. }
  241. fullPrec.rank = this.rank++;
  242. this.preconditions.set(name, new Condition(dynamicCstr, fullPrec));
  243. }
  244. inheritRules() {
  245. if (!this.inherits || !this.inherits.getSpeechRules().length) {
  246. return;
  247. }
  248. const regexp = new RegExp('^\\w+\\.\\w+\\.' + (this.domain ? '\\w+\\.' : ''));
  249. this.inherits.getSpeechRules().forEach((rule) => {
  250. const newDynamic = this.parseCstr(rule.dynamicCstr.toString().replace(regexp, ''));
  251. this.addRule(new speech_rule_js_1.SpeechRule(rule.name, newDynamic, rule.precondition, rule.action));
  252. });
  253. }
  254. ignoreRules(name, ...cstrs) {
  255. let rules = this.findAllRules((r) => r.name === name);
  256. if (!cstrs.length) {
  257. rules.forEach(this.deleteRule.bind(this));
  258. return;
  259. }
  260. let rest = [];
  261. for (const cstr of cstrs) {
  262. const dynamic = this.parseCstr(cstr);
  263. for (const rule of rules) {
  264. if (dynamic.equal(rule.dynamicCstr)) {
  265. this.deleteRule(rule);
  266. }
  267. else {
  268. rest.push(rule);
  269. }
  270. }
  271. rules = rest;
  272. rest = [];
  273. }
  274. }
  275. parsePrecondition_(cstr) {
  276. const generator = this.context.customGenerators.lookup(cstr);
  277. return generator ? generator() : [cstr];
  278. }
  279. }
  280. exports.BaseRuleStore = BaseRuleStore;
  281. class Condition {
  282. constructor(base, condition) {
  283. this.base = base;
  284. this._conditions = [];
  285. this.constraints = [];
  286. this.allCstr = {};
  287. this.constraints.push(base);
  288. this.addCondition(base, condition);
  289. }
  290. get conditions() {
  291. return this._conditions;
  292. }
  293. addConstraint(dynamic) {
  294. if (this.constraints.filter((cstr) => cstr.equal(dynamic)).length) {
  295. return;
  296. }
  297. this.constraints.push(dynamic);
  298. const newConds = [];
  299. for (const [dyn, pre] of this.conditions) {
  300. if (this.base.equal(dyn)) {
  301. newConds.push([dynamic, pre]);
  302. }
  303. }
  304. this._conditions = this._conditions.concat(newConds);
  305. }
  306. addBaseCondition(cond) {
  307. this.addCondition(this.base, cond);
  308. }
  309. addFullCondition(cond) {
  310. this.constraints.forEach((cstr) => this.addCondition(cstr, cond));
  311. }
  312. addCondition(dynamic, cond) {
  313. const condStr = dynamic.toString() + ' ' + cond.toString();
  314. if (this.allCstr.condStr) {
  315. return;
  316. }
  317. this.allCstr[condStr] = true;
  318. this._conditions.push([dynamic, cond]);
  319. }
  320. }