Skip to content

Commit 5991931

Browse files
committed
Add missing file
1 parent 1ed2f5d commit 5991931

File tree

1 file changed

+393
-0
lines changed

1 file changed

+393
-0
lines changed

src/compiler/sets.ts

+393
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
/// <reference path="checker.ts" />
2+
3+
module ts {
4+
5+
export interface NumberSetLiteral extends TypeNode, Declaration {
6+
min: LiteralExpression;
7+
max?: LiteralExpression;
8+
minValue?: number
9+
}
10+
11+
export const enum UnionReductionKind {
12+
RemoveSubtypes = 0,
13+
KeepSubtypes = 1,
14+
FromTypeNode = 2
15+
}
16+
17+
// Test type guard with this?
18+
export interface SetType extends Type {
19+
}
20+
21+
export type SetTypes = NumberSetType | StringSetType | BooleanSetType;
22+
23+
export interface NumberSetType extends SetType {
24+
min: number,
25+
max: number,
26+
onlyIntegerValues?: boolean, // TODO: after LKG ?: true
27+
values?: number[]
28+
}
29+
30+
export interface StringSetType extends SetType {
31+
values: string[] // values are stored as string literals "a", "b" (with the quotes)
32+
}
33+
34+
export const enum BooleanSetKind {
35+
True = 1,
36+
False,
37+
Domain
38+
}
39+
40+
export interface BooleanSetType extends SetType {
41+
kind: BooleanSetKind
42+
}
43+
44+
export function isValueInSet(val: any, set: SetType) {
45+
if(set.flags & TypeFlags.Domain) {
46+
return true;
47+
}
48+
if (set.flags & TypeFlags.NumberSet) {
49+
return isValueinNumberSet(val, <NumberSetType>set);
50+
}
51+
else if (set.flags & TypeFlags.StringSet) {
52+
return isValueinStringSet(val, <StringSetType>set);
53+
}
54+
return isValueinBooleanSet(val, <BooleanSetType>set);
55+
}
56+
57+
function isValueinNumberSet(val: number, set: NumberSetType) {
58+
if (val < set.min || val > set.max) {
59+
if (!set.values || set.values.indexOf(val) === -1) {
60+
return false;
61+
}
62+
}
63+
if (set.onlyIntegerValues && val === +val && val !== (val | 0)) {
64+
return true;
65+
}
66+
return isNaN(val) === false && isFinite(val) === true;
67+
}
68+
69+
function isValueinStringSet(val: string, set: StringSetType) {
70+
return set.values.indexOf('"' + val + '"') !== -1;
71+
}
72+
73+
function isValueinBooleanSet(val: boolean, set: BooleanSetType) {
74+
switch (set.kind) {
75+
case BooleanSetKind.True: return val === true;
76+
case BooleanSetKind.False: return val === false;
77+
}
78+
}
79+
80+
export interface ReducedSetTypes {
81+
numberSet?: NumberSetType
82+
stringSet?: StringSetType
83+
booleanSet?: BooleanSetType
84+
toSetType?: SetType,
85+
types: Type[]
86+
}
87+
88+
// Reduction to subsets for union types when they are declared
89+
export function reduceSubsets(types: Type[]): ReducedSetTypes {
90+
let reduce: ReducedSetTypes = {types: []};
91+
92+
let numberSets: NumberSetType[];
93+
let stringSets: StringSetType[];
94+
let boolSets: BooleanSetType[];
95+
let otherTypes: Type[] = [];
96+
97+
for (let type of types) {
98+
if(type.flags & TypeFlags.ObjectSet || !(type.flags & TypeFlags.SubsetLike)) {
99+
// could reduce by symbol names here?
100+
otherTypes.push(type);
101+
continue;
102+
}
103+
104+
if (type.flags & TypeFlags.NumberSet) {
105+
if (type.flags & TypeFlags.Domain) {
106+
reduce.numberSet = reduce.numberSet || <NumberSetType>type;
107+
}
108+
numberSets = numberSets || [];
109+
numberSets.push(<NumberSetType>type);
110+
} else if (type.flags & TypeFlags.StringSet) {
111+
if (type.flags & TypeFlags.Domain) {
112+
reduce.stringSet = reduce.stringSet || <StringSetType>type;
113+
} else if (type.flags & TypeFlags.StringLiteral) {
114+
type = <StringSetType>{ values: [(<StringLiteralType>type).text], flags: undefined, id: undefined }
115+
}
116+
stringSets = stringSets || [];
117+
stringSets.push(<StringSetType>type);
118+
} else if (type.flags & TypeFlags.BooleanSet) {
119+
if (type.flags & TypeFlags.Domain) {
120+
reduce.booleanSet = reduce.booleanSet || <BooleanSetType>type;
121+
}
122+
boolSets = boolSets || [];
123+
boolSets.push(<BooleanSetType>type);
124+
}
125+
}
126+
127+
let countDifferentTypes = otherTypes.length;
128+
if (numberSets) {
129+
if (reduce.numberSet) {
130+
reduce.types = [reduce.numberSet];
131+
} else {
132+
reduce.types = reduceNumberSets(numberSets);
133+
if (reduce.types.length === 1) {
134+
reduce.numberSet = <NumberSetType>reduce.types[0];
135+
}
136+
}
137+
countDifferentTypes += reduce.types.length;
138+
}
139+
if (stringSets) {
140+
if (reduce.stringSet) {
141+
reduce.types.push(reduce.stringSet);
142+
} else {
143+
reduce.types.push(reduce.stringSet = reduceStringSets(stringSets));
144+
}
145+
countDifferentTypes++;
146+
}
147+
if (boolSets) {
148+
if (reduce.booleanSet) {
149+
reduce.types.push(reduce.booleanSet);
150+
} else {
151+
reduce.types.push(reduce.booleanSet = reduceBooleanSets(boolSets));
152+
}
153+
countDifferentTypes++;
154+
}
155+
156+
if (countDifferentTypes === 1) {
157+
reduce.toSetType = reduce.numberSet || reduce.stringSet || reduce.booleanSet;
158+
}
159+
160+
if (otherTypes.length) {
161+
reduce.types = reduce.types.concat(otherTypes);
162+
}
163+
164+
return reduce;
165+
}
166+
167+
export function reduceStringNodesToSet(nodes: LiteralExpression[]): StringSetType {
168+
let stringSet = <StringSetType>{ values: [], id: undefined, flags: TypeFlags.StringSet }
169+
for (let node of nodes) {
170+
stringSet.values.push(node.text);
171+
}
172+
return stringSet;
173+
}
174+
175+
export function reduceNumberNodesToSets(nodes: NumberSetLiteral[]): NumberSetType[] {
176+
let reduced: NumberSetType[] = [];
177+
178+
let isInteger: boolean;
179+
let minText: string;
180+
let numSet: NumberSetType;
181+
let intValues: number[] = [];
182+
let floatValues: number[] = [];
183+
184+
let intSets: NumberSetType[] = [];
185+
let floatSets: NumberSetType[] = [];
186+
187+
for (let node of nodes) {
188+
minText = node.min.text;
189+
isInteger = (node.max && node.max.text.indexOf('.') === -1 && minText.indexOf('.') === -1) || minText.indexOf('.') === -1;
190+
191+
console.log(node);
192+
if (node.max === undefined) {
193+
if (isInteger) {
194+
intValues.push(node.minValue);
195+
} else {
196+
floatValues.push(node.minValue);
197+
}
198+
} else {
199+
numSet = <NumberSetType>{ min: Number(minText), max: Number(node.max.text), id: undefined, flags: TypeFlags.NumberSet };
200+
if (isInteger) {
201+
numSet.onlyIntegerValues = true;
202+
if (intSets.length && node.minValue < intSets[0].min) {
203+
intSets.push(intSets[0]);
204+
intSets[0] = numSet;
205+
} else {
206+
intSets.push(numSet);
207+
}
208+
} else {
209+
if (floatSets.length && node.minValue < floatSets[0].min) {
210+
floatSets.push(floatSets[0]);
211+
floatSets[0] = numSet;
212+
} else {
213+
floatSets.push(numSet);
214+
}
215+
}
216+
}
217+
}
218+
219+
if (floatValues.length) {
220+
floatValues.sort();
221+
floatSets[0] = floatSets[0] || <NumberSetType>{ min: floatValues[0], max: floatValues[0], id: undefined, flags: TypeFlags.NumberSet }
222+
addValues(floatSets[0], floatValues);
223+
}
224+
225+
if (intValues.length) {
226+
intValues.sort();
227+
intSets[0] = intSets[0] || <NumberSetType>{ min: intValues[0], max: intValues[0], id: undefined, flags: TypeFlags.NumberSet }
228+
addValues(intSets[0], intValues);
229+
}
230+
231+
if (intSets.length) {
232+
reduced = reduced.concat(intSets);
233+
}
234+
235+
if (floatSets.length) {
236+
reduced = reduced.concat(floatSets);
237+
}
238+
239+
return reduced;
240+
241+
function addValues(set: NumberSetType, values: number[]) {
242+
let valuesOutOfRange: number[] = [];
243+
for (let v of values) {
244+
if (v >= set.min && v <= set.max) {
245+
continue;
246+
}
247+
else if (v === set.min - 1) {
248+
set.min--;
249+
continue;
250+
}
251+
else if (v === set.max + 1) {
252+
set.max++;
253+
continue;
254+
}
255+
256+
valuesOutOfRange.push(v);
257+
}
258+
if (valuesOutOfRange.length) {
259+
set.values = valuesOutOfRange;
260+
}
261+
}
262+
}
263+
264+
function reduceNumberSets(types: NumberSetType[]): NumberSetType[] {
265+
return types;
266+
267+
if (types.length === 1) {
268+
return [types[0]];
269+
}
270+
271+
let reduced: NumberSetType[] = [];
272+
273+
// >{ min: Number.MAX_VALUE, max: undefined, flags: TypeFlags.NumberSet, id: undefined };
274+
275+
let [min, max, values, floatTypes] = getNumberValues(types, /* isInteger */ true);
276+
if(min.length)
277+
reduced.push(reducedType(min, max, values, /* isInteger */ true));
278+
279+
if(floatTypes.length) {
280+
[min, max, values] = getNumberValues(floatTypes);
281+
282+
reduced.push(reducedType(min, max, values));
283+
284+
// type issue?
285+
//reduced.push(reducedType(...getNumberValues(floatTypes)));
286+
}
287+
288+
return reduced;
289+
290+
function reducedType(min: number[], max: number[], values: number[], isInteger?: boolean): NumberSetType {
291+
min.sort();
292+
293+
let type = <NumberSetType>{ min: min[0], max: undefined, flags: TypeFlags.NumberSet, id: undefined };
294+
if (isInteger) {
295+
type.onlyIntegerValues = true;
296+
}
297+
298+
if (max) {
299+
max.sort();
300+
type.max = max[max.length - 1];
301+
} else {
302+
type.max = min[min.length - 1];
303+
}
304+
305+
if (values.length) {
306+
let valuesOutOfRange: number[] = [];
307+
for (let v of values) {
308+
if (v >= type.min && v <= type.max) {
309+
continue;
310+
}
311+
else if (v === type.min - 1) {
312+
type.min--;
313+
continue;
314+
}
315+
else if (v === type.max + 1) {
316+
type.max++;
317+
continue;
318+
}
319+
320+
valuesOutOfRange.push(v);
321+
}
322+
if (valuesOutOfRange.length) {
323+
type.values = valuesOutOfRange;
324+
}
325+
}
326+
327+
return type;
328+
}
329+
330+
function getNumberValues(types: NumberSetType[], isInteger?: boolean): [number[], number[], number[], NumberSetType[]] {
331+
let min: number[] = [];
332+
let max: number[] = [];
333+
let values: number[] = [];
334+
let floatTypes : NumberSetType[] = [];
335+
336+
for (let type of types) {
337+
if (isInteger && type.onlyIntegerValues === false) {
338+
floatTypes.push(type);
339+
continue;
340+
}
341+
342+
if (type.min === type.max) {
343+
values.push(type.min);
344+
} else {
345+
min.push(type.min);
346+
max.push(type.max);
347+
}
348+
if (type.values) {
349+
values = values.concat(values);
350+
}
351+
}
352+
353+
values.sort();
354+
if (!min.length) {
355+
min = [values[0]];
356+
}
357+
358+
return [min, max.length ? max : undefined, values, floatTypes];
359+
}
360+
}
361+
362+
function reduceStringSets(types: StringSetType[]): StringSetType {
363+
if (types.length === 1) {
364+
return types[0];
365+
}
366+
367+
let seen: Map<string> = {};
368+
let reduced = <StringSetType>{ values: [], flags: TypeFlags.StringSet, id: undefined };
369+
370+
for (let type of types) {
371+
for (let v of type.values) {
372+
if (!seen[v]) {
373+
reduced.values.push(v);
374+
}
375+
}
376+
}
377+
reduced.values.sort();
378+
379+
return reduced;
380+
}
381+
382+
function reduceBooleanSets(types: BooleanSetType[]): BooleanSetType {
383+
if (types.length === 1) {
384+
return types[0];
385+
}
386+
387+
let reduced = <BooleanSetType>{ flags: TypeFlags.BooleanSet, id: undefined };
388+
for (let type of types) {
389+
reduced.kind |= type.kind;
390+
}
391+
return reduced;
392+
}
393+
}

0 commit comments

Comments
 (0)