pastojs: implemented funcname:=

git-svn-id: trunk@37389 -
This commit is contained in:
Mattias Gaertner 2017-10-03 16:08:59 +00:00
parent abd8907939
commit 58454f555a
2 changed files with 121 additions and 31 deletions

View File

@ -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 else if (Decl is TPasResultElement) then
Name:=ResolverResultVar 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;

View File

@ -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([
Add('function DoIt(pA,pD: longint): longint;'); 'var vInUnit: longint;',
Add('var'); 'function DoIt(pA,pD: longint): longint;',
Add(' vB: longint;'); 'var',
Add(' vC: longint;'); ' vB: longint;',
Add(' function Nesty(pA: longint): longint; '); ' vC: longint;',
Add(' var vB: longint;'); ' function Nesty(pA: longint): longint; ',
Add(' begin'); ' var vB: longint;',
Add(' Result:=pa+vb+vc+pd+vInUnit;'); ' begin',
Add(' end;'); ' Result:=pa+vb+vc+pd+vInUnit;',
Add('begin'); ' nesty:=3;',
Add(' Result:=pa+vb+vc;'); ' doit:=4;',
Add('end;'); ' exit;',
Add('begin'); ' 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;', ' Result$1 = (((pA + vB) + vC) + pD) + $mod.vInUnit;',
' return Result;', ' 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;',
'};' '};'
]), ]),