diff --git a/src/transformation/builtins/index.ts b/src/transformation/builtins/index.ts index 64f0d4228..b7528cf6e 100644 --- a/src/transformation/builtins/index.ts +++ b/src/transformation/builtins/index.ts @@ -11,7 +11,7 @@ import { transformConsoleCall } from "./console"; import { transformFunctionPrototypeCall, transformFunctionProperty } from "./function"; import { tryTransformBuiltinGlobalCall } from "./global"; import { transformMathCall, transformMathProperty } from "./math"; -import { transformNumberConstructorCall, transformNumberPrototypeCall } from "./number"; +import { transformNumberConstructorCall, transformNumberPrototypeCall, transformNumberProperty } from "./number"; import { transformObjectConstructorCall, tryTransformObjectPrototypeCall } from "./object"; import { transformPromiseConstructorCall } from "./promise"; import { transformStringConstructorCall, transformStringProperty, transformStringPrototypeCall } from "./string"; @@ -27,6 +27,8 @@ export function transformBuiltinPropertyAccessExpression( if (ts.isIdentifier(node.expression) && isStandardLibraryType(context, ownerType, undefined)) { switch (ownerType.symbol.name) { + case "NumberConstructor": + return transformNumberProperty(context, node); case "Math": return transformMathProperty(context, node); case "SymbolConstructor": @@ -162,7 +164,6 @@ export function transformBuiltinIdentifierExpression( const huge = lua.createStringLiteral("huge"); return lua.createTableIndexExpression(math, huge, node); } - case "globalThis": return lua.createIdentifier("_G", node, getIdentifierSymbolId(context, node, symbol), "globalThis"); } diff --git a/src/transformation/builtins/number.ts b/src/transformation/builtins/number.ts index c8ca98503..d07ef7066 100644 --- a/src/transformation/builtins/number.ts +++ b/src/transformation/builtins/number.ts @@ -1,9 +1,11 @@ import ts = require("typescript"); import * as lua from "../../LuaAST"; +import { createNaN } from "../utils/lua-ast"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { transformArguments } from "../visitors/call"; +import { LuaTarget } from "../../CompilerOptions"; export function transformNumberPrototypeCall( context: TransformationContext, @@ -27,6 +29,87 @@ export function transformNumberPrototypeCall( } } +export function transformNumberProperty( + context: TransformationContext, + node: ts.PropertyAccessExpression +): lua.Expression | undefined { + const name = node.name.text; + + /* + Read the docs on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number for further info about what these numbers entail. + Most of them should be fairly straight forward base on their name(s) though. + */ + + switch (name) { + case "POSITIVE_INFINITY": + if (context.luaTarget === LuaTarget.Lua50) { + const one = lua.createNumericLiteral(1); + const zero = lua.createNumericLiteral(0); + return lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator); + } else { + const math = lua.createIdentifier("math"); + const huge = lua.createStringLiteral("huge"); + return lua.createTableIndexExpression(math, huge, node); + } + case "NEGATIVE_INFINITY": + if (context.luaTarget === LuaTarget.Lua50) { + const one = lua.createNumericLiteral(1); + const zero = lua.createNumericLiteral(0); + return lua.createUnaryExpression( + lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator), + lua.SyntaxKind.NegationOperator + ); + } else { + const math = lua.createIdentifier("math"); + const huge = lua.createStringLiteral("huge"); + return lua.createUnaryExpression( + lua.createTableIndexExpression(math, huge, node), + lua.SyntaxKind.NegationOperator + ); + } + case "NaN": + return createNaN(node); + case "EPSILON": + return lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(-52), + lua.SyntaxKind.PowerOperator, + node + ); + case "MIN_VALUE": + return lua.createBinaryExpression( + lua.createNumericLiteral(-2), + lua.createNumericLiteral(1074), + lua.SyntaxKind.PowerOperator, + node + ); + case "MIN_SAFE_INTEGER": + return lua.createBinaryExpression( + lua.createNumericLiteral(-2), + lua.createNumericLiteral(1074), + lua.SyntaxKind.PowerOperator, + node + ); + case "MAX_SAFE_INTEGER": + return lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(1024), + lua.SyntaxKind.PowerOperator, + node + ); + case "MAX_VALUE": + return lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(1024), + lua.SyntaxKind.PowerOperator, + node + ); + + default: + context.diagnostics.push(unsupportedProperty(node.name, "Number", name)); + } +} + export function transformNumberConstructorCall( context: TransformationContext, node: ts.CallExpression, diff --git a/test/unit/builtins/numbers.spec.ts b/test/unit/builtins/numbers.spec.ts index 26b90d4e6..c5f3b7d2b 100644 --- a/test/unit/builtins/numbers.spec.ts +++ b/test/unit/builtins/numbers.spec.ts @@ -206,3 +206,17 @@ test.each(["42", "undefined"])("prototype call on nullable number (%p)", value = .setOptions({ strictNullChecks: true }) .expectToMatchJsResult(); }); + +test.each([ + "Number.NEGATIVE_INFINITY <= Number.MIN_VALUE", + "Number.MIN_VALUE <= Number.MIN_SAFE_INTEGER", + + "Number.MAX_SAFE_INTEGER <= Number.MAX_VALUE", + "Number.MAX_VALUE <= Number.POSITIVE_INFINITY", + "Number.MIN_SAFE_INTEGER < 0", + + "0 < Number.EPSILON", + "Number.EPSILON < Number.MAX_SAFE_INTEGER", +])("Numer constants have correct relative sizes (%p)", comparison => { + util.testExpression(comparison).expectToEqual(true); +});