diff --git a/src/ast.ts b/src/ast.ts index d4f091f06b..e4439e6b2a 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -246,7 +246,7 @@ export abstract class Node { stmt.range = range; stmt.name = name; stmt.arguments = args; - stmt.decoratorKind = decoratorNameToKind(name); + stmt.decoratorKind = DecoratorKind.fromNode(name); return stmt; } @@ -1187,73 +1187,76 @@ export enum DecoratorKind { UNSAFE } -/** Returns the kind of the specified decorator. Defaults to {@link DecoratorKind.CUSTOM}. */ -export function decoratorNameToKind(name: Expression): DecoratorKind { - // @global, @inline, @operator, @sealed, @unmanaged - if (name.kind == NodeKind.IDENTIFIER) { - let nameStr = (name).text; - assert(nameStr.length); - switch (nameStr.charCodeAt(0)) { - case CharCode.b: { - if (nameStr == "builtin") return DecoratorKind.BUILTIN; - break; - } - case CharCode.e: { - if (nameStr == "external") return DecoratorKind.EXTERNAL; - break; - } - case CharCode.g: { - if (nameStr == "global") return DecoratorKind.GLOBAL; - break; - } - case CharCode.i: { - if (nameStr == "inline") return DecoratorKind.INLINE; - break; - } - case CharCode.l: { - if (nameStr == "lazy") return DecoratorKind.LAZY; - break; - } - case CharCode.o: { - if (nameStr == "operator") return DecoratorKind.OPERATOR; - break; - } - case CharCode.s: { - if (nameStr == "sealed") return DecoratorKind.SEALED; - break; - } - case CharCode.u: { - if (nameStr == "unmanaged") return DecoratorKind.UNMANAGED; - if (nameStr == "unsafe") return DecoratorKind.UNSAFE; - break; - } - } - } else if ( - name.kind == NodeKind.PROPERTYACCESS && - (name).expression.kind == NodeKind.IDENTIFIER - ) { - let nameStr = ((name).expression).text; - assert(nameStr.length); - let propStr = (name).property.text; - assert(propStr.length); - // @operator.binary, @operator.prefix, @operator.postfix - if (nameStr == "operator") { - switch (propStr.charCodeAt(0)) { +export namespace DecoratorKind { + + /** Returns the kind of the specified decorator name node. Defaults to {@link DecoratorKind.CUSTOM}. */ + export function fromNode(nameNode: Expression): DecoratorKind { + // @global, @inline, @operator, @sealed, @unmanaged + if (nameNode.kind == NodeKind.IDENTIFIER) { + let nameStr = (nameNode).text; + assert(nameStr.length); + switch (nameStr.charCodeAt(0)) { case CharCode.b: { - if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY; + if (nameStr == "builtin") return DecoratorKind.BUILTIN; break; } - case CharCode.p: { - switch (propStr) { - case "prefix": return DecoratorKind.OPERATOR_PREFIX; - case "postfix": return DecoratorKind.OPERATOR_POSTFIX; - } + case CharCode.e: { + if (nameStr == "external") return DecoratorKind.EXTERNAL; break; } + case CharCode.g: { + if (nameStr == "global") return DecoratorKind.GLOBAL; + break; + } + case CharCode.i: { + if (nameStr == "inline") return DecoratorKind.INLINE; + break; + } + case CharCode.l: { + if (nameStr == "lazy") return DecoratorKind.LAZY; + break; + } + case CharCode.o: { + if (nameStr == "operator") return DecoratorKind.OPERATOR; + break; + } + case CharCode.s: { + if (nameStr == "sealed") return DecoratorKind.SEALED; + break; + } + case CharCode.u: { + if (nameStr == "unmanaged") return DecoratorKind.UNMANAGED; + if (nameStr == "unsafe") return DecoratorKind.UNSAFE; + break; + } + } + } else if ( + nameNode.kind == NodeKind.PROPERTYACCESS && + (nameNode).expression.kind == NodeKind.IDENTIFIER + ) { + let nameStr = ((nameNode).expression).text; + assert(nameStr.length); + let propStr = (nameNode).property.text; + assert(propStr.length); + // @operator.binary, @operator.prefix, @operator.postfix + if (nameStr == "operator") { + switch (propStr.charCodeAt(0)) { + case CharCode.b: { + if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY; + break; + } + case CharCode.p: { + switch (propStr) { + case "prefix": return DecoratorKind.OPERATOR_PREFIX; + case "postfix": return DecoratorKind.OPERATOR_POSTFIX; + } + break; + } + } } } + return DecoratorKind.CUSTOM; } - return DecoratorKind.CUSTOM; } /** Represents a decorator. */ diff --git a/src/builtins.ts b/src/builtins.ts index fdca573e4c..df37383676 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -595,10 +595,12 @@ export function compileCall( let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - let classType = type.classReference; - if (classType) { - let stringInstance = compiler.program.stringInstance; - if (stringInstance && classType.isAssignableTo(stringInstance)) return module.i32(1); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let stringInstance = compiler.program.stringInstance; + if (stringInstance && classReference.isAssignableTo(stringInstance)) return module.i32(1); + } } return module.i32(0); } @@ -606,18 +608,25 @@ export function compileCall( let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - let classReference = type.classReference; - if (!classReference) return module.i32(0); - let classPrototype = classReference.prototype; - return module.i32(classPrototype.extends(compiler.program.arrayPrototype) ? 1 : 0); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + return module.i32(classReference.prototype.extends(compiler.program.arrayPrototype) ? 1 : 0); + } + } + return module.i32(0); } case BuiltinSymbols.isArrayLike: { // isArrayLike() / isArrayLike(value: T) -> bool let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); compiler.currentType = Type.bool; if (!type) return module.unreachable(); - let classReference = type.classReference; - if (!classReference) return module.i32(0); - return module.i32(classReference.isArrayLike ? 1 : 0); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + return module.i32(classReference.isArrayLike ? 1 : 0); + } + } + return module.i32(0); } case BuiltinSymbols.isFunction: { // isFunction / isFunction(value: T) -> bool let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); @@ -637,7 +646,7 @@ export function compileCall( checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 1, reportNode, compiler) ) return module.unreachable(); - let element = compiler.resolver.resolveExpression( + let element = compiler.resolver.lookupExpression( operands[0], compiler.currentFlow, Type.auto, @@ -747,8 +756,9 @@ export function compileCall( checkTypeRequired(typeArguments, reportNode, compiler) | checkArgsOptional(operands, 0, 1, reportNode, compiler) ) return module.unreachable(); - let classType = typeArguments![0].classReference; - if (!classType) { + let typeArgument = typeArguments![0]; + let classType = typeArgument.classReference; + if (!(typeArgument.is(TypeFlags.REFERENCE) && classType !== null)) { compiler.error( DiagnosticCode.Operation_not_supported, reportNode.typeArgumentsRange @@ -2436,8 +2446,9 @@ export function compileCall( if ( checkTypeRequired(typeArguments, reportNode, compiler, true) ) return module.unreachable(); - let classInstance = typeArguments![0].classReference; - if (!classInstance) { + let typeArgument = typeArguments![0]; + let classInstance = typeArgument.classReference; + if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) { compiler.error( DiagnosticCode.Operation_not_supported, reportNode.typeArgumentsRange @@ -3665,7 +3676,7 @@ export function compileCall( } let classReference = type.classReference; - if (!classReference || classReference.hasDecorator(DecoratorFlags.UNMANAGED)) { + if (!type.is(TypeFlags.REFERENCE) || !classReference || classReference.hasDecorator(DecoratorFlags.UNMANAGED)) { compiler.error( DiagnosticCode.Operation_not_supported, reportNode.range @@ -4102,11 +4113,13 @@ export function compileVisitGlobals(compiler: Compiler): void { for (let element of compiler.program.elementsByName.values()) { if (element.kind != ElementKind.GLOBAL) continue; let global = element; - let classReference = global.type.classReference; + let globalType = global.type; + let classType = globalType.classReference; if ( - global.is(CommonFlags.COMPILED) && - classReference !== null && - !classReference.hasDecorator(DecoratorFlags.UNMANAGED) + globalType.is(TypeFlags.REFERENCE) && + classType !== null && + !classType.hasDecorator(DecoratorFlags.UNMANAGED) && + global.is(CommonFlags.COMPILED) ) { if (global.is(CommonFlags.INLINED)) { let value = global.constantIntegerValue; diff --git a/src/compiler.ts b/src/compiler.ts index 7c49599078..c9aecb7889 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -42,7 +42,8 @@ import { isLocalTee, getLocalSetIndex, FeatureFlags, - needsExplicitUnreachable + needsExplicitUnreachable, + getLocalSetValue } from "./module"; import { @@ -2781,9 +2782,12 @@ export class Compiler extends DiagnosticEmitter { contextualType: Type, constraints: Constraints = Constraints.NONE ): ExpressionRef { + while (expression.kind == NodeKind.PARENTHESIZED) { // skip + expression = (expression).expression; + } this.currentType = contextualType; - var expr: ExpressionRef; if (contextualType == Type.void) constraints |= Constraints.WILL_DROP; + var expr: ExpressionRef; switch (expression.kind) { case NodeKind.ASSERTION: { expr = this.compileAssertionExpression(expression, contextualType, constraints); @@ -2830,10 +2834,6 @@ export class Compiler extends DiagnosticEmitter { expr = this.compileNewExpression(expression, contextualType, constraints); break; } - case NodeKind.PARENTHESIZED: { - expr = this.compileExpression((expression).expression, contextualType, constraints); - break; - } case NodeKind.PROPERTYACCESS: { expr = this.compilePropertyAccessExpression(expression, contextualType, constraints); break; @@ -4031,6 +4031,7 @@ export class Compiler extends DiagnosticEmitter { return this.module.unreachable(); } + let targetType = leftType; let instance: Function | null; // Mathf.pow if lhs is f32 (result is f32) @@ -4098,6 +4099,10 @@ export class Compiler extends DiagnosticEmitter { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); + if (compound && targetType != this.currentType) { + // this yields a proper error if target is i32 for example + expr = this.convertExpression(expr, this.currentType, targetType, false, false, expression); + } } break; } @@ -5083,8 +5088,16 @@ export class Compiler extends DiagnosticEmitter { } if (!compound) return expr; var resolver = this.resolver; - var target = resolver.resolveExpression(left, this.currentFlow); + var target = resolver.lookupExpression(left, this.currentFlow); if (!target) return module.unreachable(); + var targetType = resolver.getTypeOfElement(target) || Type.void; + if (!this.currentType.isStrictlyAssignableTo(targetType)) { + this.error( + DiagnosticCode.Type_0_is_not_assignable_to_type_1, + expression.range, this.currentType.toString(), targetType.toString() + ); + return module.unreachable(); + } return this.makeAssignment( target, expr, // TODO: delay release above if possible? @@ -5136,7 +5149,7 @@ export class Compiler extends DiagnosticEmitter { var program = this.program; var resolver = program.resolver; var flow = this.currentFlow; - var target = resolver.resolveExpression(expression, flow); // reports + var target = resolver.lookupExpression(expression, flow); // reports if (!target) return this.module.unreachable(); var thisExpression = resolver.currentThisExpression; var elementExpression = resolver.currentElementExpression; @@ -5770,7 +5783,7 @@ export class Compiler extends DiagnosticEmitter { } // otherwise resolve normally - var target = this.resolver.resolveExpression(expression.expression, flow); // reports + var target = this.resolver.lookupExpression(expression.expression, flow); // reports if (!target) return module.unreachable(); var signature: Signature | null; @@ -6774,7 +6787,7 @@ export class Compiler extends DiagnosticEmitter { )); continue; } - let resolved = this.resolver.resolveExpression(initializer, instance.flow, parameterTypes[i]); + let resolved = this.resolver.lookupExpression(initializer, instance.flow, parameterTypes[i]); if (resolved) { if (resolved.kind == ElementKind.GLOBAL) { let global = resolved; @@ -6955,35 +6968,30 @@ export class Compiler extends DiagnosticEmitter { contextualType: Type, constraints: Constraints ): ExpressionRef { - var target = this.resolver.resolveElementAccessExpression( - expression, - this.currentFlow, - contextualType - ); // reports - if (!target) return this.module.unreachable(); - switch (target.kind) { - case ElementKind.CLASS: { - let indexedGet = (target).lookupOverload(OperatorKind.INDEXED_GET, this.currentFlow.is(FlowFlags.UNCHECKED_CONTEXT)); - if (!indexedGet) { - this.error( - DiagnosticCode.Index_signature_is_missing_in_type_0, - expression.expression.range, (target).internalName - ); - return this.module.unreachable(); + var module = this.module; + var targetExpression = expression.expression; + var targetType = this.resolver.resolveExpression(targetExpression, this.currentFlow); // reports + if (targetType) { + if (targetType.is(TypeFlags.REFERENCE)) { + let classReference = targetType.classReference; + if (classReference) { + let indexedGet = classReference.lookupOverload(OperatorKind.INDEXED_GET, this.currentFlow.is(FlowFlags.UNCHECKED_CONTEXT)); + if (indexedGet) { + let thisArg = this.compileExpression(targetExpression, classReference.type, + Constraints.CONV_IMPLICIT + ); + return this.compileCallDirect(indexedGet, [ + expression.elementExpression + ], expression, thisArg, constraints); + } } - let thisArg = this.compileExpression(expression.expression, (target).type, - Constraints.CONV_IMPLICIT - ); - return this.compileCallDirect(indexedGet, [ - expression.elementExpression - ], expression, thisArg, constraints); } + this.error( + DiagnosticCode.Index_signature_is_missing_in_type_0, + expression.expression.range, targetType.toString() + ); } - this.error( - DiagnosticCode.Operation_not_supported, - expression.range - ); - return this.module.unreachable(); + return module.unreachable(); } compileFunctionExpression( @@ -7154,10 +7162,10 @@ export class Compiler extends DiagnosticEmitter { case NodeKind.NULL: { let options = this.options; let classReference = contextualType.classReference; - if (!classReference) { - this.currentType = options.usizeType; - } else { + if (contextualType.is(TypeFlags.REFERENCE) && classReference !== null) { this.currentType = classReference.type.asNullable(); + } else { + this.currentType = options.usizeType; // TODO: anyref context yields 0 } return options.isWasm64 ? module.i64(0) @@ -7261,7 +7269,7 @@ export class Compiler extends DiagnosticEmitter { this.maybeCompileEnclosingSource(expression); // otherwise resolve - var target = this.resolver.resolveIdentifier( // reports + var target = this.resolver.lookupIdentifierExpression( // reports expression, flow, this.currentEnum || actualFunction @@ -7782,7 +7790,7 @@ export class Compiler extends DiagnosticEmitter { var flow = this.currentFlow; // obtain the class being instantiated - var target = this.resolver.resolveExpression( // reports + var target = this.resolver.lookupExpression( // reports expression.expression, flow ); @@ -7959,28 +7967,27 @@ export class Compiler extends DiagnosticEmitter { * precomputes them according to context. */ compilePropertyAccessExpression( - propertyAccess: PropertyAccessExpression, - contextualType: Type, + expression: PropertyAccessExpression, + ctxType: Type, constraints: Constraints ): ExpressionRef { var module = this.module; var flow = this.currentFlow; - this.maybeCompileEnclosingSource(propertyAccess); + this.maybeCompileEnclosingSource(expression); - var target = this.resolver.resolvePropertyAccessExpression(propertyAccess, flow, contextualType); // reports + var resolver = this.resolver; + var target = resolver.lookupExpression(expression, flow, ctxType); // reports if (!target) return module.unreachable(); - if (target.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(propertyAccess); + if (target.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression); switch (target.kind) { case ElementKind.GLOBAL: { // static field - if (!this.compileGlobal(target)) { // reports; not yet compiled if a static field - return module.unreachable(); - } + if (!this.compileGlobal(target)) return module.unreachable(); // reports let globalType = (target).type; assert(globalType != Type.void); if ((target).is(CommonFlags.INLINED)) { - return this.compileInlineConstant(target, contextualType, constraints); + return this.compileInlineConstant(target, ctxType, constraints); } this.currentType = globalType; return module.global_get((target).internalName, globalType.toNativeType()); @@ -7994,8 +8001,9 @@ export class Compiler extends DiagnosticEmitter { this.currentType = Type.i32; if ((target).is(CommonFlags.INLINED)) { assert((target).constantValueKind == ConstantValueKind.INTEGER); - return module.i32(i64_low((target).constantIntegerValue)); + return this.compileInlineConstant(target, ctxType, constraints); } + assert((target).type == Type.i32); return module.global_get((target).internalName, NativeType.I32); } case ElementKind.FIELD: { // instance field @@ -8014,13 +8022,13 @@ export class Compiler extends DiagnosticEmitter { let getterPrototype = (target).getterPrototype; if (getterPrototype) { let getter = this.resolver.resolveFunction(getterPrototype, null); - if (getter) return this.compileCallDirect(getter, [], propertyAccess, 0); + if (getter) return this.compileCallDirect(getter, [], expression, 0); } return module.unreachable(); } case ElementKind.PROPERTY: { // instance property let getterInstance = assert((target).getterInstance); - return this.compileCallDirect(getterInstance, [], propertyAccess, + return this.compileCallDirect(getterInstance, [], expression, this.compileExpression(assert(this.resolver.currentThisExpression), this.options.usizeType) ); } @@ -8032,7 +8040,7 @@ export class Compiler extends DiagnosticEmitter { prototype, [], makeMap(), - propertyAccess, + expression, ); if (instance == null) { return module.unreachable(); @@ -8044,21 +8052,21 @@ export class Compiler extends DiagnosticEmitter { this.error( DiagnosticCode.Cannot_access_method_0_without_calling_it_as_it_requires_this_to_be_set, - propertyAccess.range, prototype.name + expression.range, prototype.name ); return module.unreachable(); } } this.error( DiagnosticCode.Operation_not_supported, - propertyAccess.range + expression.range ); return module.unreachable(); } compileTernaryExpression( expression: TernaryExpression, - contextualType: Type, + ctxType: Type, constraints: Constraints ): ExpressionRef { var ifThen = expression.ifThen; @@ -8078,21 +8086,21 @@ export class Compiler extends DiagnosticEmitter { getExpressionType(condExpr) == NativeType.I32 ) { return getConstValueI32(condExpr) - ? this.compileExpression(ifThen, contextualType) - : this.compileExpression(ifElse, contextualType); + ? this.compileExpression(ifThen, ctxType) + : this.compileExpression(ifElse, ctxType); } var inheritedConstraints = constraints & Constraints.WILL_RETAIN; var ifThenFlow = outerFlow.fork(); this.currentFlow = ifThenFlow; - var ifThenExpr = this.compileExpression(ifThen, contextualType, inheritedConstraints); + var ifThenExpr = this.compileExpression(ifThen, ctxType, inheritedConstraints); var ifThenType = this.currentType; var IfThenAutoreleaseSkipped = this.skippedAutoreleases.has(ifThenExpr); var ifElseFlow = outerFlow.fork(); this.currentFlow = ifElseFlow; - var ifElseExpr = this.compileExpression(ifElse, contextualType, inheritedConstraints); + var ifElseExpr = this.compileExpression(ifElse, ctxType, inheritedConstraints); var ifElseType = this.currentType; var ifElseAutoreleaseSkipped = this.skippedAutoreleases.has(ifElseExpr); @@ -8102,7 +8110,7 @@ export class Compiler extends DiagnosticEmitter { DiagnosticCode.Type_0_is_not_assignable_to_type_1, ifElse.range, ifElseType.toString(), ifThenType.toString() ); - this.currentType = contextualType; + this.currentType = ctxType; return this.module.unreachable(); } ifThenExpr = this.convertExpression( @@ -8167,7 +8175,8 @@ export class Compiler extends DiagnosticEmitter { // shortcut if compiling the getter already failed if (getExpressionId(getValue) == ExpressionId.Unreachable) return getValue; - // if the value isn't dropped, a temp. local is required to remember the original value + // if the value isn't dropped, a temp. local is required to remember the original value, + // except if a static overload is found, which reverses the use of a temp. (see below) var tempLocal: Local | null = null; if (contextualType != Type.void) { tempLocal = flow.getTempLocal(this.currentType); @@ -8181,6 +8190,32 @@ export class Compiler extends DiagnosticEmitter { switch (expression.operator) { case Token.PLUS_PLUS: { + + // check operator overload + if (this.currentType.is(TypeFlags.REFERENCE)) { + let classReference = this.currentType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.POSTFIX_INC); + if (overload) { + let isInstance = overload.is(CommonFlags.INSTANCE); + if (tempLocal !== null && !isInstance) { // revert: static overload simply returns + getValue = getLocalSetValue(getValue); + flow.freeTempLocal(tempLocal); + tempLocal = null; + } + expr = this.compileUnaryOverload(overload, expression.operand, getValue, expression); + if (isInstance) break; + return expr; // here + } + } + this.error( + DiagnosticCode.Operation_not_supported, + expression.range + ); + if (tempLocal) flow.freeTempLocal(tempLocal); + return module.unreachable(); + } + switch (this.currentType.kind) { case TypeKind.I8: case TypeKind.I16: @@ -8196,24 +8231,7 @@ export class Compiler extends DiagnosticEmitter { ); break; } - case TypeKind.USIZE: { - // check operator overload - if (this.currentType.is(TypeFlags.REFERENCE)) { - let classReference = this.currentType.classReference; - if (classReference) { - let overload = classReference.lookupOverload(OperatorKind.POSTFIX_INC); - if (overload) { - expr = this.compileUnaryOverload(overload, expression.operand, getValue, expression); - break; - } - } - this.error( - DiagnosticCode.Operation_not_supported, - expression.range - ); - return module.unreachable(); - } - } + case TypeKind.USIZE: case TypeKind.ISIZE: { let options = this.options; expr = module.binary( @@ -8258,6 +8276,32 @@ export class Compiler extends DiagnosticEmitter { break; } case Token.MINUS_MINUS: { + + // check operator overload + if (this.currentType.is(TypeFlags.REFERENCE)) { + let classReference = this.currentType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.POSTFIX_DEC); + if (overload) { + let isInstance = overload.is(CommonFlags.INSTANCE); + if (tempLocal !== null && !isInstance) { // revert: static overload simply returns + getValue = getLocalSetValue(getValue); + flow.freeTempLocal(tempLocal); + tempLocal = null; + } + expr = this.compileUnaryOverload(overload, expression.operand, getValue, expression); + if (overload.is(CommonFlags.INSTANCE)) break; + return expr; // here + } + } + this.error( + DiagnosticCode.Operation_not_supported, + expression.range + ); + if (tempLocal) flow.freeTempLocal(tempLocal); + return module.unreachable(); + } + switch (this.currentType.kind) { case TypeKind.I8: case TypeKind.I16: @@ -8273,24 +8317,7 @@ export class Compiler extends DiagnosticEmitter { ); break; } - case TypeKind.USIZE: { - // check operator overload - if (this.currentType.is(TypeFlags.REFERENCE)) { - let classReference = this.currentType.classReference; - if (classReference) { - let overload = classReference.lookupOverload(OperatorKind.POSTFIX_DEC); - if (overload) { - expr = this.compileUnaryOverload(overload, expression.operand, getValue, expression); - break; - } - } - this.error( - DiagnosticCode.Operation_not_supported, - expression.range - ); - return module.unreachable(); - } - } + case TypeKind.USIZE: case TypeKind.ISIZE: { let options = this.options; expr = module.binary( @@ -8341,12 +8368,14 @@ export class Compiler extends DiagnosticEmitter { } var resolver = this.resolver; - var target = resolver.resolveExpression(expression.operand, flow); // reports + var target = resolver.lookupExpression(expression.operand, flow); // reports + if (!target) { + if (tempLocal) flow.freeTempLocal(tempLocal); + return module.unreachable(); + } // simplify if dropped anyway if (!tempLocal) { - this.currentType = Type.void; - if (!target) return module.unreachable(); return this.makeAssignment( target, expr, @@ -8355,8 +8384,6 @@ export class Compiler extends DiagnosticEmitter { resolver.currentElementExpression, false ); - } else if (!target) { - return module.unreachable(); } // otherwise use the temp. local for the intermediate value (always possibly overflows) @@ -8401,10 +8428,7 @@ export class Compiler extends DiagnosticEmitter { let classReference = this.currentType.classReference; if (classReference) { let overload = classReference.lookupOverload(OperatorKind.PLUS); - if (overload) { - expr = this.compileUnaryOverload(overload, expression.operand, expr, expression); - break; - } + if (overload) return this.compileUnaryOverload(overload, expression.operand, expr, expression); } this.error( DiagnosticCode.Operation_not_supported, @@ -8439,10 +8463,7 @@ export class Compiler extends DiagnosticEmitter { let classReference = this.currentType.classReference; if (classReference) { let overload = classReference.lookupOverload(OperatorKind.MINUS); - if (overload) { - expr = this.compileUnaryOverload(overload, expression.operand, expr, expression); - break; - } + if (overload) return this.compileUnaryOverload(overload, expression.operand, expr, expression); } this.error( DiagnosticCode.Operation_not_supported, @@ -8508,7 +8529,8 @@ export class Compiler extends DiagnosticEmitter { let overload = classReference.lookupOverload(OperatorKind.PREFIX_INC); if (overload) { expr = this.compileUnaryOverload(overload, expression.operand, expr, expression); - break; + if (overload.is(CommonFlags.INSTANCE)) break; // re-assign + return expr; // skip re-assign } } this.error( @@ -8575,7 +8597,8 @@ export class Compiler extends DiagnosticEmitter { let overload = classReference.lookupOverload(OperatorKind.PREFIX_DEC); if (overload) { expr = this.compileUnaryOverload(overload, expression.operand, expr, expression); - break; + if (overload.is(CommonFlags.INSTANCE)) break; // re-assign + return expr; // skip re-assign } } this.error( @@ -8639,10 +8662,7 @@ export class Compiler extends DiagnosticEmitter { let classReference = this.currentType.classReference; if (classReference) { let overload = classReference.lookupOverload(OperatorKind.NOT); - if (overload) { - expr = this.compileUnaryOverload(overload, expression.operand, expr, expression); - break; - } + if (overload) return this.compileUnaryOverload(overload, expression.operand, expr, expression); } // allow '!' for references even without an overload } @@ -8667,10 +8687,7 @@ export class Compiler extends DiagnosticEmitter { let classReference = this.currentType.classReference; if (classReference) { let overload = classReference.lookupOverload(OperatorKind.BITWISE_NOT); - if (overload) { - expr = this.compileUnaryOverload(overload, expression.operand, expr, expression); - break; - } + if (overload) return this.compileUnaryOverload(overload, expression.operand, expr, expression); } this.error( DiagnosticCode.Operation_not_supported, @@ -8733,7 +8750,7 @@ export class Compiler extends DiagnosticEmitter { } if (!compound) return expr; var resolver = this.resolver; - var target = resolver.resolveExpression(expression.operand, this.currentFlow); + var target = resolver.lookupExpression(expression.operand, this.currentFlow); if (!target) return module.unreachable(); return this.makeAssignment( target, diff --git a/src/program.ts b/src/program.ts index d71a1dc445..3f77b9dd79 100644 --- a/src/program.ts +++ b/src/program.ts @@ -74,9 +74,9 @@ import { VariableLikeDeclarationStatement, VariableStatement, - decoratorNameToKind, - findDecorator, - ExportDefaultStatement + ExportDefaultStatement, + Token, + ParameterNode } from "./ast"; import { @@ -192,118 +192,180 @@ export enum OperatorKind { // LOGICAL_OR // a || b } -/** Returns the operator kind represented by the specified decorator and string argument. */ -function operatorKindFromDecorator(decoratorKind: DecoratorKind, arg: string): OperatorKind { - assert(arg.length); - switch (decoratorKind) { - case DecoratorKind.OPERATOR: - case DecoratorKind.OPERATOR_BINARY: { - switch (arg.charCodeAt(0)) { - case CharCode.OPENBRACKET: { - if (arg == "[]") return OperatorKind.INDEXED_GET; - if (arg == "[]=") return OperatorKind.INDEXED_SET; - break; - } - case CharCode.OPENBRACE: { - if (arg == "{}") return OperatorKind.UNCHECKED_INDEXED_GET; - if (arg == "{}=") return OperatorKind.UNCHECKED_INDEXED_SET; - break; - } - case CharCode.PLUS: { - if (arg == "+") return OperatorKind.ADD; - break; - } - case CharCode.MINUS: { - if (arg == "-") return OperatorKind.SUB; - break; - } - case CharCode.ASTERISK: { - if (arg == "*") return OperatorKind.MUL; - if (arg == "**") return OperatorKind.POW; - break; - } - case CharCode.SLASH: { - if (arg == "/") return OperatorKind.DIV; - break; - } - case CharCode.PERCENT: { - if (arg == "%") return OperatorKind.REM; - break; - } - case CharCode.AMPERSAND: { - if (arg == "&") return OperatorKind.BITWISE_AND; - break; - } - case CharCode.BAR: { - if (arg == "|") return OperatorKind.BITWISE_OR; - break; - } - case CharCode.CARET: { - if (arg == "^") return OperatorKind.BITWISE_XOR; - break; - } - case CharCode.EQUALS: { - if (arg == "==") return OperatorKind.EQ; - break; - } - case CharCode.EXCLAMATION: { - if (arg == "!=") return OperatorKind.NE; - break; - } - case CharCode.GREATERTHAN: { - if (arg == ">") return OperatorKind.GT; - if (arg == ">=") return OperatorKind.GE; - if (arg == ">>") return OperatorKind.BITWISE_SHR; - if (arg == ">>>") return OperatorKind.BITWISE_SHR_U; - break; - } - case CharCode.LESSTHAN: { - if (arg == "<") return OperatorKind.LT; - if (arg == "<=") return OperatorKind.LE; - if (arg == "<<") return OperatorKind.BITWISE_SHL; - break; +export namespace OperatorKind { + + /** Returns the operator kind represented by the specified decorator and string argument. */ + export function fromDecorator(decoratorKind: DecoratorKind, arg: string): OperatorKind { + assert(arg.length); + switch (decoratorKind) { + case DecoratorKind.OPERATOR: + case DecoratorKind.OPERATOR_BINARY: { + switch (arg.charCodeAt(0)) { + case CharCode.OPENBRACKET: { + if (arg == "[]") return OperatorKind.INDEXED_GET; + if (arg == "[]=") return OperatorKind.INDEXED_SET; + break; + } + case CharCode.OPENBRACE: { + if (arg == "{}") return OperatorKind.UNCHECKED_INDEXED_GET; + if (arg == "{}=") return OperatorKind.UNCHECKED_INDEXED_SET; + break; + } + case CharCode.PLUS: { + if (arg == "+") return OperatorKind.ADD; + break; + } + case CharCode.MINUS: { + if (arg == "-") return OperatorKind.SUB; + break; + } + case CharCode.ASTERISK: { + if (arg == "*") return OperatorKind.MUL; + if (arg == "**") return OperatorKind.POW; + break; + } + case CharCode.SLASH: { + if (arg == "/") return OperatorKind.DIV; + break; + } + case CharCode.PERCENT: { + if (arg == "%") return OperatorKind.REM; + break; + } + case CharCode.AMPERSAND: { + if (arg == "&") return OperatorKind.BITWISE_AND; + break; + } + case CharCode.BAR: { + if (arg == "|") return OperatorKind.BITWISE_OR; + break; + } + case CharCode.CARET: { + if (arg == "^") return OperatorKind.BITWISE_XOR; + break; + } + case CharCode.EQUALS: { + if (arg == "==") return OperatorKind.EQ; + break; + } + case CharCode.EXCLAMATION: { + if (arg == "!=") return OperatorKind.NE; + break; + } + case CharCode.GREATERTHAN: { + if (arg == ">") return OperatorKind.GT; + if (arg == ">=") return OperatorKind.GE; + if (arg == ">>") return OperatorKind.BITWISE_SHR; + if (arg == ">>>") return OperatorKind.BITWISE_SHR_U; + break; + } + case CharCode.LESSTHAN: { + if (arg == "<") return OperatorKind.LT; + if (arg == "<=") return OperatorKind.LE; + if (arg == "<<") return OperatorKind.BITWISE_SHL; + break; + } } + break; } - break; - } - case DecoratorKind.OPERATOR_PREFIX: { - switch (arg.charCodeAt(0)) { - case CharCode.PLUS: { - if (arg == "+") return OperatorKind.PLUS; - if (arg == "++") return OperatorKind.PREFIX_INC; - break; - } - case CharCode.MINUS: { - if (arg == "-") return OperatorKind.MINUS; - if (arg == "--") return OperatorKind.PREFIX_DEC; - break; - } - case CharCode.EXCLAMATION: { - if (arg == "!") return OperatorKind.NOT; - break; - } - case CharCode.TILDE: { - if (arg == "~") return OperatorKind.BITWISE_NOT; - break; + case DecoratorKind.OPERATOR_PREFIX: { + switch (arg.charCodeAt(0)) { + case CharCode.PLUS: { + if (arg == "+") return OperatorKind.PLUS; + if (arg == "++") return OperatorKind.PREFIX_INC; + break; + } + case CharCode.MINUS: { + if (arg == "-") return OperatorKind.MINUS; + if (arg == "--") return OperatorKind.PREFIX_DEC; + break; + } + case CharCode.EXCLAMATION: { + if (arg == "!") return OperatorKind.NOT; + break; + } + case CharCode.TILDE: { + if (arg == "~") return OperatorKind.BITWISE_NOT; + break; + } } + break; } - break; - } - case DecoratorKind.OPERATOR_POSTFIX: { - switch (arg.charCodeAt(0)) { - case CharCode.PLUS: { - if (arg == "++") return OperatorKind.POSTFIX_INC; - break; - } - case CharCode.MINUS: { - if (arg == "--") return OperatorKind.POSTFIX_DEC; - break; + case DecoratorKind.OPERATOR_POSTFIX: { + switch (arg.charCodeAt(0)) { + case CharCode.PLUS: { + if (arg == "++") return OperatorKind.POSTFIX_INC; + break; + } + case CharCode.MINUS: { + if (arg == "--") return OperatorKind.POSTFIX_DEC; + break; + } } + break; } - break; } + return OperatorKind.INVALID; + } + + /** Converts a binary operator token to the respective operator kind. */ + export function fromBinaryToken(token: Token): OperatorKind { + switch (token) { + case Token.PLUS: + case Token.PLUS_EQUALS: return OperatorKind.ADD; + case Token.MINUS: + case Token.MINUS_EQUALS: return OperatorKind.SUB; + case Token.ASTERISK: + case Token.ASTERISK_EQUALS: return OperatorKind.MUL; + case Token.SLASH: + case Token.SLASH_EQUALS: return OperatorKind.DIV; + case Token.PERCENT: + case Token.PERCENT_EQUALS: return OperatorKind.REM; + case Token.ASTERISK_ASTERISK: + case Token.ASTERISK_ASTERISK_EQUALS: return OperatorKind.POW; + case Token.AMPERSAND: + case Token.AMPERSAND_EQUALS: return OperatorKind.BITWISE_AND; + case Token.BAR: + case Token.BAR_EQUALS: return OperatorKind.BITWISE_OR; + case Token.CARET: + case Token.CARET_EQUALS: return OperatorKind.BITWISE_XOR; + case Token.LESSTHAN_LESSTHAN: + case Token.LESSTHAN_LESSTHAN_EQUALS: return OperatorKind.BITWISE_SHL; + case Token.GREATERTHAN_GREATERTHAN: + case Token.GREATERTHAN_GREATERTHAN_EQUALS: return OperatorKind.BITWISE_SHR; + case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: + case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return OperatorKind.BITWISE_SHR_U; + case Token.EQUALS_EQUALS: return OperatorKind.EQ; + case Token.EXCLAMATION_EQUALS: return OperatorKind.NE; + case Token.GREATERTHAN: return OperatorKind.GT; + case Token.GREATERTHAN_EQUALS: return OperatorKind.GE; + case Token.LESSTHAN: return OperatorKind.LT; + case Token.LESSTHAN_EQUALS: return OperatorKind.LE; + } + return OperatorKind.INVALID; + } + + /** Converts a unary prefix operator token to the respective operator kind. */ + export function fromUnaryPrefixToken(token: Token): OperatorKind { + switch (token) { + case Token.PLUS: return OperatorKind.PLUS; + case Token.MINUS: return OperatorKind.MINUS; + case Token.EXCLAMATION: return OperatorKind.NOT; + case Token.TILDE: return OperatorKind.BITWISE_NOT; + case Token.PLUS_PLUS: return OperatorKind.PREFIX_INC; + case Token.MINUS_MINUS: return OperatorKind.PREFIX_DEC; + } + return OperatorKind.INVALID; + } + + /** Converts a unary postfix operator token to the respective operator kind. */ + export function fromUnaryPostfixToken(token: Token): OperatorKind { + switch (token) { + case Token.PLUS_PLUS: return OperatorKind.POSTFIX_INC; + case Token.MINUS_MINUS: return OperatorKind.POSTFIX_DEC; + } + return OperatorKind.INVALID; } - return OperatorKind.INVALID; } /** Represents an AssemblyScript program. */ @@ -332,8 +394,8 @@ export class Program extends DiagnosticEmitter { elementsByDeclaration: Map = new Map(); /** Element instances by unique internal name. */ instancesByName: Map = new Map(); - /** Classes backing basic types like `i32`. */ - typeClasses: Map = new Map(); + /** Classes wrapping basic types like `i32`. */ + wrapperClasses: Map = new Map(); /** Managed classes contained in the program, by id. */ managedClasses: Map = new Map(); /** A set of unique function signatures contained in the program, by id. */ @@ -782,20 +844,20 @@ export class Program extends DiagnosticEmitter { assert(this.arrayBufferViewInstance.id == 2); // register classes backing basic types - this.registerNativeTypeClass(TypeKind.I8, CommonSymbols.I8); - this.registerNativeTypeClass(TypeKind.I16, CommonSymbols.I16); - this.registerNativeTypeClass(TypeKind.I32, CommonSymbols.I32); - this.registerNativeTypeClass(TypeKind.I64, CommonSymbols.I64); - this.registerNativeTypeClass(TypeKind.ISIZE, CommonSymbols.Isize); - this.registerNativeTypeClass(TypeKind.U8, CommonSymbols.U8); - this.registerNativeTypeClass(TypeKind.U16, CommonSymbols.U16); - this.registerNativeTypeClass(TypeKind.U32, CommonSymbols.U32); - this.registerNativeTypeClass(TypeKind.U64, CommonSymbols.U64); - this.registerNativeTypeClass(TypeKind.USIZE, CommonSymbols.Usize); - this.registerNativeTypeClass(TypeKind.BOOL, CommonSymbols.Bool); - this.registerNativeTypeClass(TypeKind.F32, CommonSymbols.F32); - this.registerNativeTypeClass(TypeKind.F64, CommonSymbols.F64); - if (options.hasFeature(Feature.SIMD)) this.registerNativeTypeClass(TypeKind.V128, CommonSymbols.V128); + this.registerWrapperClass(Type.i8, CommonSymbols.I8); + this.registerWrapperClass(Type.i16, CommonSymbols.I16); + this.registerWrapperClass(Type.i32, CommonSymbols.I32); + this.registerWrapperClass(Type.i64, CommonSymbols.I64); + this.registerWrapperClass(options.isizeType, CommonSymbols.Isize); + this.registerWrapperClass(Type.u8, CommonSymbols.U8); + this.registerWrapperClass(Type.u16, CommonSymbols.U16); + this.registerWrapperClass(Type.u32, CommonSymbols.U32); + this.registerWrapperClass(Type.u64, CommonSymbols.U64); + this.registerWrapperClass(options.usizeType, CommonSymbols.Usize); + this.registerWrapperClass(Type.bool, CommonSymbols.Bool); + this.registerWrapperClass(Type.f32, CommonSymbols.F32); + this.registerWrapperClass(Type.f64, CommonSymbols.F64); + if (options.hasFeature(Feature.SIMD)) this.registerWrapperClass(Type.v128, CommonSymbols.V128); // register views but don't instantiate them yet this.i8ArrayPrototype = this.require(CommonSymbols.Int8Array, ElementKind.CLASS_PROTOTYPE); @@ -962,14 +1024,16 @@ export class Program extends DiagnosticEmitter { } /** Registers the backing class of a native type. */ - private registerNativeTypeClass(typeKind: TypeKind, className: string): void { - assert(!this.typeClasses.has(typeKind)); + private registerWrapperClass(type: Type, className: string): void { + var wrapperClasses = this.wrapperClasses; + assert(!type.classReference && !wrapperClasses.has(type)); var element = this.lookupGlobal(className); - if (element) { - assert(element.kind == ElementKind.CLASS_PROTOTYPE); - let classElement = this.resolver.resolveClass(element, null); - if (classElement) this.typeClasses.set(typeKind, classElement); - } + if (!element) return; + assert(element.kind == ElementKind.CLASS_PROTOTYPE); + var classElement = this.resolver.resolveClass(element, null); + if (!classElement) return; + classElement.wrappedType = type; + wrapperClasses.set(type, classElement); } /** Registers a constant integer value within the global scope. */ @@ -1104,8 +1168,8 @@ export class Program extends DiagnosticEmitter { if (decorators) { for (let i = 0, k = decorators.length; i < k; ++i) { let decorator = decorators[i]; - let kind = decoratorNameToKind(decorator.name); - let flag = decoratorKindToFlag(kind); + let kind = DecoratorKind.fromNode(decorator.name); + let flag = DecoratorFlags.fromKind(kind); if (flag) { if (flag == DecoratorFlags.BUILTIN) { if (!(acceptedFlags & flag) && !decorator.range.source.isLibrary) { @@ -1301,7 +1365,7 @@ export class Program extends DiagnosticEmitter { firstArg.kind == NodeKind.LITERAL && (firstArg).literalKind == LiteralKind.STRING ) { - let kind = operatorKindFromDecorator( + let kind = OperatorKind.fromDecorator( decorator.decoratorKind, (firstArg).value ); @@ -1939,22 +2003,25 @@ export enum DecoratorFlags { UNSAFE = 1 << 10 } -/** Translates a decorator kind to the respective decorator flag. */ -export function decoratorKindToFlag(kind: DecoratorKind): DecoratorFlags { - switch (kind) { - case DecoratorKind.GLOBAL: return DecoratorFlags.GLOBAL; - case DecoratorKind.OPERATOR: - case DecoratorKind.OPERATOR_BINARY: return DecoratorFlags.OPERATOR_BINARY; - case DecoratorKind.OPERATOR_PREFIX: return DecoratorFlags.OPERATOR_PREFIX; - case DecoratorKind.OPERATOR_POSTFIX: return DecoratorFlags.OPERATOR_POSTFIX; - case DecoratorKind.UNMANAGED: return DecoratorFlags.UNMANAGED; - case DecoratorKind.SEALED: return DecoratorFlags.SEALED; - case DecoratorKind.INLINE: return DecoratorFlags.INLINE; - case DecoratorKind.EXTERNAL: return DecoratorFlags.EXTERNAL; - case DecoratorKind.BUILTIN: return DecoratorFlags.BUILTIN; - case DecoratorKind.LAZY: return DecoratorFlags.LAZY; - case DecoratorKind.UNSAFE: return DecoratorFlags.UNSAFE; - default: return DecoratorFlags.NONE; +export namespace DecoratorFlags { + + /** Translates a decorator kind to the respective decorator flag. */ + export function fromKind(kind: DecoratorKind): DecoratorFlags { + switch (kind) { + case DecoratorKind.GLOBAL: return DecoratorFlags.GLOBAL; + case DecoratorKind.OPERATOR: + case DecoratorKind.OPERATOR_BINARY: return DecoratorFlags.OPERATOR_BINARY; + case DecoratorKind.OPERATOR_PREFIX: return DecoratorFlags.OPERATOR_PREFIX; + case DecoratorKind.OPERATOR_POSTFIX: return DecoratorFlags.OPERATOR_POSTFIX; + case DecoratorKind.UNMANAGED: return DecoratorFlags.UNMANAGED; + case DecoratorKind.SEALED: return DecoratorFlags.SEALED; + case DecoratorKind.INLINE: return DecoratorFlags.INLINE; + case DecoratorKind.EXTERNAL: return DecoratorFlags.EXTERNAL; + case DecoratorKind.BUILTIN: return DecoratorFlags.BUILTIN; + case DecoratorKind.LAZY: return DecoratorFlags.LAZY; + case DecoratorKind.UNSAFE: return DecoratorFlags.UNSAFE; + default: return DecoratorFlags.NONE; + } } } @@ -2062,6 +2129,14 @@ export abstract class Element { } } +// Kinds of all declared elements +var declaredElements = new Set(); + +/** Tests if the specified element kind indicates a declared element. */ +export function isDeclaredElement(kind: ElementKind): bool { + return declaredElements.has(kind); +} + /** Base class of elements with an associated declaration statement. */ export abstract class DeclaredElement extends Element { @@ -2081,6 +2156,7 @@ export abstract class DeclaredElement extends Element { public declaration: DeclarationStatement ) { super(kind, name, internalName, program, parent); + declaredElements.add(kind); // It is necessary to have access to identifiers of all members and exports // for reporting purposes and this is the lowest common denominator. Comes // at the expense of not having more specific type information in derived @@ -2107,12 +2183,38 @@ export abstract class DeclaredElement extends Element { } } +// Kinds of all typed elements +var typedElements = new Set(); + +/** Checks if the specified element kind indicates a typed element. */ +export function isTypedElement(kind: ElementKind): bool { + return typedElements.has(kind); +} + /** Base class of elements that can be resolved to a concrete type. */ export abstract class TypedElement extends DeclaredElement { /** Resolved type. Set once `is(RESOLVED)`, otherwise void. */ type: Type = Type.void; + constructor( + /** Specific element kind. */ + kind: ElementKind, + /** Simple name. */ + name: string, + /** Internal name referring to this element. */ + internalName: string, + /** Containing {@link Program}. */ + program: Program, + /** Parent element. */ + parent: Element | null, + /** Declaration reference. */ + declaration: DeclarationStatement + ) { + super(kind, name, internalName, program, parent, declaration); + typedElements.add(kind); + } + /** Sets the resolved type of this element. */ setType(type: Type): void { assert(!this.is(CommonFlags.RESOLVED)); @@ -3105,6 +3207,8 @@ export class Class extends TypedElement { private _acyclic: AcyclicState = AcyclicState.UNKNOWN; /** Runtime type information flags. */ rttiFlags: u32 = 0; + /** Wrapped type, if a wrapper for a basic type. */ + wrappedType: Type | null = null; /** Gets the unique runtime id of this class. */ get id(): u32 { @@ -3358,14 +3462,15 @@ export class Class extends TypedElement { var members = this.members; if (members) { for (let member of members.values()) { - if ( - member.kind == ElementKind.FIELD && - (current = (member).type.classReference) !== null && - ( - current === other || - current.cyclesTo(other, except) - ) - ) return true; + if (member.kind == ElementKind.FIELD) { + let type = (member).type; + if (type.is(TypeFlags.REFERENCE)) { + if ((current = type.classReference) !== null && ( + current === other || + current.cyclesTo(other, except) + )) return true; + } + } } } diff --git a/src/resolver.ts b/src/resolver.ts index 6897b8bc56..6e335c9093 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -23,7 +23,10 @@ import { Field, FieldPrototype, Global, - TypeDefinition + TypeDefinition, + TypedElement, + FunctionTarget, + isTypedElement } from "./program"; import { @@ -57,7 +60,12 @@ import { BinaryExpression, ThisExpression, SuperExpression, - isTypeOmitted + CommaExpression, + InstanceOfExpression, + TernaryExpression, + isTypeOmitted, + FunctionExpression, + NewExpression } from "./ast"; import { @@ -79,7 +87,8 @@ import { } from "./util"; import { - Token + Token, + operatorTokenToString } from "./tokenizer"; import { @@ -124,7 +133,7 @@ export class Resolver extends DiagnosticEmitter { ctxElement: Element, /** Contextual types, i.e. `T`. */ ctxTypes: Map | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { switch (node.kind) { @@ -157,7 +166,7 @@ export class Resolver extends DiagnosticEmitter { ctxElement: Element, /** Contextual types, i.e. `T`. */ ctxTypes: Map | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { var nameNode = node.name; @@ -334,7 +343,7 @@ export class Resolver extends DiagnosticEmitter { ctxElement: Element, /** Contextual types, i.e. `T`. */ ctxTypes: Map | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { var explicitThisType = node.explicitThisType; @@ -420,7 +429,7 @@ export class Resolver extends DiagnosticEmitter { ctxElement: Element, /** Contextual types, i.e. `T`. */ ctxTypes: Map | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; @@ -463,7 +472,7 @@ export class Resolver extends DiagnosticEmitter { ctxElement: Element, /** Contextual types, i.e. `T`. */ ctxTypes: Map | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; @@ -514,7 +523,7 @@ export class Resolver extends DiagnosticEmitter { ctxElement: Element, /** Contextual types, i.e. `T`. */ ctxTypes: Map | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; @@ -592,7 +601,7 @@ export class Resolver extends DiagnosticEmitter { node: TypeName, /** Contextual element. */ ctxElement: Element, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode = ReportMode.REPORT ): Element | null { var element = ctxElement.lookup(node.identifier.text); @@ -635,7 +644,7 @@ export class Resolver extends DiagnosticEmitter { ctxTypes: Map = makeMap(), /** Alternative report node in case of empty type arguments. */ alternativeReportNode: Node | null = null, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Type[] | null { var minParameterCount = 0; @@ -682,47 +691,226 @@ export class Resolver extends DiagnosticEmitter { return typeArguments; } + /** Gets the concrete type of an element. */ + getTypeOfElement(element: Element): Type | null { + var kind = element.kind; + if (kind == ElementKind.GLOBAL) { + if (!this.ensureResolvedLazyGlobal(element, ReportMode.SWALLOW)) return null; + } + if (isTypedElement(kind)) { + let type = (element).type; + let classReference = type.classReference; + if (classReference) { + let wrappedType = classReference.wrappedType; + if (wrappedType) type = wrappedType; + } + return type; + } + if (kind == ElementKind.FUNCTION_TARGET) return (element).type; + return null; + } + + /** Gets the element of a concrete type. */ + getElementOfType(type: Type): Element | null { + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) return classReference; + let signatureReference = assert(type.signatureReference); + return signatureReference.asFunctionTarget(this.program); + } else if (type != Type.void) { + let wrapperClasses = this.program.wrapperClasses; + assert(wrapperClasses.has(type)); + return wrapperClasses.get(type); + } + return null; + } + // =================================================== Expressions =================================================== - /** Resolves an expression to the program element it refers to. */ - resolveExpression( - /** The expression to resolve. */ + /** Looks up the program element the specified expression refers to. */ + lookupExpression( + /** The expression to look up. */ node: Expression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { - while (node.kind == NodeKind.PARENTHESIZED) { // simply skip + while (node.kind == NodeKind.PARENTHESIZED) { // skip node = (node).expression; } switch (node.kind) { case NodeKind.ASSERTION: { - return this.resolveAssertionExpression( + return this.lookupAssertionExpression( node, ctxFlow, ctxType, reportMode ); } - case NodeKind.UNARYPREFIX: { - return this.resolveUnaryPrefixExpression( - node, + case NodeKind.BINARY: { + return this.lookupBinaryExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.CALL: { + return this.lookupCallExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.COMMA: { + return this.lookupCommaExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.ELEMENTACCESS: { + return this.lookupElementAccessExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.FUNCTION: { + return this.lookupFunctionExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.IDENTIFIER: + case NodeKind.FALSE: + case NodeKind.NULL: + case NodeKind.TRUE: { + return this.lookupIdentifierExpression( + node, + ctxFlow, ctxFlow.actualFunction, reportMode + ); + } + case NodeKind.THIS: { + return this.lookupThisExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.SUPER: { + return this.lookupSuperExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.INSTANCEOF: { + return this.lookupInstanceOfExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.LITERAL: { + return this.lookupLiteralExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.NEW: { + return this.lookupNewExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.PROPERTYACCESS: { + return this.lookupPropertyAccessExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.TERNARY: { + return this.lookupTernaryExpression( + node, ctxFlow, ctxType, reportMode ); } case NodeKind.UNARYPOSTFIX: { - return this.resolveUnaryPostfixExpression( + return this.lookupUnaryPostfixExpression( node, ctxFlow, ctxType, reportMode ); } + case NodeKind.UNARYPREFIX: { + return this.lookupUnaryPrefixExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + } + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + return null; + } + + /** Resolves an expression to its static type. */ + resolveExpression( + /** The expression to resolve. */ + node: Expression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + while (node.kind == NodeKind.PARENTHESIZED) { // skip + node = (node).expression; + } + switch (node.kind) { + case NodeKind.ASSERTION: { + return this.resolveAssertionExpression( + node, + ctxFlow, ctxType, reportMode + ); + } case NodeKind.BINARY: { return this.resolveBinaryExpression( node, ctxFlow, ctxType, reportMode ); } + case NodeKind.CALL: { + return this.resolveCallExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.COMMA: { + return this.resolveCommaExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.ELEMENTACCESS: { + return this.resolveElementAccessExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.FUNCTION: { + return this.resolveFunctionExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.IDENTIFIER: + case NodeKind.FALSE: + case NodeKind.NULL: + case NodeKind.TRUE: { + return this.resolveIdentifierExpression( + node, + ctxFlow, ctxFlow.actualFunction, reportMode + ); + } case NodeKind.THIS: { return this.resolveThisExpression( node, @@ -735,10 +923,10 @@ export class Resolver extends DiagnosticEmitter { ctxFlow, ctxType, reportMode ); } - case NodeKind.IDENTIFIER: { - return this.resolveIdentifier( - node, - ctxFlow, ctxFlow.actualFunction, reportMode + case NodeKind.INSTANCEOF: { + return this.resolveInstanceOfExpression( + node, + ctxFlow, ctxType, reportMode ); } case NodeKind.LITERAL: { @@ -747,25 +935,36 @@ export class Resolver extends DiagnosticEmitter { ctxFlow, ctxType, reportMode ); } + case NodeKind.NEW: { + return this.resolveNewExpression( + node, + ctxFlow, ctxType, reportMode + ); + } case NodeKind.PROPERTYACCESS: { return this.resolvePropertyAccessExpression( node, ctxFlow, ctxType, reportMode ); } - case NodeKind.ELEMENTACCESS: { - return this.resolveElementAccessExpression( - node, + case NodeKind.TERNARY: { + return this.resolveTernaryExpression( + node, ctxFlow, ctxType, reportMode ); } - case NodeKind.CALL: { - return this.resolveCallExpression( - node, + case NodeKind.UNARYPOSTFIX: { + return this.resolveUnaryPostfixExpression( + node, + ctxFlow, ctxType, reportMode + ); + } + case NodeKind.UNARYPREFIX: { + return this.resolveUnaryPrefixExpression( + node, ctxFlow, ctxType, reportMode ); } - // TODO: everything else } if (reportMode == ReportMode.REPORT) { this.error( @@ -776,15 +975,15 @@ export class Resolver extends DiagnosticEmitter { return null; } - /** Resolves an identifier to the program element it refers to. */ - resolveIdentifier( - /** The expression to resolve. */ + /** Looks up the program element the specified identifier expression refers to. */ + lookupIdentifierExpression( + /** The expression to look up. */ node: IdentifierExpression, /** Flow to search for scoped locals. */ ctxFlow: Flow, /** Element to search. */ - ctxElement: Element = ctxFlow.actualFunction, - /** How to proceed with eventualy diagnostics. */ + ctxElement: Element = ctxFlow.actualFunction, // differs for enums and namespaces + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { var name = node.text; @@ -813,6 +1012,31 @@ export class Resolver extends DiagnosticEmitter { return null; } + /** Resolves an identifier to its static type. */ + private resolveIdentifierExpression( + /** The expression to resolve. */ + node: IdentifierExpression, + /** Flow to search for scoped locals. */ + ctxFlow: Flow, + /** Element to search. */ + ctxElement: Element = ctxFlow.actualFunction, // differs for enums and namespaces + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var element = this.lookupIdentifierExpression(node, ctxFlow, ctxElement, reportMode); + if (!element) return null; + var type = this.getTypeOfElement(element); + if (!type) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return type; + } + /** Resolves a lazily compiled global, i.e. a static class field or annotated `@lazy`. */ private ensureResolvedLazyGlobal(global: Global, reportMode: ReportMode = ReportMode.REPORT): bool { if (global.is(CommonFlags.RESOLVED)) return true; @@ -829,19 +1053,19 @@ export class Resolver extends DiagnosticEmitter { return true; } - /** Resolves a property access expression to the program element it refers to. */ - resolvePropertyAccessExpression( - /** The expression to resolve. */ + /** Looks up the program element the specified property access expression refers to. */ + private lookupPropertyAccessExpression( + /** The expression to look up. */ node: PropertyAccessExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { var targetNode = node.expression; - var target = this.resolveExpression(targetNode, ctxFlow, ctxType, reportMode); // reports + var target = this.lookupExpression(targetNode, ctxFlow, ctxType, reportMode); // reports if (!target) return null; var propertyName = node.property.text; @@ -853,14 +1077,16 @@ export class Resolver extends DiagnosticEmitter { let type = (target).type; assert(type != Type.void); let classReference = type.classReference; if (!classReference) { - let typeClasses = this.program.typeClasses; - if (!type.is(TypeFlags.REFERENCE) && typeClasses.has(type.kind)) { - classReference = typeClasses.get(type.kind)!; + let wrapperClasses = this.program.wrapperClasses; + if (wrapperClasses.has(type)) { + classReference = wrapperClasses.get(type)!; } else { - this.error( - DiagnosticCode.Property_0_does_not_exist_on_type_1, - node.property.range, propertyName, (target).type.toString() - ); + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Property_0_does_not_exist_on_type_1, + node.property.range, propertyName, (target).type.toString() + ); + } return null; } } @@ -875,26 +1101,42 @@ export class Resolver extends DiagnosticEmitter { reportMode ); if (!getterInstance) return null; - let classReference = getterInstance.signature.returnType.classReference; + let type = getterInstance.signature.returnType; + let classReference = type.classReference; if (!classReference) { - this.error( - DiagnosticCode.Property_0_does_not_exist_on_type_1, - node.property.range, propertyName, getterInstance.signature.returnType.toString() - ); - return null; + let wrapperClasses = this.program.wrapperClasses; + if (wrapperClasses.has(type)) { + classReference = wrapperClasses.get(type)!; + } else { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Property_0_does_not_exist_on_type_1, + node.property.range, propertyName, type.toString() + ); + } + return null; + } } target = classReference; break; } case ElementKind.PROPERTY: { // instance let getterInstance = assert((target).getterInstance); // must have a getter - let classReference = getterInstance.signature.returnType.classReference; + let type = getterInstance.signature.returnType; + let classReference = type.classReference; if (!classReference) { - this.error( - DiagnosticCode.Property_0_does_not_exist_on_type_1, - node.property.range, propertyName, getterInstance.signature.returnType.toString() - ); - return null; + let wrapperClasses = this.program.wrapperClasses; + if (wrapperClasses.has(type)) { + classReference = wrapperClasses.get(type)!; + } else { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Property_0_does_not_exist_on_type_1, + node.property.range, propertyName, type.toString() + ); + } + return null; + } } target = classReference; break; @@ -904,23 +1146,27 @@ export class Resolver extends DiagnosticEmitter { if (elementExpression) { let indexedGet = (target).lookupOverload(OperatorKind.INDEXED_GET); if (!indexedGet) { - this.error( - DiagnosticCode.Index_signature_is_missing_in_type_0, - elementExpression.range, (target).internalName - ); + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Index_signature_is_missing_in_type_0, + elementExpression.range, (target).internalName + ); + } return null; } let arrayType = indexedGet.signature.returnType; let classReference = arrayType.classReference; if (!classReference) { - let typeClasses = this.program.typeClasses; - if (!arrayType.is(TypeFlags.REFERENCE) && typeClasses.has(arrayType.kind)) { - classReference = typeClasses.get(arrayType.kind)!; + let wrapperClasses = this.program.wrapperClasses; + if (wrapperClasses.has(arrayType)) { + classReference = wrapperClasses.get(arrayType)!; } else { - this.error( - DiagnosticCode.Property_0_does_not_exist_on_type_1, - node.property.range, propertyName, arrayType.toString() - ); + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Property_0_does_not_exist_on_type_1, + node.property.range, propertyName, arrayType.toString() + ); + } return null; } } @@ -984,68 +1230,96 @@ export class Resolver extends DiagnosticEmitter { } } - this.error( - DiagnosticCode.Property_0_does_not_exist_on_type_1, - node.property.range, propertyName, target.internalName - ); + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Property_0_does_not_exist_on_type_1, + node.property.range, propertyName, target.internalName + ); + } return null; } - /** Resolves an element access expression to the program element it refers to. */ - resolveElementAccessExpression( + /** Resolves a property access expression to its static type. */ + private resolvePropertyAccessExpression( /** The expression to resolve. */ + node: PropertyAccessExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var element = this.lookupPropertyAccessExpression(node, ctxFlow, ctxType, reportMode); + if (!element) return null; + var type = this.getTypeOfElement(element); + if (!type) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return type; + } + + /** Looks up the program element the specified element access expression refers to. */ + private lookupElementAccessExpression( + /** The expression to look up. */ node: ElementAccessExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { var targetExpression = node.expression; - var target = this.resolveExpression(targetExpression, ctxFlow, ctxType, reportMode); // reports - if (!target) return null; - switch (target.kind) { - case ElementKind.GLOBAL: if (!this.ensureResolvedLazyGlobal(target, reportMode)) return null; - case ElementKind.LOCAL: - case ElementKind.FIELD: { - let type = (target).type; - if (target = type.classReference) { - this.currentThisExpression = targetExpression; - this.currentElementExpression = node.elementExpression; - return target; - } - break; - } - case ElementKind.CLASS: { - let indexedGet = (target).lookupOverload(OperatorKind.INDEXED_GET); - if (!indexedGet) { - if (reportMode == ReportMode.REPORT) { - this.error( - DiagnosticCode.Index_signature_is_missing_in_type_0, - node.range, (target).internalName - ); - } - return null; - } - let arrayType = indexedGet.signature.returnType; - if (targetExpression.kind == NodeKind.ELEMENTACCESS) { // nested element access - if (target = arrayType.classReference) { - this.currentThisExpression = targetExpression; - this.currentElementExpression = node.elementExpression; - return target; - } - return null; - } + var targetType = this.resolveExpression(targetExpression, ctxFlow, ctxType, reportMode); + if (!targetType) return null; + if (targetType.is(TypeFlags.REFERENCE)) { + let classReference = targetType.classReference; + if (classReference) { this.currentThisExpression = targetExpression; this.currentElementExpression = node.elementExpression; - return target; + return classReference; } } if (reportMode == ReportMode.REPORT) { this.error( - DiagnosticCode.Operation_not_supported, - targetExpression.range + DiagnosticCode.Index_signature_is_missing_in_type_0, + targetExpression.range, targetType.toString() + ); + } + return null; + } + + /** Resolves an element access expression to its static type. */ + private resolveElementAccessExpression( + /** The expression to resolve. */ + node: ElementAccessExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var targetExpression = node.expression; + var targetType = this.resolveExpression(targetExpression, ctxFlow, ctxType, reportMode); + if (!targetType) return null; + if (targetType.is(TypeFlags.REFERENCE)) { + let classReference = targetType.classReference; + if (classReference) { + 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, + targetExpression.range, targetType.toString() ); } return null; @@ -1117,24 +1391,19 @@ export class Resolver extends DiagnosticEmitter { return Type.i64; // TODO: u64 if positive and larger than i64? } - /** Resolves an assertion expression to the program element it refers to. */ - resolveAssertionExpression( - /** The expression to resolve. */ + /** Looks up the program element the specified assertion expression refers to. */ + private lookupAssertionExpression( + /** The expression to look up. */ node: AssertionExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { if (node.assertionKind == AssertionKind.NONNULL) { - return this.resolveExpression( - node.expression, - ctxFlow, - ctxType, - reportMode - ); + return this.lookupExpression(node.expression, ctxFlow, ctxType, reportMode); } var type = this.resolveType( assert(node.toType), // must be set if not NONNULL @@ -1143,86 +1412,210 @@ export class Resolver extends DiagnosticEmitter { reportMode ); if (!type) return null; - var element: Element | null = type.classReference; - if (!element) { - let signature = type.signatureReference; - if (!signature) return null; - element = signature.asFunctionTarget(this.program); + var element = this.getElementOfType(type); + if (element) return element; + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); } this.currentThisExpression = null; this.currentElementExpression = null; - return element; + return null; } - /** Resolves an unary prefix expression to the program element it refers to. */ - resolveUnaryPrefixExpression( + /** Resolves an assertion expression to its static type. */ + private resolveAssertionExpression( /** The expression to resolve. */ + node: AssertionExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + if (node.assertionKind == AssertionKind.NONNULL) { + let type = this.resolveExpression(node.expression, ctxFlow, ctxType, reportMode); + return type ? type.nonNullableType : null; + } + return this.resolveType( + assert(node.toType), // must be set if not NONNULL + ctxFlow.actualFunction, + ctxFlow.contextualTypeArguments, + reportMode + ); + } + + /** Looks up the program element the specified unary prefix expression refers to. */ + private lookupUnaryPrefixExpression( + /** The expression to look up. */ node: UnaryPrefixExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { + var type = this.resolveUnaryPrefixExpression(node, ctxFlow, ctxType, reportMode); + if (!type) return null; + var element = this.getElementOfType(type); + if (!element) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, operatorTokenToString(node.operator), type.toString() + ); + } + } + return element; + } + + /** Resolves an unary prefix expression to its static type. */ + private resolveUnaryPrefixExpression( + /** The expression to resolve. */ + node: UnaryPrefixExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { var operand = node.operand; - // TODO: operator overloads - switch (node.operator) { + var operator = node.operator; + switch (operator) { case Token.MINUS: { // implicitly negate if an integer literal to distinguish between i32/u32/i64 if (operand.kind == NodeKind.LITERAL && (operand).literalKind == LiteralKind.INTEGER) { - let type = this.determineIntegerLiteralType( - i64_sub(i64_zero, (operand).value), - ctxType - ); - let typeClasses = this.program.typeClasses; - return typeClasses.has(type.kind) ? typeClasses.get(type.kind)! : null; + return this.determineIntegerLiteralType(i64_sub(i64_zero, (operand).value), ctxType); } - return this.resolveExpression(operand, ctxFlow, ctxType, reportMode); + // fall-through } case Token.PLUS: case Token.PLUS_PLUS: case Token.MINUS_MINUS: { - return this.resolveExpression(node.operand, ctxFlow, ctxType, reportMode); + let type = this.resolveExpression(operand, ctxFlow, ctxType, reportMode); + if (!type) return null; + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromUnaryPrefixToken(operator)); + if (overload) return overload.signature.returnType; + let wrappedType = classReference.wrappedType; + if (wrappedType) type = wrappedType; + } + } + if (!type.isAny(TypeFlags.FLOAT | TypeFlags.INTEGER) || type.is(TypeFlags.REFERENCE)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, operatorTokenToString(operator), type.toString() + ); + } + return null; + } + return type; } case Token.EXCLAMATION: { - let typeClasses = this.program.typeClasses; - assert(typeClasses.has(TypeKind.BOOL)); - return typeClasses.get(TypeKind.BOOL); + let type = this.resolveExpression(operand, ctxFlow, ctxType, reportMode); + if (!type) return null; + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.NOT); + if (overload) return overload.signature.returnType; + } + } + return Type.bool; // incl. references } case Token.TILDE: { - let resolvedOperand = this.resolveExpression(node.operand, ctxFlow, ctxType, reportMode); - if (!resolvedOperand) return null; - // TODO: matching integer type - break; + let type = this.resolveExpression(operand, ctxFlow, ctxType, reportMode); + if (!type) return null; + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.BITWISE_NOT); + if (overload) return overload.signature.returnType; + } + } + if (!type.isAny(TypeFlags.FLOAT | TypeFlags.INTEGER) || !type.is(TypeFlags.VALUE)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, "~", type.toString() + ); + } + return null; + } + return type.intType; } default: assert(false); } - if (reportMode == ReportMode.REPORT) { - this.error( - DiagnosticCode.Operation_not_supported, - node.range - ); - } return null; } - /** Resolves an unary postfix expression to the program element it refers to. */ - resolveUnaryPostfixExpression( + /** Looks up the program element the specified unary postfix expression refers to. */ + private lookupUnaryPostfixExpression( /** The expression to resolve. */ node: UnaryPostfixExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { - // TODO: operator overloads - switch (node.operator) { + var type = this.resolveUnaryPostfixExpression(node, ctxFlow, ctxType, reportMode); + if (!type) return null; + var element = this.getElementOfType(type); + if (!element) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, operatorTokenToString(node.operator), type.toString() + ); + } + } + return element; + } + + /** Resolves an unary postfix expression to its static type. */ + private resolveUnaryPostfixExpression( + /** The expression to resolve. */ + node: UnaryPostfixExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var operator = node.operator; + switch (operator) { case Token.PLUS_PLUS: case Token.MINUS_MINUS: { - return this.resolveExpression(node.operand, ctxFlow, ctxType, reportMode); + let type = this.resolveExpression(node.operand, ctxFlow, ctxType, reportMode); + if (!type) return null; + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromUnaryPostfixToken(operator)); + if (overload) return overload.signature.returnType; + } + } + if (!type.isAny(TypeFlags.INTEGER | TypeFlags.FLOAT) || !type.is(TypeFlags.VALUE)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, operatorTokenToString(operator), type.toString() + ); + } + return null; + } + return type; } default: assert(false); } @@ -1235,36 +1628,240 @@ export class Resolver extends DiagnosticEmitter { return null; } - /** Resolves a binary expression to the program element it refers to. */ - resolveBinaryExpression( - /** The expression to resolve. */ - name: BinaryExpression, + /** Looks up the program element the specified binary expression refers to. */ + private lookupBinaryExpression( + /** The expression to look up. */ + node: BinaryExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { - // TODO + var type = this.resolveBinaryExpression(node, ctxFlow, ctxType, reportMode); + if (!type) return null; + var element = this.getElementOfType(type); + if (element) return element; // otherwise void if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Operation_not_supported, - name.range + node.range ); } return null; } - /** Resolves a this expression to the program element it refers to. */ - resolveThisExpression( + /** Resolves a binary expression to its static type. */ + private resolveBinaryExpression( /** The expression to resolve. */ + node: BinaryExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var left = node.left; + var right = node.right; + var operator = node.operator; + + switch (operator) { + + // assignment: result is the target's type + + case Token.EQUALS: + case Token.PLUS_EQUALS: + case Token.MINUS_EQUALS: + case Token.ASTERISK_EQUALS: + case Token.ASTERISK_ASTERISK_EQUALS: + case Token.SLASH_EQUALS: + case Token.PERCENT_EQUALS: + case Token.LESSTHAN_LESSTHAN_EQUALS: + case Token.GREATERTHAN_GREATERTHAN_EQUALS: + case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: + case Token.AMPERSAND_EQUALS: + case Token.BAR_EQUALS: + case Token.CARET_EQUALS: { + return this.resolveExpression(left, ctxFlow, ctxType, reportMode); + } + + // comparison: result is Bool, preferring overloads, integer/float only + + case Token.LESSTHAN: + case Token.GREATERTHAN: + case Token.LESSTHAN_EQUALS: + case Token.GREATERTHAN_EQUALS: { + let leftType = this.resolveExpression(left, ctxFlow, ctxType, reportMode); + if (!leftType) return null; + if (leftType.is(TypeFlags.REFERENCE)) { + let classReference = leftType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromBinaryToken(operator)); + if (overload) return overload.signature.returnType; + } + } + if (!leftType.isAny(TypeFlags.INTEGER | TypeFlags.FLOAT) || leftType.is(TypeFlags.REFERENCE)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, operatorTokenToString(operator), leftType.toString() + ); + } + return null; + } + return Type.bool; + } + + // equality: result is Bool, preferring overloads, incl. references + + case Token.EQUALS_EQUALS: + case Token.EXCLAMATION_EQUALS: { + let leftType = this.resolveExpression(left, ctxFlow, ctxType, reportMode); + if (!leftType) return null; + if (leftType.is(TypeFlags.REFERENCE)) { + let classReference = leftType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromBinaryToken(operator)); + if (overload) return overload.signature.returnType; + } + } + return Type.bool; + } + + // identity: result is Bool, not supporting overloads + + case Token.EQUALS_EQUALS_EQUALS: + case Token.EXCLAMATION_EQUALS_EQUALS: { + return Type.bool; + } + + // arithmetics: result is common type of LHS and RHS, preferring overloads + + case Token.PLUS: + case Token.MINUS: + case Token.ASTERISK: + case Token.SLASH: + case Token.PERCENT: { // mod has special logic, but also behaves like this + let leftType = this.resolveExpression(left, ctxFlow, ctxType, reportMode); + if (!leftType) return null; + if (leftType.is(TypeFlags.REFERENCE)) { + let classReference = leftType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromBinaryToken(operator)); + if (overload) return overload.signature.returnType; + } + } + let rightType = this.resolveExpression(right, ctxFlow, leftType, reportMode); + if (!rightType) return null; + let commonType = Type.commonDenominator(leftType, rightType, false); + if (!commonType) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, + node.range, leftType.toString(), rightType.toString() + ); + } + } + return commonType; + } + + // pow: result is f32 if LHS is f32, otherwise f64, preferring overloads + + case Token.ASTERISK_ASTERISK: { + let leftType = this.resolveExpression(left, ctxFlow, ctxType, reportMode); + if (!leftType) return null; + if (leftType.is(TypeFlags.REFERENCE)) { + let classReference = leftType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.POW); + if (overload) return overload.signature.returnType; + } + } + return leftType == Type.f32 ? Type.f32 : Type.f64; + } + + // shift: result is LHS (RHS is converted to LHS), preferring overloads + + case Token.LESSTHAN_LESSTHAN: + case Token.GREATERTHAN_GREATERTHAN: + case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: { + let leftType = this.resolveExpression(left, ctxFlow, ctxType, reportMode); + if (!leftType) return null; + if (leftType.is(TypeFlags.REFERENCE)) { + let classReference = leftType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromBinaryToken(operator)); + if (overload) return overload.signature.returnType; + } + } + if (!leftType.is(TypeFlags.INTEGER) || leftType.is(TypeFlags.REFERENCE)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, + node.range, operatorTokenToString(operator), leftType.toString() + ); + } + return null; + } + return leftType; + } + + // bitwise: result is common type of LHS and RHS with floats not being supported, preferring overloads + + case Token.AMPERSAND: + case Token.BAR: + case Token.CARET: { + let leftType = this.resolveExpression(left, ctxFlow, ctxType, reportMode); + if (!leftType) return null; + if (leftType.is(TypeFlags.REFERENCE)) { + let classReference = leftType.classReference; + if (classReference) { + let overload = classReference.lookupOverload(OperatorKind.fromBinaryToken(operator)); + if (overload) return overload.signature.returnType; + } + } + let rightType = this.resolveExpression(right, ctxFlow, ctxType, reportMode); + if (!rightType) return null; + let commonType = Type.commonDenominator(leftType, rightType, false); + if (!commonType || !commonType.is(TypeFlags.INTEGER) || commonType.is(TypeFlags.REFERENCE)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, + node.range, operatorTokenToString(operator), leftType.toString(), rightType.toString() + ); + } + } + return commonType; + } + + // logical: result is LHS (RHS is converted to LHS), not supporting overloads + + case Token.AMPERSAND_AMPERSAND: + case Token.BAR_BAR: { + return this.resolveExpression(left, ctxFlow, ctxType, reportMode); + } + } + + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + return null; + } + + /** Looks up the program element the specified this expression refers to. */ + private lookupThisExpression( + /** The expression to look up. */ node: ThisExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { if (ctxFlow.is(FlowFlags.INLINE_CONTEXT)) { @@ -1290,15 +1887,40 @@ export class Resolver extends DiagnosticEmitter { return null; } - /** Resolves a super expression to the program element it refers to. */ - resolveSuperExpression( + /** Resolves a this expression to its static type. */ + private resolveThisExpression( /** The expression to resolve. */ + node: ThisExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var element = this.lookupThisExpression(node, ctxFlow, ctxType, reportMode); + if (!element) return null; + var type = this.getTypeOfElement(element); + if (!type) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return type; + } + + /** Looks up the program element the specified super expression refers to. */ + private lookupSuperExpression( + /** The expression to look up. */ node: SuperExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { if (ctxFlow.is(FlowFlags.INLINE_CONTEXT)) { @@ -1324,34 +1946,61 @@ export class Resolver extends DiagnosticEmitter { return null; } - /** Resolves a literal expression to the program element it refers to. */ - resolveLiteralExpression( + /** Resolves a super expression to its static type. */ + private resolveSuperExpression( /** The expression to resolve. */ + node: SuperExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var element = this.lookupSuperExpression(node, ctxFlow, ctxType, reportMode); + if (!element) return null; + var type = this.getTypeOfElement(element); + if (!type) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return type; + } + + /** Looks up the program element the specified literal expression refers to. */ + private lookupLiteralExpression( + /** The expression to look up. */ node: LiteralExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.auto, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { switch (node.literalKind) { case LiteralKind.INTEGER: { this.currentThisExpression = node; this.currentElementExpression = null; - let literalType = this.determineIntegerLiteralType( + let intType = this.determineIntegerLiteralType( (node).value, ctxType ); - let typeClasses = this.program.typeClasses; - return typeClasses.has(literalType.kind) ? typeClasses.get(literalType.kind)! : null; + let wrapperClasses = this.program.wrapperClasses; + assert(wrapperClasses.has(intType)); + return wrapperClasses.get(intType); } case LiteralKind.FLOAT: { this.currentThisExpression = node; this.currentElementExpression = null; - let literalType = ctxType == Type.f32 ? Type.f32 : Type.f64; - let typeClasses = this.program.typeClasses; - return typeClasses.has(literalType.kind) ? typeClasses.get(literalType.kind)! : null; + let fltType = ctxType == Type.f32 ? Type.f32 : Type.f64; + let wrapperClasses = this.program.wrapperClasses; + assert(wrapperClasses.has(fltType)); + return wrapperClasses.get(fltType); } case LiteralKind.STRING: { this.currentThisExpression = node; @@ -1370,81 +2019,318 @@ export class Resolver extends DiagnosticEmitter { return null; } - /** Resolves a call expression to the program element it refers to. */ - resolveCallExpression( + /** Resolves a literal expression to its static type. */ + private resolveLiteralExpression( /** The expression to resolve. */ + node: LiteralExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var element = this.lookupLiteralExpression(node, ctxFlow, ctxType, reportMode); + if (!element) return null; + var type = this.getTypeOfElement(element); + if (!type) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return type; + } + + /** Looks up the program element the specified call expression refers to. */ + private lookupCallExpression( + /** The expression to look up. */ node: CallExpression, /** Contextual flow. */ ctxFlow: Flow, /** Contextual type. */ ctxType: Type = Type.void, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Element | null { + var type = this.resolveCallExpression(node, ctxFlow, ctxType, reportMode); + if (!type) return null; + var element = this.getElementOfType(type); + if (!element) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return element; + } + + /** Resolves a call expression to its static type. */ + private resolveCallExpression( + /** The expression to resolve. */ + node: CallExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.void, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { var targetExpression = node.expression; - var target = this.resolveExpression( // reports + var target = this.lookupExpression( // reports targetExpression, ctxFlow, ctxType, reportMode ); - if (!target) return null; - if (target.kind == ElementKind.FUNCTION_PROTOTYPE) { - // `unchecked(expr: *): *` is special - if ( - (target).internalName == BuiltinSymbols.unchecked && - node.arguments.length > 0 - ) { - return this.resolveExpression(node.arguments[0], ctxFlow, ctxType, reportMode); - } - // otherwise resolve normally - let instance = this.resolveFunctionInclTypeArguments( - target, - node.typeArguments, - ctxFlow.actualFunction, - makeMap(ctxFlow.contextualTypeArguments), // don't inherit - node, - reportMode - ); - if (!instance) return null; - let returnType = instance.signature.returnType; - let classType = returnType.classReference; - if (classType) { - // reuse resolvedThisExpression (might be property access) - // reuse resolvedElementExpression (might be element access) - return classType; - } else { - let signature = returnType.signatureReference; - if (signature) { - let functionTarget = signature.asFunctionTarget(this.program); - // reuse resolvedThisExpression (might be property access) - // reuse resolvedElementExpression (might be element access) - return functionTarget; - } else { - let typeClasses = this.program.typeClasses; - if (!returnType.is(TypeFlags.REFERENCE) && typeClasses.has(returnType.kind)) { - return typeClasses.get(returnType.kind); - } + + switch (target.kind) { + case ElementKind.FUNCTION_PROTOTYPE: { + // `unchecked(expr: *): *` is special + if ( + (target).internalName == BuiltinSymbols.unchecked && + node.arguments.length > 0 + ) { + return this.resolveExpression(node.arguments[0], ctxFlow, ctxType, reportMode); } + // otherwise resolve normally + let instance = this.resolveFunctionInclTypeArguments( + target, + node.typeArguments, + ctxFlow.actualFunction, + makeMap(ctxFlow.contextualTypeArguments), // don't inherit + node, + reportMode + ); + if (!instance) return null; + return instance.signature.returnType; } + case ElementKind.FUNCTION_TARGET: { + return (target).signature.returnType; + } + } + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, + targetExpression.range, target.internalName + ); + } + return null; + } + + /** Looks up the program element the specified comma expression refers to. */ + private lookupCommaExpression( + /** The expression to look up. */ + node: CommaExpression, + /** Flow to search for scoped locals. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Element | null { + var expressions = node.expressions; + return this.lookupExpression(expressions[assert(expressions.length) - 1], ctxFlow, ctxType, reportMode); + } + + /** Resolves a comma expression to its static type. */ + private resolveCommaExpression( + /** The expression to resolve. */ + node: CommaExpression, + /** Flow to search for scoped locals. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var expressions = node.expressions; + return this.resolveExpression(expressions[assert(expressions.length) - 1], ctxFlow, ctxType, reportMode); + } + + /** Looks up the program element the specified instanceof expression refers to. */ + private lookupInstanceOfExpression( + /** The expression to look up. */ + node: InstanceOfExpression, + /** Flow to search for scoped locals. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Element | null { + var wrapperClasses = this.program.wrapperClasses; + assert(wrapperClasses.has(Type.bool)); + return wrapperClasses.get(Type.bool); + } + + /** Resolves an instanceof expression to its static type. */ + private resolveInstanceOfExpression( + /** The expression to resolve. */ + node: InstanceOfExpression, + /** Flow to search for scoped locals. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type = Type.auto, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + return Type.bool; + } + + /** Looks up the program element the specified ternary expression refers to. */ + private lookupTernaryExpression( + /** The expression to look up. */ + node: TernaryExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Element | null { + var type = this.resolveTernaryExpression(node, ctxFlow, ctxType, reportMode); + if (!type) return null; + var element = this.getElementOfType(type); + if (!element) { if (reportMode == ReportMode.REPORT) { this.error( - DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - targetExpression.range, target.internalName + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return element; + } + + /** Resolves a ternary expression to its static type. */ + private resolveTernaryExpression( + /** The expression to resolve. */ + node: TernaryExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var thenType = this.resolveExpression(node.ifThen, ctxFlow, ctxType, reportMode); + if (!thenType) return null; + var elseType = this.resolveExpression(node.ifElse, ctxFlow, thenType, reportMode); + if (!elseType) return null; + var commonType = Type.commonDenominator(thenType, elseType, false); + if (!commonType) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, + node.range, "?:", thenType.toString(), elseType.toString() ); } - return null; + } + return commonType; + } + + /** Looks up the program element the specified new expression refers to. */ + private lookupNewExpression( + /** The expression to look up. */ + node: NewExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Element | null { + var element = this.lookupExpression(node.expression, ctxFlow, ctxType, reportMode); + if (!element) return null; + if (element.kind == ElementKind.CLASS_PROTOTYPE) { + return this.resolveClassInclTypeArguments( + element, + node.typeArguments, + ctxFlow.actualFunction, + makeMap(ctxFlow.contextualTypeArguments), + node, + reportMode + ); } if (reportMode == ReportMode.REPORT) { this.error( - DiagnosticCode.Operation_not_supported, + DiagnosticCode.Cannot_use_new_with_an_expression_whose_type_lacks_a_construct_signature, node.range ); } return null; } + /** Resolves a new expression to its static type. */ + private resolveNewExpression( + /** The expression to resolve. */ + node: NewExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var element = this.lookupNewExpression(node, ctxFlow, ctxType, reportMode); + if (!element) return null; + var type = this.getTypeOfElement(element); + if (!type) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return type; + } + + /** Looks up the program element the specified function expression refers to. */ + private lookupFunctionExpression( + /** The expression to look up. */ + node: FunctionExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Element | null { + var type = this.resolveFunctionExpression(node, ctxFlow, ctxType, reportMode); + if (!type) return null; + var element = this.getElementOfType(type); + if (!element) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_not_supported, + node.range + ); + } + } + return element; + } + + /** Resolves a function expression to its static type. */ + private resolveFunctionExpression( + /** The expression to resolve. */ + node: FunctionExpression, + /** Contextual flow. */ + ctxFlow: Flow, + /** Contextual type. */ + ctxType: Type, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + return this.resolveFunctionType(node.declaration.signature, ctxFlow.actualFunction, ctxFlow.contextualTypeArguments, reportMode); + } + // ==================================================== Elements ===================================================== /** Resolves a function prototype using the specified concrete type arguments. */ @@ -1455,7 +2341,7 @@ export class Resolver extends DiagnosticEmitter { typeArguments: Type[] | null, /** Contextual types, i.e. `T`. */ ctxTypes: Map = makeMap(), - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Function | null { var actualParent = prototype.parent.kind == ElementKind.PROPERTY_PROTOTYPE @@ -1615,7 +2501,7 @@ export class Resolver extends DiagnosticEmitter { ctxTypes: Map, /** The node to use when reporting intermediate errors. */ reportNode: Node, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Function | null { var actualParent = prototype.parent.kind == ElementKind.PROPERTY_PROTOTYPE @@ -1683,7 +2569,7 @@ export class Resolver extends DiagnosticEmitter { typeArguments: Type[] | null, /** Contextual types, i.e. `T`. */ ctxTypes: Map = makeMap(), - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Class | null { var instanceKey = typeArguments ? typesToString(typeArguments) : ""; @@ -1887,6 +2773,27 @@ export class Resolver extends DiagnosticEmitter { if (!operatorInstance) continue; let overloads = instance.overloads; if (!overloads) instance.overloads = overloads = new Map(); + // inc/dec are special in that an instance overload attempts to re-assign + // the corresponding value, thus requiring a matching return type, while a + // static overload works like any other overload. + if (operatorInstance.is(CommonFlags.INSTANCE)) { + switch (kind) { + case OperatorKind.PREFIX_INC: + case OperatorKind.PREFIX_DEC: + case OperatorKind.POSTFIX_INC: + case OperatorKind.POSTFIX_DEC: { + let returnType = operatorInstance.signature.returnType; + if (!returnType.isAssignableTo(instance.type)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Type_0_is_not_assignable_to_type_1, + overloadPrototype.functionTypeNode.returnType.range, returnType.toString(), instance.type.toString() + ); + } + } + } + } + } overloads.set(kind, operatorInstance); } return instance; @@ -1904,7 +2811,7 @@ export class Resolver extends DiagnosticEmitter { ctxTypes: Map, /** The node to use when reporting intermediate errors. */ reportNode: Node, - /** How to proceed with eventualy diagnostics. */ + /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Class | null { var resolvedTypeArguments: Type[] | null = null; diff --git a/src/types.ts b/src/types.ts index f7c91fb4fd..4aafcaf1a3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -84,7 +84,7 @@ export const enum TypeFlags { LONG = 1 << 6, /** Is a value type. */ VALUE = 1 << 7, - /** Is a reference type. */ + /** Is a reference type (either a class or a function type). */ REFERENCE = 1 << 8, /** Is a nullable type. */ NULLABLE = 1 << 9, diff --git a/tests/compiler/empty.json b/tests/compiler/empty.json index 8ee35e6e7f..453cb07770 100644 --- a/tests/compiler/empty.json +++ b/tests/compiler/empty.json @@ -1,6 +1,5 @@ { "asc_flags": [ - "--runtime half", - "--use ASC_RTRACE=1" + "--runtime none" ] } diff --git a/tests/compiler/resolve-binary.json b/tests/compiler/resolve-binary.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/resolve-binary.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/resolve-binary.optimized.wat b/tests/compiler/resolve-binary.optimized.wat new file mode 100644 index 0000000000..66cff63842 --- /dev/null +++ b/tests/compiler/resolve-binary.optimized.wat @@ -0,0 +1,2395 @@ +(module + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$id (func (param f64) (result i32))) + (type $FUNCSIG$iid (func (param i32 f64) (result i32))) + (type $FUNCSIG$iijijiji (func (param i32 i64 i32 i64 i32 i64 i32) (result i32))) + (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$dd (func (param f64) (result f64))) + (type $FUNCSIG$i (func (result i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) "\08\00\00\00\01\00\00\00\01\00\00\00\08\00\00\00t\00r\00u\00e") + (data (i32.const 32) "\n\00\00\00\01\00\00\00\01\00\00\00\n\00\00\00f\00a\00l\00s\00e") + (data (i32.const 64) "\"\00\00\00\01\00\00\00\01\00\00\00\"\00\00\00r\00e\00s\00o\00l\00v\00e\00-\00b\00i\00n\00a\00r\00y\00.\00t\00s") + (data (i32.const 120) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00a") + (data (i32.const 144) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\000") + (data (i32.const 168) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\001") + (data (i32.const 192) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\002") + (data (i32.const 216) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\000\00.\000") + (data (i32.const 240) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00N\00a\00N") + (data (i32.const 264) "\12\00\00\00\01\00\00\00\01\00\00\00\12\00\00\00-\00I\00n\00f\00i\00n\00i\00t\00y") + (data (i32.const 304) "\10\00\00\00\01\00\00\00\01\00\00\00\10\00\00\00I\00n\00f\00i\00n\00i\00t\00y") + (data (i32.const 336) "\b8\02\00\00\01\00\00\00\00\00\00\00\b8\02\00\00\88\02\1c\08\a0\d5\8f\fav\bf>\a2\7f\e1\ae\bav\acU0 \fb\16\8b\ea5\ce]J\89B\cf-;eU\aa\b0k\9a\dfE\1a=\03\cf\1a\e6\ca\c6\9a\c7\17\fep\abO\dc\bc\be\fc\b1w\ff\0c\d6kA\ef\91V\be<\fc\7f\90\ad\1f\d0\8d\83\9aU1(\\Q\d3\b5\c9\a6\ad\8f\acq\9d\cb\8b\ee#w\"\9c\eamSx@\91I\cc\aeW\ce\b6]y\12<\827V\fbM6\94\10\c2O\98H8o\ea\96\90\c7:\82%\cb\85t\d7\f4\97\bf\97\cd\cf\86\a0\e5\ac*\17\98\n4\ef\8e\b25*\fbg8\b2;?\c6\d2\df\d4\c8\84\ba\cd\d3\1a\'D\dd\c5\96\c9%\bb\ce\9fk\93\84\a5b}$l\ac\db\f6\da_\0dXf\ab\a3&\f1\c3\de\93\f8\e2\f3\b8\80\ff\aa\a8\ad\b5\b5\8bJ|l\05_b\87S0\c14`\ff\bc\c9U&\ba\91\8c\85N\96\bd~)p$w\f9\df\8f\b8\e5\b8\9f\bd\df\a6\94}t\88\cf_\a9\f8\cf\9b\a8\8f\93pD\b9k\15\0f\bf\f8\f0\08\8a\b611eU%\b0\cd\ac\7f{\d0\c6\e2?\99\06;+*\c4\10\\\e4\d3\92si\99$$\aa\0e\ca\00\83\f2\b5\87\fd\eb\1a\11\92d\08\e5\bc\cc\88Po\t\cc\bc\8c,e\19\e2X\17\b7\d1\00\00\00\00\00\00@\9c\00\00\00\00\10\a5\d4\e8\00\00b\ac\c5\ebx\ad\84\t\94\f8x9?\81\b3\15\07\c9{\ce\97\c0p\\\ea{\ce2~\8fh\80\e9\ab\a48\d2\d5E\"\9a\17&\'O\9f\'\fb\c4\d41\a2c\ed\a8\ad\c8\8c8e\de\b0\dbe\ab\1a\8e\08\c7\83\9a\1dqB\f9\1d]\c4X\e7\1b\a6,iM\92\ea\8dp\1ad\ee\01\daJw\ef\9a\99\a3m\a2\85k}\b4{x\t\f2w\18\ddy\a1\e4T\b4\c2\c5\9b[\92\86[\86=]\96\c8\c5S5\c8\b3\a0\97\fa\\\b4*\95\e3_\a0\99\bd\9fF\de%\8c9\db4\c2\9b\a5\\\9f\98\a3r\9a\c6\f6\ce\be\e9TS\bf\dc\b7\e2A\"\f2\17\f3\fc\88\a5x\\\d3\9b\ce \cc\dfS!{\f3Z\16\98:0\1f\97\dc\b5\a0\e2\96\b3\e3\\S\d1\d9\a8 (; 8 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + loop $continue|0 + local.get $1 + i32.const 10 + i32.rem_u + local.set $3 + local.get $1 + i32.const 10 + i32.div_u + local.set $1 + local.get $2 + i32.const 1 + i32.sub + local.tee $2 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $3 + i32.const 48 + i32.add + i32.store16 + local.get $1 + br_if $continue|0 + end + ) + (func $~lib/util/number/itoa32 (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + i32.eqz + if + i32.const 160 + return + end + local.get $0 + i32.const 0 + i32.lt_s + local.tee $1 + if + i32.const 0 + local.get $0 + i32.sub + local.set $0 + end + local.get $0 + call $~lib/util/number/decimalCount32 + local.get $1 + i32.add + local.tee $3 + i32.const 1 + i32.shl + i32.const 1 + call $~lib/rt/stub/__alloc + local.tee $2 + local.get $0 + local.get $3 + call $~lib/util/number/utoa_simple + local.get $1 + if + local.get $2 + i32.const 45 + i32.store16 + end + local.get $2 + ) + (func $~lib/math/NativeMath.pow (; 10 ;) (type $FUNCSIG$dd) (param $0 f64) (result f64) + (local $1 i32) + (local $2 i64) + (local $3 i32) + local.get $0 + i64.reinterpret_f64 + local.tee $2 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set $1 + i32.const 1 + i32.const 0 + i32.const 1 + i32.const 0 + i32.const 1 + local.get $2 + i32.wrap_i64 + i32.const 0 + local.get $1 + i32.const 2147483647 + i32.and + local.tee $3 + i32.const 2146435072 + i32.eq + select + local.get $3 + i32.const 2146435072 + i32.gt_s + select + select + select + if + local.get $0 + f64.const 2 + f64.add + return + end + local.get $0 + local.get $0 + f64.mul + ) + (func $~lib/util/number/genDigits (; 11 ;) (type $FUNCSIG$iijijiji) (param $0 i32) (param $1 i64) (param $2 i32) (param $3 i64) (param $4 i32) (param $5 i64) (param $6 i32) (result i32) + (local $7 i32) + (local $8 i32) + (local $9 i64) + (local $10 i32) + (local $11 i64) + (local $12 i64) + (local $13 i32) + (local $14 i64) + local.get $3 + local.get $1 + i64.sub + local.set $9 + i64.const 1 + i32.const 0 + local.get $4 + i32.sub + local.tee $10 + i64.extend_i32_s + i64.shl + local.tee $11 + i64.const 1 + i64.sub + local.tee $14 + local.get $3 + i64.and + local.set $12 + local.get $3 + local.get $10 + i64.extend_i32_s + i64.shr_u + i32.wrap_i64 + local.tee $7 + call $~lib/util/number/decimalCount32 + local.set $4 + i32.const 1380 + i32.load + local.set $13 + loop $continue|0 + local.get $4 + i32.const 0 + i32.gt_s + if + block $break|1 + block $case10|1 + block $case9|1 + block $case8|1 + block $case7|1 + block $case6|1 + block $case5|1 + block $case4|1 + block $case3|1 + block $case2|1 + block $case1|1 + local.get $4 + i32.const 10 + i32.ne + if + local.get $4 + i32.const 9 + i32.eq + br_if $case1|1 + block $tablify|0 + local.get $4 + i32.const 1 + i32.sub + br_table $case9|1 $case8|1 $case7|1 $case6|1 $case5|1 $case4|1 $case3|1 $case2|1 $tablify|0 + end + br $case10|1 + end + local.get $7 + i32.const 1000000000 + i32.div_u + local.set $8 + local.get $7 + i32.const 1000000000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 100000000 + i32.div_u + local.set $8 + local.get $7 + i32.const 100000000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 10000000 + i32.div_u + local.set $8 + local.get $7 + i32.const 10000000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 1000000 + i32.div_u + local.set $8 + local.get $7 + i32.const 1000000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 100000 + i32.div_u + local.set $8 + local.get $7 + i32.const 100000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 10000 + i32.div_u + local.set $8 + local.get $7 + i32.const 10000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 1000 + i32.div_u + local.set $8 + local.get $7 + i32.const 1000 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 100 + i32.div_u + local.set $8 + local.get $7 + i32.const 100 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + i32.const 10 + i32.div_u + local.set $8 + local.get $7 + i32.const 10 + i32.rem_u + local.set $7 + br $break|1 + end + local.get $7 + local.set $8 + i32.const 0 + local.set $7 + br $break|1 + end + i32.const 0 + local.set $8 + end + local.get $6 + local.get $8 + i32.or + if + local.get $6 + local.tee $2 + i32.const 1 + i32.add + local.set $6 + local.get $2 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $8 + i32.const 65535 + i32.and + i32.const 48 + i32.add + i32.store16 + end + local.get $4 + i32.const 1 + i32.sub + local.set $4 + local.get $7 + i64.extend_i32_u + local.get $10 + i64.extend_i32_s + i64.shl + local.get $12 + i64.add + local.tee $1 + local.get $5 + i64.gt_u + br_if $continue|0 + global.get $~lib/util/number/_K + local.get $4 + i32.add + global.set $~lib/util/number/_K + local.get $4 + i32.const 2 + i32.shl + local.get $13 + i32.add + i64.load32_u + local.get $10 + i64.extend_i32_s + i64.shl + local.set $3 + local.get $6 + i32.const 1 + i32.sub + i32.const 1 + i32.shl + local.get $0 + i32.add + local.tee $2 + i32.load16_u + local.set $4 + loop $continue|2 + i32.const 1 + local.get $9 + local.get $1 + i64.sub + local.get $1 + local.get $3 + i64.add + local.get $9 + i64.sub + i64.gt_u + local.get $1 + local.get $3 + i64.add + local.get $9 + i64.lt_u + select + i32.const 0 + local.get $5 + local.get $1 + i64.sub + local.get $3 + i64.ge_u + i32.const 0 + local.get $1 + local.get $9 + i64.lt_u + select + select + if + local.get $4 + i32.const 1 + i32.sub + local.set $4 + local.get $1 + local.get $3 + i64.add + local.set $1 + br $continue|2 + end + end + local.get $2 + local.get $4 + i32.store16 + local.get $6 + return + end + end + loop $continue|3 (result i32) + local.get $5 + i64.const 10 + i64.mul + local.set $5 + local.get $12 + i64.const 10 + i64.mul + local.tee $3 + local.get $10 + i64.extend_i32_s + i64.shr_u + local.tee $1 + local.get $6 + i64.extend_i32_s + i64.or + i64.const 0 + i64.ne + if + local.get $6 + local.tee $2 + i32.const 1 + i32.add + local.set $6 + local.get $2 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $1 + i32.wrap_i64 + i32.const 65535 + i32.and + i32.const 48 + i32.add + i32.store16 + end + local.get $4 + i32.const 1 + i32.sub + local.set $4 + local.get $3 + local.get $14 + i64.and + local.tee $12 + local.get $5 + i64.ge_u + br_if $continue|3 + global.get $~lib/util/number/_K + local.get $4 + i32.add + global.set $~lib/util/number/_K + local.get $12 + local.set $1 + i32.const 0 + local.get $4 + i32.sub + i32.const 2 + i32.shl + local.get $13 + i32.add + i64.load32_u + local.get $9 + i64.mul + local.set $3 + local.get $6 + i32.const 1 + i32.sub + i32.const 1 + i32.shl + local.get $0 + i32.add + local.tee $2 + i32.load16_u + local.set $4 + loop $continue|4 + i32.const 1 + local.get $3 + local.get $1 + i64.sub + local.get $1 + local.get $11 + i64.add + local.get $3 + i64.sub + i64.gt_u + local.get $1 + local.get $11 + i64.add + local.get $3 + i64.lt_u + select + i32.const 0 + local.get $5 + local.get $1 + i64.sub + local.get $11 + i64.ge_u + i32.const 0 + local.get $1 + local.get $3 + i64.lt_u + select + select + if + local.get $4 + i32.const 1 + i32.sub + local.set $4 + local.get $1 + local.get $11 + i64.add + local.set $1 + br $continue|4 + end + end + local.get $2 + local.get $4 + i32.store16 + local.get $6 + end + ) + (func $~lib/memory/memory.copy (; 12 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + block $~lib/util/memory/memmove|inlined.0 + local.get $2 + local.set $3 + local.get $0 + local.get $1 + i32.eq + br_if $~lib/util/memory/memmove|inlined.0 + local.get $0 + local.get $1 + i32.lt_u + if + local.get $1 + i32.const 7 + i32.and + local.get $0 + i32.const 7 + i32.and + i32.eq + if + loop $continue|0 + local.get $0 + i32.const 7 + i32.and + if + local.get $3 + i32.eqz + br_if $~lib/util/memory/memmove|inlined.0 + local.get $3 + i32.const 1 + i32.sub + local.set $3 + local.get $0 + local.tee $2 + i32.const 1 + i32.add + local.set $0 + local.get $1 + local.tee $4 + i32.const 1 + i32.add + local.set $1 + local.get $2 + local.get $4 + i32.load8_u + i32.store8 + br $continue|0 + end + end + loop $continue|1 + local.get $3 + i32.const 8 + i32.lt_u + i32.eqz + if + local.get $0 + local.get $1 + i64.load + i64.store + local.get $3 + i32.const 8 + i32.sub + local.set $3 + local.get $0 + i32.const 8 + i32.add + local.set $0 + local.get $1 + i32.const 8 + i32.add + local.set $1 + br $continue|1 + end + end + end + loop $continue|2 + local.get $3 + if + local.get $0 + local.tee $2 + i32.const 1 + i32.add + local.set $0 + local.get $1 + local.tee $4 + i32.const 1 + i32.add + local.set $1 + local.get $2 + local.get $4 + i32.load8_u + i32.store8 + local.get $3 + i32.const 1 + i32.sub + local.set $3 + br $continue|2 + end + end + else + local.get $1 + i32.const 7 + i32.and + local.get $0 + i32.const 7 + i32.and + i32.eq + if + loop $continue|3 + local.get $0 + local.get $3 + i32.add + i32.const 7 + i32.and + if + local.get $3 + i32.eqz + br_if $~lib/util/memory/memmove|inlined.0 + local.get $0 + local.get $3 + i32.const 1 + i32.sub + local.tee $3 + i32.add + local.get $1 + local.get $3 + i32.add + i32.load8_u + i32.store8 + br $continue|3 + end + end + loop $continue|4 + local.get $3 + i32.const 8 + i32.lt_u + i32.eqz + if + local.get $0 + local.get $3 + i32.const 8 + i32.sub + local.tee $3 + i32.add + local.get $1 + local.get $3 + i32.add + i64.load + i64.store + br $continue|4 + end + end + end + loop $continue|5 + local.get $3 + if + local.get $0 + local.get $3 + i32.const 1 + i32.sub + local.tee $3 + i32.add + local.get $1 + local.get $3 + i32.add + i32.load8_u + i32.store8 + br $continue|5 + end + end + end + end + ) + (func $~lib/util/number/prettify (; 13 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (local $3 i32) + local.get $2 + i32.eqz + if + local.get $1 + i32.const 1 + i32.shl + local.get $0 + i32.add + i32.const 3145774 + i32.store + local.get $1 + i32.const 2 + i32.add + return + end + local.get $1 + local.get $1 + local.get $2 + i32.add + local.tee $3 + i32.le_s + if (result i32) + local.get $3 + i32.const 21 + i32.le_s + else + i32.const 0 + end + if (result i32) + loop $loop|0 + block $break|0 + local.get $1 + local.get $3 + i32.ge_s + br_if $break|0 + local.get $1 + i32.const 1 + i32.shl + local.get $0 + i32.add + i32.const 48 + i32.store16 + local.get $1 + i32.const 1 + i32.add + local.set $1 + br $loop|0 + end + end + local.get $3 + i32.const 1 + i32.shl + local.get $0 + i32.add + i32.const 3145774 + i32.store + local.get $3 + i32.const 2 + i32.add + else + local.get $3 + i32.const 21 + i32.le_s + i32.const 0 + local.get $3 + i32.const 0 + i32.gt_s + select + if (result i32) + local.get $3 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.tee $0 + i32.const 2 + i32.add + local.get $0 + i32.const 0 + local.get $2 + i32.sub + i32.const 1 + i32.shl + call $~lib/memory/memory.copy + local.get $0 + i32.const 46 + i32.store16 + local.get $1 + i32.const 1 + i32.add + else + local.get $3 + i32.const 0 + i32.le_s + i32.const 0 + i32.const -6 + local.get $3 + i32.lt_s + select + if (result i32) + i32.const 2 + local.get $3 + i32.sub + local.tee $3 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $0 + local.get $1 + i32.const 1 + i32.shl + call $~lib/memory/memory.copy + local.get $0 + i32.const 3014704 + i32.store + i32.const 2 + local.set $2 + loop $loop|1 + block $break|1 + local.get $2 + local.get $3 + i32.ge_s + br_if $break|1 + local.get $2 + i32.const 1 + i32.shl + local.get $0 + i32.add + i32.const 48 + i32.store16 + local.get $2 + i32.const 1 + i32.add + local.set $2 + br $loop|1 + end + end + local.get $1 + local.get $3 + i32.add + else + local.get $1 + i32.const 1 + i32.eq + if (result i32) + local.get $0 + i32.const 101 + i32.store16 offset=2 + local.get $0 + i32.const 4 + i32.add + local.tee $0 + local.get $3 + i32.const 1 + i32.sub + local.tee $2 + i32.const 0 + i32.lt_s + local.tee $1 + if + i32.const 0 + local.get $2 + i32.sub + local.set $2 + end + local.get $2 + local.get $2 + call $~lib/util/number/decimalCount32 + i32.const 1 + i32.add + local.tee $2 + call $~lib/util/number/utoa_simple + local.get $0 + i32.const 45 + i32.const 43 + local.get $1 + select + i32.store16 + local.get $2 + i32.const 2 + i32.add + else + local.get $0 + i32.const 4 + i32.add + local.get $0 + i32.const 2 + i32.add + local.get $1 + i32.const 1 + i32.shl + local.tee $2 + i32.const 2 + i32.sub + call $~lib/memory/memory.copy + local.get $0 + i32.const 46 + i32.store16 offset=2 + local.get $0 + local.get $2 + i32.add + local.tee $0 + i32.const 101 + i32.store16 offset=2 + local.get $0 + i32.const 4 + i32.add + local.tee $2 + local.get $3 + i32.const 1 + i32.sub + local.tee $0 + i32.const 0 + i32.lt_s + local.tee $3 + if + i32.const 0 + local.get $0 + i32.sub + local.set $0 + end + local.get $0 + local.get $0 + call $~lib/util/number/decimalCount32 + i32.const 1 + i32.add + local.tee $0 + call $~lib/util/number/utoa_simple + local.get $2 + i32.const 45 + i32.const 43 + local.get $3 + select + i32.store16 + local.get $0 + local.get $1 + i32.add + i32.const 2 + i32.add + end + end + end + end + ) + (func $~lib/util/number/dtoa_core (; 14 ;) (type $FUNCSIG$iid) (param $0 i32) (param $1 f64) (result i32) + (local $2 i64) + (local $3 i32) + (local $4 i64) + (local $5 i64) + (local $6 i64) + (local $7 i32) + (local $8 i64) + (local $9 i64) + (local $10 i32) + (local $11 i32) + local.get $1 + f64.const 0 + f64.lt + local.tee $10 + if + local.get $0 + i32.const 45 + i32.store16 + local.get $1 + f64.neg + local.set $1 + end + local.get $1 + i64.reinterpret_f64 + local.tee $2 + i64.const 9218868437227405312 + i64.and + i64.const 52 + i64.shr_u + i32.wrap_i64 + local.tee $11 + i32.const 0 + i32.ne + local.set $7 + local.get $2 + i64.const 4503599627370495 + i64.and + local.get $7 + i64.extend_i32_u + i64.const 52 + i64.shl + i64.add + local.tee $5 + i64.const 1 + i64.shl + i64.const 1 + i64.add + local.tee $2 + i64.clz + i32.wrap_i64 + local.set $3 + local.get $2 + local.get $3 + i64.extend_i32_s + i64.shl + global.set $~lib/util/number/_frc_plus + local.get $11 + i32.const 1 + local.get $7 + select + i32.const 1075 + i32.sub + local.tee $7 + i32.const 1 + i32.sub + local.get $3 + i32.sub + local.set $3 + local.get $5 + local.get $5 + i64.const 4503599627370496 + i64.eq + i32.const 1 + i32.add + local.tee $11 + i64.extend_i32_s + i64.shl + i64.const 1 + i64.sub + local.get $7 + local.get $11 + i32.sub + local.get $3 + i32.sub + i64.extend_i32_s + i64.shl + global.set $~lib/util/number/_frc_minus + local.get $3 + global.set $~lib/util/number/_exp + i32.const 348 + i32.const -61 + global.get $~lib/util/number/_exp + i32.sub + f64.convert_i32_s + f64.const 0.30102999566398114 + f64.mul + f64.const 347 + f64.add + local.tee $1 + i32.trunc_f64_s + local.tee $3 + local.get $3 + f64.convert_i32_s + local.get $1 + f64.ne + i32.add + i32.const 3 + i32.shr_s + i32.const 1 + i32.add + local.tee $3 + i32.const 3 + i32.shl + i32.sub + global.set $~lib/util/number/_K + i32.const 1068 + i32.load + local.get $3 + i32.const 3 + i32.shl + i32.add + i64.load + global.set $~lib/util/number/_frc_pow + i32.const 1292 + i32.load + local.get $3 + i32.const 1 + i32.shl + i32.add + i32.load16_s + global.set $~lib/util/number/_exp_pow + global.get $~lib/util/number/_frc_pow + local.tee $6 + i64.const 4294967295 + i64.and + local.set $2 + global.get $~lib/util/number/_frc_plus + local.tee $8 + i64.const 4294967295 + i64.and + local.tee $4 + local.get $6 + i64.const 32 + i64.shr_u + local.tee $6 + i64.mul + local.get $8 + i64.const 32 + i64.shr_u + local.tee $8 + local.get $2 + i64.mul + local.get $2 + local.get $4 + i64.mul + i64.const 32 + i64.shr_u + i64.add + local.tee $4 + i64.const 4294967295 + i64.and + i64.add + i64.const 2147483647 + i64.add + i64.const 32 + i64.shr_u + local.get $6 + local.get $8 + i64.mul + local.get $4 + i64.const 32 + i64.shr_u + i64.add + i64.add + i64.const 1 + i64.sub + local.tee $8 + local.get $6 + global.get $~lib/util/number/_frc_minus + local.tee $4 + i64.const 4294967295 + i64.and + local.tee $9 + i64.mul + local.get $4 + i64.const 32 + i64.shr_u + local.tee $4 + local.get $2 + i64.mul + local.get $2 + local.get $9 + i64.mul + i64.const 32 + i64.shr_u + i64.add + local.tee $9 + i64.const 4294967295 + i64.and + i64.add + i64.const 2147483647 + i64.add + i64.const 32 + i64.shr_u + local.get $4 + local.get $6 + i64.mul + local.get $9 + i64.const 32 + i64.shr_u + i64.add + i64.add + i64.const 1 + i64.add + i64.sub + local.set $4 + local.get $10 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $0 + local.get $6 + local.get $5 + local.get $5 + i64.clz + i32.wrap_i64 + local.tee $0 + i64.extend_i32_s + i64.shl + local.tee $5 + i64.const 4294967295 + i64.and + local.tee $9 + i64.mul + local.get $5 + i64.const 32 + i64.shr_u + local.tee $5 + local.get $2 + i64.mul + local.get $2 + local.get $9 + i64.mul + i64.const 32 + i64.shr_u + i64.add + local.tee $2 + i64.const 4294967295 + i64.and + i64.add + i64.const 2147483647 + i64.add + i64.const 32 + i64.shr_u + local.get $5 + local.get $6 + i64.mul + local.get $2 + i64.const 32 + i64.shr_u + i64.add + i64.add + global.get $~lib/util/number/_exp_pow + local.tee $3 + local.get $7 + local.get $0 + i32.sub + i32.add + i32.const -64 + i32.sub + local.get $8 + global.get $~lib/util/number/_exp + local.get $3 + i32.add + i32.const -64 + i32.sub + local.get $4 + local.get $10 + call $~lib/util/number/genDigits + local.get $10 + i32.sub + global.get $~lib/util/number/_K + call $~lib/util/number/prettify + local.get $10 + i32.add + ) + (func $~lib/string/String#substring (; 15 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + i32.const 0 + local.get $0 + call $~lib/string/String#get:length + local.tee $2 + i32.const 0 + local.get $2 + i32.lt_s + select + local.tee $3 + local.get $1 + i32.const 0 + local.get $1 + i32.const 0 + i32.gt_s + select + local.tee $1 + local.get $2 + local.get $1 + local.get $2 + i32.lt_s + select + local.tee $2 + local.get $3 + local.get $2 + i32.gt_s + select + i32.const 1 + i32.shl + local.tee $1 + local.get $3 + local.get $2 + local.get $3 + local.get $2 + i32.lt_s + select + i32.const 1 + i32.shl + local.tee $3 + i32.sub + local.tee $2 + i32.eqz + if + i32.const 1408 + return + end + local.get $3 + if (result i32) + i32.const 0 + else + local.get $0 + call $~lib/string/String#get:length + i32.const 1 + i32.shl + local.get $1 + i32.eq + end + if + local.get $0 + return + end + local.get $2 + i32.const 1 + call $~lib/rt/stub/__alloc + local.tee $1 + local.get $0 + local.get $3 + i32.add + local.get $2 + call $~lib/memory/memory.copy + local.get $1 + ) + (func $~lib/rt/stub/__free (; 16 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + local.get $0 + i32.const 15 + i32.and + i32.eqz + i32.const 0 + local.get $0 + select + i32.eqz + if + i32.const 0 + i32.const 1424 + i32.const 71 + i32.const 2 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 16 + i32.sub + local.tee $1 + i32.load offset=4 + i32.const -1 + i32.ne + if + i32.const 0 + i32.const 1424 + i32.const 73 + i32.const 13 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/rt/stub/offset + local.get $1 + i32.load + local.get $0 + i32.add + i32.eq + if + local.get $1 + global.set $~lib/rt/stub/offset + end + ) + (func $~lib/util/number/dtoa (; 17 ;) (type $FUNCSIG$id) (param $0 f64) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + f64.const 0 + f64.eq + if + i32.const 232 + return + end + local.get $0 + local.get $0 + f64.sub + f64.const 0 + f64.ne + if + local.get $0 + local.get $0 + f64.ne + if + i32.const 256 + return + end + i32.const 280 + i32.const 320 + local.get $0 + f64.const 0 + f64.lt + select + return + end + i32.const 56 + i32.const 1 + call $~lib/rt/stub/__alloc + local.tee $1 + local.get $0 + call $~lib/util/number/dtoa_core + local.tee $2 + i32.const 28 + i32.eq + if + local.get $1 + return + end + local.get $1 + local.get $2 + call $~lib/string/String#substring + local.get $1 + call $~lib/rt/stub/__free + ) + (func $resolve-binary/Bar#constructor (; 18 ;) (type $FUNCSIG$i) (result i32) + i32.const 0 + i32.const 7 + call $~lib/rt/stub/__alloc + ) + (func $start:resolve-binary (; 19 ;) (type $FUNCSIG$v) + i32.const 1 + call $~lib/number/Bool#toString + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 2 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 7 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/Bool#toString + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 12 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 17 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 22 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/Bool#toString + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 27 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/Bool#toString + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 34 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 39 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1840 + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const 1 + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 48 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.add + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 53 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.sub + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 58 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shl + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 63 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + f64.const 2 + global.set $resolve-binary/f + global.get $resolve-binary/f + call $~lib/math/NativeMath.pow + global.set $resolve-binary/f + global.get $resolve-binary/f + call $~lib/util/number/dtoa + i32.const 1472 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 69 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 4 + global.set $resolve-binary/a + global.get $resolve-binary/a + i32.const 2 + i32.div_s + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 75 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 3 + i32.rem_s + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 80 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shl + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 1496 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 85 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shr_s + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 90 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shr_u + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 95 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 3 + i32.and + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 100 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 3 + i32.or + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 1520 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 105 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 2 + i32.xor + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 110 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + call $~lib/util/number/itoa32 + i32.const 1520 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 117 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const -1 + call $~lib/util/number/itoa32 + i32.const 1544 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 122 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 127 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 132 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 137 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + f64.const 2 + call $~lib/math/NativeMath.pow + call $~lib/util/number/dtoa + i32.const 1472 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 144 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 4 + call $~lib/util/number/itoa32 + i32.const 1496 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 151 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 156 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + call $~lib/util/number/itoa32 + i32.const 1520 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 161 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 168 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + call $~lib/util/number/itoa32 + i32.const 1520 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 173 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 178 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 185 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/util/number/itoa32 + i32.const 160 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 190 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/util/number/itoa32 + i32.const 184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 195 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/util/number/itoa32 + i32.const 208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 200 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + i32.const 6 + call $~lib/rt/stub/__alloc + global.set $resolve-binary/foo + i32.const 1568 + i32.const 1568 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 261 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1592 + i32.const 1592 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 266 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1616 + i32.const 1616 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 271 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1640 + i32.const 1640 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 276 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1664 + i32.const 1664 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 281 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1688 + i32.const 1688 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 286 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1712 + i32.const 1712 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 291 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1736 + i32.const 1736 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 296 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1760 + i32.const 1760 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 301 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1784 + i32.const 1784 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 306 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1808 + i32.const 1808 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 311 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1832 + i32.const 1832 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 316 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + call $resolve-binary/Bar#constructor + global.set $resolve-binary/bar + call $resolve-binary/Bar#constructor + global.set $resolve-binary/bar2 + global.get $resolve-binary/bar2 + global.set $resolve-binary/bar + global.get $resolve-binary/bar + global.get $resolve-binary/bar2 + i32.ne + if + i32.const 0 + i32.const 80 + i32.const 334 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/bar + global.get $resolve-binary/bar2 + i32.ne + if + i32.const 0 + i32.const 80 + i32.const 339 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + ) + (func $start (; 20 ;) (type $FUNCSIG$v) + call $start:resolve-binary + ) + (func $null (; 21 ;) (type $FUNCSIG$v) + nop + ) +) diff --git a/tests/compiler/resolve-binary.ts b/tests/compiler/resolve-binary.ts new file mode 100644 index 0000000000..cdfcb417b1 --- /dev/null +++ b/tests/compiler/resolve-binary.ts @@ -0,0 +1,339 @@ +// comparison +assert( + (1 < 2).toString() + == + "true" +); +assert( + (1 > 2).toString() + == + "false" +); +assert( + (1 <= 2).toString() + == + "true" +); +assert( + (1 >= 2).toString() + == + "false" +); +assert( + (1 == 2).toString() + == + "false" +); +assert( + (1 != 2).toString() + == + "true" +); + +// identity +assert( + ("a" === "a").toString() + == + "true" +); +assert( + ("a" !== "a").toString() + == + "false" +); + +// assignment +var a: i32; +var f: f64; +assert( + (a = 1).toString() + == + "1" +); +assert( + (a += 1).toString() + == + "2" +); +assert( + (a -= 1).toString() + == + "1" +); +assert( + (a *= 2).toString() + == + "2" +); +f = 2; +assert( + (f **= 2).toString() + == + "4.0" +); +a = 4; +assert( + (a /= 2).toString() + == + "2" +); +assert( + (a %= 3).toString() + == + "2" +); +assert( + (a <<= 1).toString() + == + "4" +); +assert( + (a >>= 1).toString() + == + "2" +); +assert( + (a >>>= 1).toString() + == + "1" +); +assert( + (a &= 3).toString() + == + "1" +); +assert( + (a |= 3).toString() + == + "3" +); +assert( + (a ^= 2).toString() + == + "1" +); + +// arithmetics +assert( + (1 + 2).toString() + == + "3" +); +assert( + (1 - 2).toString() + == + "-1" +); +assert( + (1 * 2).toString() + == + "2" +); +assert( + (4 / 2).toString() + == + "2" +); +assert( + (3 % 2).toString() + == + "1" +); + +// pow +assert( + (2 ** 2).toString() + == + "4.0" // TBD +); + +// shift +assert( + (2 << 1).toString() + == + "4" +); +assert( + (2 >> 1).toString() + == + "1" +); +assert( + (-1 >>> 30).toString() + == + "3" +); + +// bitwise +assert( + (3 & 1).toString() + == + "1" +); +assert( + (1 | 2).toString() + == + "3" +); +assert( + (1 ^ 3).toString() + == + "2" +); + +// logical +assert( + (1 && 2).toString() + == + "2" +); +assert( + (0 && 2).toString() + == + "0" +); +assert( + (1 || 2).toString() + == + "1" +); +assert( + (0 || 2).toString() + == + "2" +); + +// overloads +class Foo { + @operator("<") + lt(other: Foo): string { + return "lt"; + } + @operator(">") + gt(other: Foo): string { + return "gt"; + } + @operator("<=") + le(other: Foo): string { + return "le"; + } + @operator(">=") + ge(other: Foo): string { + return "ge"; + } + @operator("==") + eq(other: Foo): string { + return "eq"; + } + @operator("!=") + ne(other: Foo): string { + return "ne"; + } + @operator("+") + add(other: Foo): string { + return "add"; + } + @operator("-") + static sub(a: Foo, b: Foo): string { // same for static + return "sub"; + } + @operator("*") + mul(other: Foo): string { + return "mul"; + } + @operator("/") + div(other: Foo): string { + return "div"; + } + @operator("%") + rem(other: Foo): string { + return "rem"; + } + @operator("**") + pow(other: Foo): string { + return "pow"; + } + self(): Foo { + return this; + } +} +var foo = new Foo(); +assert( + (foo < foo).toString() + == + "lt" +); +assert( + (foo > foo).toString() + == + "gt" +); +assert( + (foo <= foo).toString() + == + "le" +); +assert( + (foo >= foo).toString() + == + "ge" +); +assert( + (foo == foo).toString() + == + "eq" +); +assert( + (foo != foo).toString() + == + "ne" +); +assert( + (foo + foo).toString() + == + "add" +); +assert( + (foo - foo).toString() + == + "sub" +); +assert( + (foo * foo).toString() + == + "mul" +); +assert( + (foo / foo).toString() + == + "div" +); +assert( + (foo % foo).toString() + == + "rem" +); +assert( + (foo ** foo).toString() + == + "pow" +); + +// overload with compatible compound assignment +class Bar { + @operator("+") + add(other: Bar): Bar { + return other; + } + self(): Bar { + return this; + } +} +var bar = new Bar(); +var bar2 = new Bar(); +assert( + (bar += bar2).self() + == + bar2 +); +assert(bar === bar2); diff --git a/tests/compiler/resolve-binary.untouched.wat b/tests/compiler/resolve-binary.untouched.wat new file mode 100644 index 0000000000..4a3123fce0 --- /dev/null +++ b/tests/compiler/resolve-binary.untouched.wat @@ -0,0 +1,5772 @@ +(module + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$ddd (func (param f64 f64) (result f64))) + (type $FUNCSIG$ddi (func (param f64 i32) (result f64))) + (type $FUNCSIG$idi (func (param f64 i32) (result i32))) + (type $FUNCSIG$id (func (param f64) (result i32))) + (type $FUNCSIG$iid (func (param i32 f64) (result i32))) + (type $FUNCSIG$jii (func (param i32 i32) (result i64))) + (type $FUNCSIG$iijijiji (func (param i32 i64 i32 i64 i32 i64 i32) (result i32))) + (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) + (type $FUNCSIG$v (func)) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) "\08\00\00\00\01\00\00\00\01\00\00\00\08\00\00\00t\00r\00u\00e\00") + (data (i32.const 32) "\n\00\00\00\01\00\00\00\01\00\00\00\n\00\00\00f\00a\00l\00s\00e\00") + (data (i32.const 64) "\"\00\00\00\01\00\00\00\01\00\00\00\"\00\00\00r\00e\00s\00o\00l\00v\00e\00-\00b\00i\00n\00a\00r\00y\00.\00t\00s\00") + (data (i32.const 120) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00a\00") + (data (i32.const 144) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\000\00") + (data (i32.const 168) "\90\01\00\00\01\00\00\00\00\00\00\00\90\01\00\000\000\000\001\000\002\000\003\000\004\000\005\000\006\000\007\000\008\000\009\001\000\001\001\001\002\001\003\001\004\001\005\001\006\001\007\001\008\001\009\002\000\002\001\002\002\002\003\002\004\002\005\002\006\002\007\002\008\002\009\003\000\003\001\003\002\003\003\003\004\003\005\003\006\003\007\003\008\003\009\004\000\004\001\004\002\004\003\004\004\004\005\004\006\004\007\004\008\004\009\005\000\005\001\005\002\005\003\005\004\005\005\005\006\005\007\005\008\005\009\006\000\006\001\006\002\006\003\006\004\006\005\006\006\006\007\006\008\006\009\007\000\007\001\007\002\007\003\007\004\007\005\007\006\007\007\007\008\007\009\008\000\008\001\008\002\008\003\008\004\008\005\008\006\008\007\008\008\008\009\009\000\009\001\009\002\009\003\009\004\009\005\009\006\009\007\009\008\009\009\00") + (data (i32.const 584) "\10\00\00\00\01\00\00\00\03\00\00\00\10\00\00\00\b8\00\00\00\b8\00\00\00\90\01\00\00d\00\00\00") + (data (i32.const 616) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\001\00") + (data (i32.const 640) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\002\00") + (data (i32.const 664) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\000\00.\000\00") + (data (i32.const 688) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00N\00a\00N\00") + (data (i32.const 712) "\12\00\00\00\01\00\00\00\01\00\00\00\12\00\00\00-\00I\00n\00f\00i\00n\00i\00t\00y\00") + (data (i32.const 752) "\10\00\00\00\01\00\00\00\01\00\00\00\10\00\00\00I\00n\00f\00i\00n\00i\00t\00y\00") + (data (i32.const 784) "\b8\02\00\00\01\00\00\00\00\00\00\00\b8\02\00\00\88\02\1c\08\a0\d5\8f\fav\bf>\a2\7f\e1\ae\bav\acU0 \fb\16\8b\ea5\ce]J\89B\cf-;eU\aa\b0k\9a\dfE\1a=\03\cf\1a\e6\ca\c6\9a\c7\17\fep\abO\dc\bc\be\fc\b1w\ff\0c\d6kA\ef\91V\be<\fc\7f\90\ad\1f\d0\8d\83\9aU1(\\Q\d3\b5\c9\a6\ad\8f\acq\9d\cb\8b\ee#w\"\9c\eamSx@\91I\cc\aeW\ce\b6]y\12<\827V\fbM6\94\10\c2O\98H8o\ea\96\90\c7:\82%\cb\85t\d7\f4\97\bf\97\cd\cf\86\a0\e5\ac*\17\98\n4\ef\8e\b25*\fbg8\b2;?\c6\d2\df\d4\c8\84\ba\cd\d3\1a\'D\dd\c5\96\c9%\bb\ce\9fk\93\84\a5b}$l\ac\db\f6\da_\0dXf\ab\a3&\f1\c3\de\93\f8\e2\f3\b8\80\ff\aa\a8\ad\b5\b5\8bJ|l\05_b\87S0\c14`\ff\bc\c9U&\ba\91\8c\85N\96\bd~)p$w\f9\df\8f\b8\e5\b8\9f\bd\df\a6\94}t\88\cf_\a9\f8\cf\9b\a8\8f\93pD\b9k\15\0f\bf\f8\f0\08\8a\b611eU%\b0\cd\ac\7f{\d0\c6\e2?\99\06;+*\c4\10\\\e4\d3\92si\99$$\aa\0e\ca\00\83\f2\b5\87\fd\eb\1a\11\92d\08\e5\bc\cc\88Po\t\cc\bc\8c,e\19\e2X\17\b7\d1\00\00\00\00\00\00@\9c\00\00\00\00\10\a5\d4\e8\00\00b\ac\c5\ebx\ad\84\t\94\f8x9?\81\b3\15\07\c9{\ce\97\c0p\\\ea{\ce2~\8fh\80\e9\ab\a48\d2\d5E\"\9a\17&\'O\9f\'\fb\c4\d41\a2c\ed\a8\ad\c8\8c8e\de\b0\dbe\ab\1a\8e\08\c7\83\9a\1dqB\f9\1d]\c4X\e7\1b\a6,iM\92\ea\8dp\1ad\ee\01\daJw\ef\9a\99\a3m\a2\85k}\b4{x\t\f2w\18\ddy\a1\e4T\b4\c2\c5\9b[\92\86[\86=]\96\c8\c5S5\c8\b3\a0\97\fa\\\b4*\95\e3_\a0\99\bd\9fF\de%\8c9\db4\c2\9b\a5\\\9f\98\a3r\9a\c6\f6\ce\be\e9TS\bf\dc\b7\e2A\"\f2\17\f3\fc\88\a5x\\\d3\9b\ce \cc\dfS!{\f3Z\16\98:0\1f\97\dc\b5\a0\e2\96\b3\e3\\S\d1\d9\a8 (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/util/number/itoa32 + return + ) + (func $~lib/number/I32#toString (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + call $~lib/util/number/itoa + local.tee $1 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $~lib/math/NativeMath.scalbn (; 14 ;) (type $FUNCSIG$ddi) (param $0 f64) (param $1 i32) (result f64) + (local $2 f64) + (local $3 i32) + (local $4 i32) + local.get $0 + local.set $2 + local.get $1 + i32.const 1023 + i32.gt_s + if + local.get $2 + f64.const 8988465674311579538646525e283 + f64.mul + local.set $2 + local.get $1 + i32.const 1023 + i32.sub + local.set $1 + local.get $1 + i32.const 1023 + i32.gt_s + if + local.get $2 + f64.const 8988465674311579538646525e283 + f64.mul + local.set $2 + local.get $1 + i32.const 1023 + i32.sub + local.tee $3 + i32.const 1023 + local.tee $4 + local.get $3 + local.get $4 + i32.lt_s + select + local.set $1 + end + else + local.get $1 + i32.const -1022 + i32.lt_s + if + local.get $2 + f64.const 2.2250738585072014e-308 + f64.const 9007199254740992 + f64.mul + f64.mul + local.set $2 + local.get $1 + i32.const 1022 + i32.const 53 + i32.sub + i32.add + local.set $1 + local.get $1 + i32.const -1022 + i32.lt_s + if + local.get $2 + f64.const 2.2250738585072014e-308 + f64.const 9007199254740992 + f64.mul + f64.mul + local.set $2 + local.get $1 + i32.const 1022 + i32.add + i32.const 53 + i32.sub + local.tee $3 + i32.const -1022 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_s + select + local.set $1 + end + end + end + local.get $2 + i64.const 1023 + local.get $1 + i64.extend_i32_s + i64.add + i64.const 52 + i64.shl + f64.reinterpret_i64 + f64.mul + ) + (func $~lib/math/NativeMath.pow (; 15 ;) (type $FUNCSIG$ddd) (param $0 f64) (param $1 f64) (result f64) + (local $2 i64) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + (local $12 i32) + (local $13 i32) + (local $14 i32) + (local $15 f64) + (local $16 f64) + (local $17 f64) + (local $18 f64) + (local $19 f64) + (local $20 f64) + (local $21 f64) + (local $22 f64) + (local $23 f64) + (local $24 f64) + (local $25 f64) + (local $26 f64) + (local $27 f64) + (local $28 i32) + (local $29 i32) + (local $30 f64) + (local $31 f64) + (local $32 f64) + (local $33 f64) + (local $34 f64) + (local $35 f64) + (local $36 f64) + (local $37 f64) + (local $38 f64) + (local $39 f64) + (local $40 f64) + (local $41 i32) + local.get $0 + i64.reinterpret_f64 + local.set $2 + local.get $2 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set $3 + local.get $2 + i32.wrap_i64 + local.set $4 + local.get $1 + i64.reinterpret_f64 + local.set $2 + local.get $2 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set $5 + local.get $2 + i32.wrap_i64 + local.set $6 + local.get $3 + i32.const 2147483647 + i32.and + local.set $7 + local.get $5 + i32.const 2147483647 + i32.and + local.set $8 + local.get $8 + local.get $6 + i32.or + i32.const 0 + i32.eq + if + f64.const 1 + return + end + local.get $7 + i32.const 2146435072 + i32.gt_s + if (result i32) + i32.const 1 + else + local.get $7 + i32.const 2146435072 + i32.eq + if (result i32) + local.get $4 + i32.const 0 + i32.ne + else + i32.const 0 + end + end + if (result i32) + i32.const 1 + else + local.get $8 + i32.const 2146435072 + i32.gt_s + end + if (result i32) + i32.const 1 + else + local.get $8 + i32.const 2146435072 + i32.eq + if (result i32) + local.get $6 + i32.const 0 + i32.ne + else + i32.const 0 + end + end + if + local.get $0 + local.get $1 + f64.add + return + end + i32.const 0 + local.set $9 + local.get $3 + i32.const 0 + i32.lt_s + if + local.get $8 + i32.const 1128267776 + i32.ge_s + if + i32.const 2 + local.set $9 + else + local.get $8 + i32.const 1072693248 + i32.ge_s + if + local.get $8 + i32.const 20 + i32.shr_s + i32.const 1023 + i32.sub + local.set $10 + local.get $10 + i32.const 20 + i32.gt_s + local.set $11 + i32.const 52 + i32.const 20 + local.get $11 + select + local.get $10 + i32.sub + local.set $12 + local.get $6 + local.get $8 + local.get $11 + select + local.set $13 + local.get $13 + local.get $12 + i32.shr_s + local.set $14 + local.get $14 + local.get $12 + i32.shl + local.get $13 + i32.eq + if + i32.const 2 + local.get $14 + i32.const 1 + i32.and + i32.sub + local.set $9 + end + end + end + end + local.get $6 + i32.const 0 + i32.eq + if + local.get $8 + i32.const 2146435072 + i32.eq + if + local.get $7 + i32.const 1072693248 + i32.sub + local.get $4 + i32.or + i32.const 0 + i32.eq + if + f64.const nan:0x8000000000000 + return + else + local.get $7 + i32.const 1072693248 + i32.ge_s + if + local.get $5 + i32.const 0 + i32.ge_s + if (result f64) + local.get $1 + else + f64.const 0 + end + return + else + local.get $5 + i32.const 0 + i32.ge_s + if (result f64) + f64.const 0 + else + local.get $1 + f64.neg + end + return + end + unreachable + end + unreachable + end + local.get $8 + i32.const 1072693248 + i32.eq + if + local.get $5 + i32.const 0 + i32.ge_s + if + local.get $0 + return + end + f64.const 1 + local.get $0 + f64.div + return + end + local.get $5 + i32.const 1073741824 + i32.eq + if + local.get $0 + local.get $0 + f64.mul + return + end + local.get $5 + i32.const 1071644672 + i32.eq + if + local.get $3 + i32.const 0 + i32.ge_s + if + local.get $0 + f64.sqrt + return + end + end + end + local.get $0 + f64.abs + local.set $15 + local.get $4 + i32.const 0 + i32.eq + if + local.get $7 + i32.const 0 + i32.eq + if (result i32) + i32.const 1 + else + local.get $7 + i32.const 2146435072 + i32.eq + end + if (result i32) + i32.const 1 + else + local.get $7 + i32.const 1072693248 + i32.eq + end + if + local.get $15 + local.set $16 + local.get $5 + i32.const 0 + i32.lt_s + if + f64.const 1 + local.get $16 + f64.div + local.set $16 + end + local.get $3 + i32.const 0 + i32.lt_s + if + local.get $7 + i32.const 1072693248 + i32.sub + local.get $9 + i32.or + i32.const 0 + i32.eq + if + local.get $16 + local.get $16 + f64.sub + local.set $17 + local.get $17 + local.get $17 + f64.div + local.set $16 + else + local.get $9 + i32.const 1 + i32.eq + if + local.get $16 + f64.neg + local.set $16 + end + end + end + local.get $16 + return + end + end + f64.const 1 + local.set $18 + local.get $3 + i32.const 0 + i32.lt_s + if + local.get $9 + i32.const 0 + i32.eq + if + local.get $0 + local.get $0 + f64.sub + local.set $17 + local.get $17 + local.get $17 + f64.div + return + end + local.get $9 + i32.const 1 + i32.eq + if + f64.const -1 + local.set $18 + end + end + local.get $8 + i32.const 1105199104 + i32.gt_s + if + local.get $8 + i32.const 1139802112 + i32.gt_s + if + local.get $7 + i32.const 1072693247 + i32.le_s + if + local.get $5 + i32.const 0 + i32.lt_s + if (result f64) + f64.const 1.e+300 + f64.const 1.e+300 + f64.mul + else + f64.const 1e-300 + f64.const 1e-300 + f64.mul + end + return + end + local.get $7 + i32.const 1072693248 + i32.ge_s + if + local.get $5 + i32.const 0 + i32.gt_s + if (result f64) + f64.const 1.e+300 + f64.const 1.e+300 + f64.mul + else + f64.const 1e-300 + f64.const 1e-300 + f64.mul + end + return + end + end + local.get $7 + i32.const 1072693247 + i32.lt_s + if + local.get $5 + i32.const 0 + i32.lt_s + if (result f64) + local.get $18 + f64.const 1.e+300 + f64.mul + f64.const 1.e+300 + f64.mul + else + local.get $18 + f64.const 1e-300 + f64.mul + f64.const 1e-300 + f64.mul + end + return + end + local.get $7 + i32.const 1072693248 + i32.gt_s + if + local.get $5 + i32.const 0 + i32.gt_s + if (result f64) + local.get $18 + f64.const 1.e+300 + f64.mul + f64.const 1.e+300 + f64.mul + else + local.get $18 + f64.const 1e-300 + f64.mul + f64.const 1e-300 + f64.mul + end + return + end + local.get $15 + f64.const 1 + f64.sub + local.set $24 + local.get $24 + local.get $24 + f64.mul + f64.const 0.5 + local.get $24 + f64.const 0.3333333333333333 + local.get $24 + f64.const 0.25 + f64.mul + f64.sub + f64.mul + f64.sub + f64.mul + local.set $27 + f64.const 1.4426950216293335 + local.get $24 + f64.mul + local.set $25 + local.get $24 + f64.const 1.9259629911266175e-08 + f64.mul + local.get $27 + f64.const 1.4426950408889634 + f64.mul + f64.sub + local.set $26 + local.get $25 + local.get $26 + f64.add + local.set $19 + local.get $19 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $19 + local.get $26 + local.get $19 + local.get $25 + f64.sub + f64.sub + local.set $20 + else + i32.const 0 + local.set $29 + local.get $7 + i32.const 1048576 + i32.lt_s + if + local.get $15 + f64.const 9007199254740992 + f64.mul + local.set $15 + local.get $29 + i32.const 53 + i32.sub + local.set $29 + local.get $15 + i64.reinterpret_f64 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set $7 + end + local.get $29 + local.get $7 + i32.const 20 + i32.shr_s + i32.const 1023 + i32.sub + i32.add + local.set $29 + local.get $7 + i32.const 1048575 + i32.and + local.set $28 + local.get $28 + i32.const 1072693248 + i32.or + local.set $7 + local.get $28 + i32.const 235662 + i32.le_s + if + i32.const 0 + local.set $10 + else + local.get $28 + i32.const 767610 + i32.lt_s + if + i32.const 1 + local.set $10 + else + i32.const 0 + local.set $10 + local.get $29 + i32.const 1 + i32.add + local.set $29 + local.get $7 + i32.const 1048576 + i32.sub + local.set $7 + end + end + local.get $15 + i64.reinterpret_f64 + i64.const 4294967295 + i64.and + local.get $7 + i64.extend_i32_s + i64.const 32 + i64.shl + i64.or + f64.reinterpret_i64 + local.set $15 + f64.const 1.5 + f64.const 1 + local.get $10 + select + local.set $35 + local.get $15 + local.get $35 + f64.sub + local.set $25 + f64.const 1 + local.get $15 + local.get $35 + f64.add + f64.div + local.set $26 + local.get $25 + local.get $26 + f64.mul + local.set $17 + local.get $17 + local.set $31 + local.get $31 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $31 + local.get $7 + i32.const 1 + i32.shr_s + i32.const 536870912 + i32.or + i32.const 524288 + i32.add + local.get $10 + i32.const 18 + i32.shl + i32.add + i64.extend_i32_s + i64.const 32 + i64.shl + f64.reinterpret_i64 + local.set $33 + local.get $15 + local.get $33 + local.get $35 + f64.sub + f64.sub + local.set $34 + local.get $26 + local.get $25 + local.get $31 + local.get $33 + f64.mul + f64.sub + local.get $31 + local.get $34 + f64.mul + f64.sub + f64.mul + local.set $32 + local.get $17 + local.get $17 + f64.mul + local.set $30 + local.get $30 + local.get $30 + f64.mul + f64.const 0.5999999999999946 + local.get $30 + f64.const 0.4285714285785502 + local.get $30 + f64.const 0.33333332981837743 + local.get $30 + f64.const 0.272728123808534 + local.get $30 + f64.const 0.23066074577556175 + local.get $30 + f64.const 0.20697501780033842 + f64.mul + f64.add + f64.mul + f64.add + f64.mul + f64.add + f64.mul + f64.add + f64.mul + f64.add + f64.mul + local.set $23 + local.get $23 + local.get $32 + local.get $31 + local.get $17 + f64.add + f64.mul + f64.add + local.set $23 + local.get $31 + local.get $31 + f64.mul + local.set $30 + f64.const 3 + local.get $30 + f64.add + local.get $23 + f64.add + local.set $33 + local.get $33 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $33 + local.get $23 + local.get $33 + f64.const 3 + f64.sub + local.get $30 + f64.sub + f64.sub + local.set $34 + local.get $31 + local.get $33 + f64.mul + local.set $25 + local.get $32 + local.get $33 + f64.mul + local.get $34 + local.get $17 + f64.mul + f64.add + local.set $26 + local.get $25 + local.get $26 + f64.add + local.set $21 + local.get $21 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $21 + local.get $26 + local.get $21 + local.get $25 + f64.sub + f64.sub + local.set $22 + f64.const 0.9617967009544373 + local.get $21 + f64.mul + local.set $36 + f64.const 1.350039202129749e-08 + f64.const 0 + local.get $10 + select + local.set $37 + f64.const -7.028461650952758e-09 + local.get $21 + f64.mul + local.get $22 + f64.const 0.9617966939259756 + f64.mul + f64.add + local.get $37 + f64.add + local.set $38 + local.get $29 + f64.convert_i32_s + local.set $24 + f64.const 0.5849624872207642 + f64.const 0 + local.get $10 + select + local.set $39 + local.get $36 + local.get $38 + f64.add + local.get $39 + f64.add + local.get $24 + f64.add + local.set $19 + local.get $19 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $19 + local.get $38 + local.get $19 + local.get $24 + f64.sub + local.get $39 + f64.sub + local.get $36 + f64.sub + f64.sub + local.set $20 + end + local.get $1 + local.set $40 + local.get $40 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $40 + local.get $1 + local.get $40 + f64.sub + local.get $19 + f64.mul + local.get $1 + local.get $20 + f64.mul + f64.add + local.set $22 + local.get $40 + local.get $19 + f64.mul + local.set $21 + local.get $22 + local.get $21 + f64.add + local.set $16 + local.get $16 + i64.reinterpret_f64 + local.set $2 + local.get $2 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set $28 + local.get $2 + i32.wrap_i64 + local.set $41 + local.get $28 + i32.const 1083179008 + i32.ge_s + if + local.get $28 + i32.const 1083179008 + i32.sub + local.get $41 + i32.or + i32.const 0 + i32.ne + if + local.get $18 + f64.const 1.e+300 + f64.mul + f64.const 1.e+300 + f64.mul + return + end + local.get $22 + f64.const 8.008566259537294e-17 + f64.add + local.get $16 + local.get $21 + f64.sub + f64.gt + if + local.get $18 + f64.const 1.e+300 + f64.mul + f64.const 1.e+300 + f64.mul + return + end + else + local.get $28 + i32.const 2147483647 + i32.and + i32.const 1083231232 + i32.ge_s + if + local.get $28 + i32.const -1064252416 + i32.sub + local.get $41 + i32.or + i32.const 0 + i32.ne + if + local.get $18 + f64.const 1e-300 + f64.mul + f64.const 1e-300 + f64.mul + return + end + local.get $22 + local.get $16 + local.get $21 + f64.sub + f64.le + if + local.get $18 + f64.const 1e-300 + f64.mul + f64.const 1e-300 + f64.mul + return + end + end + end + local.get $28 + i32.const 2147483647 + i32.and + local.set $41 + local.get $41 + i32.const 20 + i32.shr_s + i32.const 1023 + i32.sub + local.set $10 + i32.const 0 + local.set $29 + local.get $41 + i32.const 1071644672 + i32.gt_s + if + local.get $28 + i32.const 1048576 + local.get $10 + i32.const 1 + i32.add + i32.shr_s + i32.add + local.set $29 + local.get $29 + i32.const 2147483647 + i32.and + i32.const 20 + i32.shr_s + i32.const 1023 + i32.sub + local.set $10 + f64.const 0 + local.set $24 + local.get $29 + i32.const 1048575 + local.get $10 + i32.shr_s + i32.const -1 + i32.xor + i32.and + i64.extend_i32_s + i64.const 32 + i64.shl + f64.reinterpret_i64 + local.set $24 + local.get $29 + i32.const 1048575 + i32.and + i32.const 1048576 + i32.or + i32.const 20 + local.get $10 + i32.sub + i32.shr_s + local.set $29 + local.get $28 + i32.const 0 + i32.lt_s + if + i32.const 0 + local.get $29 + i32.sub + local.set $29 + end + local.get $21 + local.get $24 + f64.sub + local.set $21 + end + local.get $22 + local.get $21 + f64.add + local.set $24 + local.get $24 + i64.reinterpret_f64 + i64.const -4294967296 + i64.and + f64.reinterpret_i64 + local.set $24 + local.get $24 + f64.const 0.6931471824645996 + f64.mul + local.set $25 + local.get $22 + local.get $24 + local.get $21 + f64.sub + f64.sub + f64.const 0.6931471805599453 + f64.mul + local.get $24 + f64.const -1.904654299957768e-09 + f64.mul + f64.add + local.set $26 + local.get $25 + local.get $26 + f64.add + local.set $16 + local.get $26 + local.get $16 + local.get $25 + f64.sub + f64.sub + local.set $27 + local.get $16 + local.get $16 + f64.mul + local.set $24 + local.get $16 + local.get $24 + f64.const 0.16666666666666602 + local.get $24 + f64.const -2.7777777777015593e-03 + local.get $24 + f64.const 6.613756321437934e-05 + local.get $24 + f64.const -1.6533902205465252e-06 + local.get $24 + f64.const 4.1381367970572385e-08 + f64.mul + f64.add + f64.mul + f64.add + f64.mul + f64.add + f64.mul + f64.add + f64.mul + f64.sub + local.set $19 + local.get $16 + local.get $19 + f64.mul + local.get $19 + f64.const 2 + f64.sub + f64.div + local.get $27 + local.get $16 + local.get $27 + f64.mul + f64.add + f64.sub + local.set $23 + f64.const 1 + local.get $23 + local.get $16 + f64.sub + f64.sub + local.set $16 + local.get $16 + i64.reinterpret_f64 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set $28 + local.get $28 + local.get $29 + i32.const 20 + i32.shl + i32.add + local.set $28 + local.get $28 + i32.const 20 + i32.shr_s + i32.const 0 + i32.le_s + if + local.get $16 + local.get $29 + call $~lib/math/NativeMath.scalbn + local.set $16 + else + local.get $16 + i64.reinterpret_f64 + i64.const 4294967295 + i64.and + local.get $28 + i64.extend_i32_s + i64.const 32 + i64.shl + i64.or + f64.reinterpret_i64 + local.set $16 + end + local.get $18 + local.get $16 + f64.mul + ) + (func $~lib/number/isFinite (; 16 ;) (type $FUNCSIG$id) (param $0 f64) (result i32) + local.get $0 + local.get $0 + f64.sub + f64.const 0 + f64.eq + ) + (func $~lib/number/isNaN (; 17 ;) (type $FUNCSIG$id) (param $0 f64) (result i32) + local.get $0 + local.get $0 + f64.ne + ) + (func $~lib/array/Array#__unchecked_get (; 18 ;) (type $FUNCSIG$jii) (param $0 i32) (param $1 i32) (result i64) + local.get $0 + i32.load offset=4 + local.get $1 + i32.const 3 + i32.shl + i32.add + i64.load + ) + (func $~lib/array/Array#__unchecked_get (; 19 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + i32.load offset=4 + local.get $1 + i32.const 1 + i32.shl + i32.add + i32.load16_s + ) + (func $~lib/util/number/genDigits (; 20 ;) (type $FUNCSIG$iijijiji) (param $0 i32) (param $1 i64) (param $2 i32) (param $3 i64) (param $4 i32) (param $5 i64) (param $6 i32) (result i32) + (local $7 i32) + (local $8 i64) + (local $9 i64) + (local $10 i64) + (local $11 i32) + (local $12 i32) + (local $13 i64) + (local $14 i32) + (local $15 i32) + (local $16 i32) + (local $17 i32) + (local $18 i32) + (local $19 i64) + (local $20 i64) + (local $21 i64) + (local $22 i64) + (local $23 i64) + (local $24 i32) + (local $25 i32) + (local $26 i32) + i32.const 0 + local.get $4 + i32.sub + local.set $7 + i64.const 1 + local.get $7 + i64.extend_i32_s + i64.shl + local.set $8 + local.get $8 + i64.const 1 + i64.sub + local.set $9 + local.get $3 + local.get $1 + i64.sub + local.set $10 + local.get $4 + local.set $11 + local.get $3 + local.get $7 + i64.extend_i32_s + i64.shr_u + i32.wrap_i64 + local.set $12 + local.get $3 + local.get $9 + i64.and + local.set $13 + local.get $12 + call $~lib/util/number/decimalCount32 + local.set $14 + local.get $6 + local.set $15 + i32.const 1824 + i32.load offset=4 + local.set $16 + block $break|0 + loop $continue|0 + local.get $14 + i32.const 0 + i32.gt_s + i32.eqz + br_if $break|0 + block $break|1 + block $case10|1 + block $case9|1 + block $case8|1 + block $case7|1 + block $case6|1 + block $case5|1 + block $case4|1 + block $case3|1 + block $case2|1 + block $case1|1 + block $case0|1 + local.get $14 + local.set $18 + local.get $18 + i32.const 10 + i32.eq + br_if $case0|1 + local.get $18 + i32.const 9 + i32.eq + br_if $case1|1 + local.get $18 + i32.const 8 + i32.eq + br_if $case2|1 + local.get $18 + i32.const 7 + i32.eq + br_if $case3|1 + local.get $18 + i32.const 6 + i32.eq + br_if $case4|1 + local.get $18 + i32.const 5 + i32.eq + br_if $case5|1 + local.get $18 + i32.const 4 + i32.eq + br_if $case6|1 + local.get $18 + i32.const 3 + i32.eq + br_if $case7|1 + local.get $18 + i32.const 2 + i32.eq + br_if $case8|1 + local.get $18 + i32.const 1 + i32.eq + br_if $case9|1 + br $case10|1 + end + local.get $12 + i32.const 1000000000 + i32.div_u + local.set $17 + local.get $12 + i32.const 1000000000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 100000000 + i32.div_u + local.set $17 + local.get $12 + i32.const 100000000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 10000000 + i32.div_u + local.set $17 + local.get $12 + i32.const 10000000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 1000000 + i32.div_u + local.set $17 + local.get $12 + i32.const 1000000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 100000 + i32.div_u + local.set $17 + local.get $12 + i32.const 100000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 10000 + i32.div_u + local.set $17 + local.get $12 + i32.const 10000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 1000 + i32.div_u + local.set $17 + local.get $12 + i32.const 1000 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 100 + i32.div_u + local.set $17 + local.get $12 + i32.const 100 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + i32.const 10 + i32.div_u + local.set $17 + local.get $12 + i32.const 10 + i32.rem_u + local.set $12 + br $break|1 + end + local.get $12 + local.set $17 + i32.const 0 + local.set $12 + br $break|1 + end + i32.const 0 + local.set $17 + br $break|1 + end + local.get $17 + local.get $15 + i32.or + if + local.get $0 + local.get $15 + local.tee $18 + i32.const 1 + i32.add + local.set $15 + local.get $18 + i32.const 1 + i32.shl + i32.add + i32.const 48 + local.get $17 + i32.const 65535 + i32.and + i32.add + i32.store16 + end + local.get $14 + i32.const 1 + i32.sub + local.set $14 + local.get $12 + i64.extend_i32_u + local.get $7 + i64.extend_i32_s + i64.shl + local.get $13 + i64.add + local.set $19 + local.get $19 + local.get $5 + i64.le_u + if + global.get $~lib/util/number/_K + local.get $14 + i32.add + global.set $~lib/util/number/_K + local.get $0 + local.set $24 + local.get $15 + local.set $18 + local.get $5 + local.set $23 + local.get $19 + local.set $22 + local.get $16 + local.get $14 + i32.const 2 + i32.shl + i32.add + i64.load32_u + local.get $7 + i64.extend_i32_s + i64.shl + local.set $21 + local.get $10 + local.set $20 + local.get $24 + local.get $18 + i32.const 1 + i32.sub + i32.const 1 + i32.shl + i32.add + local.set $25 + local.get $25 + i32.load16_u + local.set $26 + block $break|2 + loop $continue|2 + local.get $22 + local.get $20 + i64.lt_u + if (result i32) + local.get $23 + local.get $22 + i64.sub + local.get $21 + i64.ge_u + else + i32.const 0 + end + if (result i32) + local.get $22 + local.get $21 + i64.add + local.get $20 + i64.lt_u + if (result i32) + i32.const 1 + else + local.get $20 + local.get $22 + i64.sub + local.get $22 + local.get $21 + i64.add + local.get $20 + i64.sub + i64.gt_u + end + else + i32.const 0 + end + i32.eqz + br_if $break|2 + local.get $26 + i32.const 1 + i32.sub + local.set $26 + local.get $22 + local.get $21 + i64.add + local.set $22 + br $continue|2 + end + unreachable + end + local.get $25 + local.get $26 + i32.store16 + local.get $15 + return + end + br $continue|0 + end + unreachable + end + loop $continue|3 + local.get $13 + i64.const 10 + i64.mul + local.set $13 + local.get $5 + i64.const 10 + i64.mul + local.set $5 + local.get $13 + local.get $7 + i64.extend_i32_s + i64.shr_u + local.set $19 + local.get $19 + local.get $15 + i64.extend_i32_s + i64.or + i64.const 0 + i64.ne + if + local.get $0 + local.get $15 + local.tee $17 + i32.const 1 + i32.add + local.set $15 + local.get $17 + i32.const 1 + i32.shl + i32.add + i32.const 48 + local.get $19 + i32.wrap_i64 + i32.const 65535 + i32.and + i32.add + i32.store16 + end + local.get $13 + local.get $9 + i64.and + local.set $13 + local.get $14 + i32.const 1 + i32.sub + local.set $14 + local.get $13 + local.get $5 + i64.lt_u + if + global.get $~lib/util/number/_K + local.get $14 + i32.add + global.set $~lib/util/number/_K + local.get $10 + local.get $16 + i32.const 0 + local.get $14 + i32.sub + i32.const 2 + i32.shl + i32.add + i64.load32_u + i64.mul + local.set $10 + local.get $0 + local.set $24 + local.get $15 + local.set $18 + local.get $5 + local.set $23 + local.get $13 + local.set $22 + local.get $8 + local.set $21 + local.get $10 + local.set $20 + local.get $24 + local.get $18 + i32.const 1 + i32.sub + i32.const 1 + i32.shl + i32.add + local.set $17 + local.get $17 + i32.load16_u + local.set $26 + block $break|4 + loop $continue|4 + local.get $22 + local.get $20 + i64.lt_u + if (result i32) + local.get $23 + local.get $22 + i64.sub + local.get $21 + i64.ge_u + else + i32.const 0 + end + if (result i32) + local.get $22 + local.get $21 + i64.add + local.get $20 + i64.lt_u + if (result i32) + i32.const 1 + else + local.get $20 + local.get $22 + i64.sub + local.get $22 + local.get $21 + i64.add + local.get $20 + i64.sub + i64.gt_u + end + else + i32.const 0 + end + i32.eqz + br_if $break|4 + local.get $26 + i32.const 1 + i32.sub + local.set $26 + local.get $22 + local.get $21 + i64.add + local.set $22 + br $continue|4 + end + unreachable + end + local.get $17 + local.get $26 + i32.store16 + local.get $15 + return + end + br $continue|3 + end + unreachable + ) + (func $~lib/util/memory/memcpy (; 21 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + block $break|0 + loop $continue|0 + local.get $2 + if (result i32) + local.get $1 + i32.const 3 + i32.and + else + i32.const 0 + end + i32.eqz + br_if $break|0 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 1 + i32.sub + local.set $2 + br $continue|0 + end + unreachable + end + local.get $0 + i32.const 3 + i32.and + i32.const 0 + i32.eq + if + block $break|1 + loop $continue|1 + local.get $2 + i32.const 16 + i32.ge_u + i32.eqz + br_if $break|1 + local.get $0 + local.get $1 + i32.load + i32.store + local.get $0 + i32.const 4 + i32.add + local.get $1 + i32.const 4 + i32.add + i32.load + i32.store + local.get $0 + i32.const 8 + i32.add + local.get $1 + i32.const 8 + i32.add + i32.load + i32.store + local.get $0 + i32.const 12 + i32.add + local.get $1 + i32.const 12 + i32.add + i32.load + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|1 + end + unreachable + end + local.get $2 + i32.const 8 + i32.and + if + local.get $0 + local.get $1 + i32.load + i32.store + local.get $0 + i32.const 4 + i32.add + local.get $1 + i32.const 4 + i32.add + i32.load + i32.store + local.get $0 + i32.const 8 + i32.add + local.set $0 + local.get $1 + i32.const 8 + i32.add + local.set $1 + end + local.get $2 + i32.const 4 + i32.and + if + local.get $0 + local.get $1 + i32.load + i32.store + local.get $0 + i32.const 4 + i32.add + local.set $0 + local.get $1 + i32.const 4 + i32.add + local.set $1 + end + local.get $2 + i32.const 2 + i32.and + if + local.get $0 + local.get $1 + i32.load16_u + i32.store16 + local.get $0 + i32.const 2 + i32.add + local.set $0 + local.get $1 + i32.const 2 + i32.add + local.set $1 + end + local.get $2 + i32.const 1 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + return + end + local.get $2 + i32.const 32 + i32.ge_u + if + block $break|2 + block $case2|2 + block $case1|2 + block $case0|2 + local.get $0 + i32.const 3 + i32.and + local.set $5 + local.get $5 + i32.const 1 + i32.eq + br_if $case0|2 + local.get $5 + i32.const 2 + i32.eq + br_if $case1|2 + local.get $5 + i32.const 3 + i32.eq + br_if $case2|2 + br $break|2 + end + local.get $1 + i32.load + local.set $3 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 3 + i32.sub + local.set $2 + block $break|3 + loop $continue|3 + local.get $2 + i32.const 17 + i32.ge_u + i32.eqz + br_if $break|3 + local.get $1 + i32.const 1 + i32.add + i32.load + local.set $4 + local.get $0 + local.get $3 + i32.const 24 + i32.shr_u + local.get $4 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 5 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 4 + i32.add + local.get $4 + i32.const 24 + i32.shr_u + local.get $3 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 9 + i32.add + i32.load + local.set $4 + local.get $0 + i32.const 8 + i32.add + local.get $3 + i32.const 24 + i32.shr_u + local.get $4 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 13 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 12 + i32.add + local.get $4 + i32.const 24 + i32.shr_u + local.get $3 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|3 + end + unreachable + end + br $break|2 + end + local.get $1 + i32.load + local.set $3 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 2 + i32.sub + local.set $2 + block $break|4 + loop $continue|4 + local.get $2 + i32.const 18 + i32.ge_u + i32.eqz + br_if $break|4 + local.get $1 + i32.const 2 + i32.add + i32.load + local.set $4 + local.get $0 + local.get $3 + i32.const 16 + i32.shr_u + local.get $4 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 6 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 4 + i32.add + local.get $4 + i32.const 16 + i32.shr_u + local.get $3 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 10 + i32.add + i32.load + local.set $4 + local.get $0 + i32.const 8 + i32.add + local.get $3 + i32.const 16 + i32.shr_u + local.get $4 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 14 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 12 + i32.add + local.get $4 + i32.const 16 + i32.shr_u + local.get $3 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|4 + end + unreachable + end + br $break|2 + end + local.get $1 + i32.load + local.set $3 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 1 + i32.sub + local.set $2 + block $break|5 + loop $continue|5 + local.get $2 + i32.const 19 + i32.ge_u + i32.eqz + br_if $break|5 + local.get $1 + i32.const 3 + i32.add + i32.load + local.set $4 + local.get $0 + local.get $3 + i32.const 8 + i32.shr_u + local.get $4 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 7 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 4 + i32.add + local.get $4 + i32.const 8 + i32.shr_u + local.get $3 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 11 + i32.add + i32.load + local.set $4 + local.get $0 + i32.const 8 + i32.add + local.get $3 + i32.const 8 + i32.shr_u + local.get $4 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 15 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 12 + i32.add + local.get $4 + i32.const 8 + i32.shr_u + local.get $3 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|5 + end + unreachable + end + br $break|2 + end + end + local.get $2 + i32.const 16 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 8 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 4 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 2 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 1 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + ) + (func $~lib/memory/memory.copy (; 22 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + block $~lib/util/memory/memmove|inlined.0 + local.get $0 + local.set $5 + local.get $1 + local.set $4 + local.get $2 + local.set $3 + local.get $5 + local.get $4 + i32.eq + if + br $~lib/util/memory/memmove|inlined.0 + end + local.get $4 + local.get $3 + i32.add + local.get $5 + i32.le_u + if (result i32) + i32.const 1 + else + local.get $5 + local.get $3 + i32.add + local.get $4 + i32.le_u + end + if + local.get $5 + local.get $4 + local.get $3 + call $~lib/util/memory/memcpy + br $~lib/util/memory/memmove|inlined.0 + end + local.get $5 + local.get $4 + i32.lt_u + if + local.get $4 + i32.const 7 + i32.and + local.get $5 + i32.const 7 + i32.and + i32.eq + if + block $break|0 + loop $continue|0 + local.get $5 + i32.const 7 + i32.and + i32.eqz + br_if $break|0 + local.get $3 + i32.eqz + if + br $~lib/util/memory/memmove|inlined.0 + end + local.get $3 + i32.const 1 + i32.sub + local.set $3 + local.get $5 + local.tee $6 + i32.const 1 + i32.add + local.set $5 + local.get $6 + local.get $4 + local.tee $6 + i32.const 1 + i32.add + local.set $4 + local.get $6 + i32.load8_u + i32.store8 + br $continue|0 + end + unreachable + end + block $break|1 + loop $continue|1 + local.get $3 + i32.const 8 + i32.ge_u + i32.eqz + br_if $break|1 + local.get $5 + local.get $4 + i64.load + i64.store + local.get $3 + i32.const 8 + i32.sub + local.set $3 + local.get $5 + i32.const 8 + i32.add + local.set $5 + local.get $4 + i32.const 8 + i32.add + local.set $4 + br $continue|1 + end + unreachable + end + end + block $break|2 + loop $continue|2 + local.get $3 + i32.eqz + br_if $break|2 + local.get $5 + local.tee $6 + i32.const 1 + i32.add + local.set $5 + local.get $6 + local.get $4 + local.tee $6 + i32.const 1 + i32.add + local.set $4 + local.get $6 + i32.load8_u + i32.store8 + local.get $3 + i32.const 1 + i32.sub + local.set $3 + br $continue|2 + end + unreachable + end + else + local.get $4 + i32.const 7 + i32.and + local.get $5 + i32.const 7 + i32.and + i32.eq + if + block $break|3 + loop $continue|3 + local.get $5 + local.get $3 + i32.add + i32.const 7 + i32.and + i32.eqz + br_if $break|3 + local.get $3 + i32.eqz + if + br $~lib/util/memory/memmove|inlined.0 + end + local.get $5 + local.get $3 + i32.const 1 + i32.sub + local.tee $3 + i32.add + local.get $4 + local.get $3 + i32.add + i32.load8_u + i32.store8 + br $continue|3 + end + unreachable + end + block $break|4 + loop $continue|4 + local.get $3 + i32.const 8 + i32.ge_u + i32.eqz + br_if $break|4 + local.get $3 + i32.const 8 + i32.sub + local.set $3 + local.get $5 + local.get $3 + i32.add + local.get $4 + local.get $3 + i32.add + i64.load + i64.store + br $continue|4 + end + unreachable + end + end + block $break|5 + loop $continue|5 + local.get $3 + i32.eqz + br_if $break|5 + local.get $5 + local.get $3 + i32.const 1 + i32.sub + local.tee $3 + i32.add + local.get $4 + local.get $3 + i32.add + i32.load8_u + i32.store8 + br $continue|5 + end + unreachable + end + end + end + ) + (func $~lib/util/number/prettify (; 23 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + local.get $2 + i32.eqz + if + local.get $0 + local.get $1 + i32.const 1 + i32.shl + i32.add + i32.const 46 + i32.const 48 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 2 + i32.add + return + end + local.get $1 + local.get $2 + i32.add + local.set $3 + local.get $1 + local.get $3 + i32.le_s + if (result i32) + local.get $3 + i32.const 21 + i32.le_s + else + i32.const 0 + end + if + block $break|0 + local.get $1 + local.set $4 + loop $loop|0 + local.get $4 + local.get $3 + i32.lt_s + i32.eqz + br_if $break|0 + local.get $0 + local.get $4 + i32.const 1 + i32.shl + i32.add + i32.const 48 + i32.store16 + local.get $4 + i32.const 1 + i32.add + local.set $4 + br $loop|0 + end + unreachable + end + local.get $0 + local.get $3 + i32.const 1 + i32.shl + i32.add + i32.const 46 + i32.const 48 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $3 + i32.const 2 + i32.add + return + else + local.get $3 + i32.const 0 + i32.gt_s + if (result i32) + local.get $3 + i32.const 21 + i32.le_s + else + i32.const 0 + end + if + local.get $0 + local.get $3 + i32.const 1 + i32.shl + i32.add + local.set $4 + local.get $4 + i32.const 2 + i32.add + local.get $4 + i32.const 0 + local.get $2 + i32.sub + i32.const 1 + i32.shl + call $~lib/memory/memory.copy + local.get $0 + local.get $3 + i32.const 1 + i32.shl + i32.add + i32.const 46 + i32.store16 + local.get $1 + i32.const 1 + i32.add + return + else + i32.const -6 + local.get $3 + i32.lt_s + if (result i32) + local.get $3 + i32.const 0 + i32.le_s + else + i32.const 0 + end + if + i32.const 2 + local.get $3 + i32.sub + local.set $4 + local.get $0 + local.get $4 + i32.const 1 + i32.shl + i32.add + local.get $0 + local.get $1 + i32.const 1 + i32.shl + call $~lib/memory/memory.copy + local.get $0 + i32.const 48 + i32.const 46 + i32.const 16 + i32.shl + i32.or + i32.store + block $break|1 + i32.const 2 + local.set $5 + loop $loop|1 + local.get $5 + local.get $4 + i32.lt_s + i32.eqz + br_if $break|1 + local.get $0 + local.get $5 + i32.const 1 + i32.shl + i32.add + i32.const 48 + i32.store16 + local.get $5 + i32.const 1 + i32.add + local.set $5 + br $loop|1 + end + unreachable + end + local.get $1 + local.get $4 + i32.add + return + else + local.get $1 + i32.const 1 + i32.eq + if + local.get $0 + i32.const 101 + i32.store16 offset=2 + local.get $0 + i32.const 4 + i32.add + local.set $4 + local.get $3 + i32.const 1 + i32.sub + local.set $5 + local.get $5 + i32.const 0 + i32.lt_s + local.set $6 + local.get $6 + if + i32.const 0 + local.get $5 + i32.sub + local.set $5 + end + local.get $5 + call $~lib/util/number/decimalCount32 + i32.const 1 + i32.add + local.set $7 + local.get $4 + local.set $10 + local.get $5 + local.set $9 + local.get $7 + local.set $8 + local.get $10 + local.get $9 + local.get $8 + call $~lib/util/number/utoa32_lut + local.get $4 + i32.const 45 + i32.const 43 + local.get $6 + select + i32.store16 + local.get $7 + local.set $1 + local.get $1 + i32.const 2 + i32.add + return + else + local.get $1 + i32.const 1 + i32.shl + local.set $7 + local.get $0 + i32.const 4 + i32.add + local.get $0 + i32.const 2 + i32.add + local.get $7 + i32.const 2 + i32.sub + call $~lib/memory/memory.copy + local.get $0 + i32.const 46 + i32.store16 offset=2 + local.get $0 + local.get $7 + i32.add + i32.const 101 + i32.store16 offset=2 + local.get $1 + local.get $0 + local.get $7 + i32.add + i32.const 4 + i32.add + local.set $9 + local.get $3 + i32.const 1 + i32.sub + local.set $8 + local.get $8 + i32.const 0 + i32.lt_s + local.set $6 + local.get $6 + if + i32.const 0 + local.get $8 + i32.sub + local.set $8 + end + local.get $8 + call $~lib/util/number/decimalCount32 + i32.const 1 + i32.add + local.set $4 + local.get $9 + local.set $11 + local.get $8 + local.set $5 + local.get $4 + local.set $10 + local.get $11 + local.get $5 + local.get $10 + call $~lib/util/number/utoa32_lut + local.get $9 + i32.const 45 + i32.const 43 + local.get $6 + select + i32.store16 + local.get $4 + i32.add + local.set $1 + local.get $1 + i32.const 2 + i32.add + return + end + unreachable + end + unreachable + end + unreachable + end + unreachable + ) + (func $~lib/util/number/dtoa_core (; 24 ;) (type $FUNCSIG$iid) (param $0 i32) (param $1 f64) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 f64) + (local $6 i64) + (local $7 i32) + (local $8 i64) + (local $9 i64) + (local $10 i32) + (local $11 i64) + (local $12 i64) + (local $13 i32) + (local $14 i32) + (local $15 i32) + (local $16 f64) + (local $17 i64) + (local $18 i64) + (local $19 i64) + (local $20 i64) + (local $21 i64) + (local $22 i64) + (local $23 i64) + (local $24 i64) + (local $25 i64) + (local $26 i32) + (local $27 i64) + (local $28 i32) + local.get $1 + f64.const 0 + f64.lt + local.set $2 + local.get $2 + if + local.get $1 + f64.neg + local.set $1 + local.get $0 + i32.const 45 + i32.store16 + end + local.get $1 + local.set $5 + local.get $0 + local.set $4 + local.get $2 + local.set $3 + local.get $5 + i64.reinterpret_f64 + local.set $6 + local.get $6 + i64.const 9218868437227405312 + i64.and + i64.const 52 + i64.shr_u + i32.wrap_i64 + local.set $7 + local.get $6 + i64.const 4503599627370495 + i64.and + local.set $8 + local.get $7 + i32.const 0 + i32.ne + i64.extend_i32_u + i64.const 52 + i64.shl + local.get $8 + i64.add + local.set $9 + local.get $7 + i32.const 1 + local.get $7 + i32.const 0 + i32.ne + select + i32.const 1023 + i32.const 52 + i32.add + i32.sub + local.set $7 + local.get $9 + local.set $11 + local.get $7 + local.set $10 + local.get $11 + i64.const 1 + i64.shl + i64.const 1 + i64.add + local.set $12 + local.get $10 + i32.const 1 + i32.sub + local.set $13 + local.get $12 + i64.clz + i32.wrap_i64 + local.set $14 + local.get $12 + local.get $14 + i64.extend_i32_s + i64.shl + local.set $12 + local.get $13 + local.get $14 + i32.sub + local.set $13 + i32.const 1 + local.get $11 + i64.const 4503599627370496 + i64.eq + i32.add + local.set $15 + local.get $12 + global.set $~lib/util/number/_frc_plus + local.get $11 + local.get $15 + i64.extend_i32_s + i64.shl + i64.const 1 + i64.sub + local.get $10 + local.get $15 + i32.sub + local.get $13 + i32.sub + i64.extend_i32_s + i64.shl + global.set $~lib/util/number/_frc_minus + local.get $13 + global.set $~lib/util/number/_exp + global.get $~lib/util/number/_exp + local.set $10 + i32.const -61 + local.get $10 + i32.sub + f64.convert_i32_s + f64.const 0.30102999566398114 + f64.mul + f64.const 347 + f64.add + local.set $16 + local.get $16 + i32.trunc_f64_s + local.set $15 + local.get $15 + local.get $15 + f64.convert_i32_s + local.get $16 + f64.ne + i32.add + local.set $15 + local.get $15 + i32.const 3 + i32.shr_s + i32.const 1 + i32.add + local.set $14 + i32.const 348 + local.get $14 + i32.const 3 + i32.shl + i32.sub + global.set $~lib/util/number/_K + i32.const 1512 + local.get $14 + call $~lib/array/Array#__unchecked_get + global.set $~lib/util/number/_frc_pow + i32.const 1736 + local.get $14 + call $~lib/array/Array#__unchecked_get + global.set $~lib/util/number/_exp_pow + local.get $9 + i64.clz + i32.wrap_i64 + local.set $14 + local.get $9 + local.get $14 + i64.extend_i32_s + i64.shl + local.set $9 + local.get $7 + local.get $14 + i32.sub + local.set $7 + global.get $~lib/util/number/_frc_pow + local.set $12 + global.get $~lib/util/number/_exp_pow + local.set $15 + local.get $9 + local.set $17 + local.get $12 + local.set $11 + local.get $17 + i64.const 4294967295 + i64.and + local.set $18 + local.get $11 + i64.const 4294967295 + i64.and + local.set $19 + local.get $17 + i64.const 32 + i64.shr_u + local.set $20 + local.get $11 + i64.const 32 + i64.shr_u + local.set $21 + local.get $18 + local.get $19 + i64.mul + local.set $22 + local.get $20 + local.get $19 + i64.mul + local.get $22 + i64.const 32 + i64.shr_u + i64.add + local.set $23 + local.get $18 + local.get $21 + i64.mul + local.get $23 + i64.const 4294967295 + i64.and + i64.add + local.set $24 + local.get $24 + i64.const 2147483647 + i64.add + local.set $24 + local.get $23 + i64.const 32 + i64.shr_u + local.set $23 + local.get $24 + i64.const 32 + i64.shr_u + local.set $24 + local.get $20 + local.get $21 + i64.mul + local.get $23 + i64.add + local.get $24 + i64.add + local.set $24 + local.get $7 + local.set $10 + local.get $15 + local.set $13 + local.get $10 + local.get $13 + i32.add + i32.const 64 + i32.add + local.set $10 + global.get $~lib/util/number/_frc_plus + local.set $17 + local.get $12 + local.set $11 + local.get $17 + i64.const 4294967295 + i64.and + local.set $23 + local.get $11 + i64.const 4294967295 + i64.and + local.set $22 + local.get $17 + i64.const 32 + i64.shr_u + local.set $21 + local.get $11 + i64.const 32 + i64.shr_u + local.set $20 + local.get $23 + local.get $22 + i64.mul + local.set $19 + local.get $21 + local.get $22 + i64.mul + local.get $19 + i64.const 32 + i64.shr_u + i64.add + local.set $18 + local.get $23 + local.get $20 + i64.mul + local.get $18 + i64.const 4294967295 + i64.and + i64.add + local.set $25 + local.get $25 + i64.const 2147483647 + i64.add + local.set $25 + local.get $18 + i64.const 32 + i64.shr_u + local.set $18 + local.get $25 + i64.const 32 + i64.shr_u + local.set $25 + local.get $21 + local.get $20 + i64.mul + local.get $18 + i64.add + local.get $25 + i64.add + i64.const 1 + i64.sub + local.set $25 + global.get $~lib/util/number/_exp + local.set $26 + local.get $15 + local.set $13 + local.get $26 + local.get $13 + i32.add + i32.const 64 + i32.add + local.set $26 + global.get $~lib/util/number/_frc_minus + local.set $17 + local.get $12 + local.set $11 + local.get $17 + i64.const 4294967295 + i64.and + local.set $18 + local.get $11 + i64.const 4294967295 + i64.and + local.set $19 + local.get $17 + i64.const 32 + i64.shr_u + local.set $20 + local.get $11 + i64.const 32 + i64.shr_u + local.set $21 + local.get $18 + local.get $19 + i64.mul + local.set $22 + local.get $20 + local.get $19 + i64.mul + local.get $22 + i64.const 32 + i64.shr_u + i64.add + local.set $23 + local.get $18 + local.get $21 + i64.mul + local.get $23 + i64.const 4294967295 + i64.and + i64.add + local.set $27 + local.get $27 + i64.const 2147483647 + i64.add + local.set $27 + local.get $23 + i64.const 32 + i64.shr_u + local.set $23 + local.get $27 + i64.const 32 + i64.shr_u + local.set $27 + local.get $20 + local.get $21 + i64.mul + local.get $23 + i64.add + local.get $27 + i64.add + i64.const 1 + i64.add + local.set $27 + local.get $25 + local.get $27 + i64.sub + local.set $23 + local.get $4 + local.get $24 + local.get $10 + local.get $25 + local.get $26 + local.get $23 + local.get $3 + call $~lib/util/number/genDigits + local.set $28 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $28 + local.get $2 + i32.sub + global.get $~lib/util/number/_K + call $~lib/util/number/prettify + local.set $28 + local.get $28 + local.get $2 + i32.add + ) + (func $~lib/string/String#substring (; 25 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + local.get $0 + call $~lib/string/String#get:length + local.set $3 + local.get $1 + local.tee $4 + i32.const 0 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.lt_s + select + local.set $6 + local.get $2 + local.tee $4 + i32.const 0 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.lt_s + select + local.set $7 + local.get $6 + local.tee $4 + local.get $7 + local.tee $5 + local.get $4 + local.get $5 + i32.lt_s + select + i32.const 1 + i32.shl + local.set $8 + local.get $6 + local.tee $4 + local.get $7 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + i32.const 1 + i32.shl + local.set $9 + local.get $9 + local.get $8 + i32.sub + local.set $3 + local.get $3 + i32.eqz + if + i32.const 1856 + call $~lib/rt/stub/__retain + return + end + local.get $8 + i32.eqz + if (result i32) + local.get $9 + local.get $0 + call $~lib/string/String#get:length + i32.const 1 + i32.shl + i32.eq + else + i32.const 0 + end + if + local.get $0 + call $~lib/rt/stub/__retain + return + end + local.get $3 + i32.const 1 + call $~lib/rt/stub/__alloc + local.set $10 + local.get $10 + local.get $0 + local.get $8 + i32.add + local.get $3 + call $~lib/memory/memory.copy + local.get $10 + call $~lib/rt/stub/__retain + ) + (func $~lib/rt/stub/__free (; 26 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + local.get $0 + i32.const 0 + i32.ne + if (result i32) + local.get $0 + i32.const 15 + i32.and + i32.eqz + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 1872 + i32.const 71 + i32.const 2 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 16 + i32.sub + local.set $1 + local.get $1 + i32.load offset=4 + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 1872 + i32.const 73 + i32.const 13 + call $~lib/builtins/abort + unreachable + end + local.get $0 + local.get $1 + i32.load + i32.add + global.get $~lib/rt/stub/offset + i32.eq + if + local.get $1 + global.set $~lib/rt/stub/offset + end + ) + (func $~lib/util/number/dtoa (; 27 ;) (type $FUNCSIG$id) (param $0 f64) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + f64.const 0 + f64.eq + if + i32.const 680 + call $~lib/rt/stub/__retain + return + end + local.get $0 + call $~lib/number/isFinite + i32.eqz + if + local.get $0 + call $~lib/number/isNaN + if + i32.const 704 + call $~lib/rt/stub/__retain + return + end + i32.const 728 + i32.const 768 + local.get $0 + f64.const 0 + f64.lt + select + call $~lib/rt/stub/__retain + return + end + i32.const 28 + i32.const 1 + i32.shl + i32.const 1 + call $~lib/rt/stub/__alloc + local.set $1 + local.get $1 + local.get $0 + call $~lib/util/number/dtoa_core + local.set $2 + local.get $2 + i32.const 28 + i32.eq + if + local.get $1 + call $~lib/rt/stub/__retain + return + end + local.get $1 + i32.const 0 + local.get $2 + call $~lib/string/String#substring + local.set $3 + local.get $1 + call $~lib/rt/stub/__free + local.get $3 + ) + (func $~lib/number/F64#toString (; 28 ;) (type $FUNCSIG$idi) (param $0 f64) (param $1 i32) (result i32) + local.get $0 + call $~lib/util/number/dtoa + ) + (func $resolve-binary/Foo#constructor (; 29 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 6 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $resolve-binary/Foo#lt (; 30 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2016 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $~lib/string/String#toString (; 31 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-binary/Foo#gt (; 32 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2040 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#le (; 33 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2064 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#ge (; 34 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2088 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#eq (; 35 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2112 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#ne (; 36 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2136 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#add (; 37 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2160 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo.sub (; 38 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2184 + call $~lib/rt/stub/__retain + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#mul (; 39 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2208 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#div (; 40 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2232 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#rem (; 41 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2256 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Foo#pow (; 42 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + i32.const 2280 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $resolve-binary/Bar#constructor (; 43 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 7 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $resolve-binary/Bar#add (; 44 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + local.get $1 + call $~lib/rt/stub/__retain + drop + local.get $1 + ) + (func $resolve-binary/Bar#self (; 45 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $start:resolve-binary (; 46 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + (local $12 i32) + (local $13 i32) + (local $14 i32) + (local $15 i32) + (local $16 i32) + (local $17 i32) + (local $18 i32) + (local $19 i32) + (local $20 i32) + (local $21 i32) + (local $22 i32) + (local $23 i32) + (local $24 i32) + (local $25 i32) + (local $26 i32) + (local $27 i32) + (local $28 i32) + (local $29 i32) + (local $30 i32) + (local $31 i32) + (local $32 i32) + (local $33 i32) + (local $34 i32) + (local $35 i32) + (local $36 i32) + (local $37 i32) + (local $38 i32) + (local $39 i32) + (local $40 i32) + (local $41 i32) + (local $42 i32) + (local $43 i32) + (local $44 i32) + (local $45 i32) + (local $46 i32) + (local $47 i32) + (local $48 i32) + (local $49 i32) + (local $50 i32) + (local $51 i32) + (local $52 i32) + (local $53 i32) + (local $54 i32) + (local $55 i32) + (local $56 i32) + (local $57 i32) + (local $58 i32) + (local $59 i32) + (local $60 i32) + (local $61 i32) + (local $62 i32) + (local $63 i32) + i32.const 1 + call $~lib/number/Bool#toString + local.tee $0 + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 2 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + local.tee $1 + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 7 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/Bool#toString + local.tee $2 + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 12 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + local.tee $3 + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 17 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + local.tee $4 + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 22 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/Bool#toString + local.tee $5 + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 27 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/Bool#toString + local.tee $6 + i32.const 24 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 34 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/Bool#toString + local.tee $7 + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 39 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const 1 + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $8 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 48 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.add + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $9 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 53 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.sub + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $10 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 58 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 2 + i32.mul + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $11 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 63 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + f64.const 2 + global.set $resolve-binary/f + global.get $resolve-binary/f + f64.const 2 + call $~lib/math/NativeMath.pow + global.set $resolve-binary/f + global.get $resolve-binary/f + i32.const 0 + call $~lib/number/F64#toString + local.tee $12 + i32.const 1920 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 69 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 4 + global.set $resolve-binary/a + global.get $resolve-binary/a + i32.const 2 + i32.div_s + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $13 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 75 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 3 + i32.rem_s + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $14 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 80 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shl + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $15 + i32.const 1944 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 85 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shr_s + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $16 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 90 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 1 + i32.shr_u + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $17 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 95 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 3 + i32.and + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $18 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 100 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 3 + i32.or + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $19 + i32.const 1968 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 105 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/a + i32.const 2 + i32.xor + global.set $resolve-binary/a + global.get $resolve-binary/a + call $~lib/number/I32#toString + local.tee $20 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 110 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + call $~lib/number/I32#toString + local.tee $21 + i32.const 1968 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 117 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const -1 + call $~lib/number/I32#toString + local.tee $22 + i32.const 1992 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 122 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/number/I32#toString + local.tee $23 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 127 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/number/I32#toString + local.tee $24 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 132 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/I32#toString + local.tee $25 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 137 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + f64.const 2 + f64.const 2 + call $~lib/math/NativeMath.pow + i32.const 0 + call $~lib/number/F64#toString + local.tee $26 + i32.const 1920 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 144 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 4 + call $~lib/number/I32#toString + local.tee $27 + i32.const 1944 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 151 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/I32#toString + local.tee $28 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 156 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + call $~lib/number/I32#toString + local.tee $29 + i32.const 1968 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 161 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/I32#toString + local.tee $30 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 168 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + call $~lib/number/I32#toString + local.tee $31 + i32.const 1968 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 173 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/number/I32#toString + local.tee $32 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 178 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/number/I32#toString + local.tee $33 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 185 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $~lib/number/I32#toString + local.tee $34 + i32.const 160 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 190 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/I32#toString + local.tee $35 + i32.const 632 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 195 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + call $~lib/number/I32#toString + local.tee $36 + i32.const 656 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 200 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $resolve-binary/Foo#constructor + global.set $resolve-binary/foo + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#lt + local.tee $37 + call $~lib/string/String#toString + local.tee $38 + i32.const 2016 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 261 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#gt + local.tee $39 + call $~lib/string/String#toString + local.tee $40 + i32.const 2040 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 266 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#le + local.tee $41 + call $~lib/string/String#toString + local.tee $42 + i32.const 2064 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 271 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#ge + local.tee $43 + call $~lib/string/String#toString + local.tee $44 + i32.const 2088 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 276 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#eq + local.tee $45 + call $~lib/string/String#toString + local.tee $46 + i32.const 2112 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 281 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#ne + local.tee $47 + call $~lib/string/String#toString + local.tee $48 + i32.const 2136 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 286 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#add + local.tee $49 + call $~lib/string/String#toString + local.tee $50 + i32.const 2160 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 291 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo.sub + local.tee $51 + call $~lib/string/String#toString + local.tee $52 + i32.const 2184 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 296 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#mul + local.tee $53 + call $~lib/string/String#toString + local.tee $54 + i32.const 2208 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 301 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#div + local.tee $55 + call $~lib/string/String#toString + local.tee $56 + i32.const 2232 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 306 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#rem + local.tee $57 + call $~lib/string/String#toString + local.tee $58 + i32.const 2256 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 311 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/foo + global.get $resolve-binary/foo + call $resolve-binary/Foo#pow + local.tee $59 + call $~lib/string/String#toString + local.tee $60 + i32.const 2280 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 316 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $resolve-binary/Bar#constructor + global.set $resolve-binary/bar + i32.const 0 + call $resolve-binary/Bar#constructor + global.set $resolve-binary/bar2 + global.get $resolve-binary/bar + global.get $resolve-binary/bar2 + call $resolve-binary/Bar#add + local.tee $61 + local.tee $62 + global.get $resolve-binary/bar + local.tee $63 + i32.ne + if + local.get $62 + call $~lib/rt/stub/__retain + drop + local.get $63 + call $~lib/rt/stub/__release + end + local.get $62 + global.set $resolve-binary/bar + global.get $resolve-binary/bar + call $resolve-binary/Bar#self + local.tee $62 + global.get $resolve-binary/bar2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 334 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-binary/bar + global.get $resolve-binary/bar2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 339 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + call $~lib/rt/stub/__release + local.get $3 + call $~lib/rt/stub/__release + local.get $4 + call $~lib/rt/stub/__release + local.get $5 + call $~lib/rt/stub/__release + local.get $6 + call $~lib/rt/stub/__release + local.get $7 + call $~lib/rt/stub/__release + local.get $8 + call $~lib/rt/stub/__release + local.get $9 + call $~lib/rt/stub/__release + local.get $10 + call $~lib/rt/stub/__release + local.get $11 + call $~lib/rt/stub/__release + local.get $12 + call $~lib/rt/stub/__release + local.get $13 + call $~lib/rt/stub/__release + local.get $14 + call $~lib/rt/stub/__release + local.get $15 + call $~lib/rt/stub/__release + local.get $16 + call $~lib/rt/stub/__release + local.get $17 + call $~lib/rt/stub/__release + local.get $18 + call $~lib/rt/stub/__release + local.get $19 + call $~lib/rt/stub/__release + local.get $20 + call $~lib/rt/stub/__release + local.get $21 + call $~lib/rt/stub/__release + local.get $22 + call $~lib/rt/stub/__release + local.get $23 + call $~lib/rt/stub/__release + local.get $24 + call $~lib/rt/stub/__release + local.get $25 + call $~lib/rt/stub/__release + local.get $26 + call $~lib/rt/stub/__release + local.get $27 + call $~lib/rt/stub/__release + local.get $28 + call $~lib/rt/stub/__release + local.get $29 + call $~lib/rt/stub/__release + local.get $30 + call $~lib/rt/stub/__release + local.get $31 + call $~lib/rt/stub/__release + local.get $32 + call $~lib/rt/stub/__release + local.get $33 + call $~lib/rt/stub/__release + local.get $34 + call $~lib/rt/stub/__release + local.get $35 + call $~lib/rt/stub/__release + local.get $36 + call $~lib/rt/stub/__release + local.get $37 + call $~lib/rt/stub/__release + local.get $38 + call $~lib/rt/stub/__release + local.get $39 + call $~lib/rt/stub/__release + local.get $40 + call $~lib/rt/stub/__release + local.get $41 + call $~lib/rt/stub/__release + local.get $42 + call $~lib/rt/stub/__release + local.get $43 + call $~lib/rt/stub/__release + local.get $44 + call $~lib/rt/stub/__release + local.get $45 + call $~lib/rt/stub/__release + local.get $46 + call $~lib/rt/stub/__release + local.get $47 + call $~lib/rt/stub/__release + local.get $48 + call $~lib/rt/stub/__release + local.get $49 + call $~lib/rt/stub/__release + local.get $50 + call $~lib/rt/stub/__release + local.get $51 + call $~lib/rt/stub/__release + local.get $52 + call $~lib/rt/stub/__release + local.get $53 + call $~lib/rt/stub/__release + local.get $54 + call $~lib/rt/stub/__release + local.get $55 + call $~lib/rt/stub/__release + local.get $56 + call $~lib/rt/stub/__release + local.get $57 + call $~lib/rt/stub/__release + local.get $58 + call $~lib/rt/stub/__release + local.get $59 + call $~lib/rt/stub/__release + local.get $60 + call $~lib/rt/stub/__release + local.get $61 + call $~lib/rt/stub/__release + local.get $62 + call $~lib/rt/stub/__release + ) + (func $start (; 47 ;) (type $FUNCSIG$v) + call $start:resolve-binary + ) + (func $null (; 48 ;) (type $FUNCSIG$v) + ) +) diff --git a/tests/compiler/resolve-function-expression.json b/tests/compiler/resolve-function-expression.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/resolve-function-expression.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/resolve-function-expression.optimized.wat b/tests/compiler/resolve-function-expression.optimized.wat new file mode 100644 index 0000000000..0d63d12573 --- /dev/null +++ b/tests/compiler/resolve-function-expression.optimized.wat @@ -0,0 +1,366 @@ +(module + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) "<\00\00\00\01\00\00\00\01\00\00\00<\00\00\00r\00e\00s\00o\00l\00v\00e\00-\00f\00u\00n\00c\00t\00i\00o\00n\00-\00e\00x\00p\00r\00e\00s\00s\00i\00o\00n\00.\00t\00s") + (data (i32.const 88) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\000") + (data (i32.const 112) "\04\00\00\00\01\00\00\00\01\00\00\00\04\00\00\004\002") + (table $0 4 funcref) + (elem (i32.const 0) $null $start:resolve-function-expression~anonymous|0 $start:resolve-function-expression~anonymous|1 $start:resolve-function-expression~anonymous|2) + (global $~lib/argc (mut i32) (i32.const 0)) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (start $start) + (func $start:resolve-function-expression~anonymous|0 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 40 + i32.add + ) + (func $start:resolve-function-expression~anonymous|1 (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 41 + i32.add + ) + (func $start:resolve-function-expression~anonymous|2 (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 42 + i32.add + ) + (func $~lib/util/number/decimalCount32 (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 1 + i32.const 2 + local.get $0 + i32.const 10 + i32.lt_u + select + i32.const 3 + i32.const 4 + i32.const 5 + local.get $0 + i32.const 10000 + i32.lt_u + select + local.get $0 + i32.const 1000 + i32.lt_u + select + local.get $0 + i32.const 100 + i32.lt_u + select + i32.const 6 + i32.const 7 + local.get $0 + i32.const 1000000 + i32.lt_u + select + i32.const 8 + i32.const 9 + i32.const 10 + local.get $0 + i32.const 1000000000 + i32.lt_u + select + local.get $0 + i32.const 100000000 + i32.lt_u + select + local.get $0 + i32.const 10000000 + i32.lt_u + select + local.get $0 + i32.const 100000 + i32.lt_u + select + ) + (func $~lib/rt/stub/maybeGrowMemory (; 5 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + local.get $0 + memory.size + local.tee $2 + i32.const 16 + i32.shl + local.tee $1 + i32.gt_u + if + local.get $2 + local.get $0 + local.get $1 + i32.sub + i32.const 65535 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $1 + local.get $2 + local.get $1 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $1 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.tee $2 + local.get $0 + i32.const 15 + i32.add + i32.const -16 + i32.and + local.tee $1 + i32.const 16 + local.get $1 + i32.const 16 + i32.gt_u + select + local.tee $3 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.tee $1 + local.get $3 + i32.store + local.get $1 + i32.const -1 + i32.store offset=4 + local.get $1 + i32.const 1 + i32.store offset=8 + local.get $1 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/util/number/utoa_simple (; 7 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + loop $continue|0 + local.get $1 + i32.const 10 + i32.rem_u + local.set $3 + local.get $1 + i32.const 10 + i32.div_u + local.set $1 + local.get $2 + i32.const 1 + i32.sub + local.tee $2 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $3 + i32.const 48 + i32.add + i32.store16 + local.get $1 + br_if $continue|0 + end + ) + (func $~lib/util/number/itoa32 (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + i32.eqz + if + i32.const 104 + return + end + local.get $0 + i32.const 0 + i32.lt_s + local.tee $1 + if + i32.const 0 + local.get $0 + i32.sub + local.set $0 + end + local.get $0 + call $~lib/util/number/decimalCount32 + local.get $1 + i32.add + local.tee $3 + i32.const 1 + i32.shl + call $~lib/rt/stub/__alloc + local.tee $2 + local.get $0 + local.get $3 + call $~lib/util/number/utoa_simple + local.get $1 + if + local.get $2 + i32.const 45 + i32.store16 + end + local.get $2 + ) + (func $~lib/string/String#get:length (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load offset=12 + i32.const 1 + i32.shr_u + ) + (func $~lib/util/string/compareImpl (; 10 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + i32.const 128 + local.set $2 + loop $continue|0 + local.get $1 + if (result i32) + local.get $0 + i32.load16_u + local.get $2 + i32.load16_u + i32.sub + local.tee $3 + i32.eqz + else + i32.const 0 + end + if + local.get $1 + i32.const 1 + i32.sub + local.set $1 + local.get $0 + i32.const 2 + i32.add + local.set $0 + local.get $2 + i32.const 2 + i32.add + local.set $2 + br $continue|0 + end + end + local.get $3 + ) + (func $~lib/string/String.__eq (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 128 + i32.eq + if + i32.const 1 + return + end + block $folding-inner0 + i32.const 0 + i32.const 1 + local.get $0 + select + br_if $folding-inner0 + local.get $0 + call $~lib/string/String#get:length + local.tee $1 + i32.const 128 + call $~lib/string/String#get:length + i32.ne + br_if $folding-inner0 + local.get $0 + local.get $1 + call $~lib/util/string/compareImpl + i32.eqz + return + end + i32.const 0 + ) + (func $start:resolve-function-expression (; 12 ;) (type $FUNCSIG$v) + i32.const 1 + global.set $~lib/argc + i32.const 2 + call $start:resolve-function-expression~anonymous|0 + i32.const 42 + i32.ne + if + i32.const 0 + i32.const 24 + i32.const 1 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + global.set $~lib/argc + i32.const 1 + call $start:resolve-function-expression~anonymous|1 + i32.const 42 + i32.ne + if + i32.const 0 + i32.const 24 + i32.const 6 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 144 + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const 1 + global.set $~lib/argc + i32.const 0 + call $start:resolve-function-expression~anonymous|2 + call $~lib/util/number/itoa32 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 11 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + ) + (func $start (; 13 ;) (type $FUNCSIG$v) + call $start:resolve-function-expression + ) + (func $null (; 14 ;) (type $FUNCSIG$v) + nop + ) +) diff --git a/tests/compiler/resolve-function-expression.ts b/tests/compiler/resolve-function-expression.ts new file mode 100644 index 0000000000..a3b1e9a383 --- /dev/null +++ b/tests/compiler/resolve-function-expression.ts @@ -0,0 +1,15 @@ +assert( + ((a: i32): i32 => a + 40)(2) + == + 42 +); +assert( + (function(a: i32): i32 { return a + 41; })(1) + == + 42 +); +assert( + ((a: i32): i32 => a + 42)(0).toString() + == + "42" +); diff --git a/tests/compiler/resolve-function-expression.untouched.wat b/tests/compiler/resolve-function-expression.untouched.wat new file mode 100644 index 0000000000..7c92cfd389 --- /dev/null +++ b/tests/compiler/resolve-function-expression.untouched.wat @@ -0,0 +1,649 @@ +(module + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32))) + (type $FUNCSIG$v (func)) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) "<\00\00\00\01\00\00\00\01\00\00\00<\00\00\00r\00e\00s\00o\00l\00v\00e\00-\00f\00u\00n\00c\00t\00i\00o\00n\00-\00e\00x\00p\00r\00e\00s\00s\00i\00o\00n\00.\00t\00s\00") + (data (i32.const 88) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\000\00") + (data (i32.const 112) "\90\01\00\00\01\00\00\00\00\00\00\00\90\01\00\000\000\000\001\000\002\000\003\000\004\000\005\000\006\000\007\000\008\000\009\001\000\001\001\001\002\001\003\001\004\001\005\001\006\001\007\001\008\001\009\002\000\002\001\002\002\002\003\002\004\002\005\002\006\002\007\002\008\002\009\003\000\003\001\003\002\003\003\003\004\003\005\003\006\003\007\003\008\003\009\004\000\004\001\004\002\004\003\004\004\004\005\004\006\004\007\004\008\004\009\005\000\005\001\005\002\005\003\005\004\005\005\005\006\005\007\005\008\005\009\006\000\006\001\006\002\006\003\006\004\006\005\006\006\006\007\006\008\006\009\007\000\007\001\007\002\007\003\007\004\007\005\007\006\007\007\007\008\007\009\008\000\008\001\008\002\008\003\008\004\008\005\008\006\008\007\008\008\008\009\009\000\009\001\009\002\009\003\009\004\009\005\009\006\009\007\009\008\009\009\00") + (data (i32.const 528) "\10\00\00\00\01\00\00\00\03\00\00\00\10\00\00\00\80\00\00\00\80\00\00\00\90\01\00\00d\00\00\00") + (data (i32.const 560) "\04\00\00\00\01\00\00\00\01\00\00\00\04\00\00\004\002\00") + (table $0 4 funcref) + (elem (i32.const 0) $null $start:resolve-function-expression~anonymous|0 $start:resolve-function-expression~anonymous|1 $start:resolve-function-expression~anonymous|2) + (global $~lib/argc (mut i32) (i32.const 0)) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $~lib/ASC_SHRINK_LEVEL i32 (i32.const 0)) + (global $~lib/heap/__heap_base i32 (i32.const 580)) + (export "memory" (memory $0)) + (start $start) + (func $start:resolve-function-expression~anonymous|0 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 40 + i32.add + ) + (func $start:resolve-function-expression~anonymous|1 (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 41 + i32.add + ) + (func $start:resolve-function-expression~anonymous|2 (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 42 + i32.add + ) + (func $~lib/rt/stub/__retain (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $~lib/util/number/decimalCount32 (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 100000 + i32.lt_u + if + local.get $0 + i32.const 100 + i32.lt_u + if + i32.const 1 + i32.const 2 + local.get $0 + i32.const 10 + i32.lt_u + select + return + else + i32.const 4 + i32.const 5 + local.get $0 + i32.const 10000 + i32.lt_u + select + local.set $1 + i32.const 3 + local.get $1 + local.get $0 + i32.const 1000 + i32.lt_u + select + return + end + unreachable + else + local.get $0 + i32.const 10000000 + i32.lt_u + if + i32.const 6 + i32.const 7 + local.get $0 + i32.const 1000000 + i32.lt_u + select + return + else + i32.const 9 + i32.const 10 + local.get $0 + i32.const 1000000000 + i32.lt_u + select + local.set $1 + i32.const 8 + local.get $1 + local.get $0 + i32.const 100000000 + i32.lt_u + select + return + end + unreachable + end + unreachable + ) + (func $~lib/rt/stub/maybeGrowMemory (; 6 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + memory.size + local.set $1 + local.get $1 + i32.const 16 + i32.shl + local.set $2 + local.get $0 + local.get $2 + i32.gt_u + if + local.get $0 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $3 + local.get $1 + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.set $4 + local.get $4 + memory.grow + i32.const 0 + i32.lt_s + if + local.get $3 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 7 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.set $2 + local.get $0 + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.tee $3 + i32.const 16 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_u + select + local.set $5 + local.get $2 + local.get $5 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.set $6 + local.get $6 + local.get $5 + i32.store + local.get $6 + i32.const -1 + i32.store offset=4 + local.get $6 + local.get $1 + i32.store offset=8 + local.get $6 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/util/number/utoa32_lut (; 8 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i64) + (local $9 i64) + i32.const 544 + i32.load offset=4 + local.set $3 + block $break|0 + loop $continue|0 + local.get $1 + i32.const 10000 + i32.ge_u + i32.eqz + br_if $break|0 + local.get $1 + i32.const 10000 + i32.div_u + local.set $4 + local.get $1 + i32.const 10000 + i32.rem_u + local.set $5 + local.get $4 + local.set $1 + local.get $5 + i32.const 100 + i32.div_u + local.set $6 + local.get $5 + i32.const 100 + i32.rem_u + local.set $7 + local.get $3 + local.get $6 + i32.const 2 + i32.shl + i32.add + i64.load32_u + local.set $8 + local.get $3 + local.get $7 + i32.const 2 + i32.shl + i32.add + i64.load32_u + local.set $9 + local.get $2 + i32.const 4 + i32.sub + local.set $2 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $8 + local.get $9 + i64.const 32 + i64.shl + i64.or + i64.store + br $continue|0 + end + unreachable + end + local.get $1 + i32.const 100 + i32.ge_u + if + local.get $1 + i32.const 100 + i32.div_u + local.set $7 + local.get $1 + i32.const 100 + i32.rem_u + local.set $6 + local.get $7 + local.set $1 + local.get $2 + i32.const 2 + i32.sub + local.set $2 + local.get $3 + local.get $6 + i32.const 2 + i32.shl + i32.add + i32.load + local.set $5 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $5 + i32.store + end + local.get $1 + i32.const 10 + i32.ge_u + if + local.get $2 + i32.const 2 + i32.sub + local.set $2 + local.get $3 + local.get $1 + i32.const 2 + i32.shl + i32.add + i32.load + local.set $5 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $5 + i32.store + else + local.get $2 + i32.const 1 + i32.sub + local.set $2 + i32.const 48 + local.get $1 + i32.add + local.set $5 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $5 + i32.store16 + end + ) + (func $~lib/util/number/itoa32 (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.eqz + if + i32.const 104 + call $~lib/rt/stub/__retain + return + end + local.get $0 + i32.const 0 + i32.lt_s + local.set $1 + local.get $1 + if + i32.const 0 + local.get $0 + i32.sub + local.set $0 + end + local.get $0 + call $~lib/util/number/decimalCount32 + local.get $1 + i32.add + local.set $2 + local.get $2 + i32.const 1 + i32.shl + i32.const 1 + call $~lib/rt/stub/__alloc + local.set $3 + local.get $3 + local.set $6 + local.get $0 + local.set $5 + local.get $2 + local.set $4 + local.get $6 + local.get $5 + local.get $4 + call $~lib/util/number/utoa32_lut + local.get $1 + if + local.get $3 + i32.const 45 + i32.store16 + end + local.get $3 + call $~lib/rt/stub/__retain + ) + (func $~lib/util/number/itoa (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/util/number/itoa32 + return + ) + (func $~lib/rt/stub/__release (; 11 ;) (type $FUNCSIG$vi) (param $0 i32) + nop + ) + (func $~lib/number/I32#toString (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + call $~lib/util/number/itoa + local.tee $1 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $~lib/string/String#get:length (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load offset=12 + i32.const 1 + i32.shr_u + ) + (func $~lib/util/string/compareImpl (; 14 ;) (type $FUNCSIG$iiiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $2 + call $~lib/rt/stub/__retain + drop + i32.const 0 + local.set $5 + local.get $0 + local.get $1 + i32.const 1 + i32.shl + i32.add + local.set $6 + local.get $2 + local.get $3 + i32.const 1 + i32.shl + i32.add + local.set $7 + block $break|0 + loop $continue|0 + local.get $4 + if (result i32) + local.get $6 + i32.load16_u + local.get $7 + i32.load16_u + i32.sub + local.tee $5 + i32.eqz + else + i32.const 0 + end + i32.eqz + br_if $break|0 + local.get $4 + i32.const 1 + i32.sub + local.set $4 + local.get $6 + i32.const 2 + i32.add + local.set $6 + local.get $7 + i32.const 2 + i32.add + local.set $7 + br $continue|0 + end + unreachable + end + local.get $5 + local.set $8 + local.get $0 + call $~lib/rt/stub/__release + local.get $2 + call $~lib/rt/stub/__release + local.get $8 + ) + (func $~lib/string/String.__eq (; 15 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $1 + call $~lib/rt/stub/__retain + drop + local.get $0 + local.get $1 + i32.eq + if + i32.const 1 + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + return + end + local.get $0 + i32.const 0 + i32.eq + if (result i32) + i32.const 1 + else + local.get $1 + i32.const 0 + i32.eq + end + if + i32.const 0 + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + return + end + local.get $0 + call $~lib/string/String#get:length + local.set $3 + local.get $3 + local.get $1 + call $~lib/string/String#get:length + i32.ne + if + i32.const 0 + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + return + end + local.get $0 + i32.const 0 + local.get $1 + i32.const 0 + local.get $3 + call $~lib/util/string/compareImpl + i32.eqz + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $start:resolve-function-expression (; 16 ;) (type $FUNCSIG$v) + (local $0 i32) + i32.const 1 + global.set $~lib/argc + i32.const 2 + i32.const 1 + call_indirect (type $FUNCSIG$ii) + i32.const 42 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 1 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + global.set $~lib/argc + i32.const 1 + i32.const 2 + call_indirect (type $FUNCSIG$ii) + i32.const 42 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 6 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const 1 + global.set $~lib/argc + i32.const 0 + i32.const 3 + call_indirect (type $FUNCSIG$ii) + call $~lib/number/I32#toString + local.tee $0 + i32.const 576 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 11 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + local.get $0 + call $~lib/rt/stub/__release + ) + (func $start (; 17 ;) (type $FUNCSIG$v) + call $start:resolve-function-expression + ) + (func $null (; 18 ;) (type $FUNCSIG$v) + ) +) diff --git a/tests/compiler/resolve-new.json b/tests/compiler/resolve-new.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/resolve-new.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/resolve-new.optimized.wat b/tests/compiler/resolve-new.optimized.wat new file mode 100644 index 0000000000..9874dba1bf --- /dev/null +++ b/tests/compiler/resolve-new.optimized.wat @@ -0,0 +1,93 @@ +(module + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) + (memory $0 0) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $resolve-new/foo (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (start $start) + (func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + local.get $0 + memory.size + local.tee $2 + i32.const 16 + i32.shl + local.tee $1 + i32.gt_u + if + local.get $2 + local.get $0 + local.get $1 + i32.sub + i32.const 65535 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $1 + local.get $2 + local.get $1 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $1 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 1 ;) (type $FUNCSIG$i) (result i32) + (local $0 i32) + (local $1 i32) + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.tee $1 + i32.const 16 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $1 + i32.const 16 + i32.sub + local.tee $0 + i32.const 16 + i32.store + local.get $0 + i32.const -1 + i32.store offset=4 + local.get $0 + i32.const 3 + i32.store offset=8 + local.get $0 + i32.const 0 + i32.store offset=12 + local.get $1 + ) + (func $start (; 2 ;) (type $FUNCSIG$v) + i32.const 16 + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + call $~lib/rt/stub/__alloc + global.set $resolve-new/foo + call $~lib/rt/stub/__alloc + drop + ) + (func $null (; 3 ;) (type $FUNCSIG$v) + nop + ) +) diff --git a/tests/compiler/resolve-new.ts b/tests/compiler/resolve-new.ts new file mode 100644 index 0000000000..c2781956dc --- /dev/null +++ b/tests/compiler/resolve-new.ts @@ -0,0 +1,5 @@ +class Foo { + bar(): void {} +} +var foo = new Foo(); +(new Foo()).bar(); diff --git a/tests/compiler/resolve-new.untouched.wat b/tests/compiler/resolve-new.untouched.wat new file mode 100644 index 0000000000..7a764dcf44 --- /dev/null +++ b/tests/compiler/resolve-new.untouched.wat @@ -0,0 +1,170 @@ +(module + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$v (func)) + (memory $0 0) + (table $0 1 funcref) + (elem (i32.const 0) $null) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $resolve-new/foo (mut i32) (i32.const 0)) + (global $~lib/heap/__heap_base i32 (i32.const 8)) + (export "memory" (memory $0)) + (start $start) + (func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + memory.size + local.set $1 + local.get $1 + i32.const 16 + i32.shl + local.set $2 + local.get $0 + local.get $2 + i32.gt_u + if + local.get $0 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $3 + local.get $1 + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.set $4 + local.get $4 + memory.grow + i32.const 0 + i32.lt_s + if + local.get $3 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 1 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.set $2 + local.get $0 + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.tee $3 + i32.const 16 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_u + select + local.set $5 + local.get $2 + local.get $5 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.set $6 + local.get $6 + local.get $5 + i32.store + local.get $6 + i32.const -1 + i32.store offset=4 + local.get $6 + local.get $1 + i32.store offset=8 + local.get $6 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/rt/stub/__retain (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $resolve-new/Foo#constructor (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 3 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $resolve-new/Foo#bar (; 4 ;) (type $FUNCSIG$vi) (param $0 i32) + nop + ) + (func $~lib/rt/stub/__release (; 5 ;) (type $FUNCSIG$vi) (param $0 i32) + nop + ) + (func $start:resolve-new (; 6 ;) (type $FUNCSIG$v) + (local $0 i32) + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const 0 + call $resolve-new/Foo#constructor + global.set $resolve-new/foo + i32.const 0 + call $resolve-new/Foo#constructor + local.tee $0 + call $resolve-new/Foo#bar + local.get $0 + call $~lib/rt/stub/__release + ) + (func $start (; 7 ;) (type $FUNCSIG$v) + call $start:resolve-new + ) + (func $null (; 8 ;) (type $FUNCSIG$v) + ) +) diff --git a/tests/compiler/resolve-unary.json b/tests/compiler/resolve-unary.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/resolve-unary.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/resolve-unary.optimized.wat b/tests/compiler/resolve-unary.optimized.wat new file mode 100644 index 0000000000..6819ff4019 --- /dev/null +++ b/tests/compiler/resolve-unary.optimized.wat @@ -0,0 +1,602 @@ +(module + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 8) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\000") + (data (i32.const 32) "\04\00\00\00\01\00\00\00\01\00\00\00\04\00\00\00-\001") + (data (i32.const 56) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00r\00e\00s\00o\00l\00v\00e\00-\00u\00n\00a\00r\00y\00.\00t\00s") + (data (i32.const 104) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\001") + (data (i32.const 128) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\002") + (data (i32.const 152) "\08\00\00\00\01\00\00\00\01\00\00\00\08\00\00\00t\00r\00u\00e") + (data (i32.const 176) "\n\00\00\00\01\00\00\00\01\00\00\00\n\00\00\00f\00a\00l\00s\00e") + (data (i32.const 208) "\04\00\00\00\01\00\00\00\01\00\00\00\04\00\00\00-\002") + (data (i32.const 232) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00+") + (data (i32.const 256) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00-") + (data (i32.const 280) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00!") + (data (i32.const 304) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00~") + (data (i32.const 328) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00+\00+\00i") + (data (i32.const 352) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00-\00-\00i") + (data (i32.const 376) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00i\00+\00+") + (data (i32.const 400) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00i\00-\00-") + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $resolve-unary/a (mut i32) (i32.const 1)) + (global $resolve-unary/b (mut i32) (i32.const 1)) + (global $resolve-unary/foo (mut i32) (i32.const 0)) + (global $resolve-unary/bar (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (start $start) + (func $~lib/util/number/decimalCount32 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 1 + i32.const 2 + local.get $0 + i32.const 10 + i32.lt_u + select + i32.const 3 + i32.const 4 + i32.const 5 + local.get $0 + i32.const 10000 + i32.lt_u + select + local.get $0 + i32.const 1000 + i32.lt_u + select + local.get $0 + i32.const 100 + i32.lt_u + select + i32.const 6 + i32.const 7 + local.get $0 + i32.const 1000000 + i32.lt_u + select + i32.const 8 + i32.const 9 + i32.const 10 + local.get $0 + i32.const 1000000000 + i32.lt_u + select + local.get $0 + i32.const 100000000 + i32.lt_u + select + local.get $0 + i32.const 10000000 + i32.lt_u + select + local.get $0 + i32.const 100000 + i32.lt_u + select + ) + (func $~lib/rt/stub/maybeGrowMemory (; 2 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + local.get $0 + memory.size + local.tee $2 + i32.const 16 + i32.shl + local.tee $1 + i32.gt_u + if + local.get $2 + local.get $0 + local.get $1 + i32.sub + i32.const 65535 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $1 + local.get $2 + local.get $1 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $1 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 3 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.tee $3 + local.get $0 + i32.const 15 + i32.add + i32.const -16 + i32.and + local.tee $2 + i32.const 16 + local.get $2 + i32.const 16 + i32.gt_u + select + local.tee $4 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $3 + i32.const 16 + i32.sub + local.tee $2 + local.get $4 + i32.store + local.get $2 + i32.const -1 + i32.store offset=4 + local.get $2 + local.get $1 + i32.store offset=8 + local.get $2 + local.get $0 + i32.store offset=12 + local.get $3 + ) + (func $~lib/util/number/utoa_simple (; 4 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + loop $continue|0 + local.get $1 + i32.const 10 + i32.rem_u + local.set $3 + local.get $1 + i32.const 10 + i32.div_u + local.set $1 + local.get $2 + i32.const 1 + i32.sub + local.tee $2 + i32.const 1 + i32.shl + local.get $0 + i32.add + local.get $3 + i32.const 48 + i32.add + i32.store16 + local.get $1 + br_if $continue|0 + end + ) + (func $~lib/util/number/itoa32 (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + i32.eqz + if + i32.const 24 + return + end + local.get $0 + i32.const 0 + i32.lt_s + local.tee $1 + if + i32.const 0 + local.get $0 + i32.sub + local.set $0 + end + local.get $0 + call $~lib/util/number/decimalCount32 + local.get $1 + i32.add + local.tee $3 + i32.const 1 + i32.shl + i32.const 1 + call $~lib/rt/stub/__alloc + local.tee $2 + local.get $0 + local.get $3 + call $~lib/util/number/utoa_simple + local.get $1 + if + local.get $2 + i32.const 45 + i32.store16 + end + local.get $2 + ) + (func $~lib/string/String#get:length (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load offset=12 + i32.const 1 + i32.shr_u + ) + (func $~lib/util/string/compareImpl (; 7 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (local $3 i32) + loop $continue|0 + local.get $2 + if (result i32) + local.get $0 + i32.load16_u + local.get $1 + i32.load16_u + i32.sub + local.tee $3 + i32.eqz + else + i32.const 0 + end + if + local.get $2 + i32.const 1 + i32.sub + local.set $2 + local.get $0 + i32.const 2 + i32.add + local.set $0 + local.get $1 + i32.const 2 + i32.add + local.set $1 + br $continue|0 + end + end + local.get $3 + ) + (func $~lib/string/String.__eq (; 8 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $0 + local.get $1 + i32.eq + if + i32.const 1 + return + end + block $folding-inner0 + local.get $1 + i32.eqz + i32.const 1 + local.get $0 + select + br_if $folding-inner0 + local.get $0 + call $~lib/string/String#get:length + local.tee $2 + local.get $1 + call $~lib/string/String#get:length + i32.ne + br_if $folding-inner0 + local.get $0 + local.get $1 + local.get $2 + call $~lib/util/string/compareImpl + i32.eqz + return + end + i32.const 0 + ) + (func $~lib/number/Bool#toString (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 168 + i32.const 192 + local.get $0 + select + ) + (func $start:resolve-unary (; 10 ;) (type $FUNCSIG$v) + (local $0 i32) + i32.const 432 + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const -1 + call $~lib/util/number/itoa32 + i32.const 48 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 2 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/util/number/itoa32 + i32.const 120 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 7 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.const 1 + i32.add + global.set $resolve-unary/a + global.get $resolve-unary/a + call $~lib/util/number/itoa32 + i32.const 144 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 13 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.const 1 + i32.sub + global.set $resolve-unary/a + global.get $resolve-unary/a + call $~lib/util/number/itoa32 + i32.const 120 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 18 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.eqz + call $~lib/number/Bool#toString + i32.const 192 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 23 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.eqz + i32.eqz + call $~lib/number/Bool#toString + i32.const 168 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 28 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.const -1 + i32.xor + call $~lib/util/number/itoa32 + i32.const 224 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 33 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/b + local.tee $0 + i32.const 1 + i32.add + global.set $resolve-unary/b + local.get $0 + call $~lib/util/number/itoa32 + i32.const 120 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 41 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/b + local.tee $0 + i32.const 1 + i32.sub + global.set $resolve-unary/b + local.get $0 + call $~lib/util/number/itoa32 + i32.const 144 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 46 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + i32.const 3 + call $~lib/rt/stub/__alloc + global.set $resolve-unary/foo + i32.const 248 + i32.const 248 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 91 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 272 + i32.const 272 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 96 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 296 + i32.const 296 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 111 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 320 + i32.const 320 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 116 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + local.tee $0 + global.set $resolve-unary/foo + global.get $resolve-unary/foo + local.get $0 + i32.ne + if + i32.const 0 + i32.const 72 + i32.const 121 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + local.tee $0 + global.set $resolve-unary/foo + global.get $resolve-unary/foo + local.get $0 + i32.ne + if + i32.const 0 + i32.const 72 + i32.const 126 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + i32.const 4 + call $~lib/rt/stub/__alloc + global.set $resolve-unary/bar + i32.const 344 + i32.const 344 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 151 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 368 + i32.const 368 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 156 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 392 + i32.const 392 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 161 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 416 + i32.const 416 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 72 + i32.const 166 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + ) + (func $start (; 11 ;) (type $FUNCSIG$v) + call $start:resolve-unary + ) + (func $null (; 12 ;) (type $FUNCSIG$v) + nop + ) +) diff --git a/tests/compiler/resolve-unary.ts b/tests/compiler/resolve-unary.ts new file mode 100644 index 0000000000..ff598b7f60 --- /dev/null +++ b/tests/compiler/resolve-unary.ts @@ -0,0 +1,170 @@ +// prefix +assert( + (-1).toString() + == + "-1" +); +assert( + (+1).toString() + == + "1" +); +var a = 1; +assert( + (++a).toString() + == + "2" +); +assert( + (--a).toString() + == + "1" +); +assert( + (!a).toString() + == + "false" +); +assert( + (!!a).toString() + == + "true" +); +assert( + (~a).toString() + == + "-2" +); + +// postfix +var b = 1; +assert( + (b++).toString() + == + "1" +); +assert( + (b--).toString() + == + "2" +); + +// overloads +class Foo { + @operator.prefix("+") + plus(): string { + return "+"; + } + @operator.prefix("-") + minus(): string { + return "-"; + } + @operator.prefix("++") + prefix_inc(): Foo { + return this; + } + @operator.prefix("--") + prefix_dec(): Foo { + return this; + } + @operator.prefix("!") + not(): string { + return "!"; + } + @operator.prefix("~") + bitwise_not(): string { + return "~"; + } + @operator.postfix("++") + postfix_inc(): Foo { + return this; + } + @operator.postfix("--") + postfix_dec(): Foo { + return this; + } + self(): Foo { + return this; + } +} +var foo = new Foo(); +assert( + (+foo).toString() + == + "+" +); +assert( + (-foo).toString() + == + "-" +); +assert( + (++foo).self() + == + foo +); +assert( + (--foo).self() + == + foo +); +assert( + (!foo).toString() + == + "!" +); +assert( + (~foo).toString() + == + "~" +); +assert( + (foo++).self() + == + foo +); +assert( + (foo--).self() + == + foo +); +class Bar { + // static inc/dec don't reassign and can have different return type + @operator.prefix("++") + static prefix_inc(a: Foo): string { + return "++i"; + } + @operator.prefix("--") + static prefix_dec(a: Foo): string { + return "--i"; + } + @operator.postfix("++") + static postfix_inc(a: Foo): string { + return "i++"; + } + @operator.postfix("--") + static postfix_dec(a: Foo): string { + return "i--"; + } +} +var bar = new Bar(); +assert( + (++bar).toString() + == + "++i" +); +assert( + (--bar).toString() + == + "--i" +); +assert( + (bar++).toString() + == + "i++" +); +assert( + (bar--).toString() + == + "i--" +); diff --git a/tests/compiler/resolve-unary.untouched.wat b/tests/compiler/resolve-unary.untouched.wat new file mode 100644 index 0000000000..d15f06c506 --- /dev/null +++ b/tests/compiler/resolve-unary.untouched.wat @@ -0,0 +1,1228 @@ +(module + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32))) + (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) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\000\00") + (data (i32.const 32) "\90\01\00\00\01\00\00\00\00\00\00\00\90\01\00\000\000\000\001\000\002\000\003\000\004\000\005\000\006\000\007\000\008\000\009\001\000\001\001\001\002\001\003\001\004\001\005\001\006\001\007\001\008\001\009\002\000\002\001\002\002\002\003\002\004\002\005\002\006\002\007\002\008\002\009\003\000\003\001\003\002\003\003\003\004\003\005\003\006\003\007\003\008\003\009\004\000\004\001\004\002\004\003\004\004\004\005\004\006\004\007\004\008\004\009\005\000\005\001\005\002\005\003\005\004\005\005\005\006\005\007\005\008\005\009\006\000\006\001\006\002\006\003\006\004\006\005\006\006\006\007\006\008\006\009\007\000\007\001\007\002\007\003\007\004\007\005\007\006\007\007\007\008\007\009\008\000\008\001\008\002\008\003\008\004\008\005\008\006\008\007\008\008\008\009\009\000\009\001\009\002\009\003\009\004\009\005\009\006\009\007\009\008\009\009\00") + (data (i32.const 448) "\10\00\00\00\01\00\00\00\03\00\00\00\10\00\00\000\00\00\000\00\00\00\90\01\00\00d\00\00\00") + (data (i32.const 480) "\04\00\00\00\01\00\00\00\01\00\00\00\04\00\00\00-\001\00") + (data (i32.const 504) " \00\00\00\01\00\00\00\01\00\00\00 \00\00\00r\00e\00s\00o\00l\00v\00e\00-\00u\00n\00a\00r\00y\00.\00t\00s\00") + (data (i32.const 552) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\001\00") + (data (i32.const 576) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\002\00") + (data (i32.const 600) "\08\00\00\00\01\00\00\00\01\00\00\00\08\00\00\00t\00r\00u\00e\00") + (data (i32.const 624) "\n\00\00\00\01\00\00\00\01\00\00\00\n\00\00\00f\00a\00l\00s\00e\00") + (data (i32.const 656) "\04\00\00\00\01\00\00\00\01\00\00\00\04\00\00\00-\002\00") + (data (i32.const 680) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00+\00") + (data (i32.const 704) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00-\00") + (data (i32.const 728) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00!\00") + (data (i32.const 752) "\02\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00~\00") + (data (i32.const 776) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00+\00+\00i\00") + (data (i32.const 800) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00-\00-\00i\00") + (data (i32.const 824) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00i\00+\00+\00") + (data (i32.const 848) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00i\00-\00-\00") + (table $0 1 funcref) + (elem (i32.const 0) $null) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $~lib/ASC_SHRINK_LEVEL i32 (i32.const 0)) + (global $resolve-unary/a (mut i32) (i32.const 1)) + (global $resolve-unary/b (mut i32) (i32.const 1)) + (global $resolve-unary/foo (mut i32) (i32.const 0)) + (global $resolve-unary/bar (mut i32) (i32.const 0)) + (global $~lib/heap/__heap_base i32 (i32.const 872)) + (export "memory" (memory $0)) + (start $start) + (func $~lib/rt/stub/__retain (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $~lib/util/number/decimalCount32 (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + i32.const 100000 + i32.lt_u + if + local.get $0 + i32.const 100 + i32.lt_u + if + i32.const 1 + i32.const 2 + local.get $0 + i32.const 10 + i32.lt_u + select + return + else + i32.const 4 + i32.const 5 + local.get $0 + i32.const 10000 + i32.lt_u + select + local.set $1 + i32.const 3 + local.get $1 + local.get $0 + i32.const 1000 + i32.lt_u + select + return + end + unreachable + else + local.get $0 + i32.const 10000000 + i32.lt_u + if + i32.const 6 + i32.const 7 + local.get $0 + i32.const 1000000 + i32.lt_u + select + return + else + i32.const 9 + i32.const 10 + local.get $0 + i32.const 1000000000 + i32.lt_u + select + local.set $1 + i32.const 8 + local.get $1 + local.get $0 + i32.const 100000000 + i32.lt_u + select + return + end + unreachable + end + unreachable + ) + (func $~lib/rt/stub/maybeGrowMemory (; 3 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + memory.size + local.set $1 + local.get $1 + i32.const 16 + i32.shl + local.set $2 + local.get $0 + local.get $2 + i32.gt_u + if + local.get $0 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $3 + local.get $1 + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.set $4 + local.get $4 + memory.grow + i32.const 0 + i32.lt_s + if + local.get $3 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 4 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.set $2 + local.get $0 + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.tee $3 + i32.const 16 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_u + select + local.set $5 + local.get $2 + local.get $5 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.set $6 + local.get $6 + local.get $5 + i32.store + local.get $6 + i32.const -1 + i32.store offset=4 + local.get $6 + local.get $1 + i32.store offset=8 + local.get $6 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/util/number/utoa32_lut (; 5 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i64) + (local $9 i64) + i32.const 464 + i32.load offset=4 + local.set $3 + block $break|0 + loop $continue|0 + local.get $1 + i32.const 10000 + i32.ge_u + i32.eqz + br_if $break|0 + local.get $1 + i32.const 10000 + i32.div_u + local.set $4 + local.get $1 + i32.const 10000 + i32.rem_u + local.set $5 + local.get $4 + local.set $1 + local.get $5 + i32.const 100 + i32.div_u + local.set $6 + local.get $5 + i32.const 100 + i32.rem_u + local.set $7 + local.get $3 + local.get $6 + i32.const 2 + i32.shl + i32.add + i64.load32_u + local.set $8 + local.get $3 + local.get $7 + i32.const 2 + i32.shl + i32.add + i64.load32_u + local.set $9 + local.get $2 + i32.const 4 + i32.sub + local.set $2 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $8 + local.get $9 + i64.const 32 + i64.shl + i64.or + i64.store + br $continue|0 + end + unreachable + end + local.get $1 + i32.const 100 + i32.ge_u + if + local.get $1 + i32.const 100 + i32.div_u + local.set $7 + local.get $1 + i32.const 100 + i32.rem_u + local.set $6 + local.get $7 + local.set $1 + local.get $2 + i32.const 2 + i32.sub + local.set $2 + local.get $3 + local.get $6 + i32.const 2 + i32.shl + i32.add + i32.load + local.set $5 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $5 + i32.store + end + local.get $1 + i32.const 10 + i32.ge_u + if + local.get $2 + i32.const 2 + i32.sub + local.set $2 + local.get $3 + local.get $1 + i32.const 2 + i32.shl + i32.add + i32.load + local.set $5 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $5 + i32.store + else + local.get $2 + i32.const 1 + i32.sub + local.set $2 + i32.const 48 + local.get $1 + i32.add + local.set $5 + local.get $0 + local.get $2 + i32.const 1 + i32.shl + i32.add + local.get $5 + i32.store16 + end + ) + (func $~lib/util/number/itoa32 (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.eqz + if + i32.const 24 + call $~lib/rt/stub/__retain + return + end + local.get $0 + i32.const 0 + i32.lt_s + local.set $1 + local.get $1 + if + i32.const 0 + local.get $0 + i32.sub + local.set $0 + end + local.get $0 + call $~lib/util/number/decimalCount32 + local.get $1 + i32.add + local.set $2 + local.get $2 + i32.const 1 + i32.shl + i32.const 1 + call $~lib/rt/stub/__alloc + local.set $3 + local.get $3 + local.set $6 + local.get $0 + local.set $5 + local.get $2 + local.set $4 + local.get $6 + local.get $5 + local.get $4 + call $~lib/util/number/utoa32_lut + local.get $1 + if + local.get $3 + i32.const 45 + i32.store16 + end + local.get $3 + call $~lib/rt/stub/__retain + ) + (func $~lib/util/number/itoa (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/util/number/itoa32 + return + ) + (func $~lib/rt/stub/__release (; 8 ;) (type $FUNCSIG$vi) (param $0 i32) + nop + ) + (func $~lib/number/I32#toString (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + call $~lib/util/number/itoa + local.tee $1 + call $~lib/rt/stub/__retain + local.set $2 + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $~lib/string/String#get:length (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load offset=12 + i32.const 1 + i32.shr_u + ) + (func $~lib/util/string/compareImpl (; 11 ;) (type $FUNCSIG$iiiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $2 + call $~lib/rt/stub/__retain + drop + i32.const 0 + local.set $5 + local.get $0 + local.get $1 + i32.const 1 + i32.shl + i32.add + local.set $6 + local.get $2 + local.get $3 + i32.const 1 + i32.shl + i32.add + local.set $7 + block $break|0 + loop $continue|0 + local.get $4 + if (result i32) + local.get $6 + i32.load16_u + local.get $7 + i32.load16_u + i32.sub + local.tee $5 + i32.eqz + else + i32.const 0 + end + i32.eqz + br_if $break|0 + local.get $4 + i32.const 1 + i32.sub + local.set $4 + local.get $6 + i32.const 2 + i32.add + local.set $6 + local.get $7 + i32.const 2 + i32.add + local.set $7 + br $continue|0 + end + unreachable + end + local.get $5 + local.set $8 + local.get $0 + call $~lib/rt/stub/__release + local.get $2 + call $~lib/rt/stub/__release + local.get $8 + ) + (func $~lib/string/String.__eq (; 12 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + local.get $1 + call $~lib/rt/stub/__retain + drop + local.get $0 + local.get $1 + i32.eq + if + i32.const 1 + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + return + end + local.get $0 + i32.const 0 + i32.eq + if (result i32) + i32.const 1 + else + local.get $1 + i32.const 0 + i32.eq + end + if + i32.const 0 + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + return + end + local.get $0 + call $~lib/string/String#get:length + local.set $3 + local.get $3 + local.get $1 + call $~lib/string/String#get:length + i32.ne + if + i32.const 0 + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + return + end + local.get $0 + i32.const 0 + local.get $1 + i32.const 0 + local.get $3 + call $~lib/util/string/compareImpl + i32.eqz + local.set $2 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + ) + (func $~lib/number/Bool#toString (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + if (result i32) + i32.const 616 + call $~lib/rt/stub/__retain + local.tee $1 + else + i32.const 640 + call $~lib/rt/stub/__retain + local.tee $2 + end + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#constructor (; 14 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 4 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $resolve-unary/Foo#plus (; 15 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 696 + call $~lib/rt/stub/__retain + ) + (func $~lib/string/String#toString (; 16 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#minus (; 17 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 720 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#prefix_inc (; 18 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#self (; 19 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#prefix_dec (; 20 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#not (; 21 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 744 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#bitwise_not (; 22 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 768 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#postfix_inc (; 23 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Foo#postfix_dec (; 24 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/rt/stub/__retain + ) + (func $resolve-unary/Bar#constructor (; 25 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 5 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $resolve-unary/Bar.prefix_inc (; 26 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + i32.const 792 + call $~lib/rt/stub/__retain + local.set $1 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + ) + (func $resolve-unary/Bar.prefix_dec (; 27 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + i32.const 816 + call $~lib/rt/stub/__retain + local.set $1 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + ) + (func $resolve-unary/Bar.postfix_inc (; 28 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + i32.const 840 + call $~lib/rt/stub/__retain + local.set $1 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + ) + (func $resolve-unary/Bar.postfix_dec (; 29 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + call $~lib/rt/stub/__retain + drop + i32.const 864 + call $~lib/rt/stub/__retain + local.set $1 + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + ) + (func $start:resolve-unary (; 30 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + (local $12 i32) + (local $13 i32) + (local $14 i32) + (local $15 i32) + (local $16 i32) + (local $17 i32) + (local $18 i32) + (local $19 i32) + (local $20 i32) + (local $21 i32) + (local $22 i32) + (local $23 i32) + (local $24 i32) + (local $25 i32) + (local $26 i32) + (local $27 i32) + (local $28 i32) + (local $29 i32) + (local $30 i32) + (local $31 i32) + (local $32 i32) + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const -1 + call $~lib/number/I32#toString + local.tee $0 + i32.const 496 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 2 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + call $~lib/number/I32#toString + local.tee $1 + i32.const 568 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 7 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.const 1 + i32.add + global.set $resolve-unary/a + global.get $resolve-unary/a + call $~lib/number/I32#toString + local.tee $2 + i32.const 592 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 13 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.const 1 + i32.sub + global.set $resolve-unary/a + global.get $resolve-unary/a + call $~lib/number/I32#toString + local.tee $3 + i32.const 568 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 18 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.eqz + call $~lib/number/Bool#toString + local.tee $4 + i32.const 640 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 23 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.eqz + i32.eqz + call $~lib/number/Bool#toString + local.tee $5 + i32.const 616 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 28 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/a + i32.const -1 + i32.xor + call $~lib/number/I32#toString + local.tee $6 + i32.const 672 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 33 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/b + local.tee $7 + i32.const 1 + i32.add + global.set $resolve-unary/b + local.get $7 + call $~lib/number/I32#toString + local.tee $7 + i32.const 568 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 41 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/b + local.tee $8 + i32.const 1 + i32.sub + global.set $resolve-unary/b + local.get $8 + call $~lib/number/I32#toString + local.tee $8 + i32.const 592 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 46 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $resolve-unary/Foo#constructor + global.set $resolve-unary/foo + global.get $resolve-unary/foo + call $resolve-unary/Foo#plus + local.tee $9 + call $~lib/string/String#toString + local.tee $10 + i32.const 696 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 91 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + call $resolve-unary/Foo#minus + local.tee $11 + call $~lib/string/String#toString + local.tee $12 + i32.const 720 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 96 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + call $resolve-unary/Foo#prefix_inc + local.tee $13 + local.tee $14 + global.get $resolve-unary/foo + local.tee $15 + i32.ne + if + local.get $14 + call $~lib/rt/stub/__retain + drop + local.get $15 + call $~lib/rt/stub/__release + end + local.get $14 + global.set $resolve-unary/foo + global.get $resolve-unary/foo + call $resolve-unary/Foo#self + local.tee $14 + global.get $resolve-unary/foo + i32.eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 101 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + call $resolve-unary/Foo#prefix_dec + local.tee $15 + local.tee $16 + global.get $resolve-unary/foo + local.tee $17 + i32.ne + if + local.get $16 + call $~lib/rt/stub/__retain + drop + local.get $17 + call $~lib/rt/stub/__release + end + local.get $16 + global.set $resolve-unary/foo + global.get $resolve-unary/foo + call $resolve-unary/Foo#self + local.tee $16 + global.get $resolve-unary/foo + i32.eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 106 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + call $resolve-unary/Foo#not + local.tee $17 + call $~lib/string/String#toString + local.tee $18 + i32.const 744 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 111 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + call $resolve-unary/Foo#bitwise_not + local.tee $19 + call $~lib/string/String#toString + local.tee $20 + i32.const 768 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 116 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + local.tee $21 + call $resolve-unary/Foo#postfix_inc + local.tee $22 + local.tee $23 + global.get $resolve-unary/foo + local.tee $24 + i32.ne + if + local.get $23 + call $~lib/rt/stub/__retain + drop + local.get $24 + call $~lib/rt/stub/__release + end + local.get $23 + global.set $resolve-unary/foo + local.get $21 + call $resolve-unary/Foo#self + local.tee $21 + global.get $resolve-unary/foo + i32.eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 121 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/foo + local.tee $23 + call $resolve-unary/Foo#postfix_dec + local.tee $24 + local.tee $25 + global.get $resolve-unary/foo + local.tee $26 + i32.ne + if + local.get $25 + call $~lib/rt/stub/__retain + drop + local.get $26 + call $~lib/rt/stub/__release + end + local.get $25 + global.set $resolve-unary/foo + local.get $23 + call $resolve-unary/Foo#self + local.tee $23 + global.get $resolve-unary/foo + i32.eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 126 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $resolve-unary/Bar#constructor + global.set $resolve-unary/bar + global.get $resolve-unary/bar + call $resolve-unary/Bar.prefix_inc + local.tee $25 + call $~lib/string/String#toString + local.tee $26 + i32.const 792 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 151 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/bar + call $resolve-unary/Bar.prefix_dec + local.tee $27 + call $~lib/string/String#toString + local.tee $28 + i32.const 816 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 156 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/bar + call $resolve-unary/Bar.postfix_inc + local.tee $29 + call $~lib/string/String#toString + local.tee $30 + i32.const 840 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 161 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + global.get $resolve-unary/bar + call $resolve-unary/Bar.postfix_dec + local.tee $31 + call $~lib/string/String#toString + local.tee $32 + i32.const 864 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 520 + i32.const 166 + i32.const 0 + call $~lib/builtins/abort + unreachable + end + local.get $0 + call $~lib/rt/stub/__release + local.get $1 + call $~lib/rt/stub/__release + local.get $2 + call $~lib/rt/stub/__release + local.get $3 + call $~lib/rt/stub/__release + local.get $4 + call $~lib/rt/stub/__release + local.get $5 + call $~lib/rt/stub/__release + local.get $6 + call $~lib/rt/stub/__release + local.get $7 + call $~lib/rt/stub/__release + local.get $8 + call $~lib/rt/stub/__release + local.get $9 + call $~lib/rt/stub/__release + local.get $10 + call $~lib/rt/stub/__release + local.get $11 + call $~lib/rt/stub/__release + local.get $12 + call $~lib/rt/stub/__release + local.get $13 + call $~lib/rt/stub/__release + local.get $14 + call $~lib/rt/stub/__release + local.get $15 + call $~lib/rt/stub/__release + local.get $16 + call $~lib/rt/stub/__release + local.get $17 + call $~lib/rt/stub/__release + local.get $18 + call $~lib/rt/stub/__release + local.get $19 + call $~lib/rt/stub/__release + local.get $20 + call $~lib/rt/stub/__release + local.get $21 + call $~lib/rt/stub/__release + local.get $22 + call $~lib/rt/stub/__release + local.get $23 + call $~lib/rt/stub/__release + local.get $24 + call $~lib/rt/stub/__release + local.get $25 + call $~lib/rt/stub/__release + local.get $26 + call $~lib/rt/stub/__release + local.get $27 + call $~lib/rt/stub/__release + local.get $28 + call $~lib/rt/stub/__release + local.get $29 + call $~lib/rt/stub/__release + local.get $30 + call $~lib/rt/stub/__release + local.get $31 + call $~lib/rt/stub/__release + local.get $32 + call $~lib/rt/stub/__release + ) + (func $start (; 31 ;) (type $FUNCSIG$v) + call $start:resolve-unary + ) + (func $null (; 32 ;) (type $FUNCSIG$v) + ) +) diff --git a/tests/compiler/std/operator-overloading.ts b/tests/compiler/std/operator-overloading.ts index d8cca19adc..314f5cc9fa 100644 --- a/tests/compiler/std/operator-overloading.ts +++ b/tests/compiler/std/operator-overloading.ts @@ -306,7 +306,7 @@ class TesterInlineStatic { } } var ais1 = new TesterInlineStatic(1, 2); -ais1++; // 2, 3 +ais1 = ais1++; // 2, 3 (static skips re-assign) var ais2 = new TesterInlineStatic(2, 3); var ais = ais1 + ais2; assert(ais.x == 4 && ais.y == 6);