mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 07:02:13 +00:00
Implement explicit this type (#373)
* Add backing classes for basic types (I32...) * Move standard numeric constants to backing classes
This commit is contained in:
parent
d5f72e32d7
commit
f714afab3c
@ -153,7 +153,12 @@ export function compileCall(
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let element = compiler.resolver.resolveExpression(operands[0], compiler.currentFunction, ReportMode.SWALLOW);
|
||||
let element = compiler.resolver.resolveExpression(
|
||||
operands[0],
|
||||
compiler.currentFunction,
|
||||
Type.void,
|
||||
ReportMode.SWALLOW
|
||||
);
|
||||
return module.createI32(element ? 1 : 0);
|
||||
}
|
||||
case "isConstant": { // isConstant(expression) -> bool
|
||||
|
131
src/compiler.ts
131
src/compiler.ts
@ -5421,33 +5421,22 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (thisArg) {
|
||||
let parent = assert(instance.parent);
|
||||
assert(parent.kind == ElementKind.CLASS);
|
||||
if (getExpressionId(thisArg) == ExpressionId.GetLocal) {
|
||||
flow.addScopedLocalAlias(
|
||||
getGetLocalIndex(thisArg),
|
||||
(<Class>parent).type,
|
||||
"this"
|
||||
);
|
||||
let parentBase = (<Class>parent).base;
|
||||
if (parentBase) {
|
||||
flow.addScopedLocalAlias(
|
||||
getGetLocalIndex(thisArg),
|
||||
parentBase.type,
|
||||
"super"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let thisLocal = flow.addScopedLocal((<Class>parent).type, "this", false);
|
||||
let thisType = assert(instance.signature.thisType);
|
||||
let classType = thisType.classReference;
|
||||
let superType = classType
|
||||
? classType.base
|
||||
? classType.base.type
|
||||
: null
|
||||
: null;
|
||||
if (getExpressionId(thisArg) == ExpressionId.GetLocal) { // reuse this var
|
||||
flow.addScopedLocalAlias(getGetLocalIndex(thisArg), thisType, "this");
|
||||
if (superType) flow.addScopedLocalAlias(getGetLocalIndex(thisArg), superType, "super");
|
||||
} else { // use a temp var
|
||||
let thisLocal = flow.addScopedLocal(thisType, "this", false);
|
||||
body.push(
|
||||
module.createSetLocal(thisLocal.index, thisArg)
|
||||
);
|
||||
let parentBase = (<Class>parent).base;
|
||||
if (parentBase) {
|
||||
flow.addScopedLocalAlias(
|
||||
thisLocal.index,
|
||||
parentBase.type,
|
||||
"super"
|
||||
);
|
||||
}
|
||||
if (superType) flow.addScopedLocalAlias(thisLocal.index, superType, "super");
|
||||
}
|
||||
}
|
||||
var parameterTypes = signature.parameterTypes;
|
||||
@ -5895,7 +5884,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef {
|
||||
var target = this.resolver.resolveElementAccess(expression, this.currentFunction); // reports
|
||||
var target = this.resolver.resolveElementAccess(expression, this.currentFunction, contextualType); // reports
|
||||
if (!target) return this.module.createUnreachable();
|
||||
switch (target.kind) {
|
||||
case ElementKind.CLASS: {
|
||||
@ -6003,7 +5992,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (currentFunction.is(CommonFlags.INSTANCE)) {
|
||||
let parent = assert(currentFunction.parent);
|
||||
assert(parent.kind == ElementKind.CLASS);
|
||||
let thisType = (<Class>parent).type;
|
||||
let thisType = assert(currentFunction.signature.thisType);
|
||||
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
|
||||
if (!flow.is(FlowFlags.ALLOCATES)) {
|
||||
flow.set(FlowFlags.ALLOCATES);
|
||||
@ -6194,84 +6183,16 @@ export class Compiler extends DiagnosticEmitter {
|
||||
intValue
|
||||
);
|
||||
}
|
||||
switch (contextualType.kind) {
|
||||
|
||||
// compile to contextualType if matching
|
||||
|
||||
case TypeKind.I8: {
|
||||
if (i64_is_i8(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.U8: {
|
||||
if (i64_is_u8(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.I16: {
|
||||
if (i64_is_i16(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.U16: {
|
||||
if (i64_is_u16(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.I32: {
|
||||
if (i64_is_i32(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.U32: {
|
||||
if (i64_is_u32(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.BOOL: {
|
||||
if (i64_is_bool(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.ISIZE: {
|
||||
if (!this.options.isWasm64) {
|
||||
if (i64_is_i32(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
return module.createI64(i64_low(intValue), i64_high(intValue));
|
||||
}
|
||||
case TypeKind.USIZE: {
|
||||
if (!this.options.isWasm64) {
|
||||
if (i64_is_u32(intValue)) return module.createI32(i64_low(intValue));
|
||||
break;
|
||||
}
|
||||
return module.createI64(i64_low(intValue), i64_high(intValue));
|
||||
}
|
||||
case TypeKind.I64:
|
||||
case TypeKind.U64: {
|
||||
return module.createI64(i64_low(intValue), i64_high(intValue));
|
||||
}
|
||||
case TypeKind.F32: {
|
||||
if (i64_is_f32(intValue)) return module.createF32(i64_to_f32(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.F64: {
|
||||
if (i64_is_f64(intValue)) return module.createF64(i64_to_f64(intValue));
|
||||
break;
|
||||
}
|
||||
case TypeKind.VOID: {
|
||||
break; // compiles to best fitting type below, being dropped
|
||||
}
|
||||
default: {
|
||||
assert(false);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise compile to best fitting native type
|
||||
|
||||
if (i64_is_i32(intValue)) {
|
||||
this.currentType = Type.i32;
|
||||
return module.createI32(i64_low(intValue));
|
||||
} else if (i64_is_u32(intValue)) {
|
||||
this.currentType = Type.u32;
|
||||
return module.createI32(i64_low(intValue));
|
||||
} else {
|
||||
this.currentType = Type.i64;
|
||||
return module.createI64(i64_low(intValue), i64_high(intValue));
|
||||
let type = this.resolver.determineIntegerLiteralType(intValue, contextualType);
|
||||
this.currentType = type;
|
||||
switch (type.kind) {
|
||||
case TypeKind.ISIZE: if (!this.options.isWasm64) return module.createI32(i64_low(intValue));
|
||||
case TypeKind.I64: return module.createI64(i64_low(intValue), i64_high(intValue));
|
||||
case TypeKind.USIZE: if (!this.options.isWasm64) return module.createI32(i64_low(intValue));
|
||||
case TypeKind.U64: return module.createI64(i64_low(intValue), i64_high(intValue));
|
||||
case TypeKind.F32: return module.createF32(i64_to_f32(intValue));
|
||||
case TypeKind.F64: return module.createF64(i64_to_f64(intValue));
|
||||
default: return module.createI32(i64_low(intValue));
|
||||
}
|
||||
}
|
||||
case LiteralKind.STRING: {
|
||||
@ -6749,7 +6670,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
): ExpressionRef {
|
||||
var module = this.module;
|
||||
|
||||
var target = this.resolver.resolvePropertyAccess(propertyAccess, this.currentFunction); // reports
|
||||
var target = this.resolver.resolvePropertyAccess(propertyAccess, this.currentFunction, contextualType); // reports
|
||||
if (!target) return module.createUnreachable();
|
||||
|
||||
switch (target.kind) {
|
||||
|
@ -328,6 +328,8 @@ export class Program extends DiagnosticEmitter {
|
||||
fileLevelExports: Map<string,Element> = new Map();
|
||||
/** Module-level exports by exported name. */
|
||||
moduleLevelExports: Map<string,ModuleExport> = new Map();
|
||||
/** Classes backing basic types like `i32`. */
|
||||
basicClasses: Map<TypeKind,Class> = new Map();
|
||||
|
||||
/** ArrayBuffer instance reference. */
|
||||
arrayBufferInstance: Class | null = null;
|
||||
@ -641,6 +643,21 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// register classes backing basic types
|
||||
this.registerBasicClass(TypeKind.I8, "I8");
|
||||
this.registerBasicClass(TypeKind.I16, "I16");
|
||||
this.registerBasicClass(TypeKind.I32, "I32");
|
||||
this.registerBasicClass(TypeKind.I64, "I64");
|
||||
this.registerBasicClass(TypeKind.ISIZE, "Isize");
|
||||
this.registerBasicClass(TypeKind.U8, "U8");
|
||||
this.registerBasicClass(TypeKind.U16, "U16");
|
||||
this.registerBasicClass(TypeKind.U32, "U32");
|
||||
this.registerBasicClass(TypeKind.U64, "U64");
|
||||
this.registerBasicClass(TypeKind.USIZE, "Usize");
|
||||
this.registerBasicClass(TypeKind.BOOL, "Bool");
|
||||
this.registerBasicClass(TypeKind.F32, "F32");
|
||||
this.registerBasicClass(TypeKind.F64, "F64");
|
||||
|
||||
// register 'start'
|
||||
{
|
||||
let element = assert(this.elementsLookup.get("start"));
|
||||
@ -727,6 +744,15 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
private registerBasicClass(typeKind: TypeKind, className: string): void {
|
||||
if (this.elementsLookup.has(className)) {
|
||||
let element = assert(this.elementsLookup.get(className));
|
||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||
let classElement = this.resolver.resolveClass(<ClassPrototype>element, null);
|
||||
if (classElement) this.basicClasses.set(typeKind, classElement);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a constant integer value. */
|
||||
setConstantInteger(globalName: string, type: Type, value: I64): void {
|
||||
assert(type.is(TypeFlags.INTEGER));
|
||||
|
218
src/resolver.ts
218
src/resolver.ts
@ -45,14 +45,18 @@ import {
|
||||
LiteralKind,
|
||||
ParenthesizedExpression,
|
||||
AssertionExpression,
|
||||
Expression
|
||||
Expression,
|
||||
IntegerLiteralExpression,
|
||||
UnaryPrefixExpression,
|
||||
UnaryPostfixExpression
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
Type,
|
||||
Signature,
|
||||
typesToString,
|
||||
TypeKind
|
||||
TypeKind,
|
||||
TypeFlags
|
||||
} from "./types";
|
||||
|
||||
import {
|
||||
@ -65,6 +69,10 @@ import {
|
||||
makeMap
|
||||
} from "./util";
|
||||
|
||||
import {
|
||||
Token
|
||||
} from "./tokenizer";
|
||||
|
||||
/** Indicates whether errors are reported or not. */
|
||||
export enum ReportMode {
|
||||
/** Report errors. */
|
||||
@ -83,8 +91,6 @@ export class Resolver extends DiagnosticEmitter {
|
||||
currentThisExpression: Expression | null = null;
|
||||
/** Element expression of the previously resolved element access. */
|
||||
currentElementExpression : Expression | null = null;
|
||||
/** Whether the last resolved type has been resolved from a placeholder, i.e. `T`. */
|
||||
currentTypeIsPlaceholder: bool = false;
|
||||
|
||||
/** Constructs the resolver for the specified program. */
|
||||
constructor(program: Program) {
|
||||
@ -419,11 +425,12 @@ export class Resolver extends DiagnosticEmitter {
|
||||
resolvePropertyAccess(
|
||||
propertyAccess: PropertyAccessExpression,
|
||||
contextualFunction: Function,
|
||||
contextualType: Type,
|
||||
reportMode: ReportMode = ReportMode.REPORT
|
||||
): Element | null {
|
||||
// start by resolving the lhs target (expression before the last dot)
|
||||
var targetExpression = propertyAccess.expression;
|
||||
var target = this.resolveExpression(targetExpression, contextualFunction, reportMode); // reports
|
||||
var target = this.resolveExpression(targetExpression, contextualFunction, contextualType, reportMode); // reports
|
||||
if (!target) return null;
|
||||
|
||||
// at this point we know exactly what the target is, so look up the element within
|
||||
@ -438,11 +445,16 @@ export class Resolver extends DiagnosticEmitter {
|
||||
assert(type != Type.void);
|
||||
let classReference = type.classReference;
|
||||
if (!classReference) {
|
||||
this.error(
|
||||
DiagnosticCode.Property_0_does_not_exist_on_type_1,
|
||||
propertyAccess.property.range, propertyName, (<VariableLikeElement>target).type.toString()
|
||||
);
|
||||
return null;
|
||||
let basicClasses = this.program.basicClasses;
|
||||
if (!type.is(TypeFlags.REFERENCE) && basicClasses.has(type.kind)) {
|
||||
classReference = assert(basicClasses.get(type.kind));
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Property_0_does_not_exist_on_type_1,
|
||||
propertyAccess.property.range, propertyName, (<VariableLikeElement>target).type.toString()
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
target = classReference;
|
||||
break;
|
||||
@ -545,10 +557,11 @@ export class Resolver extends DiagnosticEmitter {
|
||||
resolveElementAccess(
|
||||
elementAccess: ElementAccessExpression,
|
||||
contextualFunction: Function,
|
||||
contextualType: Type,
|
||||
reportMode: ReportMode = ReportMode.REPORT
|
||||
): Element | null {
|
||||
var targetExpression = elementAccess.expression;
|
||||
var target = this.resolveExpression(targetExpression, contextualFunction, reportMode);
|
||||
var target = this.resolveExpression(targetExpression, contextualFunction, contextualType, reportMode);
|
||||
if (!target) return null;
|
||||
switch (target.kind) {
|
||||
case ElementKind.GLOBAL: if (!this.ensureResolvedLazyGlobal(<Global>target, reportMode)) return null;
|
||||
@ -596,9 +609,75 @@ export class Resolver extends DiagnosticEmitter {
|
||||
return null;
|
||||
}
|
||||
|
||||
determineIntegerLiteralType(
|
||||
intValue: I64,
|
||||
contextualType: Type
|
||||
): Type {
|
||||
|
||||
if (!contextualType.is(TypeFlags.REFERENCE)) {
|
||||
// compile to contextualType if matching
|
||||
switch (contextualType.kind) {
|
||||
case TypeKind.I8: {
|
||||
if (i64_is_i8(intValue)) return Type.i8;
|
||||
break;
|
||||
}
|
||||
case TypeKind.U8: {
|
||||
if (i64_is_u8(intValue)) return Type.u8;
|
||||
break;
|
||||
}
|
||||
case TypeKind.I16: {
|
||||
if (i64_is_i16(intValue)) return Type.i16;
|
||||
break;
|
||||
}
|
||||
case TypeKind.U16: {
|
||||
if (i64_is_u16(intValue)) return Type.u16;
|
||||
break;
|
||||
}
|
||||
case TypeKind.I32: {
|
||||
if (i64_is_i32(intValue)) return Type.i32;
|
||||
break;
|
||||
}
|
||||
case TypeKind.U32: {
|
||||
if (i64_is_u32(intValue)) return Type.u32;
|
||||
break;
|
||||
}
|
||||
case TypeKind.BOOL: {
|
||||
if (i64_is_bool(intValue)) return Type.bool;
|
||||
break;
|
||||
}
|
||||
case TypeKind.ISIZE: {
|
||||
if (!this.program.options.isWasm64) {
|
||||
if (i64_is_i32(intValue)) return Type.isize32;
|
||||
break;
|
||||
}
|
||||
return Type.isize64;
|
||||
}
|
||||
case TypeKind.USIZE: {
|
||||
if (!this.program.options.isWasm64) {
|
||||
if (i64_is_u32(intValue)) return Type.usize32;
|
||||
break;
|
||||
}
|
||||
return Type.usize64;
|
||||
}
|
||||
case TypeKind.I64: return Type.i64;
|
||||
case TypeKind.U64: return Type.u64;
|
||||
case TypeKind.F32: return Type.f32;
|
||||
case TypeKind.F64: return Type.f64;
|
||||
case TypeKind.VOID: break; // best fitting below
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise compile to best fitting native type
|
||||
if (i64_is_i32(intValue)) return Type.i32;
|
||||
if (i64_is_u32(intValue)) return Type.u32;
|
||||
return Type.i64;
|
||||
}
|
||||
|
||||
resolveExpression(
|
||||
expression: Expression,
|
||||
contextualFunction: Function,
|
||||
contextualType: Type = Type.void,
|
||||
reportMode: ReportMode = ReportMode.REPORT
|
||||
): Element | null {
|
||||
while (expression.kind == NodeKind.PARENTHESIZED) {
|
||||
@ -611,17 +690,80 @@ export class Resolver extends DiagnosticEmitter {
|
||||
contextualFunction.flow.contextualTypeArguments,
|
||||
reportMode
|
||||
);
|
||||
if (type) {
|
||||
let classType = type.classReference;
|
||||
if (classType) {
|
||||
this.currentThisExpression = null;
|
||||
this.currentElementExpression = null;
|
||||
return classType;
|
||||
if (!type) return null;
|
||||
let classType = type.classReference;
|
||||
if (!classType) return null;
|
||||
this.currentThisExpression = null;
|
||||
this.currentElementExpression = null;
|
||||
return classType;
|
||||
}
|
||||
case NodeKind.UNARYPREFIX: {
|
||||
// TODO: overloads
|
||||
switch ((<UnaryPrefixExpression>expression).operator) {
|
||||
case Token.MINUS: {
|
||||
let operand = (<UnaryPrefixExpression>expression).operand;
|
||||
// implicitly negate if an integer literal to distinguish between i32/u32/i64
|
||||
if (operand.kind == NodeKind.LITERAL && (<LiteralExpression>operand).literalKind == LiteralKind.INTEGER) {
|
||||
let type = this.determineIntegerLiteralType(
|
||||
i64_sub(i64_zero, (<IntegerLiteralExpression>operand).value),
|
||||
contextualType
|
||||
);
|
||||
return assert(this.program.basicClasses.get(type.kind));
|
||||
}
|
||||
return this.resolveExpression(
|
||||
operand,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
}
|
||||
case Token.PLUS:
|
||||
case Token.PLUS_PLUS:
|
||||
case Token.MINUS_MINUS: {
|
||||
return this.resolveExpression(
|
||||
(<UnaryPrefixExpression>expression).operand,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
}
|
||||
case Token.EXCLAMATION: {
|
||||
return assert(this.program.basicClasses.get(TypeKind.BOOL));
|
||||
}
|
||||
case Token.TILDE: {
|
||||
let resolvedOperand = this.resolveExpression(
|
||||
(<UnaryPrefixExpression>expression).operand,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
if (!resolvedOperand) return null;
|
||||
throw new Error("not implemented"); // TODO: should all elements have a corresponding type right away?
|
||||
}
|
||||
default: assert(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case NodeKind.BINARY: { // TODO: string concatenation, mostly
|
||||
case NodeKind.UNARYPOSTFIX: {
|
||||
// TODO: overloads
|
||||
switch ((<UnaryPostfixExpression>expression).operator) {
|
||||
case Token.PLUS_PLUS:
|
||||
case Token.MINUS_MINUS: {
|
||||
return this.resolveExpression(
|
||||
(<UnaryPostfixExpression>expression).operand,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
}
|
||||
default: assert(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case NodeKind.BINARY: {
|
||||
// TODO: all sorts of unary and binary expressions, which means looking up overloads and
|
||||
// evaluating their return types, knowing the semantics of different operators etc.
|
||||
// should probably share that code with the compiler somehow, as it also does exactly this.
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
case NodeKind.THIS: { // -> Class / ClassPrototype
|
||||
@ -675,6 +817,27 @@ export class Resolver extends DiagnosticEmitter {
|
||||
}
|
||||
case NodeKind.LITERAL: {
|
||||
switch ((<LiteralExpression>expression).literalKind) {
|
||||
case LiteralKind.INTEGER: {
|
||||
return assert(
|
||||
this.program.basicClasses.get(
|
||||
this.determineIntegerLiteralType(
|
||||
(<IntegerLiteralExpression>expression).value,
|
||||
contextualType
|
||||
).kind
|
||||
)
|
||||
);
|
||||
}
|
||||
case LiteralKind.FLOAT: {
|
||||
this.currentThisExpression = expression;
|
||||
this.currentElementExpression = null;
|
||||
return assert(
|
||||
this.program.basicClasses.get(
|
||||
contextualType == Type.f32
|
||||
? TypeKind.F32
|
||||
: TypeKind.F64
|
||||
)
|
||||
);
|
||||
}
|
||||
case LiteralKind.STRING: {
|
||||
this.currentThisExpression = expression;
|
||||
this.currentElementExpression = null;
|
||||
@ -688,6 +851,7 @@ export class Resolver extends DiagnosticEmitter {
|
||||
return this.resolvePropertyAccess(
|
||||
<PropertyAccessExpression>expression,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
}
|
||||
@ -695,12 +859,13 @@ export class Resolver extends DiagnosticEmitter {
|
||||
return this.resolveElementAccess(
|
||||
<ElementAccessExpression>expression,
|
||||
contextualFunction,
|
||||
contextualType,
|
||||
reportMode
|
||||
);
|
||||
}
|
||||
case NodeKind.CALL: {
|
||||
let targetExpression = (<CallExpression>expression).expression;
|
||||
let target = this.resolveExpression(targetExpression, contextualFunction, reportMode);
|
||||
let target = this.resolveExpression(targetExpression, contextualFunction, contextualType, reportMode);
|
||||
if (!target) return null;
|
||||
if (target.kind == ElementKind.FUNCTION_PROTOTYPE) {
|
||||
let instance = this.resolveFunctionInclTypeArguments(
|
||||
@ -800,8 +965,21 @@ export class Resolver extends DiagnosticEmitter {
|
||||
reportMode
|
||||
);
|
||||
if (!classInstance) return null;
|
||||
thisType = classInstance.type;
|
||||
let explicitThisType = signatureNode.explicitThisType;
|
||||
if (explicitThisType) {
|
||||
thisType = this.resolveType(explicitThisType, contextualTypeArguments, reportMode);
|
||||
if (!thisType) return null;
|
||||
} else {
|
||||
thisType = classInstance.type;
|
||||
}
|
||||
contextualTypeArguments.set("this", thisType);
|
||||
} else {
|
||||
if (signatureNode.explicitThisType) {
|
||||
this.error(
|
||||
DiagnosticCode._this_cannot_be_referenced_in_current_location,
|
||||
signatureNode.explicitThisType.range
|
||||
); // recoverable
|
||||
}
|
||||
}
|
||||
|
||||
// resolve signature node
|
||||
|
@ -47,16 +47,12 @@
|
||||
export namespace i8 {
|
||||
export const MIN_VALUE: i8 = -128;
|
||||
export const MAX_VALUE: i8 = 127;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): i8 { return <i8>parseI32(value, radix) }
|
||||
@inline export function parseFloat(value: string): i8 { return <i8>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function i16(value: void): i16;
|
||||
export namespace i16 {
|
||||
export const MIN_VALUE: i16 = -32768;
|
||||
export const MAX_VALUE: i16 = 32767;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): i16 { return <i16>parseI32(value, radix) }
|
||||
@inline export function parseFloat(value: string): i16 { return <i16>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function i32(value: void): i32;
|
||||
@ -77,8 +73,6 @@ export namespace i32 {
|
||||
@builtin export declare function store8(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function store16(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function store(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): i32 { return <i32>parseI32(value, radix) }
|
||||
@inline export function parseFloat(value: string): i32 { return <i32>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function i64(value: void): i64;
|
||||
@ -102,8 +96,6 @@ export namespace i64 {
|
||||
@builtin export declare function store16(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function store32(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function store(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): i64 { return <i64>parseI64(value, radix) }
|
||||
@inline export function parseFloat(value: string): i64 { return <i64>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function isize(value: void): isize;
|
||||
@ -114,40 +106,30 @@ export namespace isize {
|
||||
export const MAX_VALUE: isize = sizeof<i32>() == sizeof<isize>()
|
||||
? 2147483647
|
||||
: <isize>9223372036854775807;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): isize { return <isize>parseI64(value, radix) }
|
||||
@inline export function parseFloat(value: string): isize { return <isize>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function u8(value: void): u8;
|
||||
export namespace u8 {
|
||||
export const MIN_VALUE: u8 = 0;
|
||||
export const MAX_VALUE: u8 = 255;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): u8 { return <u8>parseI32(value, radix) }
|
||||
@inline export function parseFloat(value: string): u8 { return <u8>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function u16(value: void): u16;
|
||||
export namespace u16 {
|
||||
export const MIN_VALUE: u16 = 0;
|
||||
export const MAX_VALUE: u16 = 65535;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): u16 { return <u16>parseI32(value, radix) }
|
||||
@inline export function parseFloat(value: string): u16 { return <u16>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function u32(value: void): u32;
|
||||
export namespace u32 {
|
||||
export const MIN_VALUE: u32 = 0;
|
||||
export const MAX_VALUE: u32 = 4294967295;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): u32 { return <u32>parseI32(value, radix) }
|
||||
@inline export function parseFloat(value: string): u32 { return <u32>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function u64(value: void): u64;
|
||||
export namespace u64 {
|
||||
export const MIN_VALUE: u64 = 0;
|
||||
export const MAX_VALUE: u64 = 18446744073709551615;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): u64 { return <u64>parseI64(value, radix) }
|
||||
@inline export function parseFloat(value: string): u64 { return <u64>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function usize(value: void): usize;
|
||||
@ -156,8 +138,6 @@ export namespace usize {
|
||||
export const MAX_VALUE: usize = sizeof<u32>() == sizeof<usize>()
|
||||
? 4294967295
|
||||
: <usize>18446744073709551615;
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): usize { return <usize>parseI64(value, radix) }
|
||||
@inline export function parseFloat(value: string): usize { return <usize>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function bool(value: void): bool;
|
||||
@ -174,9 +154,6 @@ export namespace f32 {
|
||||
export const MIN_NORMAL_VALUE = reinterpret<f32>(0x00800000); // 0x1p-126f
|
||||
export const MIN_SAFE_INTEGER: f32 = -16777215;
|
||||
export const MAX_SAFE_INTEGER: f32 = 16777215;
|
||||
export const POSITIVE_INFINITY: f32 = Infinity;
|
||||
export const NEGATIVE_INFINITY: f32 = -Infinity;
|
||||
export const NaN: f32 = NaN;
|
||||
@builtin export declare function abs(value: f32): f32;
|
||||
@builtin export declare function ceil(value: f32): f32;
|
||||
@builtin export declare function copysign(x: f32, y: f32): f32;
|
||||
@ -189,12 +166,6 @@ export namespace f32 {
|
||||
@builtin export declare function sqrt(value: f32): f32;
|
||||
@builtin export declare function store(offset: usize, value: f32, constantOffset?: usize): void;
|
||||
@builtin export declare function trunc(value: f32): f32;
|
||||
@inline export function isNaN(value: f32): bool { return isNaN<f32>(value) }
|
||||
@inline export function isFinite(value: f32): bool { return isFinite<f32>(value) }
|
||||
@inline export function isSafeInteger(value: f32): bool { return abs<f32>(value) <= f32.MAX_SAFE_INTEGER && trunc<f32>(value) == value }
|
||||
@inline export function isInteger(value: f32): bool { return isFinite<f32>(value) && trunc<f32>(value) == value }
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): f32 { return <f32>parseI64(value, radix) }
|
||||
@inline export function parseFloat(value: string): f32 { return <f32>parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function f64(value: void): f64;
|
||||
@ -205,9 +176,6 @@ export namespace f64 {
|
||||
export const MIN_NORMAL_VALUE = reinterpret<f64>(0x0010000000000000); // 0x1p-1022
|
||||
export const MIN_SAFE_INTEGER: f64 = -9007199254740991;
|
||||
export const MAX_SAFE_INTEGER: f64 = 9007199254740991;
|
||||
export const POSITIVE_INFINITY: f64 = Infinity;
|
||||
export const NEGATIVE_INFINITY: f64 = -Infinity;
|
||||
export const NaN: f64 = NaN;
|
||||
@builtin export declare function abs(value: f64): f64;
|
||||
@builtin export declare function ceil(value: f64): f64;
|
||||
@builtin export declare function copysign(x: f64, y: f64): f64;
|
||||
@ -220,12 +188,6 @@ export namespace f64 {
|
||||
@builtin export declare function sqrt(value: f64): f64;
|
||||
@builtin export declare function store(offset: usize, value: f64, constantOffset?: usize): void;
|
||||
@builtin export declare function trunc(value: f64): f64;
|
||||
@inline export function isNaN(value: f64): bool { return isNaN<f64>(value) }
|
||||
@inline export function isFinite(value: f64): bool { return isFinite<f64>(value) }
|
||||
@inline export function isSafeInteger(value: f64): bool { return abs<f64>(value) <= f64.MAX_SAFE_INTEGER && trunc<f64>(value) == value }
|
||||
@inline export function isInteger(value: f64): bool { return isFinite<f64>(value) && trunc<f64>(value) == value }
|
||||
@inline export function parseInt(value: string, radix: i32 = 0): f64 { return <f64>parseI64(value, radix) }
|
||||
@inline export function parseFloat(value: string): f64 { return parseFloat(value) }
|
||||
}
|
||||
|
||||
@builtin export declare function start(): void;
|
||||
|
89
std/assembly/index.d.ts
vendored
89
std/assembly/index.d.ts
vendored
@ -238,7 +238,7 @@ declare namespace i64 {
|
||||
export function parseInt(string: string, radix?: i32): i64;
|
||||
}
|
||||
/** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) signed integer. */
|
||||
declare var isize: i32 | i64;
|
||||
declare var isize: typeof i32 | typeof i64;
|
||||
/** Converts any other numeric value to an 8-bit unsigned integer. */
|
||||
declare function u8(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): i8;
|
||||
declare namespace u8 {
|
||||
@ -288,7 +288,7 @@ declare namespace u64 {
|
||||
export function parseInt(string: string, radix?: i32): u64;
|
||||
}
|
||||
/** Converts any other numeric value to a 32-bit (in WASM32) respectivel 64-bit (in WASM64) unsigned integer. */
|
||||
declare var usize: u32 | u64;
|
||||
declare var usize: typeof u32 | typeof u64;
|
||||
/** Converts any other numeric value to a 1-bit unsigned integer. */
|
||||
declare function bool(value: i8 | i16 | i32 | i64 | isize | u8 | u16 | u32 | u64 | usize | bool | f32 | f64): bool;
|
||||
declare namespace bool {
|
||||
@ -330,7 +330,7 @@ declare namespace f32 {
|
||||
export function isInteger(value: f32): bool;
|
||||
/** Converts a string to a floating-point number. */
|
||||
export function parseFloat(string: string): f32;
|
||||
/** Converts A string to an integer. */
|
||||
/** Converts a string to an integer. */
|
||||
export function parseInt(string: string, radix?: i32): f32;
|
||||
}
|
||||
/** Converts any other numeric value to a 64-bit float. */
|
||||
@ -352,22 +352,81 @@ declare namespace f64 {
|
||||
export function load(offset: usize, constantOffset?: usize): f64;
|
||||
/** Stores a 64-bit float to memory. */
|
||||
export function store(offset: usize, value: f64, constantOffset?: usize): void;
|
||||
/** Returns a boolean value that indicates whether a value is the reserved value NaN (not a number). */
|
||||
export function isNaN(value: f32): bool;
|
||||
/** Returns true if passed value is finite. */
|
||||
export function isFinite(value: f32): bool;
|
||||
/** Returns true if the value passed is a safe integer. */
|
||||
export function isSafeInteger(value: f64): bool;
|
||||
/** Returns true if the value passed is an integer, false otherwise. */
|
||||
export function isInteger(value: f64): bool;
|
||||
/** Converts a string to a floating-point number. */
|
||||
export function parseFloat(string: string): f64;
|
||||
/** Converts A string to an integer. */
|
||||
export function parseInt(string: string, radix?: i32): f64;
|
||||
}
|
||||
/** Macro type evaluating to the underlying native WebAssembly type. */
|
||||
declare type NATIVE<T> = T;
|
||||
|
||||
/** Pseudo-class representing the backing class of integer types. */
|
||||
declare class _Integer {
|
||||
/** Smallest representable value. */
|
||||
static readonly MIN_VALUE: number;
|
||||
/** Largest representable value. */
|
||||
static readonly MAX_VALUE: number;
|
||||
/** Converts a string to an integer of this type. */
|
||||
static parseInt(value: string, radix?: number): number;
|
||||
/** Converts this integer to a string. */
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
/** Pseudo-class representing the backing class of floating-point types. */
|
||||
declare class _Float {
|
||||
/** Difference between 1 and the smallest representable value greater than 1. */
|
||||
static readonly EPSILON: f32 | f64;
|
||||
/** Smallest representable value. */
|
||||
static readonly MIN_VALUE: f32 | f64;
|
||||
/** Largest representable value. */
|
||||
static readonly MAX_VALUE: f32 | f64;
|
||||
/** Smallest safely representable integer value. */
|
||||
static readonly MIN_SAFE_INTEGER: f32 | f64;
|
||||
/** Largest safely representable integer value. */
|
||||
static readonly MAX_SAFE_INTEGER: f32 | f64;
|
||||
/** Value representing positive infinity. */
|
||||
static readonly POSITIVE_INFINITY: f32 | f64;
|
||||
/** Value representing negative infinity. */
|
||||
static readonly NEGATIVE_INFINITY: f32 | f64;
|
||||
/** Value representing 'not a number'. */
|
||||
static readonly NaN: f32 | f64;
|
||||
/** Returns a boolean value that indicates whether a value is the reserved value NaN (not a number). */
|
||||
static isNaN(value: f32 | f64): bool;
|
||||
/** Returns true if passed value is finite. */
|
||||
static isFinite(value: f32 | f64): bool;
|
||||
/** Returns true if the value passed is a safe integer. */
|
||||
static isSafeInteger(value: f32 | f64): bool;
|
||||
/** Returns true if the value passed is an integer, false otherwise. */
|
||||
static isInteger(value: f32 | f64): bool;
|
||||
/** Converts A string to an integer. */
|
||||
static parseInt(value: string, radix?: i32): f32 | f64;
|
||||
/** Converts a string to a floating-point number. */
|
||||
static parseFloat(value: string): f32 | f64;
|
||||
/** Converts this floating-point number to a string. */
|
||||
toString(this: f64): string;
|
||||
}
|
||||
|
||||
/** Backing class of signed 8-bit integers. */
|
||||
declare const I8: typeof _Integer;
|
||||
/** Backing class of signed 16-bit integers. */
|
||||
declare const I16: typeof _Integer;
|
||||
/** Backing class of signed 32-bit integers. */
|
||||
declare const I32: typeof _Integer;
|
||||
/** Backing class of signed 64-bit integers. */
|
||||
declare const I64: typeof _Integer;
|
||||
/** Backing class of signed size integers. */
|
||||
declare const Isize: typeof _Integer;
|
||||
/** Backing class of unsigned 8-bit integers. */
|
||||
declare const U8: typeof _Integer;
|
||||
/** Backing class of unsigned 16-bit integers. */
|
||||
declare const U16: typeof _Integer;
|
||||
/** Backing class of unsigned 32-bit integers. */
|
||||
declare const U32: typeof _Integer;
|
||||
/** Backing class of unsigned 64-bit integers. */
|
||||
declare const U64: typeof _Integer;
|
||||
/** Backing class of unsigned size integers. */
|
||||
declare const Usize: typeof _Integer;
|
||||
/** Backing class of 32-bit floating-point values. */
|
||||
declare const F32: typeof _Float;
|
||||
/** Backing class of 64-bit floating-point values. */
|
||||
declare const F64: typeof _Float;
|
||||
|
||||
// User-defined diagnostic macros
|
||||
|
||||
/** Emits a user-defined diagnostic error when encountered. */
|
||||
|
@ -1,4 +1,35 @@
|
||||
// export abstract class Iterator<T> {
|
||||
// abstract get done(): bool;
|
||||
// abstract next(): T;
|
||||
// }
|
||||
export abstract class Iterable<T> {
|
||||
// ?
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class Iterator<T> {
|
||||
|
||||
// private constructor(iterable: Iterable<T>) {
|
||||
// }
|
||||
|
||||
// TODO: these need to evaluate the classId at the respective reference in order to obtain the
|
||||
// next value, i.e. arrays work differently than maps. we'd then have:
|
||||
//
|
||||
// ╒═══════════════════ Iterator layout (32-bit) ══════════════════╕
|
||||
// 3 2 1
|
||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
|
||||
// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤
|
||||
// │ index │
|
||||
// ├─────────────────────────────────────────────────────────┬───┬─┤
|
||||
// │ reference │ 0 │D│
|
||||
// └─────────────────────────────────────────────────────────┴───┴─┘
|
||||
// D: Done flag
|
||||
|
||||
// get value(this: u64): T {
|
||||
// ?
|
||||
// }
|
||||
|
||||
// next(this: u64): Iterator<T> {
|
||||
// ?
|
||||
// }
|
||||
|
||||
done(this: u64): bool {
|
||||
return <bool>(this & 1);
|
||||
}
|
||||
}
|
||||
|
271
std/assembly/number.ts
Normal file
271
std/assembly/number.ts
Normal file
@ -0,0 +1,271 @@
|
||||
import {
|
||||
itoa,
|
||||
dtoa
|
||||
} from "./internal/number";
|
||||
|
||||
import {
|
||||
isNaN as builtin_isNaN,
|
||||
isFinite as builtin_isFinite
|
||||
} from "./builtins";
|
||||
|
||||
@sealed
|
||||
export abstract class I8 {
|
||||
|
||||
static readonly MIN_VALUE: i8 = i8.MIN_VALUE;
|
||||
static readonly MAX_VALUE: i8 = i8.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): i8 {
|
||||
return <i8>parseI32(value, radix);
|
||||
}
|
||||
|
||||
toString(this: i8): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class I16 {
|
||||
|
||||
static readonly MIN_VALUE: i16 = i16.MIN_VALUE;
|
||||
static readonly MAX_VALUE: i16 = i16.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): i16 {
|
||||
return <i16>parseI32(value, radix);
|
||||
}
|
||||
|
||||
toString(this: i16): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class I32 {
|
||||
|
||||
static readonly MIN_VALUE: i32 = i32.MIN_VALUE;
|
||||
static readonly MAX_VALUE: i32 = i32.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): i32 {
|
||||
return <i32>parseI32(value, radix);
|
||||
}
|
||||
|
||||
toString(this: i32): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class I64 {
|
||||
|
||||
static readonly MIN_VALUE: i64 = i64.MIN_VALUE;
|
||||
static readonly MAX_VALUE: i64 = i64.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): i64 {
|
||||
return <i64>parseI64(value, radix);
|
||||
}
|
||||
|
||||
toString(this: i64): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class Isize {
|
||||
|
||||
static readonly MIN_VALUE: isize = isize.MIN_VALUE;
|
||||
static readonly MAX_VALUE: isize = isize.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): isize {
|
||||
return <isize>parseI64(value, radix);
|
||||
}
|
||||
|
||||
toString(this: isize): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class U8 {
|
||||
|
||||
static readonly MIN_VALUE: u8 = u8.MIN_VALUE;
|
||||
static readonly MAX_VALUE: u8 = u8.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): u8 {
|
||||
return <u8>parseI32(value, radix);
|
||||
}
|
||||
|
||||
toString(this: u8): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class U16 {
|
||||
|
||||
static readonly MIN_VALUE: u16 = u16.MIN_VALUE;
|
||||
static readonly MAX_VALUE: u16 = u16.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): u16 {
|
||||
return <u16>parseI32(value, radix);
|
||||
}
|
||||
|
||||
toString(this: u16): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class U32 {
|
||||
|
||||
static readonly MIN_VALUE: u32 = u32.MIN_VALUE;
|
||||
static readonly MAX_VALUE: u32 = u32.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): u32 {
|
||||
return <u32>parseI32(value, radix);
|
||||
}
|
||||
|
||||
toString(this: u32): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class U64 {
|
||||
|
||||
static readonly MIN_VALUE: u64 = u64.MIN_VALUE;
|
||||
static readonly MAX_VALUE: u64 = u64.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): u64 {
|
||||
return <u64>parseI64(value, radix);
|
||||
}
|
||||
|
||||
toString(this: u64): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class Usize {
|
||||
|
||||
static readonly MIN_VALUE: usize = usize.MIN_VALUE;
|
||||
static readonly MAX_VALUE: usize = usize.MAX_VALUE;
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): usize {
|
||||
return <usize>parseI64(value, radix);
|
||||
}
|
||||
|
||||
toString(this: usize): String {
|
||||
// TODO: radix
|
||||
return itoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class Bool {
|
||||
|
||||
static readonly MIN_VALUE: bool = bool.MIN_VALUE;
|
||||
static readonly MAX_VALUE: bool = bool.MAX_VALUE;
|
||||
|
||||
toString(this: bool): String {
|
||||
// TODO: radix?
|
||||
return this ? "true" : "false";
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class Boolean extends Bool {}
|
||||
|
||||
@sealed
|
||||
export abstract class F32 {
|
||||
|
||||
static readonly EPSILON: f32 = f32.EPSILON;
|
||||
static readonly MIN_VALUE: f32 = f32.MIN_VALUE;
|
||||
static readonly MAX_VALUE: f32 = f32.MAX_VALUE;
|
||||
static readonly MIN_SAFE_INTEGER: f32 = f32.MIN_SAFE_INTEGER;
|
||||
static readonly MAX_SAFE_INTEGER: f32 = f32.MAX_SAFE_INTEGER;
|
||||
static readonly POSITIVE_INFINITY: f32 = Infinity;
|
||||
static readonly NEGATIVE_INFINITY: f32 = -Infinity;
|
||||
static readonly NaN: f32 = NaN;
|
||||
|
||||
static isNaN(value: f32): bool {
|
||||
return isNaN<f32>(value);
|
||||
}
|
||||
|
||||
static isFinite(value: f32): bool {
|
||||
return isFinite<f32>(value);
|
||||
}
|
||||
|
||||
static isSafeInteger(value: f32): bool {
|
||||
return abs<f32>(value) <= f32.MAX_SAFE_INTEGER && trunc<f32>(value) == value;
|
||||
}
|
||||
|
||||
static isInteger(value: f32): bool {
|
||||
return isFinite<f32>(value) && trunc<f32>(value) == value;
|
||||
}
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): f32 {
|
||||
return <f32>parseI64(value, radix);
|
||||
}
|
||||
|
||||
static parseFloat(value: string): f32 {
|
||||
return <f32>parseFloat(value);
|
||||
}
|
||||
|
||||
toString(this: f32): String {
|
||||
// TODO: radix
|
||||
return dtoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class F64 {
|
||||
|
||||
static readonly EPSILON: f64 = f64.EPSILON;
|
||||
static readonly MIN_VALUE: f64 = f64.MIN_VALUE;
|
||||
static readonly MAX_VALUE: f64 = f64.MAX_VALUE;
|
||||
static readonly MIN_SAFE_INTEGER: f64 = f64.MIN_SAFE_INTEGER;
|
||||
static readonly MAX_SAFE_INTEGER: f64 = f64.MAX_SAFE_INTEGER;
|
||||
static readonly POSITIVE_INFINITY: f64 = Infinity;
|
||||
static readonly NEGATIVE_INFINITY: f64 = -Infinity;
|
||||
static readonly NaN: f64 = NaN;
|
||||
|
||||
static isNaN(value: f64): bool {
|
||||
return builtin_isNaN<f64>(value);
|
||||
}
|
||||
|
||||
static isFinite(value: f64): bool {
|
||||
return builtin_isFinite<f64>(value);
|
||||
}
|
||||
|
||||
static isSafeInteger(value: f64): bool {
|
||||
return abs<f64>(value) <= f64.MAX_SAFE_INTEGER && trunc<f64>(value) == value;
|
||||
}
|
||||
|
||||
static isInteger(value: f64): bool {
|
||||
return builtin_isFinite<f64>(value) && trunc<f64>(value) == value;
|
||||
}
|
||||
|
||||
static parseInt(value: string, radix: i32 = 0): f64 {
|
||||
return <f64>parseI64(value, radix);
|
||||
}
|
||||
|
||||
static parseFloat(value: string): f64 {
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
toString(this: f64): String {
|
||||
// TODO: radix
|
||||
return dtoa(this);
|
||||
}
|
||||
}
|
||||
|
||||
@sealed
|
||||
export abstract class Number extends F64 {}
|
@ -64,10 +64,7 @@ Object.defineProperties(
|
||||
"MAX_VALUE": { value: Math.fround(3.4028235e+38), writable: false },
|
||||
"MIN_NORMAL_VALUE": { value: Math.fround(1.17549435e-38), writable: false },
|
||||
"MIN_SAFE_INTEGER": { value: -16777215, writable: false },
|
||||
"MAX_SAFE_INTEGER": { value: 16777215, writable: false },
|
||||
"POSITIVE_INFINITY": { value: Infinity, writable: false },
|
||||
"NEGATIVE_INFINITY": { value: -Infinity, writable: false },
|
||||
"NaN": { value: NaN, writable: false }
|
||||
"MAX_SAFE_INTEGER": { value: 16777215, writable: false }
|
||||
});
|
||||
|
||||
Object.defineProperties(
|
||||
@ -78,10 +75,7 @@ Object.defineProperties(
|
||||
"MAX_VALUE": { value: 1.7976931348623157e+308, writable: false },
|
||||
"MIN_NORMAL_VALUE": { value: 2.2250738585072014e-308 , writable: false },
|
||||
"MIN_SAFE_INTEGER": { value: -9007199254740991, writable: false },
|
||||
"MAX_SAFE_INTEGER": { value: 9007199254740991, writable: false },
|
||||
"POSITIVE_INFINITY": { value: Infinity, writable: false },
|
||||
"NEGATIVE_INFINITY": { value: -Infinity, writable: false },
|
||||
"NaN": { value: NaN, writable: false }
|
||||
"MAX_SAFE_INTEGER": { value: 9007199254740991, writable: false }
|
||||
});
|
||||
|
||||
globalScope["clz"] = Math.clz32;
|
||||
|
@ -314,27 +314,6 @@ assert(f32.MAX_VALUE == 3.40282347e+38);
|
||||
assert(f32.MIN_SAFE_INTEGER == -16777215);
|
||||
assert(f32.MAX_SAFE_INTEGER == 16777215);
|
||||
assert(f32.EPSILON == 1.19209290e-07);
|
||||
assert(isNaN<f32>(f32.NaN));
|
||||
assert(f32.isSafeInteger(f32.MIN_SAFE_INTEGER - 1) == false);
|
||||
assert(f32.isSafeInteger(f32.MIN_SAFE_INTEGER) == true);
|
||||
assert(f32.isSafeInteger(+0.0) == true);
|
||||
assert(f32.isSafeInteger(-0.0) == true);
|
||||
assert(f32.isSafeInteger(NaN) == false);
|
||||
assert(f32.isSafeInteger(Infinity) == false);
|
||||
assert(f32.isSafeInteger(f32.MAX_SAFE_INTEGER) == true);
|
||||
assert(f32.isSafeInteger(f32.MAX_SAFE_INTEGER + 1) == false);
|
||||
assert(f32.isSafeInteger(0.5) == false);
|
||||
assert(f32.isInteger(+0.0) == true);
|
||||
assert(f32.isInteger(-0.0) == true);
|
||||
assert(f32.isInteger(NaN) == false);
|
||||
assert(f32.isInteger(Infinity) == false);
|
||||
assert(f32.isInteger(f32.EPSILON) == false);
|
||||
assert(f32.isInteger(+1.0) == true);
|
||||
assert(f32.isInteger(-1.0) == true);
|
||||
assert(f32.isInteger(f32.MIN_SAFE_INTEGER) == true);
|
||||
assert(f32.isInteger(f32.MAX_SAFE_INTEGER) == true);
|
||||
assert(f32.isInteger(+0.5) == false);
|
||||
assert(f32.isInteger(-1.5) == false);
|
||||
|
||||
assert(f64.MIN_NORMAL_VALUE == 2.2250738585072014e-308);
|
||||
assert(f64.MIN_VALUE == 5e-324);
|
||||
@ -342,27 +321,6 @@ assert(f64.MAX_VALUE == 1.7976931348623157e+308);
|
||||
assert(f64.MIN_SAFE_INTEGER == -9007199254740991);
|
||||
assert(f64.MAX_SAFE_INTEGER == 9007199254740991);
|
||||
assert(f64.EPSILON == 2.2204460492503131e-16);
|
||||
assert(isNaN<f64>(f64.NaN));
|
||||
assert(f64.isSafeInteger(f64.MIN_SAFE_INTEGER - 1) == false);
|
||||
assert(f64.isSafeInteger(f64.MIN_SAFE_INTEGER) == true);
|
||||
assert(f64.isSafeInteger(+0.0) == true);
|
||||
assert(f64.isSafeInteger(-0.0) == true);
|
||||
assert(f64.isSafeInteger(NaN) == false);
|
||||
assert(f64.isSafeInteger(Infinity) == false);
|
||||
assert(f64.isSafeInteger(f64.MAX_SAFE_INTEGER) == true);
|
||||
assert(f64.isSafeInteger(f64.MAX_SAFE_INTEGER + 1) == false);
|
||||
assert(f64.isSafeInteger(0.5) == false);
|
||||
assert(f64.isInteger(+0.0) == true);
|
||||
assert(f64.isInteger(-0.0) == true);
|
||||
assert(f64.isInteger(NaN) == false);
|
||||
assert(f64.isInteger(Infinity) == false);
|
||||
assert(f64.isInteger(f64.EPSILON) == false);
|
||||
assert(f64.isInteger(+1.0) == true);
|
||||
assert(f64.isInteger(-1.0) == true);
|
||||
assert(f64.isInteger(f64.MIN_SAFE_INTEGER) == true);
|
||||
assert(f64.isInteger(f64.MAX_SAFE_INTEGER) == true);
|
||||
assert(f64.isInteger(+0.5) == false);
|
||||
assert(f64.isInteger(-1.5) == false);
|
||||
|
||||
// inline-assembler
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
2839
tests/compiler/number.optimized.wat
Normal file
2839
tests/compiler/number.optimized.wat
Normal file
File diff suppressed because it is too large
Load Diff
69
tests/compiler/number.ts
Normal file
69
tests/compiler/number.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import "allocator/arena";
|
||||
|
||||
// basic class bindings
|
||||
|
||||
// variable
|
||||
var a = 1;
|
||||
assert(a.toString() == "1");
|
||||
// literal
|
||||
assert(2..toString() == "2.0");
|
||||
assert((3).toString() == "3");
|
||||
// unary prefix
|
||||
assert((-5).toString() == "-5");
|
||||
assert((+4).toString() == "4");
|
||||
assert((++a).toString() == "2");
|
||||
assert((--a).toString() == "1");
|
||||
assert((!0).toString() == "true");
|
||||
assert((!1).toString() == "false");
|
||||
// assert((~a).toString() == "-2");
|
||||
// unary postfix
|
||||
assert((a++).toString() == "1");
|
||||
assert((a--).toString() == "2");
|
||||
|
||||
// float
|
||||
|
||||
assert(isNaN<f32>(F32.NaN));
|
||||
|
||||
assert(F32.isSafeInteger(f32.MIN_SAFE_INTEGER - 1) == false);
|
||||
assert(F32.isSafeInteger(f32.MIN_SAFE_INTEGER) == true);
|
||||
assert(F32.isSafeInteger(+0.0) == true);
|
||||
assert(F32.isSafeInteger(-0.0) == true);
|
||||
assert(F32.isSafeInteger(NaN) == false);
|
||||
assert(F32.isSafeInteger(Infinity) == false);
|
||||
assert(F32.isSafeInteger(f32.MAX_SAFE_INTEGER) == true);
|
||||
assert(F32.isSafeInteger(f32.MAX_SAFE_INTEGER + 1) == false);
|
||||
assert(F32.isSafeInteger(0.5) == false);
|
||||
assert(F32.isInteger(+0.0) == true);
|
||||
assert(F32.isInteger(-0.0) == true);
|
||||
assert(F32.isInteger(NaN) == false);
|
||||
assert(F32.isInteger(Infinity) == false);
|
||||
assert(F32.isInteger(f32.EPSILON) == false);
|
||||
assert(F32.isInteger(+1.0) == true);
|
||||
assert(F32.isInteger(-1.0) == true);
|
||||
assert(F32.isInteger(f32.MIN_SAFE_INTEGER) == true);
|
||||
assert(F32.isInteger(f32.MAX_SAFE_INTEGER) == true);
|
||||
assert(F32.isInteger(+0.5) == false);
|
||||
assert(F32.isInteger(-1.5) == false);
|
||||
|
||||
assert(isNaN<f64>(F64.NaN));
|
||||
|
||||
assert(F64.isSafeInteger(f64.MIN_SAFE_INTEGER - 1) == false);
|
||||
assert(F64.isSafeInteger(f64.MIN_SAFE_INTEGER) == true);
|
||||
assert(F64.isSafeInteger(+0.0) == true);
|
||||
assert(F64.isSafeInteger(-0.0) == true);
|
||||
assert(F64.isSafeInteger(NaN) == false);
|
||||
assert(F64.isSafeInteger(Infinity) == false);
|
||||
assert(F64.isSafeInteger(f64.MAX_SAFE_INTEGER) == true);
|
||||
assert(F64.isSafeInteger(f64.MAX_SAFE_INTEGER + 1) == false);
|
||||
assert(F64.isSafeInteger(0.5) == false);
|
||||
assert(F64.isInteger(+0.0) == true);
|
||||
assert(F64.isInteger(-0.0) == true);
|
||||
assert(F64.isInteger(NaN) == false);
|
||||
assert(F64.isInteger(Infinity) == false);
|
||||
assert(F64.isInteger(f64.EPSILON) == false);
|
||||
assert(F64.isInteger(+1.0) == true);
|
||||
assert(F64.isInteger(-1.0) == true);
|
||||
assert(F64.isInteger(f64.MIN_SAFE_INTEGER) == true);
|
||||
assert(F64.isInteger(f64.MAX_SAFE_INTEGER) == true);
|
||||
assert(F64.isInteger(+0.5) == false);
|
||||
assert(F64.isInteger(-1.5) == false);
|
4475
tests/compiler/number.untouched.wat
Normal file
4475
tests/compiler/number.untouched.wat
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user