Skip to content

Commit 2dfca0b

Browse files
authored
Implement Number.toFixed (#1413)
1 parent 1af3db3 commit 2dfca0b

File tree

4 files changed

+37
-0
lines changed

4 files changed

+37
-0
lines changed

src/LuaLib.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export enum LuaLibFeature {
5858
NumberIsFinite = "NumberIsFinite",
5959
NumberIsNaN = "NumberIsNaN",
6060
NumberToString = "NumberToString",
61+
NumberToFixed = "NumberToFixed",
6162
ObjectAssign = "ObjectAssign",
6263
ObjectDefineProperty = "ObjectDefineProperty",
6364
ObjectEntries = "ObjectEntries",

src/lualib/NumberToFixed.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-number.prototype.tofixed
2+
export function __TS__NumberToFixed(this: number, fractionDigits?: number): string {
3+
if (Math.abs(this) >= 1e21 || this !== this) {
4+
return this.toString();
5+
}
6+
const f = Math.floor(fractionDigits ?? 0);
7+
// reduced to 99 as string.format only supports 2-digit numbers
8+
if (f < 0 || f > 99) {
9+
throw "toFixed() digits argument must be between 0 and 99";
10+
}
11+
// throws "invalid format (width or precision too long)" if strlen > 99
12+
// if (f < 80) return fmt; else try {return fmt} catch(_) { throw "toFixed() digits argument..." }
13+
return string.format(`%.${f}f`, this);
14+
}

src/transformation/builtins/number.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export function transformNumberPrototypeCall(
2020
return params.length === 0
2121
? lua.createCallExpression(lua.createIdentifier("tostring"), [caller], node)
2222
: transformLuaLibFunction(context, LuaLibFeature.NumberToString, node, caller, ...params);
23+
case "toFixed":
24+
return transformLuaLibFunction(context, LuaLibFeature.NumberToFixed, node, caller, ...params);
2325
default:
2426
context.diagnostics.push(unsupportedProperty(calledMethod.name, "number", expressionName));
2527
}

test/unit/builtins/numbers.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ test.each([
6969
util.testExpressionTemplate`(${value}).toString(2)`.expectToEqual(luaNativeSpecialNumString);
7070
});
7171

72+
const toFixedFractions = [undefined, 0, 1, 2, Math.PI, 5, 99];
73+
// 1.5, 1.25 and 1.125 fails as rounding differ
74+
const toFixedValues = [-1, 0, 1, Math.PI, -1.1234, -9.99e19, 1e22];
75+
const toFixedPairs = toFixedValues.flatMap(value => toFixedFractions.map(frac => [value, frac] as const));
76+
test.each(toFixedPairs)("(%p).toFixed(%p)", (value, frac) => {
77+
util.testExpressionTemplate`(${value}).toFixed(${frac})`.expectToMatchJsResult();
78+
});
79+
80+
test.each([
81+
[NaN, "(0/0)"],
82+
[Infinity, "(1/0)"],
83+
[-Infinity, "(-(1/0))"],
84+
])("%p.toFixed(2)", (value, luaNativeSpecialNum) => {
85+
// Need to get the actual lua tostring version of inf/nan
86+
// this is platform dependent so we can/should not hardcode it
87+
const luaNativeSpecialNumString = util.testExpression`${luaNativeSpecialNum}.toString()`.getLuaExecutionResult();
88+
// Cannot use expectToMatchJsResult because this actually wont be the same in JS in Lua
89+
util.testExpressionTemplate`(${value}).toFixed(2)`.expectToEqual(luaNativeSpecialNumString);
90+
});
91+
7292
test.each(cases)("isNaN(%p)", value => {
7393
util.testExpressionTemplate`isNaN(${value} as any)`.expectToMatchJsResult();
7494
});

0 commit comments

Comments
 (0)