From 7f101cc3bb2eb4d0e2e222a3a040dfc4f1276e56 Mon Sep 17 00:00:00 2001 From: mattias Date: Mon, 26 Oct 2020 21:57:37 +0000 Subject: [PATCH] pastojs: fixed a div b<0 --- compiler/packages/pastojs/src/fppas2js.pp | 69 +++++++++++-------- compiler/packages/pastojs/tests/tcmodules.pas | 42 +++++------ compiler/utils/pas2js/dist/rtl.js | 4 ++ 3 files changed, 64 insertions(+), 51 deletions(-) diff --git a/compiler/packages/pastojs/src/fppas2js.pp b/compiler/packages/pastojs/src/fppas2js.pp index 153430f..f7e5d49 100644 --- a/compiler/packages/pastojs/src/fppas2js.pp +++ b/compiler/packages/pastojs/src/fppas2js.pp @@ -665,6 +665,7 @@ type pbifnSet_Union, pbifnSpaceLeft, pbifnStringSetLength, + pbifnTrunc, // rtl.trunc pbifnUnitInit, pbivnExceptObject, pbivnIntfExprRefs, @@ -830,6 +831,7 @@ const 'unionSet', // rtl.unionSet + 'spaceLeft', // rtl.spaceLeft 'strSetLength', // rtl.strSetLength + 'trunc', // pbifnTrunc '$init', '$e', '$ir', @@ -1783,7 +1785,7 @@ type // simple JS expressions Function CreateMulNumber(El: TPasElement; JS: TJSElement; n: TMaxPrecInt): TJSElement; virtual; Function CreateDivideNumber(El: TPasElement; JS: TJSElement; n: TMaxPrecInt): TJSElement; virtual; - Function CreateMathFloor(El: TPasElement; JS: TJSElement): TJSElement; virtual; + Function CreateTruncFloor(El: TPasElement; JS: TJSElement; FloorAndCeil: boolean): TJSElement; virtual; Function CreateDotNameExpr(PosEl: TPasElement; MExpr: TJSElement; const aName: TJSString): TJSDotMemberExpression; virtual; Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement; @@ -7115,8 +7117,8 @@ begin case El.OpCode of eopDiv: begin - // convert "a div b" to "Math.floor(a/b)" - Result:=CreateMathFloor(El,Result); + // convert "a div b" to "rtl.trunc(a/b)" + Result:=CreateTruncFloor(El,Result,true); end; end; @@ -7305,7 +7307,7 @@ begin else if El.OpCode=eopShr then begin // BigInt shr const -> Math.floor(A/otherconst) - Result:=CreateMathFloor(El,CreateDivideNumber(El,A,TMaxPrecInt(1) shl BInt)); + Result:=CreateTruncFloor(El,CreateDivideNumber(El,A,TMaxPrecInt(1) shl BInt),false); A:=nil; FreeAndNil(B); exit; @@ -7379,22 +7381,22 @@ begin end; eopDivide: begin - // currency / currency -> Math.floor((currency/currency)*10000) - // currency / number -> Math.floor(currency/number) - // number / currency -> Math.floor(number/currency) + // currency / currency -> rtl.trunc((currency/currency)*10000) + // currency / number -> rtl.trunc(currency/number) + // number / currency -> rtl.trunc(number/currency) Result:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El)); TJSBinaryExpression(Result).A:=A; A:=nil; TJSBinaryExpression(Result).B:=B; B:=nil; if (LeftResolved.BaseType=btCurrency) and (RightResolved.BaseType=btCurrency) then Result:=CreateMulNumber(El,Result,10000); - Result:=CreateMathFloor(El,Result); + Result:=CreateTruncFloor(El,Result,true); exit; end; eopPower: begin - // currency^^currency -> Math.floor(Math.pow(currency/10000,currency/10000)*10000) - // currency^^number -> Math.floor(Math.pow(currency/10000,number)*10000) - // number^^currency -> Math.floor(Math.pow(number,currency/10000)*10000) + // currency^^currency -> rtl.trunc(Math.pow(currency/10000,currency/10000)*10000) + // currency^^number -> rtl.trunc(Math.pow(currency/10000,number)*10000) + // number^^currency -> rtl.trunc(Math.pow(number,currency/10000)*10000) if LeftResolved.BaseType=btCurrency then A:=CreateDivideNumber(El,A,10000); if RightResolved.BaseType=btCurrency then @@ -7404,7 +7406,7 @@ begin Call.AddArg(A); A:=nil; Call.AddArg(B); B:=nil; Result:=CreateMulNumber(El,Call,10000); - Result:=CreateMathFloor(El,Result); + Result:=CreateTruncFloor(El,Result,true); end else RaiseNotSupported(El,AContext,20180422104215); @@ -8468,8 +8470,8 @@ begin if FromBT=btCurrency then begin if ToBT<>btCurrency then - // currency to integer -> Math.floor(value/10000) - Result:=CreateMathFloor(PosEl,CreateDivideNumber(PosEl,Result,10000)); + // currency to integer -> rtl.trunc(value/10000) + Result:=CreateTruncFloor(PosEl,CreateDivideNumber(PosEl,Result,10000),true); end else if ToBT=btCurrency then // integer to currency -> value*10000 @@ -10302,13 +10304,13 @@ begin begin if JSBaseType=pbtJSValue then begin - // convert jsvalue to integer -> Math.floor(value) + // convert jsvalue to integer -> rtl.trunc(value) Result:=ConvertExpression(Param,AContext); // Note: convert Param first in case it raises an exception if to_bt=btCurrency then - // jsvalue to currency -> Math.floor(value*10000) + // jsvalue to currency -> rtl.trunc(value*10000) Result:=CreateMulNumber(Param,Result,10000); - Result:=CreateMathFloor(El,Result); + Result:=CreateTruncFloor(El,Result,true); exit; end; end @@ -11873,7 +11875,7 @@ begin if Shift=32 then begin // JS bitwise operations work only 32bit -> use division for bigger shifts - Result:=CreateMathFloor(El,CreateDivideNumber(El,Result,$100000000)); + Result:=CreateTruncFloor(El,CreateDivideNumber(El,Result,$100000000),false); end else begin @@ -18762,9 +18764,9 @@ begin // currency := currency else if AssignContext.RightResolved.BaseType in btAllJSFloats then begin - // currency := double -> currency := Math.floor(double*10000) + // currency := double -> currency := rtl.trunc(double*10000) AssignContext.RightSide:=CreateMulNumber(El,AssignContext.RightSide,10000); - AssignContext.RightSide:=CreateMathFloor(El,AssignContext.RightSide); + AssignContext.RightSide:=CreateTruncFloor(El,AssignContext.RightSide,true); end else if AssignContext.RightResolved.BaseType in btAllJSInteger then begin @@ -20845,11 +20847,12 @@ begin Mul.B:=CreateLiteralNumber(El,n); end; -function TPasToJSConverter.CreateMathFloor(El: TPasElement; JS: TJSElement - ): TJSElement; +function TPasToJSConverter.CreateTruncFloor(El: TPasElement; JS: TJSElement; + FloorAndCeil: boolean): TJSElement; // create Math.floor(JS) var Value: TJSValue; + Call: TJSCallExpression; begin if JS is TJSLiteral then begin @@ -20877,18 +20880,24 @@ begin exit(JS); end; jstNumber: + begin if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then - exit(JS) - else - begin - Value.AsNumber:=Trunc(Value.AsNumber); exit(JS); - end; + if FloorAndCeil then + Value.AsNumber:=Trunc(Value.AsNumber) + else + Value.AsNumber:=Floor(Value.AsNumber); + exit(JS); + end; end; end; - Result:=CreateCallExpression(El); - TJSCallExpression(Result).Expr:=CreatePrimitiveDotExpr('Math.floor',El); - TJSCallExpression(Result).AddArg(JS); + Call:=CreateCallExpression(El); + Result:=Call; + if FloorAndCeil then + Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnTrunc),El) + else + Call.Expr:=CreatePrimitiveDotExpr('Math.floor',El); + Call.AddArg(JS); end; function TPasToJSConverter.CreateDotNameExpr(PosEl: TPasElement; diff --git a/compiler/packages/pastojs/tests/tcmodules.pas b/compiler/packages/pastojs/tests/tcmodules.pas index cc76869..680d6df 100644 --- a/compiler/packages/pastojs/tests/tcmodules.pas +++ b/compiler/packages/pastojs/tests/tcmodules.pas @@ -3057,9 +3057,9 @@ begin LinesToStr([ // this.$main '$mod.vA = 1;', '$mod.vB = $mod.vA + $mod.vA;', - '$mod.vB = Math.floor($mod.vA / $mod.vB);', + '$mod.vB = rtl.trunc($mod.vA / $mod.vB);', '$mod.vB = $mod.vA % $mod.vB;', - '$mod.vB = $mod.vA + ($mod.vA * $mod.vB) + Math.floor($mod.vA / $mod.vB);', + '$mod.vB = $mod.vA + ($mod.vA * $mod.vB) + rtl.trunc($mod.vA / $mod.vB);', '$mod.vC = -$mod.vA;', '$mod.vA = $mod.vA - $mod.vB;', '$mod.vB = $mod.vA;', @@ -6618,7 +6618,7 @@ begin '$mod.d = -5.00E-1;', '$mod.d = Math.pow(10, 3);', '$mod.d = 10 % 3;', - '$mod.d = Math.floor(10 / 3);', + '$mod.d = rtl.trunc(10 / 3);', '$mod.d = 1;', '$mod.d = 0.1;', '$mod.d = 0.3;', @@ -6947,17 +6947,17 @@ begin LinesToStr([ '$mod.c = 10000;', '$mod.c = 1000;', - '$mod.c = Math.floor((1.0 / 3.0) * 10000);', - '$mod.c = Math.floor((1 / 3) * 10000);', + '$mod.c = rtl.trunc((1.0 / 3.0) * 10000);', + '$mod.c = rtl.trunc((1 / 3) * 10000);', '$mod.c = $mod.a;', '$mod.d = $mod.c / 10000;', - '$mod.c = Math.floor($mod.d * 10000);', + '$mod.c = rtl.trunc($mod.d * 10000);', '$mod.c = $mod.c;', '$mod.c = $mod.d * 10000;', '$mod.d = $mod.c / 10000;', '$mod.c = $mod.i * 10000;', '$mod.c = $mod.i * 10000;', - '$mod.i = Math.floor($mod.c / 10000);', + '$mod.i = rtl.trunc($mod.c / 10000);', '$mod.c = $mod.c + $mod.a;', '$mod.c = -$mod.c - $mod.a;', '$mod.c = ($mod.d * 10000) + $mod.c;', @@ -6968,14 +6968,14 @@ begin '$mod.c = ($mod.a * $mod.c) / 10000;', '$mod.c = $mod.d * $mod.c;', '$mod.c = $mod.c * $mod.d;', - '$mod.c = Math.floor(($mod.c / $mod.a) * 10000);', - '$mod.c = Math.floor(($mod.a / $mod.c) * 10000);', - '$mod.c = Math.floor($mod.d / $mod.c);', - '$mod.c = Math.floor($mod.c / $mod.d);', - '$mod.c = Math.floor(Math.pow($mod.c / 10000, $mod.a / 10000) * 10000);', - '$mod.c = Math.floor(Math.pow($mod.a / 10000, $mod.c / 10000) * 10000);', - '$mod.c = Math.floor(Math.pow($mod.d, $mod.c / 10000) * 10000);', - '$mod.c = Math.floor(Math.pow($mod.c / 10000, $mod.d) * 10000);', + '$mod.c = rtl.trunc(($mod.c / $mod.a) * 10000);', + '$mod.c = rtl.trunc(($mod.a / $mod.c) * 10000);', + '$mod.c = rtl.trunc($mod.d / $mod.c);', + '$mod.c = rtl.trunc($mod.c / $mod.d);', + '$mod.c = rtl.trunc(Math.pow($mod.c / 10000, $mod.a / 10000) * 10000);', + '$mod.c = rtl.trunc(Math.pow($mod.a / 10000, $mod.c / 10000) * 10000);', + '$mod.c = rtl.trunc(Math.pow($mod.d, $mod.c / 10000) * 10000);', + '$mod.c = rtl.trunc(Math.pow($mod.c / 10000, $mod.d) * 10000);', 'if ($mod.c === $mod.c) ;', 'if ($mod.c === $mod.a) ;', 'if ($mod.a === $mod.c) ;', @@ -6984,7 +6984,7 @@ begin '$mod.c = $mod.DoIt($mod.c);', '$mod.c = $mod.DoIt($mod.i * 10000);', '$mod.c = $mod.DoIt($mod.d * 10000);', - '$mod.c = Math.floor($mod.GetIt($mod.c / 10000) * 10000);', + '$mod.c = rtl.trunc($mod.GetIt($mod.c / 10000) * 10000);', '$mod.j = $mod.c / 10000;', '$mod.Write($mod.c / 10000);', '$mod.c = 0;', @@ -8042,7 +8042,7 @@ begin LinesToStr([ // $mod.$main 'try {', ' $mod.i = 0;', - ' $mod.i = Math.floor(2 / $mod.i);', + ' $mod.i = rtl.trunc(2 / $mod.i);', '} finally {', ' $mod.i = 3;', '};' @@ -17513,7 +17513,7 @@ begin '']), LinesToStr([ // $mod.$main '$mod.v = $mod.Arr[$mod.i];', - '$mod.Arr[Math.floor($mod.v)] = $mod.Arr[$mod.IntArr[0]];', + '$mod.Arr[rtl.trunc($mod.v)] = $mod.Arr[$mod.IntArr[0]];', '$mod.Arr[$mod.IntArr[1]] = $mod.Arr[$mod.IntArr[2]];', ''])); end; @@ -26057,8 +26057,8 @@ begin 'this.c = "";', '']), LinesToStr([ // $mod.$main - '$mod.i = Math.floor($mod.v);', - '$mod.i = Math.floor($mod.v);', + '$mod.i = rtl.trunc($mod.v);', + '$mod.i = rtl.trunc($mod.v);', '$mod.s = "" + $mod.v;', '$mod.s = "" + $mod.v;', '$mod.b = !($mod.v == false);', @@ -26566,7 +26566,7 @@ begin ' this.p.v = v;', ' }', '});', - '$mod.i = Math.floor($mod.DoSome($mod.i, $mod.i));', + '$mod.i = rtl.trunc($mod.DoSome($mod.i, $mod.i));', '$mod.b = !($mod.DoSome($mod.b, $mod.b) == false);', '$mod.d = rtl.getNumber($mod.DoSome($mod.d, $mod.d));', '$mod.s = "" + $mod.DoSome($mod.s, $mod.s);', diff --git a/compiler/utils/pas2js/dist/rtl.js b/compiler/utils/pas2js/dist/rtl.js index d70635d..b640e95 100644 --- a/compiler/utils/pas2js/dist/rtl.js +++ b/compiler/utils/pas2js/dist/rtl.js @@ -749,6 +749,10 @@ var rtl = { return intf; }, + trunc: function(a){ + return a<0 ? Math.ceil(a) : Math.floor(a); + }, + checkMethodCall: function(obj,type){ if (rtl.isObject(obj) && rtl.is(obj,type)) return; rtl.raiseE("EInvalidCast");