Skip to content

Commit bf63f60

Browse files
committed
Merge remote-tracking branch 'upstream/master' into transformation-pipeline-refactor
2 parents a6e3d3b + c7b3810 commit bf63f60

7 files changed

Lines changed: 95 additions & 3 deletions

File tree

src/LuaLib.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export enum LuaLibFeature {
4040
Number = "Number",
4141
NumberIsFinite = "NumberIsFinite",
4242
NumberIsNaN = "NumberIsNaN",
43+
NumberToString = "NumberToString",
4344
ObjectAssign = "ObjectAssign",
4445
ObjectEntries = "ObjectEntries",
4546
ObjectFromEntries = "ObjectFromEntries",

src/lualib/NumberToString.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// tslint:disable-next-line: variable-name
2+
const ____radixChars = "0123456789abcdefghijklmnopqrstuvwxyz";
3+
4+
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-number.prototype.tostring
5+
function __TS__NumberToString(this: number, radix?: number): string {
6+
if (radix === undefined || radix === 10 || this === Infinity || this === -Infinity || this !== this) {
7+
return this.toString();
8+
}
9+
10+
radix = Math.floor(radix);
11+
if (radix < 2 || radix > 36) {
12+
// tslint:disable-next-line: no-string-throw
13+
throw "toString() radix argument must be between 2 and 36";
14+
}
15+
16+
let [integer, fraction] = math.modf(Math.abs(this));
17+
18+
let result = "";
19+
if (radix === 8) {
20+
result = string.format("%o", integer);
21+
} else if (radix === 16) {
22+
result = string.format("%x", integer);
23+
} else {
24+
do {
25+
result = ____radixChars[integer % radix] + result;
26+
integer = Math.floor(integer / radix);
27+
} while (integer !== 0);
28+
}
29+
30+
// https://github.com/v8/v8/blob/f78e8d43c224847fa56b3220a90be250fc0f0d6e/src/numbers/conversions.cc#L1221
31+
if (fraction !== 0) {
32+
result += ".";
33+
let delta = 1e-16;
34+
do {
35+
fraction *= radix;
36+
delta *= radix;
37+
const digit = Math.floor(fraction);
38+
result += ____radixChars[digit];
39+
fraction -= digit;
40+
// TODO: Round to even
41+
} while (fraction >= delta);
42+
}
43+
44+
if (this < 0) {
45+
result = "-" + result;
46+
}
47+
48+
return result;
49+
}

src/lualib/declarations/math.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @noSelf */
2+
declare namespace math {
3+
/** @tupleReturn */
4+
function modf(x: number): [number, number];
5+
}

src/lualib/declarations/string.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ declare namespace string {
88
n?: number
99
): [string, number];
1010
function sub(s: string, i: number, j?: number): string;
11+
function format(formatstring: string, ...args: any[]): string;
1112
}

src/transformation/builtins/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import { PropertyCallExpression } from "../transformers/call";
55
import { checkForLuaLibType } from "../transformers/class/new";
66
import { importLuaLibFeature, LuaLibFeature } from "../utils/lualib";
77
import { getIdentifierSymbolId } from "../utils/symbols";
8-
import { isArrayType, isFunctionType, isStandardLibraryType, isStringType } from "../utils/typescript";
8+
import { isArrayType, isFunctionType, isNumberType, isStandardLibraryType, isStringType } from "../utils/typescript";
99
import { transformArrayProperty, transformArrayPrototypeCall } from "./array";
1010
import { transformConsoleCall } from "./console";
1111
import { transformFunctionPrototypeCall } from "./function";
1212
import { transformGlobalCall } from "./global";
1313
import { transformMathCall, transformMathProperty } from "./math";
14-
import { transformNumberConstructorCall } from "./number";
14+
import { transformNumberConstructorCall, transformNumberPrototypeCall } from "./number";
1515
import { transformObjectConstructorCall, transformObjectPrototypeCall } from "./object";
1616
import { transformStringConstructorCall, transformStringProperty, transformStringPrototypeCall } from "./string";
1717
import { transformSymbolConstructorCall } from "./symbol";
@@ -89,6 +89,10 @@ export function transformBuiltinCallExpression(
8989
return transformStringPrototypeCall(context, propertyCall);
9090
}
9191

92+
if (isNumberType(context, ownerType)) {
93+
return transformNumberPrototypeCall(context, propertyCall);
94+
}
95+
9296
if (isArrayType(context, ownerType)) {
9397
const result = transformArrayPrototypeCall(context, propertyCall);
9498
if (result) {

src/transformation/builtins/number.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,26 @@ import { PropertyCallExpression, transformArguments } from "../transformers/call
44
import { UnsupportedProperty } from "../utils/errors";
55
import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib";
66

7-
// Transpile a Number._ property
7+
export function transformNumberPrototypeCall(
8+
context: TransformationContext,
9+
node: PropertyCallExpression
10+
): lua.Expression {
11+
const expression = node.expression;
12+
const signature = context.checker.getResolvedSignature(node);
13+
const params = transformArguments(context, node.arguments, signature);
14+
const caller = context.transformExpression(expression.expression);
15+
16+
const expressionName = expression.name.text;
17+
switch (expressionName) {
18+
case "toString":
19+
return params.length === 0
20+
? lua.createCallExpression(lua.createIdentifier("tostring"), [caller], node)
21+
: transformLuaLibFunction(context, LuaLibFeature.NumberToString, node, caller, ...params);
22+
default:
23+
throw UnsupportedProperty("number", expressionName, node);
24+
}
25+
}
26+
827
export function transformNumberConstructorCall(
928
context: TransformationContext,
1029
expression: PropertyCallExpression

test/unit/builtins/numbers.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flatMap } from "../../../src/utils";
12
import * as util from "../../util";
23

34
test.each([
@@ -48,6 +49,18 @@ describe("Number", () => {
4849
});
4950
});
5051

52+
const toStringRadixes = [undefined, 10, 2, 8, 9, 16, 17, 36, 36.9];
53+
const toStringValues = [-1, 0, 1, 1.5, 1024, 1.2];
54+
const toStringPairs = flatMap(toStringValues, value => toStringRadixes.map(radix => [value, radix] as const));
55+
56+
test.each(toStringPairs)("(%p).toString(%p)", (value, radix) => {
57+
util.testExpressionTemplate`(${value}).toString(${radix})`.expectToMatchJsResult();
58+
});
59+
60+
test.each([NaN, Infinity, -Infinity])("%p.toString(2)", value => {
61+
util.testExpressionTemplate`(${value}).toString(2)`.expectToMatchJsResult();
62+
});
63+
5164
test.each(cases)("isNaN(%p)", value => {
5265
util.testExpressionTemplate`isNaN(${value} as any)`.expectToMatchJsResult();
5366
});

0 commit comments

Comments
 (0)