Skip to content

Commit aad263e

Browse files
MaxGraeydcodeIO
authored andcommitted
Add isArrayLike builtin (AssemblyScript#453)
1 parent e8b0767 commit aad263e

File tree

8 files changed

+205
-90
lines changed

8 files changed

+205
-90
lines changed

src/builtins.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747

4848
import {
4949
ElementKind,
50+
OperatorKind,
5051
FunctionPrototype,
5152
Class,
5253
Field,
@@ -64,7 +65,7 @@ import {
6465
} from "./resolver";
6566

6667
import {
67-
CommonFlags, CommonSymbols
68+
CommonFlags
6869
} from "./common";
6970

7071
/** Symbols of various compiler built-ins. */
@@ -76,6 +77,7 @@ export namespace BuiltinSymbols {
7677
export const isReference = "~lib/builtins/isReference";
7778
export const isString = "~lib/builtins/isString";
7879
export const isArray = "~lib/builtins/isArray";
80+
export const isArrayLike = "~lib/builtins/isArrayLike";
7981
export const isFunction = "~lib/builtins/isFunction";
8082
export const isNullable = "~lib/builtins/isNullable";
8183
export const isDefined = "~lib/builtins/isDefined";
@@ -350,6 +352,19 @@ export function compileCall(
350352
: 0
351353
);
352354
}
355+
case BuiltinSymbols.isArrayLike: { // isArrayLike<T!>() / isArrayLike<T?>(value: T) -> bool
356+
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
357+
compiler.currentType = Type.bool;
358+
if (!type) return module.createUnreachable();
359+
let classReference = type.classReference;
360+
if (!classReference) return module.createI32(0);
361+
return module.createI32(
362+
classReference.lookupInSelf("length") && (
363+
classReference.lookupOverload(OperatorKind.INDEXED_GET) ||
364+
classReference.lookupOverload(OperatorKind.UNCHECKED_INDEXED_GET)
365+
) ? 1 : 0
366+
);
367+
}
353368
case BuiltinSymbols.isFunction: { // isFunction<T!> / isFunction<T?>(value: T) -> bool
354369
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
355370
compiler.currentType = Type.bool;

std/assembly/builtins.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
@builtin export declare function isReference<T>(value?: T): bool;
1010
@builtin export declare function isString<T>(value?: T): bool;
1111
@builtin export declare function isArray<T>(value?: T): bool;
12+
@builtin export declare function isArrayLike<T>(value?: T): bool;
1213
@builtin export declare function isFunction<T>(value?: T): bool;
1314
@builtin export declare function isNullable<T>(value?: T): bool;
1415
@builtin export declare function isDefined(expression: void): bool;

std/assembly/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ declare function isReference<T>(value?: any): value is object | string;
128128
declare function isString<T>(value?: any): value is string | String;
129129
/** Tests if the specified type *or* expression can be used as an array. Compiles to a constant. */
130130
declare function isArray<T>(value?: any): value is Array<any>;
131+
/** Tests if the specified type *or* expression can be used as an array like object. Compiles to a constant. */
132+
declare function isArrayLike<T>(value?: any): value is ArrayLike<any>;
131133
/** Tests if the specified type *or* expression is of a function type. Compiles to a constant. */
132134
declare function isFunction<T>(value?: any): value is (...args: any) => any;
133135
/** Tests if the specified type *or* expression is of a nullable reference type. Compiles to a constant. */
@@ -559,6 +561,11 @@ declare class DataView {
559561
toString(): string;
560562
}
561563

564+
interface ArrayLike<T> {
565+
length: i32;
566+
// [key: number]: T;
567+
}
568+
562569
/** Interface for a typed view on an array buffer. */
563570
interface ArrayBufferView<T> {
564571
[key: number]: T;

std/portable/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ declare function isReference(value: any): value is object | string;
106106
declare function isString(value: any): value is string | String;
107107
/** Tests if the specified value can be used as an array. */
108108
declare function isArray(value: any): value is Array<any>;
109+
/** Tests if the specified type *or* expression can be used as an array like object. Compiles to a constant. */
110+
declare function isArrayLike(value: any): value is ArrayLike<any>;
109111
/** Tests if the specified expression resolves to a defined element. */
110112
declare function isDefined(expression: any): bool;
111113
/** Tests if the specified expression evaluates to a constant value. */
@@ -411,6 +413,11 @@ declare class Int32Array extends Array<i32> {}
411413
declare class Float32Array extends Array<f32> {}
412414
declare class Float64Array extends Array<f64> {}
413415

416+
interface ArrayLike<T> {
417+
length: i32;
418+
[key: number]: T;
419+
}
420+
414421
/** Interface for a typed view on an array buffer. */
415422
interface ArrayBufferView<T> {
416423
[key: number]: T;

std/portable/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ globalScope["isString"] = function isString(arg) {
215215
};
216216

217217
globalScope["isArray"] = Array.isArray;
218+
globalScope["isArrayLike"] = function isArrayLike(expr) {
219+
return expr
220+
&& typeof expr === 'object'
221+
&& typeof expr.length === 'number'
222+
&& expr.length >= 0
223+
&& Math.trunc(expr.length) === expr.length;
224+
}
218225

219226
globalScope["isDefined"] = function isDefined(expr) {
220227
return typeof expr !== "undefined";

tests/compiler/builtins.optimized.wat

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
if
4444
i32.const 0
4545
i32.const 8
46-
i32.const 59
46+
i32.const 66
4747
i32.const 19
4848
call $~lib/env/abort
4949
unreachable
@@ -56,7 +56,7 @@
5656
if
5757
i32.const 0
5858
i32.const 8
59-
i32.const 60
59+
i32.const 67
6060
i32.const 20
6161
call $~lib/env/abort
6262
unreachable
@@ -69,7 +69,7 @@
6969
if
7070
i32.const 0
7171
i32.const 8
72-
i32.const 61
72+
i32.const 68
7373
i32.const 20
7474
call $~lib/env/abort
7575
unreachable
@@ -92,7 +92,7 @@
9292
if
9393
i32.const 0
9494
i32.const 8
95-
i32.const 77
95+
i32.const 84
9696
i32.const 19
9797
call $~lib/env/abort
9898
unreachable
@@ -105,7 +105,7 @@
105105
if
106106
i32.const 0
107107
i32.const 8
108-
i32.const 78
108+
i32.const 85
109109
i32.const 20
110110
call $~lib/env/abort
111111
unreachable
@@ -118,7 +118,7 @@
118118
if
119119
i32.const 0
120120
i32.const 8
121-
i32.const 79
121+
i32.const 86
122122
i32.const 20
123123
call $~lib/env/abort
124124
unreachable

tests/compiler/builtins.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ assert(isReference<string>());
1111
assert(!isReference<usize>());
1212
assert(isArray<i32[]>());
1313
assert(!isArray<usize>());
14+
assert(isArrayLike<i32[]>());
15+
assert(isArrayLike<string>());
16+
assert(isArrayLike<Uint8Array>());
17+
assert(!isArrayLike<i32>());
1418
assert(isFunction<() => void>());
1519
assert(!isFunction<u32>());
1620
assert(isNullable<C | null>());
@@ -25,6 +29,9 @@ assert(!isReference(changetype<usize>(null)));
2529
assert(isString("1"));
2630
assert(!isString(1));
2731
assert(isArray(changetype<i32[]>(null)));
32+
assert(isArrayLike(changetype<i32[]>(null)));
33+
assert(isArrayLike(changetype<string>(null)));
34+
assert(isArrayLike(changetype<Uint8Array>(null)));
2835
assert(!isArray(changetype<usize>(null)));
2936
assert(isFunction(changetype<() => void>(null)));
3037
assert(!isFunction(changetype<u32>(null)));

0 commit comments

Comments
 (0)