Discriminated unions for rule objects + other PR concerns.

This commit is contained in:
Joshua A. Horton 2018-02-23 10:15:39 +07:00
parent a636b5f259
commit 2d389a8053
3 changed files with 113 additions and 80 deletions

View file

@ -22,24 +22,32 @@ type KeyboardStore = PlainKeyboardStore; // | ComplexKeyboardStore;
type RuleChar = string;
class RuleDeadkey {
/** Discriminant field - 'd' for Deadkey.
*/
['t']: 'd';
/**
* Existence of this property indicates the object is a deadkey.
*
* Value: the deadkey's ID.
*/
['d']: number; // For 'd'eadkey; also reflects the Deadkey class's 'd' property.
}
class ContextAny {
/** Discriminant field - 'a' for `any()`.
*/
['t']: 'a';
/**
* Existence of this property indicates the object reflects an "any" statement.
*
* Value: the store to search.
*/
['a']: KeyboardStore; // For 'a'ny statement.
}
class RuleIndex {
/** Discriminant field - 'i' for `index()`.
*/
['t']: 'i';
/**
* Existence of this property indicates the object reflects an "index" statement.
*
@ -49,6 +57,10 @@ class RuleIndex {
}
class ContextEx {
/** Discriminant field - 'c' for `context()`.
*/
['t']: 'c';
/**
* Existence of this property indicates that the object reflects a "context" Keyman language statement.
*
@ -57,7 +69,8 @@ class ContextEx {
['c']: number; // For 'c'ontext statement.
}
type ContextEntry = RuleChar | RuleDeadkey | ContextAny | RuleIndex | ContextEx;
type ContextNonCharEntry = RuleDeadkey | ContextAny | RuleIndex | ContextEx;
type ContextEntry = RuleChar | ContextNonCharEntry;
/**
* Cache of context storing and retrieving return values from KC
@ -414,40 +427,56 @@ class KeyboardInterface {
var mismatch = false;
var assertNever = function(x: never): never {
// Could be accessed by improperly handwritten calls to `fullContextMatch`.
throw new Error("Unexpected object in fullContextMatch specification: " + x);
}
// Stage two: time to match against the rule specified.
for(var i=0; i < rule.length; i++) {
if(typeof(rule[i]) == 'string') {
if(typeof rule[i] == 'string') {
var str = rule[i] as string;
if(str != context[i]) {
mismatch = true;
break;
}
} else if(rule[i]['d'] !== undefined) {
var deadSpec = rule[i] as RuleDeadkey;
// We still need to set a flag here;
if(deadSpec['d'] != context[i]) {
mismatch = true;
} else {
deadContext[i].set();
}
} else if(rule[i]['a'] !== undefined) {
var anySpec = rule[i] as ContextAny;
// TODO: Remove the `string` requirement.
if(!this.any(i, context[i] as string, anySpec.a)) {
mismatch = true;
}
} else if(rule[i]['i'] !== undefined) {
var indexSpec = rule[i] as RuleIndex;
var ch = this._Index(indexSpec.i.s, indexSpec.i.o);
} else {
// TypeScript needs a cast to this intermediate type to do its discriminated union magic.
var r = rule[i] as ContextNonCharEntry;
switch(r.t) {
case 'd':
var deadSpec = r as RuleDeadkey;
// We still need to set a flag here;
if(deadSpec['d'] != context[i]) {
mismatch = true;
} else {
deadContext[i].set();
}
break;
case 'a':
var anySpec = r as ContextAny;
// TODO: Remove the `string` requirement.
if(!this.any(i, context[i] as string, anySpec.a)) {
mismatch = true;
}
break;
case 'i':
var indexSpec = r as RuleIndex;
var ch = this._Index(indexSpec.i.s, indexSpec.i.o);
if(ch != context[i]) {
mismatch = true;
}
} else if(rule[i]['c'] !== undefined) {
var contextSpec = rule[i] as ContextEx;
if(context[contextSpec.c - 1] != context[i]) {
mismatch = true;
if(ch != context[i]) {
mismatch = true;
}
break;
case 'c':
var contextSpec = r as ContextEx;
if(context[contextSpec.c - 1] != context[i]) {
mismatch = true;
}
break;
default:
assertNever(r);
}
}
}
@ -820,9 +849,10 @@ class KeyboardInterface {
if(this._AnyIndices[Pn] < Ps._kmwLength()) { //I3319
return Ps._kmwCharAt(this._AnyIndices[Pn]);
} else {
/* Should this really be possible for a compiled keyboard?
* Should we throw an error / output a console.error("")?
/* Should not be possible for a compiled keyboard, but may arise
* during the development of handwritten keyboards.
*/
console.warn("Unmatched contextual index() statement detected in rule with index " + Pn + "!");
return "";
}
}
@ -841,6 +871,11 @@ class KeyboardInterface {
var indexChar = this._Index(Ps, Pn-1);
if(indexChar) {
this.output(Pdn,Pelem,indexChar); //I3319
} else {
/* Should not be possible for a compiled keyboard, but may arise
* during the development of handwritten keyboards.
*/
console.warn("Unmatched output index() statement detected in rule with index " + Pn + "!");
}
}
@ -1034,9 +1069,8 @@ class KeyboardInterface {
* Description Clear all matched deadkey flags
*/
_DeadkeyResetMatched(): void {
var _Dk = this._DeadKeys;
for(var Li = 0; Li < _Dk.length; Li++) {
_Dk[Li].reset();
for(let dk of this._DeadKeys) {
dk.reset();
}
}
@ -1062,10 +1096,9 @@ class KeyboardInterface {
* Description Adjust saved positions of deadkeys in context
*/
_DeadkeyAdjustPos(Lstart: number, Ldelta: number): void {
var _Dk = this._DeadKeys;
for(var Li = 0; Li < _Dk.length; Li++) {
if(_Dk[Li].p > Lstart) {
_Dk[Li].p += Ldelta;
for(let dk of this._DeadKeys) {
if(dk.p > Lstart) {
dk.p += Ldelta;
}
}
}

View file

@ -44,7 +44,7 @@ function runEngineRuleSet(ruleSet, defaultNoun) {
var DEADKEY_TEST_1 = {
id: 1,
// Match condition for rule
rule: [{d: 1}],
rule: [{t:'d', d: 1}],
// Start of context relative to cursor
n: 1,
ln: 1,
@ -82,7 +82,7 @@ var DEADKEY_TEST_1 = {
var DEADKEY_TEST_2 = {
id: 2,
// Match condition for rule
rule: ['a', {d: 0}, {d: 1}, 'b'],
rule: ['a', {t:'d', d: 0}, {t:'d', d: 1}, 'b'],
// Start of context relative to cursor
n: 5,
ln: 4,
@ -150,7 +150,7 @@ var DEADKEY_TEST_2 = {
var DEADKEY_TEST_3 = {
id: 3,
// Match condition for rule
rule: [{d: 0}, 'a', {d: 0}, {d: 0}, 'b'],
rule: [{t:'d', d: 0}, 'a', {t:'d', d: 0}, {t:'d', d: 0}, 'b'],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -238,7 +238,7 @@ var DEADKEY_TEST_3 = {
var DEADKEY_TEST_4 = {
id: 4,
// Match condition for rule
rule: ['a', {d: 0}, {d: 0}, 'b', {d: 0}],
rule: ['a', {t:'d', d: 0}, {t:'d', d: 0}, 'b', {t:'d', d: 0}],
// Start of context relative to cursor
n: 6,
ln: 5,
@ -280,7 +280,7 @@ var DEADKEY_TEST_5 = {
var DEADKEY_TEST_6 = {
id: 6,
// Match condition for rule
rule: [{d: 1}, {d: 2}, {d: 0}, {d: 1}, {d: 2}],
rule: [{t:'d', d: 1}, {t:'d', d: 2}, {t:'d', d: 0}, {t:'d', d: 1}, {t:'d', d: 2}],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -301,7 +301,7 @@ var DEADKEY_TEST_6 = {
var ANY_CONTEXT_TEST_1 = {
id: 1,
// Match condition for rule
rule: ['c', "a", "b", {c:3}, {c:2}],
rule: ['c', "a", "b", {t:'c', c:3}, {t:'c', c:2}],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -341,7 +341,7 @@ var ANY_CONTEXT_TEST_1 = {
var ANY_CONTEXT_TEST_2 = {
id: 2,
// Match condition for rule
rule: ['c', 'a', {a: "bc"}, {c:3}, 'a'],
rule: ['c', 'a', {t:'a', a: "bc"}, {t:'c', c:3}, 'a'],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -381,7 +381,7 @@ var ANY_CONTEXT_TEST_2 = {
var ANY_CONTEXT_TEST_3 = {
id: 3,
// Match condition for rule
rule: ['c', {a: "ac"}, {a: "bc"}, {c:3}, {c:2}],
rule: ['c', {t:'a', a: "ac"}, {t:'a', a: "bc"}, {t:'c', c:3}, {t:'c', c:2}],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -431,7 +431,7 @@ var ANY_CONTEXT_TEST_3 = {
var ANY_INDEX_TEST_1 = {
id: 1,
// Match condition for rule
rule: ['c', 'a', {a: "bc"}, {i:{s:"bc", o:2}}, 'a'],
rule: ['c', 'a', {t:'a', a: "bc"}, {t:'i', i:{s:"bc", o:2}}, 'a'],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -471,7 +471,7 @@ var ANY_INDEX_TEST_1 = {
var ANY_INDEX_TEST_2 = {
id: 2,
// Match condition for rule
rule: ['c', {a:"ab"}, {i: {s:"bc", o:1}}, {i:{s:"bc", o:1}}, {i:{s:"ab", o:1}}],
rule: ['c', {t:'a', a:"ab"}, {t:'i', i: {s:"bc", o:1}}, {t:'i', i:{s:"bc", o:1}}, {t:'i', i:{s:"ab", o:1}}],
// Start of context relative to cursor
n: 5,
ln: 5,
@ -511,7 +511,7 @@ var ANY_INDEX_TEST_2 = {
var ANY_INDEX_TEST_3 = {
id: 3,
// Match condition for rule
rule: ['c', {a:"ab"}, {a:"bc"}, {i:{s:"bc", o:2}}, {i:{s:"ab", o:1}}],
rule: ['c', {t:'a', a:"ab"}, {t:'a', a:"bc"}, {t:'i', i:{s:"bc", o:2}}, {t:'i', i:{s:"ab", o:1}}],
// Start of context relative to cursor
n: 5,
ln: 5,

View file

@ -39,23 +39,23 @@ function Keyboard_test_deadkeys()
};
this.g_main=function(t,e) {
var k=KeymanWeb,r=0,m=0;
if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(7,t,['(','o',')',{d:18},'(','o',')'])) { // Line 51
if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(7,t,['(','o',')',{t:'d',d:18},'(','o',')'])) { // Line 51
r=m=1;
k.KO(6,t,"dk(o)");
}
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(4,t,[{d:18},'(','m',')'])) { // Line 45
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(4,t,[{t:'d',d:18},'(','m',')'])) { // Line 45
r=m=1;
k.KO(3,t,"dk(m)");
}
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(4,t,['(','n',')',{d:18}])) { // Line 48
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(4,t,['(','n',')',{t:'d',d:18}])) { // Line 48
r=m=1;
k.KO(3,t,"dk(n)");
}
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(2,t,[{d:16},{d:17}])) { // Line 40
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(2,t,[{t:'d',d:16},{t:'d',d:17}])) { // Line 40
r=m=1;
k.KO(0,t,"(a)-(s)");
}
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(2,t,[{d:17},{d:16}])) { // Line 41
else if(k.KKM(e, 0x4000, 0xBE)&&k.KFCM(2,t,[{t:'d',d:17},{t:'d',d:16}])) { // Line 41
r=m=1;
k.KO(0,t,"(s)+(a)");
}
@ -107,12 +107,12 @@ function Keyboard_test_deadkeys()
r=m=1;
k.KDO(0,t,16);
}
else if(k.KKM(e, 0x4010, 0x42)&&k.KFCM(1, t, [{d:16}])) { // Line 94
else if(k.KKM(e, 0x4010, 0x42)&&k.KFCM(1, t, [{t:'d',d:16}])) { // Line 94
r=m=1;
k.KO(0,t,"ab");
k.KDO(-1,t,21);
}
else if(k.KKM(e, 0x4010, 0x43)&&k.KFCM(1, t, [{d:22}])) { // Line 95
else if(k.KKM(e, 0x4010, 0x43)&&k.KFCM(1, t, [{t:'d',d:22}])) { // Line 95
r=m=1;
k.KO(0,t,"abc");
}
@ -120,7 +120,7 @@ function Keyboard_test_deadkeys()
r=m=1;
k.KO(3,t,"$abc$d");
}
else if(k.KKM(e, 0x4010, 0x45)&&k.KFCM(4,t,['a','b',{d:23},'d'])) { // Line 96
else if(k.KKM(e, 0x4010, 0x45)&&k.KFCM(4,t,['a','b',{t:'d',d:23},'d'])) { // Line 96
r=m=1;
k.KO(3,t,"success");
}
@ -130,15 +130,15 @@ function Keyboard_test_deadkeys()
k.KDO(-1,t,20);
k.KO(-1,t,"(P)");
}
else if(k.KKM(e, 0x4010, 0x51)&&k.KFCM(4,t,[{d:20},'(','P',')'])) { // Line 59
else if(k.KKM(e, 0x4010, 0x51)&&k.KFCM(4,t,[{t:'d',d:20},'(','P',')'])) { // Line 59
r=m=1;
k.KO(3,t,"(P)(Q)");
}
else if(k.KKM(e, 0x4010, 0x52)&&k.KFCM(8,t,[{d:20},{d:20},'(','P',')','(','Q',')'])) { // Line 61
else if(k.KKM(e, 0x4010, 0x52)&&k.KFCM(8,t,[{t:'d',d:20},{t:'d',d:20},'(','P',')','(','Q',')'])) { // Line 61
r=m=1;
k.KO(6,t,"ERROR");
}
else if(k.KKM(e, 0x4010, 0x52)&&k.KFCM(7,t,[{d:20},'(','P',')','(','Q',')'])) { // Line 60
else if(k.KKM(e, 0x4010, 0x52)&&k.KFCM(7,t,[{t:'d',d:20},'(','P',')','(','Q',')'])) { // Line 60
r=m=1;
k.KO(6,t,"(P)(Q)(R)");
}
@ -146,23 +146,23 @@ function Keyboard_test_deadkeys()
r=m=1;
k.KDO(0,t,16);
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{d:2},'d','e','a','d','1'])) { // Line 84
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{t:'d',d:2},'d','e','a','d','1'])) { // Line 84
r=m=1;
k.KO(5,t,"ERROR");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{d:1},'d','e','a','d','2'])) { // Line 85
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{t:'d',d:1},'d','e','a','d','2'])) { // Line 85
r=m=1;
k.KO(5,t,"success");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{d:4},'d','e','a','d','3'])) { // Line 89
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{t:'d',d:4},'d','e','a','d','3'])) { // Line 89
r=m=1;
k.KO(5,t,"success");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{d:3},'d','e','a','d','4'])) { // Line 90
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(6,t,[{t:'d',d:3},'d','e','a','d','4'])) { // Line 90
r=m=1;
k.KO(5,t,"ERROR");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(4,t,['(','b',')',{d:16}])) { // Line 24
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(4,t,['(','b',')',{t:'d',d:16}])) { // Line 24
r=m=1;
k.KO(3,t,"(b)+(a)+(b)");
}
@ -170,23 +170,23 @@ function Keyboard_test_deadkeys()
r=m=1;
k.KO(3,t,"(b)+(b)");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{d:16}])) { // Line 19
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{t:'d',d:16}])) { // Line 19
r=m=1;
k.KO(0,t,"(a)(b)");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{d:2}])) { // Line 82
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{t:'d',d:2}])) { // Line 82
r=m=1;
k.KO(0,t,"dead2");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{d:1}])) { // Line 83
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{t:'d',d:1}])) { // Line 83
r=m=1;
k.KO(0,t,"dead1");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{d:4}])) { // Line 87
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{t:'d',d:4}])) { // Line 87
r=m=1;
k.KO(0,t,"dead4");
}
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{d:3}])) { // Line 88
else if(k.KKM(e, 0x4000, 0x42)&&k.KFCM(1, t, [{t:'d',d:3}])) { // Line 88
r=m=1;
k.KO(0,t,"dead3");
}
@ -194,7 +194,7 @@ function Keyboard_test_deadkeys()
r=m=1;
k.KO(0,t,"(b)");
}
else if(k.KKM(e, 0x4000, 0x43)&&k.KFCM(1, t, [{d:16}])) { // Line 27
else if(k.KKM(e, 0x4000, 0x43)&&k.KFCM(1, t, [{t:'d',d:16}])) { // Line 27
r=m=1;
k.KO(0,t,"x");
}
@ -202,11 +202,11 @@ function Keyboard_test_deadkeys()
r=m=1;
k.KO(0,t,"d");
}
else if(k.KKM(e, 0x4000, 0x45)&&k.KFCM(3,t,['f',{d:16},'d'])) { // Line 35
else if(k.KKM(e, 0x4000, 0x45)&&k.KFCM(3,t,['f',{t:'d',d:16},'d'])) { // Line 35
r=m=1;
k.KO(2,t,"(f)-(a)-(d)-(e)");
}
else if(k.KKM(e, 0x4000, 0x45)&&k.KFCM(2,t,[{d:16},'d'])) { // Line 34
else if(k.KKM(e, 0x4000, 0x45)&&k.KFCM(2,t,[{t:'d',d:16},'d'])) { // Line 34
r=m=1;
k.KO(1,t,"(a)(d)(e)");
}
@ -236,11 +236,11 @@ function Keyboard_test_deadkeys()
k.KDO(-1,t,10);
k.KO(-1,t,"(p)");
}
else if(k.KKM(e, 0x4000, 0x51)&&k.KFCM(4,t,[{d:10},'(','p',')'])) { // Line 55
else if(k.KKM(e, 0x4000, 0x51)&&k.KFCM(4,t,[{t:'d',d:10},'(','p',')'])) { // Line 55
r=m=1;
k.KO(3,t,"(p)(q)");
}
else if(k.KKM(e, 0x4000, 0x52)&&k.KFCM(7,t,[{d:19},'(','p',')','(','q',')'])) { // Line 56
else if(k.KKM(e, 0x4000, 0x52)&&k.KFCM(7,t,[{t:'d',d:19},'(','p',')','(','q',')'])) { // Line 56
r=m=1;
k.KO(6,t,"(p)(q)(r)");
}
@ -262,16 +262,16 @@ function Keyboard_test_deadkeys()
k.KDO(-1,t,23);
k.KO(-1,t,"d");
}
else if(k.KFCM(3,t,['a','b',{d:21}])) { // Line 133
else if(k.KFCM(3,t,['a','b',{t:'d',d:21}])) { // Line 133
m=1;
k.KDO(2,t,22);
}
else if(k.KFCM(2,t,[{d:2},{d:1}])) { // Line 130
else if(k.KFCM(2,t,[{t:'d',d:2},{t:'d',d:1}])) { // Line 130
m=1;
k.KDO(0,t,1);
k.KDO(-1,t,2);
}
else if(k.KFCM(2,t,[{d:3},{d:4}])) { // Line 131
else if(k.KFCM(2,t,[{t:'d',d:3},{t:'d',d:4}])) { // Line 131
m=1;
k.KDO(0,t,4);
k.KDO(-1,t,3);