Skip to content

Commit 49d29fc

Browse files
committed
More std array
1 parent 827bb4a commit 49d29fc

File tree

13 files changed

+1178
-342
lines changed

13 files changed

+1178
-342
lines changed

src/compiler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,7 +2469,7 @@ export class Compiler extends DiagnosticEmitter {
24692469

24702470
} else { // too few arguments
24712471
this.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range,
2472-
(operandIndex + numParametersInclThis - numParameters).toString(10),
2472+
(operandIndex + numParameters - numParametersInclThis).toString(10),
24732473
numArguments.toString(10)
24742474
);
24752475
return this.module.createUnreachable();
@@ -2686,7 +2686,7 @@ export class Compiler extends DiagnosticEmitter {
26862686
case ElementKind.PROPERTY: // instance property (here: getter)
26872687
var getter = (<Property>element).getterPrototype;
26882688
assert(getter != null);
2689-
var getterInstance = (<FunctionPrototype>getter).resolve(); // reports
2689+
var getterInstance = (<FunctionPrototype>getter).resolve(null); // reports
26902690
if (!getterInstance)
26912691
return this.module.createUnreachable();
26922692
assert(getterInstance.parameters.length == 0);

src/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ export class Parser extends DiagnosticEmitter {
564564
}
565565
var initializer: Expression | null = null;
566566
if (tn.skip(Token.EQUALS)) {
567-
initializer = this.parseExpression(tn);
567+
initializer = this.parseExpression(tn, Precedence.COMMA + 1);
568568
if (!initializer)
569569
return null;
570570
}

src/program.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,7 @@ export class FunctionPrototype extends Element {
15621562
if (typeNode = declaration.parameters[i].type) {
15631563
var parameterType = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports
15641564
if (parameterType) {
1565-
parameters[i] = new Parameter(declaration.parameters[i].name.name, parameterType);
1565+
parameters[i] = new Parameter(declaration.parameters[i].name.name, parameterType, declaration.parameters[i].initializer);
15661566
parameterTypes[i] = parameterType;
15671567
} else
15681568
return null;
@@ -2006,10 +2006,15 @@ export class ClassPrototype extends Element {
20062006
instance.members.set(member.simpleName, methodPrototype);
20072007
break;
20082008

2009-
case ElementKind.PROPERTY: // instance properties are just copied because there is nothing to partially-resolve
2009+
case ElementKind.PROPERTY: // instance properties are cloned with partially resolved getters and setters
20102010
if (!instance.members)
20112011
instance.members = new Map();
2012-
instance.members.set(member.simpleName, member);
2012+
assert((<Property>member).getterPrototype);
2013+
var instanceProperty = new Property(this.program, member.simpleName, member.internalName, this);
2014+
instanceProperty.getterPrototype = (<FunctionPrototype>(<Property>member).getterPrototype).resolvePartial(typeArguments);
2015+
if ((<Property>member).setterPrototype)
2016+
instanceProperty.setterPrototype = (<FunctionPrototype>(<Property>member).setterPrototype).resolvePartial(typeArguments);
2017+
instance.members.set(member.simpleName, instanceProperty);
20132018
break;
20142019

20152020
default:

std/assembly.d.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,15 +201,19 @@ declare function parseFloat(str: string): f64;
201201
/** Class representing a sequence of values of type `T`. */
202202
declare class Array<T> {
203203
[key: number]: T;
204-
205-
/** Current maximum capacity of the array. */
206-
readonly capacity: i32;
207-
208204
/** Current length of the array. */
209205
length: i32;
210-
211206
/** Constructs a new array. */
212207
constructor(capacity?: i32);
208+
indexOf(searchElement: T, fromIndex?: i32): i32;
209+
lastIndexOf(searchElement: T, fromIndex?: i32): i32;
210+
push(element: T): void;
211+
pop(): T;
212+
shift(): T;
213+
unshift(element: T): i32;
214+
slice(from: i32, to?: i32): T[];
215+
splice(start: i32, deleteCount?: i32): void;
216+
reverse(): T[];
213217
}
214218

215219
/** Class representing a C-like array of values of type `T` with limited capabilities. */

std/assembly/array.ts

Lines changed: 112 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,107 @@
11
export class Array<T> {
22

33
private __memory: usize;
4-
private __capacity: i32;
5-
length: i32;
4+
private __capacity: i32; // capped to [0, 0x7fffffff]
5+
private __length: i32; // capped to [0, __capacity]
6+
7+
private __grow(newCapacity: i32): void {
8+
assert(newCapacity > this.__capacity);
9+
var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
10+
if (this.__memory) {
11+
move_memory(newMemory, this.__memory, this.__capacity * sizeof<T>());
12+
free_memory(this.__memory);
13+
}
14+
this.__memory = newMemory;
15+
this.__capacity = newCapacity;
16+
}
617

718
constructor(capacity: i32 = 0) {
819
if (capacity < 0)
9-
throw new RangeError("invalid array length");
10-
this.__capacity = this.length = capacity;
11-
this.__memory = capacity > 0 ? allocate_memory(<usize>capacity * sizeof<T>()) : 0;
20+
throw new RangeError("Invalid array length");
21+
this.__memory = capacity ? allocate_memory(<usize>capacity * sizeof<T>()) : 0;
22+
this.__capacity = this.__length = capacity;
23+
}
24+
25+
get length(): i32 {
26+
return this.__length;
27+
}
28+
29+
set length(length: i32) {
30+
if (length < 0)
31+
throw new RangeError("Invalid array length");
32+
if (length > this.__capacity)
33+
this.__grow(max(length, this.__capacity << 1));
34+
this.__length = length;
1235
}
1336

1437
@operator("[]")
1538
private __get(index: i32): T {
1639
if (<u32>index >= this.__capacity)
17-
throw new RangeError("index out of range");
40+
throw new Error("Index out of bounds"); // return changetype<T>(0) ?
1841
return load<T>(this.__memory + <usize>index * sizeof<T>());
1942
}
2043

2144
@operator("[]=")
2245
private __set(index: i32, value: T): void {
23-
if (<u32>index >= this.__capacity)
24-
throw new RangeError("index out of range");
46+
if (index < 0)
47+
throw new Error("Index out of bounds");
48+
if (index >= this.__capacity)
49+
this.__grow(max(index + 1, this.__capacity << 1));
2550
store<T>(this.__memory + <usize>index * sizeof<T>(), value);
2651
}
2752

2853
indexOf(searchElement: T, fromIndex: i32 = 0): i32 {
29-
if (<u32>fromIndex >= this.__capacity)
30-
throw new RangeError("fromIndex out of range");
31-
for (var index: usize = <usize>fromIndex, length: usize = min<u32>(this.length, this.__capacity); index < length; ++index)
32-
if (load<T>(this.__memory + index * sizeof<T>()) == searchElement)
33-
return index;
54+
if (fromIndex < 0)
55+
fromIndex = this.__length + fromIndex;
56+
while (<u32>fromIndex < this.__length) {
57+
if (load<T>(this.__memory + fromIndex * sizeof<T>()) == searchElement)
58+
return fromIndex;
59+
++fromIndex;
60+
}
3461
return -1;
3562
}
3663

37-
private __grow(newCapacity: i32): void {
38-
assert(newCapacity > this.__capacity);
39-
var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
40-
if (this.__memory) {
41-
move_memory(newMemory, this.__memory, this.__capacity * sizeof<T>());
42-
free_memory(this.__memory);
64+
lastIndexOf(searchElement: T, fromIndex: i32 = 0): i32 {
65+
if (fromIndex < 0)
66+
fromIndex = this.__length + fromIndex;
67+
else if (fromIndex >= this.__length)
68+
fromIndex = this.__length - 1;
69+
while (fromIndex >= 0) {
70+
if (load<T>(this.__memory + fromIndex * sizeof<T>()) == searchElement)
71+
return fromIndex;
72+
--fromIndex;
4373
}
44-
this.__memory = newMemory;
45-
this.__capacity = newCapacity;
74+
return -1;
4675
}
4776

4877
push(element: T): i32 {
49-
if (<u32>this.length >= this.__capacity)
50-
this.__grow(max(this.length + 1, this.__capacity << 1));
51-
store<T>(this.__memory + <usize>this.length * sizeof<T>(), element);
52-
return ++this.length;
78+
if (this.__length == this.__capacity)
79+
this.__grow(this.__capacity ? this.__capacity << 1 : 1);
80+
store<T>(this.__memory + this.__length * sizeof<T>(), element);
81+
return ++this.__length;
5382
}
5483

5584
pop(): T {
56-
if (this.length < 1 || <u32>this.length > this.__capacity)
57-
throw new RangeError("index out of range");
58-
--this.length;
59-
return load<T>(this.__memory + <usize>this.length * sizeof<T>());
85+
if (this.__length < 1)
86+
throw new RangeError("Array is empty"); // return changetype<T>(0) ?
87+
return load<T>(this.__memory + --this.__length * sizeof<T>());
6088
}
6189

6290
shift(): T {
63-
if (this.length < 1 || <u32>this.length > this.__capacity)
64-
throw new RangeError("index out of range");
91+
if (this.__length < 1)
92+
throw new RangeError("Array is empty"); // return changetype<T>(0) ?
6593
var element = load<T>(this.__memory);
6694
move_memory(this.__memory, this.__memory + sizeof<T>(), (this.__capacity - 1) * sizeof<T>());
6795
set_memory(this.__memory + (this.__capacity - 1) * sizeof<T>(), 0, sizeof<T>());
68-
--this.length;
96+
--this.__length;
6997
return element;
7098
}
7199

72100
unshift(element: T): i32 {
73101
var oldCapacity = this.__capacity;
74-
if (<u32>this.length >= oldCapacity) {
75-
// inlined `this.__grow(max(this.length + 1, oldCapacity * 2))` (avoids moving twice)
76-
var newCapacity = max(this.length + 1, oldCapacity * 2);
102+
if (this.__length == oldCapacity) {
103+
// inlined __grow (avoids moving twice)
104+
var newCapacity: i32 = oldCapacity ? oldCapacity << 1 : 1;
77105
assert(newCapacity > this.__capacity);
78106
var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
79107
if (this.__memory) {
@@ -85,7 +113,53 @@ export class Array<T> {
85113
} else
86114
move_memory(this.__memory + sizeof<T>(), this.__memory, oldCapacity * sizeof<T>());
87115
store<T>(this.__memory, element);
88-
return ++this.length;
116+
return ++this.__length;
117+
}
118+
119+
slice(begin: i32 = 0, end: i32 = i32.MAX_VALUE): Array<T> {
120+
if (begin < 0) {
121+
begin = this.__length + begin;
122+
if (begin < 0)
123+
begin = 0;
124+
} else if (begin > this.__length)
125+
begin = this.__length;
126+
if (end < 0)
127+
end = this.__length + end;
128+
else if (end > this.__length)
129+
end = this.__length;
130+
if (end < begin)
131+
end = begin;
132+
var capacity = end - begin;
133+
assert(capacity >= 0);
134+
var sliced = new Array<T>(capacity);
135+
if (capacity)
136+
move_memory(sliced.__memory, this.__memory + <usize>begin * sizeof<T>(), <usize>capacity * sizeof<T>());
137+
return sliced;
138+
}
139+
140+
splice(start: i32, deleteCount: i32 = i32.MAX_VALUE): void {
141+
if (deleteCount < 1)
142+
return;
143+
if (start < 0) {
144+
start = this.__length + start;
145+
if (start < 0)
146+
start = 0;
147+
else if (start >= this.__length)
148+
return;
149+
} else if (start >= this.__length)
150+
return;
151+
deleteCount = min(deleteCount, this.__length - start);
152+
move_memory(this.__memory + <usize>start * sizeof<T>(), this.__memory + <usize>(start + deleteCount) * sizeof<T>(), deleteCount * sizeof<T>());
153+
this.__length -= deleteCount;
154+
}
155+
156+
reverse(): Array<T> {
157+
for (var front: usize = 0, back: usize = <usize>this.__length - 1; front < back; ++front, --back) {
158+
var temp = load<T>(this.__memory + front * sizeof<T>());
159+
store<T>(this.__memory + front * sizeof<T>(), load<T>(this.__memory + back * sizeof<T>()));
160+
store<T>(this.__memory + back * sizeof<T>(), temp);
161+
}
162+
return this;
89163
}
90164
}
91165

@@ -97,14 +171,14 @@ export class CArray<T> {
97171
@operator("[]")
98172
private __get(index: i32): T {
99173
if (index < 0)
100-
throw new RangeError("index out of range");
174+
throw new RangeError("Index out of range");
101175
return load<T>(changetype<usize>(this) + <usize>index * sizeof<T>());
102176
}
103177

104178
@operator("[]=")
105179
private __set(index: i32, value: T): void {
106180
if (index < 0)
107-
throw new RangeError("index out of range");
181+
throw new RangeError("Index out of range");
108182
store<T>(changetype<usize>(this) + <usize>index * sizeof<T>(), value);
109183
}
110184
}

std/portable.d.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,17 @@ declare class Array<T> {
148148
[key: number]: T;
149149
length: i32;
150150
constructor(capacity?: i32);
151-
push(value: T): void;
151+
indexOf(searchElement: T, fromIndex?: i32): i32;
152+
lastIndexOf(searchElement: T, fromIndex?: i32): i32;
153+
push(element: T): void;
152154
pop(): T;
153-
unshift(value: T): void;
154155
shift(): T;
155-
join(delim: string): string;
156+
unshift(element: T): i32;
156157
slice(from: i32, to?: i32): T[];
157-
splice(index: i32, count: i32): T[];
158+
splice(start: i32, deleteCount?: i32): void;
159+
reverse(): T[];
160+
161+
join(delim: string): string;
158162
}
159163

160164
declare class Uint8Array extends Array<u8> {}

tests/compiler.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
9797
actualOptimized = module.toText();
9898
module.runPasses([ "inlining" ]);
9999
actualInlined = module.toText();
100+
if (isCreate)
101+
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wasm", module.toBinary());
100102
} else {
101103
failed = true;
102104
console.log(chalk.red("validate ERROR"));

tests/compiler/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.wasm

0 commit comments

Comments
 (0)