Skip to content

Commit 4e83e93

Browse files
committed
(third) Implement exact integer matching
2 parents 51df1f3 + e00b643 commit 4e83e93

File tree

9 files changed

+78
-76
lines changed

9 files changed

+78
-76
lines changed

experiments/stasm/third/example/example_glossary.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ console.log("==== English ====");
111111
lang: "en",
112112
id: "accord",
113113
phrases: {},
114-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
114+
selectors: [],
115115
variants: [
116116
{
117-
keys: [{type: "StringLiteral", value: "default"}],
117+
keys: [],
118118
value: [
119119
{type: "StringLiteral", value: "The "},
120120
{
@@ -157,10 +157,10 @@ console.log("==== English ====");
157157
lang: "en",
158158
id: "you-see",
159159
phrases: {},
160-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
160+
selectors: [],
161161
variants: [
162162
{
163-
keys: [{type: "StringLiteral", value: "default"}],
163+
keys: [],
164164
value: [
165165
{type: "StringLiteral", value: "You see "},
166166
{
@@ -188,10 +188,10 @@ console.log("==== English ====");
188188
lang: "en",
189189
id: "they-wave",
190190
phrases: {},
191-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
191+
selectors: [],
192192
variants: [
193193
{
194-
keys: [{type: "StringLiteral", value: "default"}],
194+
keys: [],
195195
value: [
196196
{
197197
type: "FunctionCall",
@@ -221,10 +221,10 @@ console.log("==== polski ====");
221221
lang: "pl",
222222
id: "accord",
223223
phrases: {},
224-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
224+
selectors: [],
225225
variants: [
226226
{
227-
keys: [{type: "StringLiteral", value: "default"}],
227+
keys: [],
228228
value: [
229229
{
230230
type: "FunctionCall",
@@ -261,10 +261,10 @@ console.log("==== polski ====");
261261
lang: "pl",
262262
id: "you-see",
263263
phrases: {},
264-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
264+
selectors: [],
265265
variants: [
266266
{
267-
keys: [{type: "StringLiteral", value: "default"}],
267+
keys: [],
268268
value: [
269269
{type: "StringLiteral", value: "Widzisz "},
270270
{
@@ -292,10 +292,10 @@ console.log("==== polski ====");
292292
lang: "pl",
293293
id: "they-wave",
294294
phrases: {},
295-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
295+
selectors: [],
296296
variants: [
297297
{
298-
keys: [{type: "StringLiteral", value: "default"}],
298+
keys: [],
299299
value: [
300300
{
301301
type: "FunctionCall",

experiments/stasm/third/example/example_list.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ REGISTRY["PLURAL_LEN"] = function (
5151
throw new TypeError();
5252
}
5353

54-
return new PluralValue(elements.value.length);
54+
// TODO(stasm): Cache PluralRules.
55+
let pr = new Intl.PluralRules(ctx.locale);
56+
let category = pr.select(elements.value.length);
57+
return new PluralValue(category, elements.value.length);
5558
};
5659

5760
REGISTRY["PEOPLE_LIST"] = function (

experiments/stasm/third/example/example_number.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,10 @@ console.log("==== English ====");
99
lang: "en",
1010
id: "transferred",
1111
phrases: {},
12-
selectors: [
13-
{
14-
expr: null,
15-
default: {type: "StringLiteral", value: "default"},
16-
},
17-
],
12+
selectors: [],
1813
variants: [
1914
{
20-
keys: [{type: "StringLiteral", value: "default"}],
15+
keys: [],
2116
value: [
2217
{type: "StringLiteral", value: "Transferred "},
2318
{
@@ -49,15 +44,10 @@ console.log("==== French ====");
4944
lang: "fr",
5045
id: "transferred",
5146
phrases: {},
52-
selectors: [
53-
{
54-
expr: null,
55-
default: {type: "StringLiteral", value: "default"},
56-
},
57-
],
47+
selectors: [],
5848
variants: [
5949
{
60-
keys: [{type: "StringLiteral", value: "default"}],
50+
keys: [],
6151
value: [
6252
{
6353
type: "FunctionCall",

experiments/stasm/third/example/example_opaque.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,10 @@ console.log("==== English ====");
2424
lang: "en",
2525
id: "submit",
2626
phrases: {},
27-
selectors: [
28-
{
29-
expr: null,
30-
default: {type: "StringLiteral", value: "default"},
31-
},
32-
],
27+
selectors: [],
3328
variants: [
3429
{
35-
keys: [{type: "StringLiteral", value: "default"}],
30+
keys: [],
3631
value: [
3732
{type: "StringLiteral", value: "Ready? Then "},
3833
{

experiments/stasm/third/example/example_phrases.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ console.log("==== English ====");
5858
],
5959
},
6060
},
61-
selectors: [{expr: null, default: {type: "StringLiteral", value: "default"}}],
61+
selectors: [],
6262
variants: [
6363
{
64-
keys: [{type: "StringLiteral", value: "default"}],
64+
keys: [],
6565
value: [
6666
{type: "VariableReference", name: "userName"},
6767
{type: "StringLiteral", value: " "},

experiments/stasm/third/impl/context.ts

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
import {Message, Parameter, PatternElement, Selector, StringLiteral, Variant} from "./model.js";
1+
import {
2+
IntegerLiteral,
3+
Message,
4+
Parameter,
5+
PatternElement,
6+
Selector,
7+
StringLiteral,
8+
Variant,
9+
} from "./model.js";
210
import {REGISTRY} from "./registry.js";
3-
import {BooleanValue, NumberValue, RuntimeValue, StringValue} from "./runtime.js";
11+
import {BooleanValue, NumberValue, PluralValue, RuntimeValue, StringValue} from "./runtime.js";
412

513
// Resolution context for a single formatMessage() call.
614

@@ -56,41 +64,25 @@ export class FormattingContext {
5664
}
5765

5866
selectVariant(variants: Array<Variant>, selectors: Array<Selector>): Variant {
59-
interface ResolvedSelector<T> {
60-
value: T | null;
61-
string: string | null;
67+
interface ResolvedSelector {
68+
value: RuntimeValue<unknown>;
6269
default: string;
6370
}
6471

65-
let resolved_selectors: Array<ResolvedSelector<unknown>> = [];
72+
let resolved_selectors: Array<ResolvedSelector> = [];
6673
for (let selector of selectors) {
67-
if (selector.expr === null) {
68-
// A special selector which only selects its default value. Used in the
69-
// data model of single-variant messages.
70-
resolved_selectors.push({
71-
value: null,
72-
string: null,
73-
default: selector.default.value,
74-
});
75-
continue;
76-
}
77-
7874
switch (selector.expr.type) {
7975
case "VariableReference": {
80-
let value = this.vars[selector.expr.name];
8176
resolved_selectors.push({
82-
value: value.value,
83-
string: value.formatToString(this),
77+
value: this.vars[selector.expr.name],
8478
default: selector.default.value,
8579
});
8680
break;
8781
}
8882
case "FunctionCall": {
8983
let callable = REGISTRY[selector.expr.name];
90-
let value = callable(this, selector.expr.args, selector.expr.opts);
9184
resolved_selectors.push({
92-
value: value.value,
93-
string: value.formatToString(this),
85+
value: callable(this, selector.expr.args, selector.expr.opts),
9486
default: selector.default.value,
9587
});
9688
break;
@@ -101,15 +93,36 @@ export class FormattingContext {
10193
}
10294
}
10395

104-
// TODO(stasm): Add NumberLiterals as keys (maybe).
105-
function matches_corresponding_selector(key: StringLiteral, idx: number) {
106-
return (
107-
key.value === resolved_selectors[idx].string ||
108-
key.value === resolved_selectors[idx].default
109-
);
96+
function matches_corresponding_selector(key: StringLiteral | IntegerLiteral, idx: number) {
97+
let selector = resolved_selectors[idx];
98+
switch (key.type) {
99+
case "StringLiteral": {
100+
if (key.value === selector.value.value) {
101+
return true;
102+
}
103+
break;
104+
}
105+
case "IntegerLiteral": {
106+
let num = parseInt(key.value);
107+
if (selector.value instanceof NumberValue) {
108+
if (num === selector.value.value) {
109+
return true;
110+
}
111+
} else if (selector.value instanceof PluralValue) {
112+
if (key.value === selector.value.value || num === selector.value.count) {
113+
return true;
114+
}
115+
}
116+
break;
117+
}
118+
}
119+
120+
return key.value === selector.default;
110121
}
111122

112123
for (let variant of variants) {
124+
// When keys is an empty array, every() always returns true. This is
125+
// used single-variant messages to return their only variant.
113126
if (variant.keys.every(matches_corresponding_selector)) {
114127
return variant;
115128
}

experiments/stasm/third/impl/model.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ export interface Phrase {
1212
}
1313

1414
export interface Selector {
15-
expr: VariableReference | FunctionCall | null;
15+
expr: VariableReference | FunctionCall;
1616
default: StringLiteral;
1717
}
1818

1919
export interface Variant {
20-
keys: Array<StringLiteral>;
20+
keys: Array<StringLiteral | IntegerLiteral>;
2121
value: Array<PatternElement>;
2222
}
2323

experiments/stasm/third/impl/registry.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ function select_plural(
2525
throw new TypeError();
2626
}
2727

28-
return new PluralValue(count.value);
28+
// TODO(stasm): Cache PluralRules.
29+
let pr = new Intl.PluralRules(ctx.locale);
30+
let category = pr.select(count.value);
31+
return new PluralValue(category, count.value);
2932
}
3033

3134
function get_phrase(

experiments/stasm/third/impl/runtime.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,20 @@ export class NumberValue extends RuntimeValue<number> {
5656
}
5757
}
5858

59-
export class PluralValue extends RuntimeValue<number> {
60-
private opts: Intl.PluralRulesOptions;
59+
export class PluralValue extends RuntimeValue<Intl.LDMLPluralRule> {
60+
public count: number;
6161

62-
constructor(value: number, opts: Intl.PluralRulesOptions = {}) {
62+
constructor(value: Intl.LDMLPluralRule, count: number) {
6363
super(value);
64-
this.opts = opts;
64+
this.count = count;
6565
}
6666

6767
formatToString(ctx: FormattingContext): string {
68-
// TODO(stasm): Cache PluralRules.
69-
let pr = new Intl.PluralRules(ctx.locale, this.opts);
70-
return pr.select(this.value);
68+
throw new TypeError("PluralValue is not formattable.");
7169
}
7270

7371
*formatToParts(ctx: FormattingContext): IterableIterator<FormattedPart> {
74-
throw new TypeError("Pluralvalue is not formattable to parts.");
72+
throw new TypeError("PluralValue is not formattable.");
7573
}
7674
}
7775

0 commit comments

Comments
 (0)