pastojs: added FindAvailableLocalName

git-svn-id: trunk@38454 -
This commit is contained in:
Mattias Gaertner 2018-03-08 10:58:26 +00:00
parent 5c6eb1b9a3
commit 27508cdd23
2 changed files with 182 additions and 14 deletions

View File

@ -1228,7 +1228,7 @@ type
TPasToJSConverter = Class(TObject)
private
// inline at top, only functions declared after the inline implementation actually use it
// inline at ttop, because fpc 3.1 requires inline implementation in front of use
function GetUseEnumNumbers: boolean; inline;
function GetUseLowerCase: boolean; inline;
function GetUseSwitchStatement: boolean; inline;
@ -1289,11 +1289,13 @@ type
Function IsPreservedWord(const aName: string): boolean; virtual;
Function GetTypeInfoName(El: TPasType; AContext: TConvertContext;
ErrorEl: TPasElement): String; virtual;
// Never create an element manually, always use the below functions
// utility functions for creating stuff
Function IsElementUsed(El: TPasElement): boolean; virtual;
Function IsSystemUnit(aModule: TPasModule): boolean; virtual;
Function HasTypeInfo(El: TPasType; AContext: TConvertContext): boolean; virtual;
Function IsClassRTTICreatedBefore(aClass: TPasClassType; Before: TPasElement; AConText: TConvertContext): boolean;
Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
// Never create an element manually, always use the below functions
Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
AContext : TConvertContext): TJSCallExpression; virtual;
@ -1375,7 +1377,7 @@ type
Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
Function CreatePropertyGet(Prop: TPasProperty; Ref: TResolvedReference;
AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
Function StorePrecompiledJS(El: TJSElement): string; virtual;
Function CreatePrecompiledJS(El: TJSElement): string; virtual;
// Statements
Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
@ -1545,7 +1547,6 @@ const
TempRefObjGetterName = 'get';
TempRefObjSetterName = 'set';
TempRefObjSetterArgName = 'v';
TempRefObjSetterArgNameAlt = 'p';
function CodePointToJSString(u: longword): TJSString;
begin
@ -9701,7 +9702,7 @@ begin
if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
begin
if AContext.Resolver.GetTopLvlProc(El)=El then
ImplProcScope.BodyJS:=StorePrecompiledJS(Result);
ImplProcScope.BodyJS:=CreatePrecompiledJS(Result);
end;
end;
@ -9801,7 +9802,7 @@ begin
end;
if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
Scope.JS:=StorePrecompiledJS(Result);
Scope.JS:=CreatePrecompiledJS(Result);
end;
function TPasToJSConverter.ConvertFinalizationSection(El: TFinalizationSection;
@ -11111,7 +11112,7 @@ begin
end;
end;
function TPasToJSConverter.StorePrecompiledJS(El: TJSElement): string;
function TPasToJSConverter.CreatePrecompiledJS(El: TJSElement): string;
var
aWriter: TBufferWriter;
aJSWriter: TJSWriter;
@ -12303,6 +12304,162 @@ begin
end;
end;
procedure TPasToJSConverter.FindAvailableLocalName(var aName: string;
JSExpr: TJSElement);
var
StartJSName, JSName: TJSString;
n: integer;
Changed: boolean;
procedure Next;
var
ch: WideChar;
begin
Changed:=true;
// name clash -> change JSName
if (n=0) and (length(JSName)=1) then
begin
// single letter -> choose next single letter
ch:=JSName[1];
case ch of
'a'..'x': JSName:=succ(ch);
'z': JSName:='a';
end;
if JSName=StartJSName then
begin
n:=1;
JSName:=StartJSName+TJSString(IntToStr(n));
end;
end
else
begin
inc(n);
JSName:=StartJSName+TJSString(IntToStr(n));
end;
end;
procedure Find(El: TJSElement);
var
C: TClass;
Call: TJSCallExpression;
i: Integer;
begin
if El=nil then exit;
C:=El.ClassType;
if C=TJSPrimaryExpressionIdent then
begin
if TJSPrimaryExpressionIdent(El).Name=JSName then
Next;
end
else if C.InheritsFrom(TJSMemberExpression) then
begin
Find(TJSMemberExpression(El).MExpr);
if C=TJSBracketMemberExpression then
Find(TJSBracketMemberExpression(El).Name)
else if C=TJSNewMemberExpression then
with TJSNewMemberExpression(El).Args.Elements do
for i:=0 to Count-1 do
Find(Elements[i].Expr)
end
else if C=TJSCallExpression then
begin
Call:=TJSCallExpression(El);
Find(Call.Expr);
if Call.Args<>nil then
with Call.Args.Elements do
for i:=0 to Count-1 do
Find(Elements[i].Expr);
end
else if C.InheritsFrom(TJSUnary) then
Find(TJSUnary(El).A)
else if C.InheritsFrom(TJSBinary) then
begin
Find(TJSBinary(El).A);
Find(TJSBinary(El).B);
end
else if C=TJSArrayLiteral then
begin
with TJSArrayLiteral(El).Elements do
for i:=0 to Count-1 do
Find(Elements[i].Expr);
end
else if C=TJSConditionalExpression then
begin
Find(TJSConditionalExpression(El).A);
Find(TJSConditionalExpression(El).B);
Find(TJSConditionalExpression(El).C);
end
else if C.InheritsFrom(TJSAssignStatement) then
begin
Find(TJSAssignStatement(El).LHS);
Find(TJSAssignStatement(El).Expr);
end
else if C=TJSVarDeclaration then
Find(TJSVarDeclaration(El).Init)
else if C=TJSObjectLiteral then
begin
with TJSObjectLiteral(El).Elements do
for i:=0 to Count-1 do
Find(Elements[i].Expr);
end
else if C=TJSIfStatement then
begin
Find(TJSIfStatement(El).Cond);
Find(TJSIfStatement(El).BTrue);
Find(TJSIfStatement(El).BFalse);
end
else if C.InheritsFrom(TJSBodyStatement) then
begin
Find(TJSBodyStatement(El).Body);
if C.InheritsFrom(TJSCondLoopStatement) then
begin
Find(TJSCondLoopStatement(El).Cond);
if C=TJSForStatement then
begin
Find(TJSForStatement(El).Init);
Find(TJSForStatement(El).Incr);
end;
end
else if C=TJSForInStatement then
begin
Find(TJSForInStatement(El).LHS);
Find(TJSForInStatement(El).List);
end;
end
else if C=TJSSwitchStatement then
begin
Find(TJSSwitchStatement(El).Cond);
with TJSSwitchStatement(El).Cases do
for i:=0 to Count-1 do
with Cases[i] do
begin
Find(Expr);
Find(Body);
end;
if TJSSwitchStatement(El).TheDefault<>nil then
with TJSSwitchStatement(El).TheDefault do
begin
Find(Expr);
Find(Body);
end;
end;
end;
begin
if JSExpr=nil then exit;
StartJSName:=TJSString(aName);
JSName:=StartJSName;
n:=0;
Changed:=false;
Find(JSExpr);
if not Changed then exit;
repeat
Changed:=false;
Find(JSExpr);
until not changed;
aName:=UTF8Encode(JSName);
end;
function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
var
unary: TJSUnary;
@ -13407,7 +13564,7 @@ var
GetPath, SetPath: String;
BracketExpr: TJSBracketMemberExpression;
DotExpr: TJSDotMemberExpression;
SetterArgName: Char;
SetterArgName: String;
begin
// pass reference -> create a temporary JS object with a FullGetter and setter
Obj:=nil;
@ -13575,9 +13732,7 @@ begin
// create SetExpr = v;
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
AssignSt.LHS:=SetExpr;
if (SetExpr is TJSPrimaryExpressionIdent)
and (TJSPrimaryExpressionIdent(SetExpr).Name=TJSString(SetterArgName)) then
SetterArgName:=TempRefObjSetterArgNameAlt;
FindAvailableLocalName(SetterArgName,SetExpr);
AssignSt.Expr:=CreatePrimitiveDotExpr(SetterArgName,El);
SetExpr:=AssignSt;
end
@ -13800,7 +13955,7 @@ begin
if Proc<>nil then
begin
ProcScope:=TPas2JSProcedureScope(Proc.CustomData);
ProcScope.AddGlobalJS(StorePrecompiledJS(V));
ProcScope.AddGlobalJS(CreatePrecompiledJS(V));
end;
end;
end

View File

@ -2987,8 +2987,10 @@ begin
' i:=i+2;',
'end;',
'procedure DoIt(v: longint);',
'var p: array of longint;',
'begin',
' Inc2(v);',
' Inc2(p[v]);',
'end;',
'begin']);
ConvertProgram;
@ -2998,11 +3000,22 @@ begin
' i.set(i.get()+2);',
'};',
'this.DoIt = function (v) {',
' var p = [];',
' $mod.Inc2({get: function () {',
' return v;',
' }, set: function (p) {',
' v = p;',
' }, set: function (w) {',
' v = w;',
' }});',
' $mod.Inc2({',
' a: v,',
' p: p,',
' get: function () {',
' return this.p[this.a];',
' },',
' set: function (v) {',
' this.p[this.a] = v;',
' }',
' });',
'};',
'']),
LinesToStr([