Browse Source

pastojs: implemented funcname:=

git-svn-id: trunk@37389 -
Mattias Gaertner 8 years ago
parent
commit
58454f555a
2 changed files with 121 additions and 31 deletions
  1. 91 14
      packages/pastojs/src/fppas2js.pp
  2. 30 17
      packages/pastojs/tests/tcmodules.pas

+ 91 - 14
packages/pastojs/src/fppas2js.pp

@@ -43,6 +43,7 @@ Works:
   - modifier public to protect from removing by optimizer
   - modifier public to protect from removing by optimizer
   - choose overloads based on type and precision
   - choose overloads based on type and precision
   - fail overload on multiple with loss of precision or one used default param
   - fail overload on multiple with loss of precision or one used default param
+  - FuncName:=, auto rename lower lvl Result variables
 - assign statements
 - assign statements
 - char
 - char
   - literals
   - literals
@@ -110,6 +111,7 @@ Works:
   - const
   - const
   - bracket accessor, getter/setter has external name '[]'
   - bracket accessor, getter/setter has external name '[]'
   - TObject.Free sets variable to nil
   - TObject.Free sets variable to nil
+  - property stored and index modifier
 - dynamic arrays
 - dynamic arrays
   - arrays can be null
   - arrays can be null
   - init as "arr = []"  so typeof works
   - init as "arr = []"  so typeof works
@@ -223,7 +225,7 @@ Works:
   - callback: assign to jsvalue, equal, not equal
   - callback: assign to jsvalue, equal, not equal
 - RTTI
 - RTTI
   - base types
   - base types
-  - unit $rtti
+  - $mod.$rtti
   - enum type tkEnumeration
   - enum type tkEnumeration
   - set type tkSet
   - set type tkSet
   - procedure type  tkProcVar, tkMethod
   - procedure type  tkProcVar, tkMethod
@@ -241,7 +243,7 @@ Works:
     - typeinfo(class) -> class.$rtti
     - typeinfo(class) -> class.$rtti
   - WPO skip not used typeinfo
   - WPO skip not used typeinfo
   - open array param
   - open array param
-  - property stored modifier
+  - property stored and index modifier
   - property default value
   - property default value
 - pointer
 - pointer
   - compare with and assign nil
   - compare with and assign nil
@@ -251,22 +253,18 @@ Works:
 - dotted unit names, namespaces
 - dotted unit names, namespaces
 
 
 ToDos:
 ToDos:
-- ignore attributes
 - static arrays
 - static arrays
-  - a[][]
   - a[] of record
   - a[] of record
-  - RTTI
-- property index specifier
 - RTTI
 - RTTI
   - class property
   - class property
   - type alias type
   - type alias type
   - documentation
   - documentation
 - move local types to unit scope
 - move local types to unit scope
 - var absolute
 - var absolute
-- FuncName:= (instead of Result:=)
 - check memleaks
 - check memleaks
 - make records more lightweight
 - make records more lightweight
 - enumeration  for..in..do
 - enumeration  for..in..do
+- resourcestring
 - pointer of record
 - pointer of record
 - nested types in class
 - nested types in class
 - asm: pas() - useful for overloads and protect an identifier from optimization
 - asm: pas() - useful for overloads and protect an identifier from optimization
@@ -756,11 +754,20 @@ type
   end;
   end;
   TPas2JsElementDataClass = class of TPas2JsElementData;
   TPas2JsElementDataClass = class of TPas2JsElementData;
 
 
+  { TPas2JSClassScope }
+
   TPas2JSClassScope = class(TPasClassScope)
   TPas2JSClassScope = class(TPasClassScope)
   public
   public
     NewInstanceFunction: TPasClassFunction;
     NewInstanceFunction: TPasClassFunction;
   end;
   end;
 
 
+  { TPas2JSProcedureScope }
+
+  TPas2JSProcedureScope = class(TPasProcedureScope)
+  public
+    ResultVarName: string; // valid in implementation ProcScope, empty means use ResolverResultVar
+  end;
+
   { TPas2JSWithExprScope }
   { TPas2JSWithExprScope }
 
 
   TPas2JSWithExprScope = class(TPasWithExprScope)
   TPas2JSWithExprScope = class(TPasWithExprScope)
@@ -1918,6 +1925,47 @@ procedure TPas2JSResolver.ResolveNameExpr(El: TPasExpr; const aName: string;
     RaiseMsg(20170516152455,nFreeNeedsVar,sFreeNeedsVar,[],El);
     RaiseMsg(20170516152455,nFreeNeedsVar,sFreeNeedsVar,[],El);
   end;
   end;
 
 
+  procedure CheckResultEl(Ref: TResolvedReference);
+  var
+    Func: TPasFunction;
+    CurEl: TPasElement;
+    Lvl: Integer;
+    ProcScope, CurProcScope: TPas2JSProcedureScope;
+  begin
+    // result refers to a function result
+    // -> check if it is referring to a parent function result
+    Lvl:=0;
+    CurEl:=El;
+    CurProcScope:=nil;
+    while CurEl<>nil do
+      begin
+      if CurEl is TPasFunction then
+        begin
+        inc(Lvl);
+        ProcScope:=CurEl.CustomData as TPas2JSProcedureScope;
+        Func:=ProcScope.DeclarationProc as TPasFunction;
+        if Func=nil then
+          Func:=TPasFunction(CurEl);
+        if Lvl=1 then
+          begin
+          // current function (where the statement of El is)
+          if (Func.FuncType.ResultEl=Ref.Declaration) then
+            exit; // accessing current function -> ok
+          // accessing Result variable of higher function -> need rename
+          if ProcScope.ResultVarName<>'' then
+            exit; // is already renamed
+          CurProcScope:=ProcScope;
+          end;
+        end;
+      CurEl:=CurEl.Parent;
+      end;
+    if Lvl<2 then
+      RaiseNotYetImplemented(20171003112020,El);
+    // El refers to a higher Result variable
+    // -> current function needs another name for its Result variable
+    CurProcScope.ResultVarName:=ResolverResultVar+'$'+IntToStr(Lvl-1);
+  end;
+
 var
 var
   Ref: TResolvedReference;
   Ref: TResolvedReference;
 begin
 begin
@@ -1926,7 +1974,9 @@ begin
     begin
     begin
     Ref:=TResolvedReference(El.CustomData);
     Ref:=TResolvedReference(El.CustomData);
     if (CompareText(aName,'free')=0) then
     if (CompareText(aName,'free')=0) then
-      CheckTObjectFree(Ref);
+      CheckTObjectFree(Ref)
+    else if (Ref.Declaration is TPasResultElement) then
+      CheckResultEl(Ref);
     end;
     end;
 end;
 end;
 
 
@@ -2720,6 +2770,7 @@ begin
   StoreSrcColumns:=true;
   StoreSrcColumns:=true;
   Options:=Options+DefaultPasResolverOptions;
   Options:=Options+DefaultPasResolverOptions;
   ScopeClass_Class:=TPas2JSClassScope;
   ScopeClass_Class:=TPas2JSClassScope;
+  ScopeClass_Procedure:=TPas2JSProcedureScope;
   ScopeClass_WithExpr:=TPas2JSWithExprScope;
   ScopeClass_WithExpr:=TPas2JSWithExprScope;
   for bt in [pbtJSValue] do
   for bt in [pbtJSValue] do
     AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);
     AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);
@@ -4507,6 +4558,8 @@ var
   ProcType, TargetProcType: TPasProcedureType;
   ProcType, TargetProcType: TPasProcedureType;
   ArrLit: TJSArrayLiteral;
   ArrLit: TJSArrayLiteral;
   IndexExpr: TPasExpr;
   IndexExpr: TPasExpr;
+  Func: TPasFunction;
+  FuncScope: TPas2JSProcedureScope;
 begin
 begin
   Result:=nil;
   Result:=nil;
   if not (El.CustomData is TResolvedReference) then
   if not (El.CustomData is TResolvedReference) then
@@ -4683,7 +4736,7 @@ begin
 
 
   {$IFDEF VerbosePas2JS}
   {$IFDEF VerbosePas2JS}
   writeln('TPasToJSConverter.ConvertIdentifierExpr ',GetObjName(El),' Decl=',GetObjName(Decl),' Decl.Parent=',GetObjName(Decl.Parent));
   writeln('TPasToJSConverter.ConvertIdentifierExpr ',GetObjName(El),' Decl=',GetObjName(Decl),' Decl.Parent=',GetObjName(Decl.Parent));
-  //if CompareText(aName,'Self')=0 then
+  //if CompareText(aName,'Result')=0 then
   //  begin
   //  begin
   //  writeln('TPasToJSConverter.ConvertIdentifierExpr AContext=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext),' LocalVar=',AContext.GetLocalName(Decl),' ',GetObjName(Decl));
   //  writeln('TPasToJSConverter.ConvertIdentifierExpr AContext=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext),' LocalVar=',AContext.GetLocalName(Decl),' ',GetObjName(Decl));
   //  AContext.WriteStack;
   //  AContext.WriteStack;
@@ -4692,8 +4745,16 @@ begin
 
 
   if Decl is TPasModule then
   if Decl is TPasModule then
     Name:=TransformModuleName(TPasModule(Decl),true,AContext)
     Name:=TransformModuleName(TPasModule(Decl),true,AContext)
-  else if (Decl is TPasFunctionType) and (CompareText(ResolverResultVar,aName)=0) then
-    Name:=ResolverResultVar
+  else if (Decl is TPasResultElement) then
+    begin
+    Name:=ResolverResultVar;
+    Func:=Decl.Parent as TPasFunction;
+    FuncScope:=Func.CustomData as TPas2JSProcedureScope;
+    if FuncScope.ImplProc<>nil then
+      FuncScope:=FuncScope.ImplProc.CustomData as TPas2JSProcedureScope;
+    if FuncScope.ResultVarName<>'' then
+      Name:=FuncScope.ResultVarName;
+    end
   else if Decl.ClassType=TPasEnumValue then
   else if Decl.ClassType=TPasEnumValue then
     begin
     begin
     if UseEnumNumbers then
     if UseEnumNumbers then
@@ -6469,6 +6530,8 @@ function TPasToJSConverter.ConvertBuiltIn_Exit(El: TPasExpr;
 // convert "exit(param);" -> "return param;"
 // convert "exit(param);" -> "return param;"
 var
 var
   ProcEl: TPasElement;
   ProcEl: TPasElement;
+  Scope: TPas2JSProcedureScope;
+  VarName: String;
 begin
 begin
   Result:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
   Result:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
   if (El is TParamsExpr) and (length(TParamsExpr(El).Params)>0) then
   if (El is TParamsExpr) and (length(TParamsExpr(El).Params)>0) then
@@ -6483,8 +6546,14 @@ begin
     while (ProcEl<>nil) and not (ProcEl is TPasProcedure) do
     while (ProcEl<>nil) and not (ProcEl is TPasProcedure) do
       ProcEl:=ProcEl.Parent;
       ProcEl:=ProcEl.Parent;
     if ProcEl is TPasFunction then
     if ProcEl is TPasFunction then
+      begin
       // in a function, "return result;"
       // in a function, "return result;"
-      TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(ResolverResultVar,El)
+      Scope:=ProcEl.CustomData as TPas2JSProcedureScope;
+      VarName:=Scope.ResultVarName;
+      if VarName='' then
+        VarName:=ResolverResultVar;
+      TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(VarName,El);
+      end
     else
     else
       ; // in a procedure, "return;" which means "return undefined;"
       ; // in a procedure, "return;" which means "return undefined;"
     end;
     end;
@@ -7624,6 +7693,7 @@ Var
   ProcScope: TPasProcedureScope;
   ProcScope: TPasProcedureScope;
   ProcBody: TPasImplBlock;
   ProcBody: TPasImplBlock;
   ResultEl: TPasResultElement;
   ResultEl: TPasResultElement;
+  ResultVarName: String;
 
 
   Procedure Add(NewEl: TJSElement; PosEl: TPasElement);
   Procedure Add(NewEl: TJSElement; PosEl: TPasElement);
   begin
   begin
@@ -7646,14 +7716,20 @@ Var
     PasFun: TPasFunction;
     PasFun: TPasFunction;
     FunType: TPasFunctionType;
     FunType: TPasFunctionType;
     SrcEl: TPasElement;
     SrcEl: TPasElement;
+    Scope: TPas2JSProcedureScope;
   begin
   begin
     PasFun:=El.Parent as TPasFunction;
     PasFun:=El.Parent as TPasFunction;
     FunType:=PasFun.FuncType;
     FunType:=PasFun.FuncType;
     ResultEl:=FunType.ResultEl;
     ResultEl:=FunType.ResultEl;
+    Scope:=PasFun.CustomData as TPas2JSProcedureScope;
+    if Scope.ResultVarName<>'' then
+      ResultVarName:=Scope.ResultVarName
+    else
+      ResultVarName:=ResolverResultVar;
 
 
     // add 'var result=initvalue'
     // add 'var result=initvalue'
     SrcEl:=ResultEl;
     SrcEl:=ResultEl;
-    VarSt:=CreateVarStatement(ResolverResultVar,
+    VarSt:=CreateVarStatement(ResultVarName,
       CreateValInit(ResultEl.ResultType,nil,SrcEl,aContext),ResultEl);
       CreateValInit(ResultEl.ResultType,nil,SrcEl,aContext),ResultEl);
     Add(VarSt,ResultEl);
     Add(VarSt,ResultEl);
     Result:=SLFirst;
     Result:=SLFirst;
@@ -7664,7 +7740,7 @@ Var
     RetSt: TJSReturnStatement;
     RetSt: TJSReturnStatement;
   begin
   begin
     RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,ResultEl));
     RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,ResultEl));
-    RetSt.Expr:=CreatePrimitiveDotExpr(ResolverResultVar,ResultEl);
+    RetSt.Expr:=CreatePrimitiveDotExpr(ResultVarName,ResultEl);
     Add(RetSt,ResultEl);
     Add(RetSt,ResultEl);
   end;
   end;
 
 
@@ -7687,6 +7763,7 @@ begin
   SLFirst:=nil;
   SLFirst:=nil;
   SLLast:=nil;
   SLLast:=nil;
   ResultEl:=nil;
   ResultEl:=nil;
+  ResultVarName:='';
 
 
   if HasResult then
   if HasResult then
     AddFunctionResultInit;
     AddFunctionResultInit;

+ 30 - 17
packages/pastojs/tests/tcmodules.pas

@@ -2220,6 +2220,7 @@ begin
   Add('function Func1: longint;');
   Add('function Func1: longint;');
   Add('begin');
   Add('begin');
   Add('  Result:=3;');
   Add('  Result:=3;');
+  Add('  Func1:=4;');
   Add('end;');
   Add('end;');
   Add('begin');
   Add('begin');
   ConvertProgram;
   ConvertProgram;
@@ -2228,6 +2229,7 @@ begin
     'this.Func1 = function () {',
     'this.Func1 = function () {',
     '  var Result = 0;',
     '  var Result = 0;',
     '  Result = 3;',
     '  Result = 3;',
+    '  Result = 4;',
     '  return Result;',
     '  return Result;',
     '};'
     '};'
     ]),
     ]),
@@ -2237,20 +2239,26 @@ end;
 procedure TTestModule.TestNestedProc;
 procedure TTestModule.TestNestedProc;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
-  Add('var vInUnit: longint;');
-  Add('function DoIt(pA,pD: longint): longint;');
-  Add('var');
-  Add('  vB: longint;');
-  Add('  vC: longint;');
-  Add('  function Nesty(pA: longint): longint; ');
-  Add('  var vB: longint;');
-  Add('  begin');
-  Add('    Result:=pa+vb+vc+pd+vInUnit;');
-  Add('  end;');
-  Add('begin');
-  Add('  Result:=pa+vb+vc;');
-  Add('end;');
-  Add('begin');
+  Add([
+  'var vInUnit: longint;',
+  'function DoIt(pA,pD: longint): longint;',
+  'var',
+  '  vB: longint;',
+  '  vC: longint;',
+  '  function Nesty(pA: longint): longint; ',
+  '  var vB: longint;',
+  '  begin',
+  '    Result:=pa+vb+vc+pd+vInUnit;',
+  '    nesty:=3;',
+  '    doit:=4;',
+  '    exit;',
+  '  end;',
+  'begin',
+  '  Result:=pa+vb+vc;',
+  '  doit:=6;',
+  '  exit;',
+  'end;',
+  'begin']);
   ConvertProgram;
   ConvertProgram;
   CheckSource('TestNestedProc',
   CheckSource('TestNestedProc',
     LinesToStr([ // statements
     LinesToStr([ // statements
@@ -2260,12 +2268,17 @@ begin
     '  var vB = 0;',
     '  var vB = 0;',
     '  var vC = 0;',
     '  var vC = 0;',
     '  function Nesty(pA) {',
     '  function Nesty(pA) {',
-    '    var Result = 0;',
+    '    var Result$1 = 0;',
     '    var vB = 0;',
     '    var vB = 0;',
-    '    Result = (((pA + vB) + vC) + pD) + $mod.vInUnit;',
-    '    return Result;',
+    '    Result$1 = (((pA + vB) + vC) + pD) + $mod.vInUnit;',
+    '    Result$1 = 3;',
+    '    Result = 4;',
+    '    return Result$1;',
+    '    return Result$1;',
     '  };',
     '  };',
     '  Result = (pA + vB) + vC;',
     '  Result = (pA + vB) + vC;',
+    '  Result = 6;',
+    '  return Result;',
     '  return Result;',
     '  return Result;',
     '};'
     '};'
     ]),
     ]),