Browse Source

pastojs: typecast int(int)

git-svn-id: trunk@38842 -
Mattias Gaertner 7 years ago
parent
commit
80b008b76d
2 changed files with 177 additions and 5 deletions
  1. 92 5
      packages/pastojs/src/fppas2js.pp
  2. 85 0
      packages/pastojs/tests/tcmodules.pas

+ 92 - 5
packages/pastojs/src/fppas2js.pp

@@ -7962,6 +7962,43 @@ var
     JSBaseType:=JSBaseTypeData.JSBaseType;
     JSBaseType:=JSBaseTypeData.JSBaseType;
   end;
   end;
 
 
+  function CreateModulo(Value: TJSElement; const Mask: MaxPrecInt; Sign: boolean): TJSElement;
+  // ig sign=false: Value & Mask
+  // if sign=true:  Value & Mask << ZeroBits >> ZeroBits
+  var
+    ModEx: TJSMultiplicativeExpressionMod;
+    Hex: String;
+    i: Integer;
+    ShiftEx: TJSShiftExpression;
+  begin
+    ModEx:=TJSMultiplicativeExpressionMod(CreateElement(TJSMultiplicativeExpressionMod,El));
+    Result:=ModEx;
+    ModEx.A:=Value;
+    ModEx.B:=CreateLiteralNumber(El,Mask);
+    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(ModEx.B).Value.CustomValue:=TJSString('0x'+Hex);
+    if Sign then
+      begin
+      // value << ZeroBits
+      ShiftEx:=TJSLShiftExpression(CreateElement(TJSLShiftExpression,El));
+      ShiftEx.A:=Result;
+      Result:=ShiftEx;
+      ShiftEx.B:=CreateLiteralNumber(El,i*4-4);
+      // value << ZeroBits >> ZeroBits
+      ShiftEx:=TJSRShiftExpression(CreateElement(TJSRShiftExpression,El));
+      ShiftEx.A:=Result;
+      Result:=ShiftEx;
+      ShiftEx.B:=CreateLiteralNumber(El,i*4-4);
+      end;
+  end;
+
 var
 var
   NotEqual: TJSEqualityExpressionNE;
   NotEqual: TJSEqualityExpressionNE;
   CondExpr: TJSConditionalExpression;
   CondExpr: TJSConditionalExpression;
@@ -7970,11 +8007,14 @@ var
   AddExpr: TJSAdditiveExpressionPlus;
   AddExpr: TJSAdditiveExpressionPlus;
   TypeEl: TPasType;
   TypeEl: TPasType;
   C: TClass;
   C: TClass;
-  Int: MaxPrecInt;
+  Int, MinVal, MaxVal: MaxPrecInt;
+  aResolver: TPas2JSResolver;
+  ShiftEx: TJSURShiftExpression;
 begin
 begin
   Result:=nil;
   Result:=nil;
   Param:=El.Params[0];
   Param:=El.Params[0];
-  AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
+  aResolver:=AContext.Resolver;
+  aResolver.ComputeElement(Param,ParamResolved,[]);
   JSBaseTypeData:=nil;
   JSBaseTypeData:=nil;
   JSBaseType:=pbtNone;
   JSBaseType:=pbtNone;
 
 
@@ -7988,6 +8028,53 @@ begin
       if to_bt=btCurrency then
       if to_bt=btCurrency then
         // integer to currency -> value*10000
         // integer to currency -> value*10000
         Result:=CreateMulNumber(Param,Result,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(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[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 & 0xff
+            if ParamResolved.BaseType<>btByte then
+              Result:=CreateModulo(Result,$ff,false);
+          btShortInt:
+            // value to shortint  ->  value & 0xff << 24 >> 24
+            if ParamResolved.BaseType<>btShortInt then
+              Result:=CreateModulo(Result,$ff,true);
+          btWord:
+            // value to word  ->  value & 0xffff
+            if not (ParamResolved.BaseType in [btByte,btWord]) then
+              Result:=CreateModulo(Result,$ffff,false);
+          btSmallInt:
+            // value to smallint  ->  value & 0xffff << 16 >> 16
+            if not (ParamResolved.BaseType in [btShortInt,btSmallInt]) then
+              Result:=CreateModulo(Result,$ffff,true);
+          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:=CreateModulo(Result,$ffffffff,false);
+          end;
+        end;
       exit;
       exit;
       end
       end
     else if ParamResolved.BaseType in btAllJSBooleans then
     else if ParamResolved.BaseType in btAllJSBooleans then
@@ -8133,7 +8220,7 @@ begin
       end
       end
     else if (ParamResolved.BaseType in btAllJSInteger)
     else if (ParamResolved.BaseType in btAllJSInteger)
         or ((ParamResolved.BaseType=btContext)
         or ((ParamResolved.BaseType=btContext)
-          and (AContext.Resolver.ResolveAliasType(ParamResolved.TypeEl).ClassType=TPasEnumType))
+          and (aResolver.ResolveAliasType(ParamResolved.TypeEl).ClassType=TPasEnumType))
         then
         then
       begin
       begin
       // Note: convert value first in case it raises an exception
       // Note: convert value first in case it raises an exception
@@ -8209,7 +8296,7 @@ begin
       // Note: convert value first in case it raises an exception
       // Note: convert value first in case it raises an exception
       if ParamResolved.BaseType=btContext then
       if ParamResolved.BaseType=btContext then
         begin
         begin
-        TypeEl:=AContext.Resolver.ResolveAliasType(ParamResolved.TypeEl);
+        TypeEl:=aResolver.ResolveAliasType(ParamResolved.TypeEl);
         C:=TypeEl.ClassType;
         C:=TypeEl.ClassType;
         if C=TPasClassType then
         if C=TPasClassType then
           begin
           begin
@@ -8224,7 +8311,7 @@ begin
       end;
       end;
     end;
     end;
   {$IFDEF VerbosePas2JS}
   {$IFDEF VerbosePas2JS}
-  writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',AContext.Resolver.BaseTypeNames[to_bt],' ParamResolved=',GetResolverResultDbg(ParamResolved));
+  writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',aResolver.BaseTypeNames[to_bt],' ParamResolved=',GetResolverResultDbg(ParamResolved));
   {$ENDIF}
   {$ENDIF}
   RaiseNotSupported(El,AContext,20170325161150);
   RaiseNotSupported(El,AContext,20170325161150);
 end;
 end;

+ 85 - 0
packages/pastojs/tests/tcmodules.pas

@@ -210,6 +210,7 @@ type
     Procedure TestDouble;
     Procedure TestDouble;
     Procedure TestInteger;
     Procedure TestInteger;
     Procedure TestIntegerRange;
     Procedure TestIntegerRange;
+    Procedure TestIntegerTypecasts;
     Procedure TestCurrency;
     Procedure TestCurrency;
     Procedure TestForBoolDo;
     Procedure TestForBoolDo;
     Procedure TestForIntDo;
     Procedure TestForIntDo;
@@ -639,6 +640,7 @@ type
     procedure TestRangeChecks_AssignCharRange;
     procedure TestRangeChecks_AssignCharRange;
     procedure TestRangeChecks_ArrayIndex;
     procedure TestRangeChecks_ArrayIndex;
     procedure TestRangeChecks_StringIndex;
     procedure TestRangeChecks_StringIndex;
+    procedure TestRangeChecks_TypecastInt;
   end;
   end;
 
 
 function LinesToStr(Args: array of const): string;
 function LinesToStr(Args: array of const): string;
@@ -4947,6 +4949,47 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestModule.TestIntegerTypecasts;
+begin
+  StartProgram(false);
+  Add([
+  'var',
+  '  i: nativeint;',
+  '  b: byte;',
+  '  sh: shortint;',
+  '  w: word;',
+  '  sm: smallint;',
+  '  lw: longword;',
+  '  li: longint;',
+  'begin',
+  '  b:=byte(i);',
+  '  sh:=shortint(i);',
+  '  w:=word(i);',
+  '  sm:=smallint(i);',
+  '  lw:=longword(i);',
+  '  li:=longint(i);',
+  '']);
+  ConvertProgram;
+  CheckSource('TestIntegerTypecasts',
+    LinesToStr([
+    'this.i = 0;',
+    'this.b = 0;',
+    'this.sh = 0;',
+    'this.w = 0;',
+    'this.sm = 0;',
+    'this.lw = 0;',
+    'this.li = 0;',
+    '']),
+    LinesToStr([
+    '$mod.b = $mod.i % 0xFF;',
+    '$mod.sh = (($mod.i % 0xFF) << 24) >> 24;',
+    '$mod.w = $mod.i % 0xFFFF;',
+    '$mod.sm = (($mod.i % 0xFFFF) << 16) >> 16;',
+    '$mod.lw = $mod.i >>> 0;',
+    '$mod.li = $mod.i % 0xFFFFFFFF;',
+    '']));
+end;
+
 procedure TTestModule.TestCurrency;
 procedure TTestModule.TestCurrency;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
@@ -20146,6 +20189,48 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestModule.TestRangeChecks_TypecastInt;
+begin
+  StartProgram(false);
+  Add([
+  '{$R+}',
+  'var',
+  '  i: nativeint;',
+  '  b: byte;',
+  '  sh: shortint;',
+  '  w: word;',
+  '  sm: smallint;',
+  '  lw: longword;',
+  '  li: longint;',
+  'begin',
+  '  b:=12+byte(i);',
+  '  sh:=12+shortint(i);',
+  '  w:=12+word(i);',
+  '  sm:=12+smallint(i);',
+  '  lw:=12+longword(i);',
+  '  li:=12+longint(i);',
+  '']);
+  ConvertProgram;
+  CheckSource('TestRangeChecks_TypecastInt',
+    LinesToStr([
+    'this.i = 0;',
+    'this.b = 0;',
+    'this.sh = 0;',
+    'this.w = 0;',
+    'this.sm = 0;',
+    'this.lw = 0;',
+    'this.li = 0;',
+    '']),
+    LinesToStr([
+    '$mod.b = rtl.rc(12 + rtl.rc($mod.i, 0, 255), 0, 255);',
+    '$mod.sh = rtl.rc(12 + rtl.rc($mod.i, -128, 127), -128, 127);',
+    '$mod.w = rtl.rc(12 + rtl.rc($mod.i, 0, 65535), 0, 65535);',
+    '$mod.sm = rtl.rc(12 + rtl.rc($mod.i, -32768, 32767), -32768, 32767);',
+    '$mod.lw = rtl.rc(12 + rtl.rc($mod.i, 0, 4294967295), 0, 4294967295);',
+    '$mod.li = rtl.rc(12 + rtl.rc($mod.i, -2147483648, 2147483647), -2147483648, 2147483647);',
+    '']));
+end;
+
 Initialization
 Initialization
   RegisterTests([TTestModule]);
   RegisterTests([TTestModule]);
 end.
 end.