clearspeak_preferences.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.ClearspeakPreferences = void 0;
  4. const engine_js_1 = require("../common/engine.js");
  5. const EngineConst = require("../common/engine_const.js");
  6. const dynamic_cstr_js_1 = require("../rule_engine/dynamic_cstr.js");
  7. const dynamic_cstr_js_2 = require("../rule_engine/dynamic_cstr.js");
  8. const MathCompoundStore = require("../rule_engine/math_compound_store.js");
  9. const speech_rule_engine_js_1 = require("../rule_engine/speech_rule_engine.js");
  10. const semantic_meaning_js_1 = require("../semantic_tree/semantic_meaning.js");
  11. class ClearspeakPreferences extends dynamic_cstr_js_1.DynamicCstr {
  12. static comparator() {
  13. return new Comparator(engine_js_1.Engine.getInstance().dynamicCstr, dynamic_cstr_js_2.DynamicProperties.createProp([dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_2.Axis.LOCALE]], [dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_2.Axis.MODALITY]], [dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_2.Axis.DOMAIN]], [dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_2.Axis.STYLE]]));
  14. }
  15. static fromPreference(pref) {
  16. const pairs = pref.split(':');
  17. const preferences = {};
  18. const properties = PREFERENCES.getProperties();
  19. const validKeys = Object.keys(properties);
  20. for (let i = 0, key; (key = pairs[i]); i++) {
  21. const pair = key.split('_');
  22. if (validKeys.indexOf(pair[0]) === -1) {
  23. continue;
  24. }
  25. const value = pair[1];
  26. if (value &&
  27. value !== ClearspeakPreferences.AUTO &&
  28. properties[pair[0]].indexOf(value) !== -1) {
  29. preferences[pair[0]] = pair[1];
  30. }
  31. }
  32. return preferences;
  33. }
  34. static toPreference(pref) {
  35. const keys = Object.keys(pref);
  36. const str = [];
  37. for (let i = 0; i < keys.length; i++) {
  38. str.push(keys[i] + '_' + pref[keys[i]]);
  39. }
  40. return str.length ? str.join(':') : dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUE;
  41. }
  42. static getLocalePreferences(opt_dynamic) {
  43. const dynamic = opt_dynamic ||
  44. MathCompoundStore.enumerate(speech_rule_engine_js_1.SpeechRuleEngine.getInstance().enumerate());
  45. return ClearspeakPreferences.getLocalePreferences_(dynamic);
  46. }
  47. static currentPreference() {
  48. return EngineConst.DOMAIN_TO_STYLES['clearspeak'];
  49. }
  50. static relevantPreferences(node) {
  51. const roles = SEMANTIC_MAPPING_[node.type];
  52. if (!roles) {
  53. return 'ImpliedTimes';
  54. }
  55. return roles[node.role] || roles[''] || 'ImpliedTimes';
  56. }
  57. static findPreference(prefs, kind) {
  58. if (prefs === 'default') {
  59. return ClearspeakPreferences.AUTO;
  60. }
  61. const parsed = ClearspeakPreferences.fromPreference(prefs);
  62. return parsed[kind] || ClearspeakPreferences.AUTO;
  63. }
  64. static addPreference(prefs, kind, value) {
  65. if (prefs === 'default') {
  66. return kind + '_' + value;
  67. }
  68. const parsed = ClearspeakPreferences.fromPreference(prefs);
  69. parsed[kind] = value;
  70. return ClearspeakPreferences.toPreference(parsed);
  71. }
  72. static getLocalePreferences_(dynamic) {
  73. const result = {};
  74. for (const locale of Object.keys(dynamic)) {
  75. if (!dynamic[locale]['speech'] ||
  76. !dynamic[locale]['speech']['clearspeak']) {
  77. continue;
  78. }
  79. const locPrefs = Object.keys(dynamic[locale]['speech']['clearspeak']);
  80. if (locPrefs.length < 3)
  81. continue;
  82. const prefs = (result[locale] = {});
  83. for (const axis in PREFERENCES.getProperties()) {
  84. const allSty = PREFERENCES.getProperties()[axis];
  85. const values = [axis + '_Auto'];
  86. if (allSty) {
  87. for (const sty of allSty) {
  88. if (locPrefs.indexOf(axis + '_' + sty) !== -1) {
  89. values.push(axis + '_' + sty);
  90. }
  91. }
  92. }
  93. prefs[axis] = values;
  94. }
  95. }
  96. return result;
  97. }
  98. constructor(cstr, preference) {
  99. super(cstr);
  100. this.preference = preference;
  101. }
  102. equal(cstr) {
  103. const top = super.equal(cstr);
  104. if (!top) {
  105. return false;
  106. }
  107. const keys = Object.keys(this.preference);
  108. const preference = cstr.preference;
  109. if (keys.length !== Object.keys(preference).length) {
  110. return false;
  111. }
  112. for (let i = 0, key; (key = keys[i]); i++) {
  113. if (this.preference[key] !== preference[key]) {
  114. return false;
  115. }
  116. }
  117. return true;
  118. }
  119. }
  120. exports.ClearspeakPreferences = ClearspeakPreferences;
  121. ClearspeakPreferences.AUTO = 'Auto';
  122. const PREFERENCES = new dynamic_cstr_js_2.DynamicProperties({
  123. AbsoluteValue: ['Auto', 'AbsEnd', 'Cardinality', 'Determinant'],
  124. Bar: ['Auto', 'Conjugate'],
  125. Caps: ['Auto', 'SayCaps'],
  126. CombinationPermutation: ['Auto', 'ChoosePermute'],
  127. Currency: ['Auto', 'Position', 'Prefix'],
  128. Ellipses: ['Auto', 'AndSoOn'],
  129. Enclosed: ['Auto', 'EndEnclose'],
  130. Exponent: [
  131. 'Auto',
  132. 'AfterPower',
  133. 'Ordinal',
  134. 'OrdinalPower',
  135. 'Exponent'
  136. ],
  137. Fraction: [
  138. 'Auto',
  139. 'EndFrac',
  140. 'FracOver',
  141. 'General',
  142. 'GeneralEndFrac',
  143. 'Ordinal',
  144. 'Over',
  145. 'OverEndFrac',
  146. 'Per'
  147. ],
  148. Functions: [
  149. 'Auto',
  150. 'None',
  151. 'Reciprocal'
  152. ],
  153. ImpliedTimes: ['Auto', 'MoreImpliedTimes', 'None'],
  154. Log: ['Auto', 'LnAsNaturalLog'],
  155. Matrix: [
  156. 'Auto',
  157. 'Combinatoric',
  158. 'EndMatrix',
  159. 'EndVector',
  160. 'SilentColNum',
  161. 'SpeakColNum',
  162. 'Vector'
  163. ],
  164. MultiLineLabel: [
  165. 'Auto',
  166. 'Case',
  167. 'Constraint',
  168. 'Equation',
  169. 'Line',
  170. 'None',
  171. 'Row',
  172. 'Step'
  173. ],
  174. MultiLineOverview: ['Auto', 'None'],
  175. MultiLinePausesBetweenColumns: ['Auto', 'Long', 'Short'],
  176. MultsymbolDot: ['Auto', 'Dot'],
  177. MultsymbolX: ['Auto', 'By', 'Cross'],
  178. Paren: [
  179. 'Auto',
  180. 'CoordPoint',
  181. 'Interval',
  182. 'Silent',
  183. 'Speak',
  184. 'SpeakNestingLevel'
  185. ],
  186. Prime: ['Auto', 'Angle', 'Length'],
  187. Roots: ['Auto', 'PosNegSqRoot', 'PosNegSqRootEnd', 'RootEnd'],
  188. SetMemberSymbol: ['Auto', 'Belongs', 'Element', 'Member', 'In'],
  189. Sets: ['Auto', 'SilentBracket', 'woAll'],
  190. TriangleSymbol: ['Auto', 'Delta'],
  191. Trig: [
  192. 'Auto',
  193. 'ArcTrig',
  194. 'TrigInverse',
  195. 'Reciprocal'
  196. ],
  197. VerticalLine: ['Auto', 'Divides', 'Given', 'SuchThat']
  198. });
  199. class Comparator extends dynamic_cstr_js_2.DefaultComparator {
  200. constructor(cstr, props) {
  201. super(cstr, props);
  202. this.preference =
  203. cstr instanceof ClearspeakPreferences ? cstr.preference : {};
  204. }
  205. match(cstr) {
  206. if (!(cstr instanceof ClearspeakPreferences)) {
  207. return super.match(cstr);
  208. }
  209. if (cstr.getComponents()[dynamic_cstr_js_2.Axis.STYLE] === 'default') {
  210. return true;
  211. }
  212. const keys = Object.keys(cstr.preference);
  213. for (let i = 0, key; (key = keys[i]); i++) {
  214. if (this.preference[key] !== cstr.preference[key]) {
  215. return false;
  216. }
  217. }
  218. return true;
  219. }
  220. compare(cstr1, cstr2) {
  221. const top = super.compare(cstr1, cstr2);
  222. if (top !== 0) {
  223. return top;
  224. }
  225. const pref1 = cstr1 instanceof ClearspeakPreferences;
  226. const pref2 = cstr2 instanceof ClearspeakPreferences;
  227. if (!pref1 && pref2) {
  228. return 1;
  229. }
  230. if (pref1 && !pref2) {
  231. return -1;
  232. }
  233. if (!pref1 && !pref2) {
  234. return 0;
  235. }
  236. const length1 = Object.keys(cstr1.preference).length;
  237. const length2 = Object.keys(cstr2.preference).length;
  238. return length1 > length2 ? -1 : length1 < length2 ? 1 : 0;
  239. }
  240. }
  241. class Parser extends dynamic_cstr_js_2.DynamicCstrParser {
  242. constructor() {
  243. super([dynamic_cstr_js_2.Axis.LOCALE, dynamic_cstr_js_2.Axis.MODALITY, dynamic_cstr_js_2.Axis.DOMAIN, dynamic_cstr_js_2.Axis.STYLE]);
  244. }
  245. parse(str) {
  246. const initial = super.parse(str);
  247. let style = initial.getValue(dynamic_cstr_js_2.Axis.STYLE);
  248. const locale = initial.getValue(dynamic_cstr_js_2.Axis.LOCALE);
  249. const modality = initial.getValue(dynamic_cstr_js_2.Axis.MODALITY);
  250. let pref = {};
  251. if (style !== dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUE) {
  252. pref = this.fromPreference(style);
  253. style = this.toPreference(pref);
  254. }
  255. return new ClearspeakPreferences({
  256. locale: locale,
  257. modality: modality,
  258. domain: 'clearspeak',
  259. style: style
  260. }, pref);
  261. }
  262. fromPreference(pref) {
  263. return ClearspeakPreferences.fromPreference(pref);
  264. }
  265. toPreference(pref) {
  266. return ClearspeakPreferences.toPreference(pref);
  267. }
  268. }
  269. const REVERSE_MAPPING = [
  270. [
  271. 'AbsoluteValue',
  272. semantic_meaning_js_1.SemanticType.FENCED,
  273. semantic_meaning_js_1.SemanticRole.NEUTRAL,
  274. semantic_meaning_js_1.SemanticRole.METRIC
  275. ],
  276. ['Bar', semantic_meaning_js_1.SemanticType.OVERSCORE, semantic_meaning_js_1.SemanticRole.OVERACCENT],
  277. ['Caps', semantic_meaning_js_1.SemanticType.IDENTIFIER, semantic_meaning_js_1.SemanticRole.LATINLETTER],
  278. ['CombinationPermutation', semantic_meaning_js_1.SemanticType.APPL, semantic_meaning_js_1.SemanticRole.UNKNOWN],
  279. ['Ellipses', semantic_meaning_js_1.SemanticType.PUNCTUATION, semantic_meaning_js_1.SemanticRole.ELLIPSIS],
  280. ['Exponent', semantic_meaning_js_1.SemanticType.SUPERSCRIPT, ''],
  281. ['Fraction', semantic_meaning_js_1.SemanticType.FRACTION, ''],
  282. ['Functions', semantic_meaning_js_1.SemanticType.APPL, semantic_meaning_js_1.SemanticRole.SIMPLEFUNC],
  283. ['ImpliedTimes', semantic_meaning_js_1.SemanticType.OPERATOR, semantic_meaning_js_1.SemanticRole.IMPLICIT],
  284. ['Log', semantic_meaning_js_1.SemanticType.APPL, semantic_meaning_js_1.SemanticRole.PREFIXFUNC],
  285. ['Matrix', semantic_meaning_js_1.SemanticType.MATRIX, ''],
  286. ['Matrix', semantic_meaning_js_1.SemanticType.VECTOR, ''],
  287. ['MultiLineLabel', semantic_meaning_js_1.SemanticType.MULTILINE, semantic_meaning_js_1.SemanticRole.LABEL],
  288. ['MultiLineOverview', semantic_meaning_js_1.SemanticType.MULTILINE, semantic_meaning_js_1.SemanticRole.TABLE],
  289. ['MultiLinePausesBetweenColumns', semantic_meaning_js_1.SemanticType.MULTILINE, semantic_meaning_js_1.SemanticRole.TABLE],
  290. ['MultiLineLabel', semantic_meaning_js_1.SemanticType.TABLE, semantic_meaning_js_1.SemanticRole.LABEL],
  291. ['MultiLineOverview', semantic_meaning_js_1.SemanticType.TABLE, semantic_meaning_js_1.SemanticRole.TABLE],
  292. ['MultiLinePausesBetweenColumns', semantic_meaning_js_1.SemanticType.TABLE, semantic_meaning_js_1.SemanticRole.TABLE],
  293. ['MultiLineLabel', semantic_meaning_js_1.SemanticType.CASES, semantic_meaning_js_1.SemanticRole.LABEL],
  294. ['MultiLineOverview', semantic_meaning_js_1.SemanticType.CASES, semantic_meaning_js_1.SemanticRole.TABLE],
  295. ['MultiLinePausesBetweenColumns', semantic_meaning_js_1.SemanticType.CASES, semantic_meaning_js_1.SemanticRole.TABLE],
  296. ['MultsymbolDot', semantic_meaning_js_1.SemanticType.OPERATOR, semantic_meaning_js_1.SemanticRole.MULTIPLICATION],
  297. ['MultsymbolX', semantic_meaning_js_1.SemanticType.OPERATOR, semantic_meaning_js_1.SemanticRole.MULTIPLICATION],
  298. ['Paren', semantic_meaning_js_1.SemanticType.FENCED, semantic_meaning_js_1.SemanticRole.LEFTRIGHT],
  299. ['Prime', semantic_meaning_js_1.SemanticType.SUPERSCRIPT, semantic_meaning_js_1.SemanticRole.PRIME],
  300. ['Roots', semantic_meaning_js_1.SemanticType.ROOT, ''],
  301. ['Roots', semantic_meaning_js_1.SemanticType.SQRT, ''],
  302. ['SetMemberSymbol', semantic_meaning_js_1.SemanticType.RELATION, semantic_meaning_js_1.SemanticRole.ELEMENT],
  303. ['Sets', semantic_meaning_js_1.SemanticType.FENCED, semantic_meaning_js_1.SemanticRole.SETEXT],
  304. ['TriangleSymbol', semantic_meaning_js_1.SemanticType.IDENTIFIER, semantic_meaning_js_1.SemanticRole.GREEKLETTER],
  305. ['Trig', semantic_meaning_js_1.SemanticType.APPL, semantic_meaning_js_1.SemanticRole.PREFIXFUNC],
  306. ['VerticalLine', semantic_meaning_js_1.SemanticType.PUNCTUATED, semantic_meaning_js_1.SemanticRole.VBAR]
  307. ];
  308. const SEMANTIC_MAPPING_ = (function () {
  309. const result = {};
  310. for (let i = 0, triple; (triple = REVERSE_MAPPING[i]); i++) {
  311. const pref = triple[0];
  312. let role = result[triple[1]];
  313. if (!role) {
  314. role = {};
  315. result[triple[1]] = role;
  316. }
  317. role[triple[2]] = pref;
  318. }
  319. return result;
  320. })();
  321. engine_js_1.Engine.getInstance().comparators['clearspeak'] =
  322. ClearspeakPreferences.comparator;
  323. engine_js_1.Engine.getInstance().parsers['clearspeak'] = new Parser();