mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Add built-in valueof type
This commit is contained in:
parent
a4e5857f7f
commit
8571df939f
@ -134,6 +134,7 @@ export namespace CommonSymbols {
|
||||
export const boolean = "boolean";
|
||||
export const string = "string";
|
||||
export const native = "native";
|
||||
export const valueof = "valueof";
|
||||
// aliases
|
||||
export const null_ = "null";
|
||||
export const true_ = "true";
|
||||
|
@ -567,6 +567,12 @@ export class Program extends DiagnosticEmitter {
|
||||
this.makeNativeTypeDeclaration(CommonSymbols.native, CommonFlags.EXPORT | CommonFlags.GENERIC),
|
||||
DecoratorFlags.BUILTIN
|
||||
));
|
||||
this.nativeFile.add(CommonSymbols.valueof, new TypeDefinition(
|
||||
CommonSymbols.valueof,
|
||||
this.nativeFile,
|
||||
this.makeNativeTypeDeclaration(CommonSymbols.valueof, CommonFlags.EXPORT | CommonFlags.GENERIC),
|
||||
DecoratorFlags.BUILTIN
|
||||
));
|
||||
if (options.hasFeature(Feature.SIMD)) this.registerNativeType(CommonSymbols.v128, Type.v128);
|
||||
|
||||
// register compiler hints
|
||||
|
150
src/resolver.ts
150
src/resolver.ts
@ -212,10 +212,10 @@ export class Resolver extends DiagnosticEmitter {
|
||||
var typeNode = <TypeNode>node;
|
||||
var typeName = typeNode.name;
|
||||
var typeArgumentNodes = typeNode.typeArguments;
|
||||
var possiblyPlaceholder = !typeName.next;
|
||||
var isSimpleType = !typeName.next;
|
||||
|
||||
// look up in contextual type arguments if possibly a placeholder
|
||||
if (possiblyPlaceholder) {
|
||||
// look up in contextual type arguments if a simple type
|
||||
if (isSimpleType) {
|
||||
if (contextualTypeArguments && contextualTypeArguments.has(typeName.identifier.text)) {
|
||||
let type = contextualTypeArguments.get(typeName.identifier.text)!;
|
||||
if (typeArgumentNodes !== null && typeArgumentNodes.length) {
|
||||
@ -314,41 +314,11 @@ export class Resolver extends DiagnosticEmitter {
|
||||
return type;
|
||||
}
|
||||
|
||||
// handle special native type
|
||||
if (possiblyPlaceholder && typeName.identifier.text == CommonSymbols.native) {
|
||||
if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) {
|
||||
if (reportMode == ReportMode.REPORT) {
|
||||
this.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
typeNode.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
let typeArgument = this.resolveType(
|
||||
typeArgumentNodes[0],
|
||||
context,
|
||||
contextualTypeArguments,
|
||||
reportMode
|
||||
);
|
||||
if (!typeArgument) return null;
|
||||
switch (typeArgument.kind) {
|
||||
case TypeKind.I8:
|
||||
case TypeKind.I16:
|
||||
case TypeKind.I32: return Type.i32;
|
||||
case TypeKind.ISIZE: if (!this.program.options.isWasm64) return Type.i32;
|
||||
case TypeKind.I64: return Type.i64;
|
||||
case TypeKind.U8:
|
||||
case TypeKind.U16:
|
||||
case TypeKind.U32:
|
||||
case TypeKind.BOOL: return Type.u32;
|
||||
case TypeKind.USIZE: if (!this.program.options.isWasm64) return Type.u32;
|
||||
case TypeKind.U64: return Type.u64;
|
||||
case TypeKind.F32: return Type.f32;
|
||||
case TypeKind.F64: return Type.f64;
|
||||
case TypeKind.V128: return Type.v128;
|
||||
case TypeKind.VOID: return Type.void;
|
||||
default: assert(false);
|
||||
// handle built-in types
|
||||
if (isSimpleType) {
|
||||
switch (typeName.identifier.symbol) {
|
||||
case CommonSymbols.native: return this.resolveBuiltinNativeType(typeNode, context, contextualTypeArguments, reportMode);
|
||||
case CommonSymbols.valueof: return this.resolveBuiltinValueofType(typeNode, context, contextualTypeArguments, reportMode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,6 +372,110 @@ export class Resolver extends DiagnosticEmitter {
|
||||
return null;
|
||||
}
|
||||
|
||||
private resolveBuiltinNativeType(
|
||||
/** The type to resolve. */
|
||||
typeNode: TypeNode,
|
||||
/** Relative context. */
|
||||
context: Element,
|
||||
/** Type arguments inherited through context, i.e. `T`. */
|
||||
contextualTypeArguments: Map<string,Type> | null = null,
|
||||
/** How to proceed with eventualy diagnostics. */
|
||||
reportMode: ReportMode = ReportMode.REPORT
|
||||
): Type | null {
|
||||
var typeArgumentNodes = typeNode.typeArguments;
|
||||
if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) {
|
||||
if (reportMode == ReportMode.REPORT) {
|
||||
this.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
typeNode.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var typeArgument = this.resolveType(typeArgumentNodes[0], context, contextualTypeArguments, reportMode);
|
||||
if (!typeArgument) return null;
|
||||
switch (typeArgument.kind) {
|
||||
case TypeKind.I8:
|
||||
case TypeKind.I16:
|
||||
case TypeKind.I32: return Type.i32;
|
||||
case TypeKind.ISIZE: if (!this.program.options.isWasm64) return Type.i32;
|
||||
case TypeKind.I64: return Type.i64;
|
||||
case TypeKind.U8:
|
||||
case TypeKind.U16:
|
||||
case TypeKind.U32:
|
||||
case TypeKind.BOOL: return Type.u32;
|
||||
case TypeKind.USIZE: if (!this.program.options.isWasm64) return Type.u32;
|
||||
case TypeKind.U64: return Type.u64;
|
||||
case TypeKind.F32: return Type.f32;
|
||||
case TypeKind.F64: return Type.f64;
|
||||
case TypeKind.V128: return Type.v128;
|
||||
case TypeKind.VOID: return Type.void;
|
||||
default: assert(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private resolveBuiltinValueofType(
|
||||
/** The type to resolve. */
|
||||
typeNode: TypeNode,
|
||||
/** Relative context. */
|
||||
context: Element,
|
||||
/** Type arguments inherited through context, i.e. `T`. */
|
||||
contextualTypeArguments: Map<string,Type> | null = null,
|
||||
/** How to proceed with eventualy diagnostics. */
|
||||
reportMode: ReportMode = ReportMode.REPORT
|
||||
): Type | null {
|
||||
var typeArgumentNodes = typeNode.typeArguments;
|
||||
if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) {
|
||||
if (reportMode == ReportMode.REPORT) {
|
||||
this.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
typeNode.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var typeArgument = this.resolveType(typeArgumentNodes[0], context, contextualTypeArguments, reportMode);
|
||||
if (!typeArgument) return null;
|
||||
var classReference = typeArgument.classReference;
|
||||
if (!classReference) {
|
||||
if (reportMode == ReportMode.REPORT) {
|
||||
this.error(
|
||||
DiagnosticCode.Index_signature_is_missing_in_type_0,
|
||||
typeArgumentNodes[0].range, typeArgument.toString()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var program = this.program;
|
||||
var mapPrototype = program.mapPrototype;
|
||||
var setPrototype = program.setPrototype;
|
||||
var arrayPrototype = program.arrayPrototype;
|
||||
if (classReference.extends(arrayPrototype)) {
|
||||
let actualTypeArguments = assert(classReference.getTypeArgumentsTo(arrayPrototype));
|
||||
assert(actualTypeArguments.length == 1);
|
||||
return actualTypeArguments[0];
|
||||
} else if (classReference.extends(mapPrototype)) {
|
||||
let actualTypeArguments = assert(classReference.getTypeArgumentsTo(arrayPrototype));
|
||||
assert(actualTypeArguments.length == 2);
|
||||
return actualTypeArguments[1];
|
||||
} else if (classReference.extends(setPrototype)) {
|
||||
let actualTypeArguments = assert(classReference.getTypeArgumentsTo(arrayPrototype));
|
||||
assert(actualTypeArguments.length == 1);
|
||||
return actualTypeArguments[0];
|
||||
} else {
|
||||
let overload = classReference.lookupOverload(OperatorKind.INDEXED_GET);
|
||||
if (overload) return overload.signature.returnType;
|
||||
if (reportMode == ReportMode.REPORT) {
|
||||
this.error(
|
||||
DiagnosticCode.Index_signature_is_missing_in_type_0,
|
||||
typeArgumentNodes[0].range, typeArgument.toString()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolves a type name to the program element it refers to. */
|
||||
resolveTypeName(
|
||||
/** The type name to resolve. */
|
||||
|
2
std/assembly/index.d.ts
vendored
2
std/assembly/index.d.ts
vendored
@ -882,6 +882,8 @@ declare namespace v8x16 {
|
||||
}
|
||||
/** Macro type evaluating to the underlying native WebAssembly type. */
|
||||
declare type native<T> = T;
|
||||
/** Special type evaluating the value type of a collection. */
|
||||
declare type valueof<T extends unknown[]> = T[0];
|
||||
|
||||
/** Pseudo-class representing the backing class of integer types. */
|
||||
declare class _Integer {
|
||||
|
@ -1068,7 +1068,7 @@ function FOREACH<TArray extends ArrayBufferView, T>(
|
||||
|
||||
// @ts-ignore: decorator
|
||||
@inline
|
||||
export function REVERSE<TArray extends ArrayBufferView, T>(array: TArray): TArray {
|
||||
function REVERSE<TArray extends ArrayBufferView, T>(array: TArray): TArray {
|
||||
var dataStart = array.dataStart;
|
||||
for (let front = 0, back = array.length - 1; front < back; ++front, --back) {
|
||||
let frontPtr = dataStart + (<usize>front << alignof<T>());
|
||||
|
3
std/portable/index.d.ts
vendored
3
std/portable/index.d.ts
vendored
@ -28,6 +28,9 @@ declare type usize = number;
|
||||
declare type f32 = number;
|
||||
declare type f64 = number;
|
||||
|
||||
/** Special type evaluating the value type of a collection. */
|
||||
declare type valueof<T extends unknown[]> = T[0];
|
||||
|
||||
// Compiler hints
|
||||
|
||||
/** Compiler target. 0 = JS, 1 = WASM32, 2 = WASM64. */
|
||||
|
5
tests/compiler/valueof.json
Normal file
5
tests/compiler/valueof.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"asc_flags": [
|
||||
"--runtime none"
|
||||
]
|
||||
}
|
9
tests/compiler/valueof.optimized.wat
Normal file
9
tests/compiler/valueof.optimized.wat
Normal file
@ -0,0 +1,9 @@
|
||||
(module
|
||||
(type $FUNCSIG$v (func))
|
||||
(memory $0 1)
|
||||
(data (i32.const 8) "\14\00\00\00\01\00\00\00\01\00\00\00\14\00\00\00v\00a\00l\00u\00e\00o\00f\00.\00t\00s")
|
||||
(export "memory" (memory $0))
|
||||
(func $start (; 0 ;) (type $FUNCSIG$v)
|
||||
nop
|
||||
)
|
||||
)
|
26
tests/compiler/valueof.ts
Normal file
26
tests/compiler/valueof.ts
Normal file
@ -0,0 +1,26 @@
|
||||
// simple
|
||||
assert(isInteger<valueof<i8[]>>());
|
||||
assert(isSigned<valueof<i8[]>>());
|
||||
assert(sizeof<valueof<i8[]>>() == 1);
|
||||
|
||||
// alias
|
||||
type u32Array = u32[];
|
||||
assert(isInteger<valueof<u32Array>>());
|
||||
assert(!isSigned<valueof<u32Array>>());
|
||||
assert(sizeof<valueof<u32Array>>() == 4);
|
||||
|
||||
// float
|
||||
assert(isFloat<valueof<f32[]>>());
|
||||
assert(sizeof<valueof<f32[]>>() == 4);
|
||||
|
||||
// string
|
||||
assert(isString<valueof<string[]>>());
|
||||
assert(isManaged<valueof<string[]>>());
|
||||
|
||||
// array
|
||||
assert(isArray<valueof<string[][]>>());
|
||||
|
||||
// typed array
|
||||
assert(isInteger<valueof<Uint8ClampedArray>>());
|
||||
assert(!isSigned<valueof<Uint8ClampedArray>>());
|
||||
assert(sizeof<valueof<Uint8ClampedArray>>() == 1);
|
168
tests/compiler/valueof.untouched.wat
Normal file
168
tests/compiler/valueof.untouched.wat
Normal file
@ -0,0 +1,168 @@
|
||||
(module
|
||||
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
|
||||
(type $FUNCSIG$v (func))
|
||||
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
|
||||
(memory $0 1)
|
||||
(data (i32.const 8) "\14\00\00\00\01\00\00\00\01\00\00\00\14\00\00\00v\00a\00l\00u\00e\00o\00f\00.\00t\00s\00")
|
||||
(table $0 1 funcref)
|
||||
(elem (i32.const 0) $null)
|
||||
(export "memory" (memory $0))
|
||||
(start $start)
|
||||
(func $start:valueof (; 1 ;) (type $FUNCSIG$v)
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 3
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.const 1
|
||||
i32.eq
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 4
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 8
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 0
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 9
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 4
|
||||
i32.const 4
|
||||
i32.eq
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 10
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 13
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 4
|
||||
i32.const 4
|
||||
i32.eq
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 14
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 17
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 18
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 21
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 24
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 0
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 25
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 1
|
||||
i32.const 1
|
||||
i32.eq
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 26
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
)
|
||||
(func $start (; 2 ;) (type $FUNCSIG$v)
|
||||
call $start:valueof
|
||||
)
|
||||
(func $null (; 3 ;) (type $FUNCSIG$v)
|
||||
)
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user