From 1a59a4a4a3125e0aba59105498b5cbc522c68bfc Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Thu, 24 Jan 2019 22:03:43 +0000 Subject: [PATCH] pastojs: typecast char to word git-svn-id: trunk@41062 - --- packages/fcl-js/src/jswriter.pp | 3 +- packages/pastojs/src/fppas2js.pp | 257 +++++++++++++++------------ packages/pastojs/tests/tcmodules.pas | 6 + 3 files changed, 149 insertions(+), 117 deletions(-) diff --git a/packages/fcl-js/src/jswriter.pp b/packages/fcl-js/src/jswriter.pp index 510f33c991..4e8435225f 100644 --- a/packages/fcl-js/src/jswriter.pp +++ b/packages/fcl-js/src/jswriter.pp @@ -272,6 +272,7 @@ begin // conversion magic SetCodePage(RawByteString(Result), CP_ACP, False); end; +{$endif} function QuoteJSString(const S: TJSString; Quote: TJSChar): TJSString; var @@ -302,8 +303,6 @@ begin Result := Result + Quote; end; -{$endif} - { TBufferWriter } function TBufferWriter.GetBufferLength: Integer; diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index e001a3e1d6..468fd01008 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -1803,6 +1803,9 @@ type Function ConvertArrayValues(El: TArrayValues; AContext: TConvertContext): TJSElement; virtual; Function ConvertInheritedExpr(El: TInheritedExpr; AContext: TConvertContext): TJSElement; virtual; Function ConvertNilExpr(El: TNilExpr; AContext: TConvertContext): TJSElement; virtual; + Function ConvertCharToInt(Arg: TJSElement; PosEl: TPasElement; ArgContext: TConvertContext): TJSElement; virtual; + Function ConvertIntToInt(Arg: TJSElement; FromBT, ToBT: TResolverBaseType; PosEl: TPasElement; ArgContext: TConvertContext): TJSElement; virtual; + Function CreateBitWiseAnd(El: TPasElement; Value: TJSElement; const Mask: TMaxPrecInt; Shift: integer): TJSElement; virtual; Function ConvertParamsExpr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual; Function ConvertArrayParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual; Function ConvertFuncParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual; @@ -7753,6 +7756,132 @@ begin Result:=CreateLiteralNull(El); end; +function TPasToJSConverter.ConvertCharToInt(Arg: TJSElement; + PosEl: TPasElement; ArgContext: TConvertContext): TJSElement; +begin + if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstString) then + begin + // convert char literal to int + ConvertCharLiteralToInt(TJSLiteral(Arg),PosEl,ArgContext); + Result:=Arg; + end + else + begin + // convert char to int -> Arg.charCodeAt(0) + Result:=CreateCallCharCodeAt(Arg,0,PosEl); + end; +end; + +function TPasToJSConverter.ConvertIntToInt(Arg: TJSElement; FromBT, + ToBT: TResolverBaseType; PosEl: TPasElement; ArgContext: TConvertContext + ): TJSElement; +var + aResolver: TPas2JSResolver; + MinVal, MaxVal: TMaxPrecInt; + Call: TJSCallExpression; + ShiftEx: TJSURShiftExpression; +begin + Result:=Arg; + aResolver:=ArgContext.Resolver; + if FromBT=btCurrency then + begin + if ToBT<>btCurrency then + // currency to integer -> Math.floor(value/10000) + Result:=CreateMathFloor(PosEl,CreateDivideNumber(PosEl,Result,10000)); + end + else if ToBT=btCurrency then + // integer to currency -> value*10000 + Result:=CreateMulNumber(PosEl,Result,10000); + if (ToBT<>btIntDouble) and not (Result is TJSLiteral) then + begin + if bsRangeChecks in ArgContext.ScannerBoolSwitches then + begin + // rtl.rc(param,MinInt,MaxInt) + if not aResolver.GetIntegerRange(ToBT,MinVal,MaxVal) then + RaiseNotSupported(PosEl,ArgContext,20180425131839); + Call:=CreateCallExpression(PosEl); + Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnRangeCheckInt),PosEl); + Call.AddArg(Result); + Result:=Call; + Call.AddArg(CreateLiteralNumber(PosEl,MinVal)); + Call.AddArg(CreateLiteralNumber(PosEl,MaxVal)); + end + else + case ToBT of + btByte: + // value to byte -> value & 255 + if FromBT<>btByte then + Result:=CreateBitWiseAnd(PosEl,Result,255,0); + btShortInt: + // value to shortint -> value & 255 << 24 >> 24 + if FromBT<>btShortInt then + Result:=CreateBitWiseAnd(PosEl,Result,255,24); + btWord: + // value to word -> value & 65535 + if not (FromBT in [btByte,btWord]) then + Result:=CreateBitWiseAnd(PosEl,Result,65535,0); + btSmallInt: + // value to smallint -> value & 65535 << 16 >> 16 + if not (FromBT in [btShortInt,btSmallInt]) then + Result:=CreateBitWiseAnd(PosEl,Result,65535,16); + btLongWord: + // value to longword -> value >>> 0 + if not (FromBT in [btByte,btWord,btLongWord,btUIntSingle]) then + begin + ShiftEx:=TJSURShiftExpression(CreateElement(TJSURShiftExpression,PosEl)); + ShiftEx.A:=Result; + ShiftEx.B:=CreateLiteralNumber(PosEl,0); + Result:=ShiftEx; + end; + btLongint: + // value to longint -> value & 0xffffffff + if not (FromBT in [btShortInt,btSmallInt,btLongint,btIntSingle]) then + Result:=CreateBitWiseAnd(PosEl,Result,$ffffffff,0); + end; + end; +end; + +function TPasToJSConverter.CreateBitWiseAnd(El: TPasElement; Value: TJSElement; + const Mask: TMaxPrecInt; Shift: integer): TJSElement; +// if sign=false: Value & Mask +// if sign=true: Value & Mask << ZeroBits >> ZeroBits +var + AndEx: TJSBitwiseAndExpression; + Hex: String; + i: Integer; + ShiftEx: TJSShiftExpression; +begin + AndEx:=TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression,El)); + Result:=AndEx; + AndEx.A:=Value; + AndEx.B:=CreateLiteralNumber(El,Mask); + if Mask>999999 then + begin + Hex:=HexStr(Mask,8); + i:=1; + while i<8 do + if Hex[i]='0' then + inc(i) + else + break; + Hex:=Copy(Hex,i,8); + TJSLiteral(AndEx.B).Value.CustomValue:=TJSString('0x'+Hex); + end; + if Shift>0 then + begin + // value << ZeroBits + ShiftEx:=TJSLShiftExpression(CreateElement(TJSLShiftExpression,El)); + ShiftEx.A:=Result; + Result:=ShiftEx; + ShiftEx.B:=CreateLiteralNumber(El,Shift); + // value << ZeroBits >> ZeroBits + ShiftEx:=TJSRShiftExpression(CreateElement(TJSRShiftExpression,El)); + ShiftEx.A:=Result; + Result:=ShiftEx; + ShiftEx.B:=CreateLiteralNumber(El,Shift); + end; +end; + function TPasToJSConverter.ConvertInheritedExpr(El: TInheritedExpr; AContext: TConvertContext): TJSElement; @@ -7967,7 +8096,7 @@ var begin Result:=ConvertExpression(Param,ArgContext); NeedMinus1:=true; - if (Result is TJSLiteral) then + if Result is TJSLiteral then begin JSVal:=TJSLiteral(Result).Value; if (JSVal.ValueType=jstNumber) then @@ -8107,20 +8236,6 @@ var end; end; - procedure ConvCharToInt(var Arg: TJSElement; Param: TPasElement); - begin - if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstString) then - begin - // convert char literal to int - ConvertCharLiteralToInt(TJSLiteral(Arg),Param,ArgContext); - end - else - begin - // convert char to int -> Arg.charCodeAt(0) - Arg:=CreateCallCharCodeAt(Arg,0,Param); - end; - end; - procedure ConvertArray(ArrayEl: TPasArrayType); var BracketEx, Sub: TJSBracketMemberExpression; @@ -8232,7 +8347,7 @@ var end else Int:=ord(TResEvalString(LowRg).S[1]); - ConvCharToInt(Arg,Param); + Arg:=ConvertCharToInt(Arg,Param,ArgContext); end; {$ENDIF} revkUnicodeString: @@ -8241,7 +8356,7 @@ var ArgContext.Resolver.RaiseXExpectedButYFound(20170910213247,'char','string',Param) else Int:=ord(TResEvalUTF16(LowRg).S[1]); - ConvCharToInt(Arg,Param); + Arg:=ConvertCharToInt(Arg,Param,ArgContext); end else RaiseNotSupported(Param,ArgContext,20170910170446); @@ -9459,46 +9574,6 @@ var JSBaseType:=JSBaseTypeData.JSBaseType; end; - function CreateBitWiseAnd(Value: TJSElement; const Mask: TMaxPrecInt; Shift: integer): TJSElement; - // if sign=false: Value & Mask - // if sign=true: Value & Mask << ZeroBits >> ZeroBits - var - AndEx: TJSBitwiseAndExpression; - Hex: String; - i: Integer; - ShiftEx: TJSShiftExpression; - begin - AndEx:=TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression,El)); - Result:=AndEx; - AndEx.A:=Value; - AndEx.B:=CreateLiteralNumber(El,Mask); - if Mask>999999 then - begin - Hex:=HexStr(Mask,8); - i:=1; - while i<8 do - if Hex[i]='0' then - inc(i) - else - break; - Hex:=Copy(Hex,i,8); - TJSLiteral(AndEx.B).Value.CustomValue:=TJSString('0x'+Hex); - end; - if Shift>0 then - begin - // value << ZeroBits - ShiftEx:=TJSLShiftExpression(CreateElement(TJSLShiftExpression,El)); - ShiftEx.A:=Result; - Result:=ShiftEx; - ShiftEx.B:=CreateLiteralNumber(El,Shift); - // value << ZeroBits >> ZeroBits - ShiftEx:=TJSRShiftExpression(CreateElement(TJSRShiftExpression,El)); - ShiftEx.A:=Result; - Result:=ShiftEx; - ShiftEx.B:=CreateLiteralNumber(El,Shift); - end; - end; - var NotEqual: TJSEqualityExpressionNE; CondExpr: TJSConditionalExpression; @@ -9507,9 +9582,8 @@ var AddExpr: TJSAdditiveExpressionPlus; TypeEl: TPasType; C: TClass; - Int, MinVal, MaxVal: TMaxPrecInt; + Int: TMaxPrecInt; aResolver: TPas2JSResolver; - ShiftEx: TJSURShiftExpression; begin Result:=nil; Param:=El.Params[0]; @@ -9525,62 +9599,7 @@ begin begin // integer to integer -> value Result:=ConvertExpression(Param,AContext); - if ParamResolved.BaseType=btCurrency then - begin - if to_bt<>btCurrency then - // currency to integer -> Math.floor(value/10000) - Result:=CreateMathFloor(Param,CreateDivideNumber(Param,Result,10000)); - end - else if to_bt=btCurrency then - // integer to currency -> value*10000 - Result:=CreateMulNumber(Param,Result,10000); - if (to_bt<>btIntDouble) and not (Result is TJSLiteral) then - begin - if bsRangeChecks in AContext.ScannerBoolSwitches then - begin - // rtl.rc(param,MinInt,MaxInt) - if not aResolver.GetIntegerRange(to_bt,MinVal,MaxVal) then - RaiseNotSupported(Param,AContext,20180425131839); - Call:=CreateCallExpression(El); - Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnRangeCheckInt),El); - Call.AddArg(Result); - Result:=Call; - Call.AddArg(CreateLiteralNumber(El,MinVal)); - Call.AddArg(CreateLiteralNumber(El,MaxVal)); - end - else - case to_bt of - btByte: - // value to byte -> value & 255 - if ParamResolved.BaseType<>btByte then - Result:=CreateBitWiseAnd(Result,255,0); - btShortInt: - // value to shortint -> value & 255 << 24 >> 24 - if ParamResolved.BaseType<>btShortInt then - Result:=CreateBitWiseAnd(Result,255,24); - btWord: - // value to word -> value & 65535 - if not (ParamResolved.BaseType in [btByte,btWord]) then - Result:=CreateBitWiseAnd(Result,65535,0); - btSmallInt: - // value to smallint -> value & 65535 << 16 >> 16 - if not (ParamResolved.BaseType in [btShortInt,btSmallInt]) then - Result:=CreateBitWiseAnd(Result,65535,16); - btLongWord: - // value to longword -> value >>> 0 - if not (ParamResolved.BaseType in [btByte,btWord,btLongWord,btUIntSingle]) then - begin - ShiftEx:=TJSURShiftExpression(CreateElement(TJSURShiftExpression,El)); - ShiftEx.A:=Result; - ShiftEx.B:=CreateLiteralNumber(El,0); - Result:=ShiftEx; - end; - btLongint: - // value to longint -> value & 0xffffffff - if not (ParamResolved.BaseType in [btShortInt,btSmallInt,btLongint,btIntSingle]) then - Result:=CreateBitWiseAnd(Result,$ffffffff,0); - end; - end; + Result:=ConvertIntToInt(Result,ParamResolved.BaseType,to_bt,El,AContext); exit; end else if ParamResolved.BaseType in btAllJSBooleans then @@ -9598,6 +9617,14 @@ begin Result:=CondExpr; exit; end + else if ParamResolved.BaseType in btAllJSChars then + begin + // char to integer + Result:=ConvertExpression(Param,AContext); + Result:=ConvertCharToInt(Result,El,AContext); + Result:=ConvertIntToInt(Result,btWord,to_bt,El,AContext); + exit; + end else if ParamResolved.BaseType=btContext then begin if ParamResolved.LoTypeEl.ClassType=TPasEnumType then diff --git a/packages/pastojs/tests/tcmodules.pas b/packages/pastojs/tests/tcmodules.pas index 75ec681cfb..7c93acc15e 100644 --- a/packages/pastojs/tests/tcmodules.pas +++ b/packages/pastojs/tests/tcmodules.pas @@ -6431,6 +6431,9 @@ begin ' c:=succ(c);', ' c:=low(c);', ' c:=high(c);', + ' i:=byte(c);', + ' i:=word(c);', + ' i:=longint(c);', '']); ConvertProgram; CheckSource('TestChar_BuiltInProcs', @@ -6447,6 +6450,9 @@ begin '$mod.c = String.fromCharCode($mod.c.charCodeAt() + 1);', '$mod.c = "\x00";', '$mod.c = "\uFFFF";', + '$mod.i = $mod.c.charCodeAt() & 255;', + '$mod.i = $mod.c.charCodeAt();', + '$mod.i = $mod.c.charCodeAt() & 0xFFFFFFFF;', ''])); end;