|
@@ -2308,8 +2308,6 @@ end;
|
|
procedure TPas2JSResolver.AddType(El: TPasType);
|
|
procedure TPas2JSResolver.AddType(El: TPasType);
|
|
begin
|
|
begin
|
|
inherited AddType(El);
|
|
inherited AddType(El);
|
|
- if (El.Name<>'') and (TopScope is TPasClassScope) then
|
|
|
|
- RaiseNotYetImplemented(20170608232534,El,'nested types');
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
|
|
procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
|
|
@@ -4446,7 +4444,11 @@ begin
|
|
else if ThisPas=El then
|
|
else if ThisPas=El then
|
|
Result:='this'
|
|
Result:='this'
|
|
else
|
|
else
|
|
|
|
+ begin
|
|
Result:=inherited GetLocalName(El);
|
|
Result:=inherited GetLocalName(El);
|
|
|
|
+ if Result='this' then
|
|
|
|
+ Result:='';
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TFunctionContext.IndexOfLocalVar(const aName: string): integer;
|
|
function TFunctionContext.IndexOfLocalVar(const aName: string): integer;
|
|
@@ -4636,17 +4638,23 @@ end;
|
|
|
|
|
|
procedure TConvertContext.WriteStack;
|
|
procedure TConvertContext.WriteStack;
|
|
{AllowWriteln}
|
|
{AllowWriteln}
|
|
|
|
+var
|
|
|
|
+ SelfCtx: TFunctionContext;
|
|
|
|
|
|
procedure W(Index: integer; AContext: TConvertContext);
|
|
procedure W(Index: integer; AContext: TConvertContext);
|
|
begin
|
|
begin
|
|
|
|
+ if AContext=SelfCtx then
|
|
|
|
+ writeln(' SelfContext:');
|
|
AContext.DoWriteStack(Index);
|
|
AContext.DoWriteStack(Index);
|
|
if AContext.Parent<>nil then
|
|
if AContext.Parent<>nil then
|
|
W(Index+1,AContext.Parent);
|
|
W(Index+1,AContext.Parent);
|
|
end;
|
|
end;
|
|
|
|
|
|
begin
|
|
begin
|
|
- writeln('TConvertContext.WriteStack: ');
|
|
|
|
|
|
+ SelfCtx:=GetSelfContext;
|
|
|
|
+ writeln('TConvertContext.WriteStack: START');
|
|
W(1,Self);
|
|
W(1,Self);
|
|
|
|
+ writeln('TConvertContext.WriteStack: END');
|
|
end;
|
|
end;
|
|
{AllowWriteln-}
|
|
{AllowWriteln-}
|
|
|
|
|
|
@@ -10683,10 +10691,12 @@ begin
|
|
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FnName]);
|
|
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FnName]);
|
|
|
|
|
|
// add parameter: owner. For top level class, the module is the owner.
|
|
// add parameter: owner. For top level class, the module is the owner.
|
|
- if (El.Parent<>nil) and (El.Parent.ClassType=TImplementationSection) then
|
|
|
|
- OwnerName:=AContext.GetLocalName(El.Parent)
|
|
|
|
|
|
+ if (El.Parent=nil)
|
|
|
|
+ or ((El.Parent is TPasSection)
|
|
|
|
+ and (El.Parent.ClassType<>TImplementationSection)) then
|
|
|
|
+ OwnerName:=AContext.GetLocalName(El.GetModule)
|
|
else
|
|
else
|
|
- OwnerName:=AContext.GetLocalName(El.GetModule);
|
|
|
|
|
|
+ OwnerName:=AContext.GetLocalName(El.Parent);
|
|
if OwnerName='' then
|
|
if OwnerName='' then
|
|
OwnerName:='this';
|
|
OwnerName:='this';
|
|
Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El));
|
|
Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El));
|
|
@@ -10782,10 +10792,7 @@ begin
|
|
else if C=TPasConst then
|
|
else if C=TPasConst then
|
|
NewEl:=ConvertConst(TPasConst(P),aContext)
|
|
NewEl:=ConvertConst(TPasConst(P),aContext)
|
|
else if C=TPasProperty then
|
|
else if C=TPasProperty then
|
|
- begin
|
|
|
|
- NewEl:=ConvertProperty(TPasProperty(P),AContext);
|
|
|
|
- if NewEl=nil then continue;
|
|
|
|
- end
|
|
|
|
|
|
+ NewEl:=ConvertProperty(TPasProperty(P),AContext)
|
|
else if C.InheritsFrom(TPasType) then
|
|
else if C.InheritsFrom(TPasType) then
|
|
NewEl:=CreateTypeDecl(TPasType(P),aContext)
|
|
NewEl:=CreateTypeDecl(TPasType(P),aContext)
|
|
else if C.InheritsFrom(TPasProcedure) then
|
|
else if C.InheritsFrom(TPasProcedure) then
|
|
@@ -10794,9 +10801,8 @@ begin
|
|
continue
|
|
continue
|
|
else
|
|
else
|
|
RaiseNotSupported(P,FuncContext,20161221233338);
|
|
RaiseNotSupported(P,FuncContext,20161221233338);
|
|
- if NewEl=nil then
|
|
|
|
- RaiseNotSupported(P,FuncContext,20170204223922);
|
|
|
|
- AddToSourceElements(Src,NewEl);
|
|
|
|
|
|
+ if NewEl<>nil then
|
|
|
|
+ AddToSourceElements(Src,NewEl);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -11810,35 +11816,40 @@ begin
|
|
if ProcScope.ClassScope<>nil then
|
|
if ProcScope.ClassScope<>nil then
|
|
begin
|
|
begin
|
|
// method or class method
|
|
// method or class method
|
|
- FuncContext.ThisPas:=ProcScope.ClassScope.Element;
|
|
|
|
- if bsObjectChecks in FuncContext.ScannerBoolSwitches then
|
|
|
|
|
|
+ if El.Parent is TProcedureBody then
|
|
begin
|
|
begin
|
|
- // rtl.checkMethodCall(this,<class>)
|
|
|
|
- Call:=CreateCallExpression(PosEl);
|
|
|
|
- AddBodyStatement(Call,PosEl);
|
|
|
|
- Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],
|
|
|
|
- FBuiltInNames[pbifnCheckMethodCall]]);
|
|
|
|
- Call.AddArg(CreatePrimitiveDotExpr('this',PosEl));
|
|
|
|
- ClassPath:=CreateReferencePath(ProcScope.ClassScope.Element,AContext,rpkPathAndName);
|
|
|
|
- Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- if ImplProc.Body.Functions.Count>0 then
|
|
|
|
- begin
|
|
|
|
- // has nested procs -> add "var self = this;"
|
|
|
|
- FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
|
|
|
|
- SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
|
|
|
|
- CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
|
|
|
|
- AddBodyStatement(SelfSt,PosEl);
|
|
|
|
- if ImplProcScope.SelfArg<>nil then
|
|
|
|
- begin
|
|
|
|
- // redirect Pascal-Self to JS-Self
|
|
|
|
- FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],ImplProcScope.SelfArg);
|
|
|
|
- end;
|
|
|
|
|
|
+ // nested sub procedure -> no 'this'
|
|
|
|
+ FuncContext.ThisPas:=nil;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- if ImplProcScope.SelfArg<>nil then
|
|
|
|
|
|
+ FuncContext.ThisPas:=ProcScope.ClassScope.Element;
|
|
|
|
+ if bsObjectChecks in FuncContext.ScannerBoolSwitches then
|
|
|
|
+ begin
|
|
|
|
+ // rtl.checkMethodCall(this,<class>)
|
|
|
|
+ Call:=CreateCallExpression(PosEl);
|
|
|
|
+ AddBodyStatement(Call,PosEl);
|
|
|
|
+ Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],
|
|
|
|
+ FBuiltInNames[pbifnCheckMethodCall]]);
|
|
|
|
+ Call.AddArg(CreatePrimitiveDotExpr('this',PosEl));
|
|
|
|
+ ClassPath:=CreateReferencePath(ProcScope.ClassScope.Element,AContext,rpkPathAndName);
|
|
|
|
+ Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if ImplProc.Body.Functions.Count>0 then
|
|
|
|
+ begin
|
|
|
|
+ // has nested procs -> add "var self = this;"
|
|
|
|
+ FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
|
|
|
|
+ SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
|
|
|
|
+ CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
|
|
|
|
+ AddBodyStatement(SelfSt,PosEl);
|
|
|
|
+ if ImplProcScope.SelfArg<>nil then
|
|
|
|
+ begin
|
|
|
|
+ // redirect Pascal-Self to JS-Self
|
|
|
|
+ FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],ImplProcScope.SelfArg);
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
|
|
+ else if ImplProcScope.SelfArg<>nil then
|
|
begin
|
|
begin
|
|
// no nested procs -> redirect Pascal-Self to JS-this
|
|
// no nested procs -> redirect Pascal-Self to JS-this
|
|
FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
|
|
FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
|
|
@@ -16267,12 +16278,41 @@ function TPasToJSConverter.CreateReferencePath(El: TPasElement;
|
|
Result:=CreateReferencePath(AbsolResolved.IdentEl,AContext,Kind,Full,Ref);
|
|
Result:=CreateReferencePath(AbsolResolved.IdentEl,AContext,Kind,Full,Ref);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+ function ImplToDecl(El: TPasElement): TPasElement;
|
|
|
|
+ var
|
|
|
|
+ ProcScope: TPasProcedureScope;
|
|
|
|
+ begin
|
|
|
|
+ Result:=El;
|
|
|
|
+ if El.CustomData is TPasProcedureScope then
|
|
|
|
+ begin
|
|
|
|
+ // proc: always use the declaration, not the body
|
|
|
|
+ ProcScope:=TPasProcedureScope(El.CustomData);
|
|
|
|
+ if ProcScope.DeclarationProc<>nil then
|
|
|
|
+ Result:=ProcScope.DeclarationProc;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ function IsA(SrcType, DstType: TPasType): boolean;
|
|
|
|
+ begin
|
|
|
|
+ while SrcType<>nil do
|
|
|
|
+ begin
|
|
|
|
+ if SrcType=DstType then exit(true);
|
|
|
|
+ if SrcType.ClassType=TPasClassType then
|
|
|
|
+ SrcType:=TPas2JSClassScope(SrcType.CustomData).DirectAncestor
|
|
|
|
+ else if (SrcType.ClassType=TPasAliasType)
|
|
|
|
+ or (SrcType.ClassType=TPasTypeAliasType) then
|
|
|
|
+ SrcType:=TPasAliasType(SrcType).DestType
|
|
|
|
+ else
|
|
|
|
+ exit(false);
|
|
|
|
+ end;
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+
|
|
var
|
|
var
|
|
FoundModule: TPasModule;
|
|
FoundModule: TPasModule;
|
|
ParentEl: TPasElement;
|
|
ParentEl: TPasElement;
|
|
Dot: TDotContext;
|
|
Dot: TDotContext;
|
|
WithData: TPas2JSWithExprScope;
|
|
WithData: TPas2JSWithExprScope;
|
|
- ProcScope: TPasProcedureScope;
|
|
|
|
ShortName: String;
|
|
ShortName: String;
|
|
SelfContext: TFunctionContext;
|
|
SelfContext: TFunctionContext;
|
|
ElClass: TClass;
|
|
ElClass: TClass;
|
|
@@ -16346,7 +16386,7 @@ begin
|
|
end
|
|
end
|
|
else if (ElClass=TPasClassType) and TPasClassType(El).IsExternal then
|
|
else if (ElClass=TPasClassType) and TPasClassType(El).IsExternal then
|
|
begin
|
|
begin
|
|
- // an external var -> use the literal
|
|
|
|
|
|
+ // an external class -> use the literal
|
|
Result:=TPasClassType(El).ExternalName;
|
|
Result:=TPasClassType(El).ExternalName;
|
|
exit;
|
|
exit;
|
|
end
|
|
end
|
|
@@ -16355,24 +16395,12 @@ begin
|
|
// need full path
|
|
// need full path
|
|
if El.Parent=nil then
|
|
if El.Parent=nil then
|
|
RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
|
|
RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
|
|
- if (El.CustomData is TPasProcedureScope) then
|
|
|
|
- begin
|
|
|
|
- // proc: always use the declaration, not the body
|
|
|
|
- ProcScope:=TPasProcedureScope(El.CustomData);
|
|
|
|
- if ProcScope.DeclarationProc<>nil then
|
|
|
|
- El:=ProcScope.DeclarationProc;
|
|
|
|
- end;
|
|
|
|
|
|
+ El:=ImplToDecl(El);
|
|
|
|
|
|
ParentEl:=El.Parent;
|
|
ParentEl:=El.Parent;
|
|
while ParentEl<>nil do
|
|
while ParentEl<>nil do
|
|
begin
|
|
begin
|
|
- if (ParentEl.CustomData is TPasProcedureScope) then
|
|
|
|
- begin
|
|
|
|
- // proc: always use the the declaration, not the body
|
|
|
|
- ProcScope:=TPasProcedureScope(ParentEl.CustomData);
|
|
|
|
- if ProcScope.DeclarationProc<>nil then
|
|
|
|
- ParentEl:=ProcScope.DeclarationProc;
|
|
|
|
- end;
|
|
|
|
|
|
+ ParentEl:=ImplToDecl(ParentEl);
|
|
|
|
|
|
// check if there is a local var
|
|
// check if there is a local var
|
|
ShortName:=AContext.GetLocalName(ParentEl);
|
|
ShortName:=AContext.GetLocalName(ParentEl);
|
|
@@ -16410,37 +16438,62 @@ begin
|
|
Prepend(Result,ParentEl.Name)
|
|
Prepend(Result,ParentEl.Name)
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- // Pascal and JS have similar scoping rules (we are not in a dotscope),
|
|
|
|
- // so 'this' can be used.
|
|
|
|
|
|
+ // Not in a Pascal dotscope and accessing a class member.
|
|
|
|
+ // Possible results: this.v, module.path.path.v, this.path.v
|
|
|
|
+ // In nested proc 'this' can have another name, e.g. '$Self'
|
|
SelfContext:=AContext.GetSelfContext;
|
|
SelfContext:=AContext.GetSelfContext;
|
|
if ShortName<>'' then
|
|
if ShortName<>'' then
|
|
- Result:=ShortName
|
|
|
|
- else if AContext.GetFunctionContext.ThisPas<>nil then
|
|
|
|
- Result:='this'
|
|
|
|
- else if SelfContext<>nil then
|
|
|
|
- Result:=SelfContext.GetLocalName(SelfContext.ThisPas)
|
|
|
|
|
|
+ Prepend(Result,ShortName)
|
|
|
|
+ else if (El.Parent<>ParentEl) or (El is TPasType) then
|
|
|
|
+ Prepend(Result,ParentEl.Name)
|
|
|
|
+ else if (SelfContext<>nil)
|
|
|
|
+ and IsA(TPasType(SelfContext.ThisPas),TPasType(ParentEl)) then
|
|
|
|
+ begin
|
|
|
|
+ ShortName:=SelfContext.GetLocalName(SelfContext.ThisPas);
|
|
|
|
+ Prepend(Result,ShortName);
|
|
|
|
+ end
|
|
else
|
|
else
|
|
|
|
+ begin
|
|
|
|
+ // missing JS var for Self
|
|
|
|
+ {$IFDEF VerbosePas2JS}
|
|
|
|
+ writeln('TPasToJSConverter.CreateReferencePath missing JS var for Self: El=',El.FullName,':',El.ClassName,' CurParentEl=',ParentEl.FullName,':',ParentEl.ClassName,' AContext:');
|
|
|
|
+ AContext.WriteStack;
|
|
|
|
+ {$ENDIF}
|
|
RaiseNotSupported(El,AContext,20180125004049);
|
|
RaiseNotSupported(El,AContext,20180125004049);
|
|
- if (SelfContext<>nil) and not IsClassFunction(SelfContext.PasElement) then
|
|
|
|
|
|
+ end;
|
|
|
|
+ if (El.Parent=ParentEl) and (SelfContext<>nil)
|
|
|
|
+ and not IsClassFunction(SelfContext.PasElement) then
|
|
begin
|
|
begin
|
|
// inside a method -> Self is a class instance
|
|
// inside a method -> Self is a class instance
|
|
if El is TPasVariable then
|
|
if El is TPasVariable then
|
|
begin
|
|
begin
|
|
//writeln('TPasToJSConverter.CreateReferencePath class var ',GetObjName(El),' This=',GetObjName(This));
|
|
//writeln('TPasToJSConverter.CreateReferencePath class var ',GetObjName(El),' This=',GetObjName(This));
|
|
|
|
+ // Note: reading a class var does not need accessing the class
|
|
|
|
+ // For example: read v -> this.v
|
|
|
|
+ // write v -> this.$class.v
|
|
if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
|
|
if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
|
|
and (AContext.Access=caAssign) then
|
|
and (AContext.Access=caAssign) then
|
|
begin
|
|
begin
|
|
- Append_GetClass(El); // writing a class var
|
|
|
|
|
|
+ Append_GetClass(El); // writing a class var
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
else if IsClassFunction(El) then
|
|
else if IsClassFunction(El) then
|
|
Append_GetClass(El); // accessing a class function
|
|
Append_GetClass(El); // accessing a class function
|
|
end;
|
|
end;
|
|
- break;
|
|
|
|
|
|
+ if ShortName<>'' then
|
|
|
|
+ break;
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
else if ParentEl.ClassType=TPasEnumType then
|
|
else if ParentEl.ClassType=TPasEnumType then
|
|
- Prepend(Result,ParentEl.Name);
|
|
|
|
|
|
+ begin
|
|
|
|
+ if (ShortName<>'') and not Full then
|
|
|
|
+ begin
|
|
|
|
+ Prepend(Result,ShortName);
|
|
|
|
+ break;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Prepend(Result,ParentEl.Name);
|
|
|
|
+ end;
|
|
ParentEl:=ParentEl.Parent;
|
|
ParentEl:=ParentEl.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|