pastojs: filer: write/restore proc body js

git-svn-id: trunk@38378 -
This commit is contained in:
Mattias Gaertner 2018-02-28 13:49:59 +00:00
parent a1033eb1af
commit b4c9f54d89
4 changed files with 395 additions and 226 deletions

View File

@ -363,8 +363,9 @@ unit FPPas2Js;
interface
uses
Classes, SysUtils, math, contnrs, jsbase, jstree, PasTree, PScanner,
PasResolver, PasResolveEval;
Classes, SysUtils, math, contnrs,
jsbase, jstree, jswriter,
PasTree, PScanner, PasResolveEval, PasResolver;
// message numbers
const
@ -827,6 +828,8 @@ type
TPas2JSProcedureScope = class(TPasProcedureScope)
public
ResultVarName: string; // valid in implementation ProcScope, empty means use ResolverResultVar
// Option coStoreProcJS
BodyJS: string;// stored in ImplScope
end;
{ TPas2JSWithExprScope }
@ -1167,7 +1170,8 @@ type
coEnumNumbers, // use enum numbers instead of names
coUseStrict, // insert 'use strict'
coNoTypeInfo, // do not generate RTTI
coEliminateDeadCode // skip code that is never executed
coEliminateDeadCode, // skip code that is never executed
coStoreProcJS // store references to JS code in procscopes
);
TPasToJsConverterOptions = set of TPasToJsConverterOption;
@ -1255,7 +1259,7 @@ type
Procedure DoError(Id: int64; MsgNumber: integer; const MsgPattern: string; Const Args : Array of Const; El: TPasElement);
procedure RaiseNotSupported(El: TPasElement; AContext: TConvertContext; Id: int64; const Msg: string = '');
procedure RaiseIdentifierNotFound(Identifier: string; El: TPasElement; Id: int64);
procedure RaiseInconsistency(Id: int64);
procedure RaiseInconsistency(Id: int64; El: TPasElement);
// Computation, value conversions
Function GetExpressionValueType(El: TPasExpr; AContext: TConvertContext ): TJSType; virtual;
Function GetPasIdentValueType(AName: String; AContext: TConvertContext): TJSType; virtual;
@ -1355,6 +1359,7 @@ type
Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
Function CreatePropertyGet(Prop: TPasProperty; Ref: TResolvedReference;
AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
Procedure StorePrecompiledProcedure(ImplProc: TPasProcedure; JS: TJSElement); virtual;
// Statements
Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
@ -4086,14 +4091,14 @@ begin
//writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr Ref.Declaration=',GetObjName(Ref.Declaration));
Proc:=Ref.Declaration as TPasProcedure;
if Proc.Name='' then
RaiseInconsistency(20170125191914);
RaiseInconsistency(20170125191914,Proc);
//writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr Proc.Name=',Proc.Name);
ProcScope:=Proc.CustomData as TPasProcedureScope;
//writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr ProcScope.Element=',GetObjName(ProcScope.Element),' ProcScope.ClassScope=',GetObjName(ProcScope.ClassScope),' ProcScope.DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ProcScope.ImplProc=',GetObjName(ProcScope.ImplProc),' ProcScope.CustomData=',GetObjName(ProcScope.CustomData));
ClassScope:=ProcScope.ClassScope;
aClass:=ClassScope.Element;
if aClass.Name='' then
RaiseInconsistency(20170125191923);
RaiseInconsistency(20170125191923,aClass);
//writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr aClass.Name=',aClass.Name);
C:=CreateCallExpression(Ref.Element);
ok:=false;
@ -4775,7 +4780,7 @@ begin
AContext.Access:=caRead;
Left:=ConvertElement(El.left,AContext);
if Left=nil then
RaiseInconsistency(20170201140821);
RaiseInconsistency(20170201140821,El);
AContext.Access:=OldAccess;
// convert right side
DotContext:=TDotContext.Create(El,Left,AContext);
@ -5103,7 +5108,7 @@ begin
RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
end;
if Result=nil then
RaiseInconsistency(20170214120048);
RaiseInconsistency(20170214120048,Decl);
exit;
end;
@ -5182,7 +5187,7 @@ function TPasToJSConverter.ConvertInheritedExpression(El: TInheritedExpr;
Result:=nil;
SelfContext:=AContext.GetSelfContext;
if SelfContext=nil then
RaiseInconsistency(20170418114702);
RaiseInconsistency(20170418114702,El);
SelfName:=SelfContext.GetLocalName(SelfContext.ThisPas);
if Apply and (SelfContext<>AContext) then
@ -5197,11 +5202,11 @@ function TPasToJSConverter.ConvertInheritedExpression(El: TInheritedExpr;
// -> use the direct ancestor class of the current proc
aClass:=SelfContext.ThisPas as TPasClassType;
if aClass.CustomData=nil then
RaiseInconsistency(20170323111252);
RaiseInconsistency(20170323111252,aClass);
ClassScope:=TPasClassScope(aClass.CustomData);
AncestorScope:=ClassScope.AncestorScope;
if AncestorScope=nil then
RaiseInconsistency(20170323111306);
RaiseInconsistency(20170323111306,aClass);
AncestorClass:=AncestorScope.Element as TPasClassType;
FunName:=CreateReferencePath(AncestorClass,AContext,rpkPathAndName,true)
+'.'+TransformVariableName(AncestorProc,AContext);
@ -5409,7 +5414,7 @@ var
// s[index] := value
AssignContext:=AContext.AccessContext as TAssignContext;
if AssignContext.RightSide=nil then
RaiseInconsistency(20180123192020);
RaiseInconsistency(20180123192020,El);
AssignSt:=nil;
SetStrCall:=nil;
@ -5654,7 +5659,7 @@ var
Arg:=nil;
inc(ArgNo);
if ArgNo>length(El.Params) then
RaiseInconsistency(20170206180553);
RaiseInconsistency(20170206180553,El);
end;
if ArgNo=length(El.Params) then
break;
@ -5712,7 +5717,7 @@ var
Result:=true;
// bracket accessor of external class
if AContext.Resolver.GetPasPropertyArgs(Prop).Count<>1 then
RaiseInconsistency(20170403003753);
RaiseInconsistency(20170403003753,Prop);
// bracket accessor of external class -> create PathEl[param]
Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El.Params[0]));
try
@ -5822,7 +5827,7 @@ var
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertArrayParams.ConvertIndexedProperty missing default value: Prop=',Prop.Name,' i=',i);
{$ENDIF}
RaiseInconsistency(20170206185126);
RaiseInconsistency(20170206185126,TargetArg);
end;
AContext.Access:=caRead;
Arg:=ConvertElement(TargetArg.ValueExpr,ArgContext);
@ -5932,7 +5937,7 @@ Var
aClass: TPasClassType;
begin
if El.Kind<>pekArrayParams then
RaiseInconsistency(20170209113713);
RaiseInconsistency(20170209113713,El);
ArgContext:=AContext;
while ArgContext is TDotContext do
ArgContext:=ArgContext.Parent;
@ -5984,7 +5989,7 @@ begin
// anObject[]
ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty)
else
RaiseInconsistency(20170206180448);
RaiseInconsistency(20170206180448,aClass);
end
else if TypeEl.ClassType=TPasClassOfType then
begin
@ -5992,7 +5997,7 @@ begin
DestType:=AContext.Resolver.ResolveAliasType(TPasClassOfType(TypeEl).DestType);
ClassScope:=DestType.CustomData as TPas2JSClassScope;
if ClassScope.DefaultProperty=nil then
RaiseInconsistency(20170206180503);
RaiseInconsistency(20170206180503,DestType);
ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty);
end
else if TypeEl.ClassType=TPasArrayType then
@ -6025,7 +6030,7 @@ var
begin
Result:=nil;
if El.Kind<>pekFuncParams then
RaiseInconsistency(20170209113515);
RaiseInconsistency(20170209113515,El);
//writeln('TPasToJSConverter.ConvertFuncParams START pekFuncParams ',GetObjName(El.CustomData),' ',GetObjName(El.Value.CustomData));
Call:=nil;
Elements:=nil;
@ -6078,7 +6083,7 @@ begin
RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
end;
if Result=nil then
RaiseInconsistency(20170210121932);
RaiseInconsistency(20170210121932,El);
exit;
end
else if Decl.CustomData is TResElDataBaseType then
@ -6318,7 +6323,7 @@ begin
NewExpr:=nil;
end
else
RaiseInconsistency(20170323083214);
RaiseInconsistency(20170323083214,Proc);
finally
ExtNameEl.Free;
NewExpr.Free;
@ -6367,7 +6372,7 @@ begin
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.ConvertTObjectFree With=',GetObjName(WithExprScope.Expr));
{$ENDIF}
RaiseInconsistency(20170517092248);
RaiseInconsistency(20170517092248,Bin);
end;
LeftJS:=ConvertElement(Bin.left,AContext);
@ -6379,7 +6384,7 @@ begin
begin
aName:=TJSPrimaryExpressionIdent(LeftJS).Name;
if Pos('.',aName)>0 then
RaiseInconsistency(20170516173832);
RaiseInconsistency(20170516173832,Bin.left);
// v.free
// -> v=rtl.freeLoc(v);
Getter:=LeftJS;
@ -6704,7 +6709,7 @@ var
ArgEl: TPasExpr;
begin
if El.Kind<>pekSet then
RaiseInconsistency(20170209112737);
RaiseInconsistency(20170209112737,El);
if AContext.Access<>caRead then
DoError(20170209112926,nCantWriteSetLiteral,sCantWriteSetLiteral,[],El);
if length(El.Params)=0 then
@ -6840,7 +6845,7 @@ begin
Result:=nil;
Param0:=El.Params[0];
if AContext.Access<>caRead then
RaiseInconsistency(20170213213621);
RaiseInconsistency(20170213213621,El);
AContext.Resolver.ComputeElement(Param0,ResolvedParam0,[rcNoImplicitProc]);
{$IFDEF VerbosePasResolver}
writeln('TPasToJSConverter.ConvertBuiltInSetLength ',GetResolverResultDbg(ResolvedParam0));
@ -7107,7 +7112,7 @@ var
begin
Result:=nil;
if AContext.Resolver=nil then
RaiseInconsistency(20170210105235);
RaiseInconsistency(20170210105235,El);
Param:=El.Params[0];
AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProcType]);
{$IFDEF VerbosePas2JS}
@ -7164,7 +7169,7 @@ var
begin
Result:=nil;
if AContext.Resolver=nil then
RaiseInconsistency(20170325185847);
RaiseInconsistency(20170325185847,El);
Param:=El.Params[0];
AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
if ParamResolved.BaseType in btAllJSInteger then
@ -7192,7 +7197,7 @@ var
begin
Result:=nil;
if AContext.Resolver=nil then
RaiseInconsistency(20170210105235);
RaiseInconsistency(20170210105235,El);
Param:=El.Params[0];
AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
if ParamResolved.BaseType=btChar then
@ -7218,7 +7223,7 @@ begin
Minus:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
Call.AddArg(Minus);
if length(SubParams.Params)<>1 then
RaiseInconsistency(20170405231706);
RaiseInconsistency(20170405231706,El);
Minus.A:=ConvertElement(SubParams.Params[0],AContext);
Minus.B:=CreateLiteralNumber(Param,1);
Result:=Call;
@ -7295,7 +7300,7 @@ var
begin
Result:=nil;
if AContext.Resolver=nil then
RaiseInconsistency(20170210120659);
RaiseInconsistency(20170210120659,El);
Param:=El.Params[0];
AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
case ResolvedEl.BaseType of
@ -7456,7 +7461,7 @@ var
begin
Result:=nil;
if AContext.Resolver=nil then
RaiseInconsistency(20170210120648);
RaiseInconsistency(20170210120648,El);
Param:=El.Params[0];
AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
if (ResolvedEl.BaseType in btAllJSInteger)
@ -7655,7 +7660,7 @@ var
i: Integer;
begin
if length(El.Params)<1 then
RaiseInconsistency(20170331000332);
RaiseInconsistency(20170331000332,El);
if length(El.Params)=1 then
begin
// concat(array1) -> array1
@ -7727,9 +7732,9 @@ begin
Param:=El.Params[0];
AContext.Resolver.ComputeElement(El,ParamResolved,[]);
if ParamResolved.BaseType<>btContext then
RaiseInconsistency(20170401003242);
RaiseInconsistency(20170401003242,El);
if ParamResolved.TypeEl.ClassType<>TPasArrayType then
RaiseInconsistency(20170401003256);
RaiseInconsistency(20170401003256,El);
ArrayType:=TPasArrayType(ParamResolved.TypeEl);
AContext.Resolver.ComputeElement(ArrayType.ElType,ElTypeResolved,[rcType]);
// rtl.arrayCopy(type,src,start,count)
@ -8014,7 +8019,7 @@ var
Ident: TJSPrimaryExpressionIdent;
begin
if AName='' then
RaiseInconsistency(20170402230134);
RaiseInconsistency(20170402230134,Src);
p:=PosLast('.',AName);
if p>0 then
begin
@ -8764,7 +8769,7 @@ begin
// module.$rtti.$Class("classname");
Result:=CreateRTTINewType(aClass,FBuiltInNames[pbifnRTTINewClass],true,AContext,ObjLit);
if ObjLit<>nil then
RaiseInconsistency(20170412093427);
RaiseInconsistency(20170412093427,El);
end;
function TPasToJSConverter.ConvertClassExternalType(El: TPasClassType;
@ -8846,7 +8851,7 @@ begin
// prepend module.$rtti.$Class("classname");
Call:=CreateRTTINewType(DestType,FBuiltInNames[pbifnRTTINewClass],true,AContext,ObjLit);
if ObjLit<>nil then
RaiseInconsistency(20170412102654);
RaiseInconsistency(20170412102654,El);
List:=TJSStatementList(CreateElement(TJSStatementList,El));
List.A:=Call;
List.B:=Result;
@ -9488,7 +9493,7 @@ Var
n, i:Integer;
AssignSt: TJSSimpleAssignStatement;
FuncContext: TFunctionContext;
ProcScope, ImplProcScope: TPasProcedureScope;
ProcScope, ImplProcScope: TPas2JSProcedureScope;
Arg: TPasArgument;
SelfSt: TJSVariableStatement;
ImplProc: TPasProcedure;
@ -9504,7 +9509,7 @@ begin
if El.IsAbstract then exit;
if El.IsExternal then exit;
ProcScope:=TPasProcedureScope(El.CustomData);
ProcScope:=TPas2JSProcedureScope(El.CustomData);
if ProcScope.DeclarationProc<>nil then
exit;
@ -9515,7 +9520,7 @@ begin
ImplProc:=El;
if ProcScope.ImplProc<>nil then
ImplProc:=ProcScope.ImplProc;
ImplProcScope:=TPasProcedureScope(ImplProc.CustomData);
ImplProcScope:=TPas2JSProcedureScope(ImplProc.CustomData);
AssignSt:=nil;
if AContext.IsGlobal then
@ -9535,6 +9540,7 @@ begin
Result:=FS;
FD.Name:=TJSString(TransformVariableName(El,AContext));
end;
for n := 0 to El.ProcType.Args.Count - 1 do
begin
Arg:=TPasArgument(El.ProcType.Args[n]);
@ -9625,6 +9631,9 @@ begin
FuncContext.Free;
end;
end;
if coStoreProcJS in Options then
StorePrecompiledProcedure(ImplProc,Result);
end;
function TPasToJSConverter.ConvertBeginEndStatement(El: TPasImplBeginBlock;
@ -10062,7 +10071,7 @@ begin
// create implementation declarations
ImplDecl:=ConvertDeclarations(El.ImplementationSection,ImplContext);
if ImplDecl<>nil then
RaiseInconsistency(20170910175032); // elements should have been added directly
RaiseInconsistency(20170910175032,El); // elements should have been added directly
if Src.Statements[Src.Statements.Count-1].Node=ImplVarSt then
exit; // no implementation
// add impl declarations
@ -10095,9 +10104,9 @@ var
begin
Result:=nil;
if Left=nil then
RaiseInconsistency(20170201140827);
RaiseInconsistency(20170201140827,aParent);
if Right=nil then
RaiseInconsistency(20170211192018);
RaiseInconsistency(20170211192018,aParent);
ok:=false;
try
// create a TJSDotMemberExpression of Left and the left-most identifier of Right
@ -10160,7 +10169,7 @@ begin
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.CreateDotExpression Right=',GetObjName(Right),' RightParent=',GetObjName(RightParent),' Result=',GetObjName(Result));
{$ENDIF}
RaiseInconsistency(20170129141307);
RaiseInconsistency(20170129141307,aParent);
end;
Dot.MExpr := Left;
Dot.Name := TJSPrimaryExpressionIdent(Right).Name;
@ -10261,7 +10270,7 @@ var
begin
Result:=nil;
if not (ResolvedEl.IdentEl is TPasProcedure) then
RaiseInconsistency(20170215140756);
RaiseInconsistency(20170215140756,El);
Target:=ConvertElement(El,AContext);
@ -10370,7 +10379,7 @@ begin
if AssignContext.RightSide<>nil then
begin
LHS.Free;
RaiseInconsistency(20170207215447);
RaiseInconsistency(20170207215447,LeftEl);
end;
Result:=LHS;
end
@ -10502,7 +10511,7 @@ begin
// get module path
aModule:=El.GetModule;
if aModule=nil then
RaiseInconsistency(20170418115552);
RaiseInconsistency(20170418115552,El);
RttiPath:=AContext.GetLocalName(aModule);
if RttiPath='' then
RttiPath:=TransformModuleName(aContext.GetRootModule,true,AContext);
@ -10730,7 +10739,7 @@ begin
try
// stored <const bool>
if StoredValue.Kind<>revkBool then
RaiseInconsistency(20170924082845);
RaiseInconsistency(20170924082845,Prop);
StoredExpr:=nil;
if TResEvalBool(StoredValue).B then
inc(Flags,pfStoredTrue)
@ -11016,6 +11025,29 @@ begin
end;
end;
procedure TPasToJSConverter.StorePrecompiledProcedure(ImplProc: TPasProcedure;
JS: TJSElement);
var
ImplScope: TPas2JSProcedureScope;
aWriter: TBufferWriter;
aJSWriter: TJSWriter;
begin
ImplScope:=TPas2JSProcedureScope(ImplProc.CustomData);
if ImplScope.ImplProc<>nil then
RaiseInconsistency(20180228124545,ImplProc);
aJSWriter:=nil;
aWriter:=TBufferWriter.Create(1000);
try
aJSWriter:=TJSWriter.Create(aWriter);
aJSWriter.IndentSize:=2;
aJSWriter.WriteJS(JS);
ImplScope.BodyJS:=aWriter.AsAnsistring;
finally
aJSWriter.Free;
aWriter.Free;
end;
end;
function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
AContext: TConvertContext): TJSElement;
@ -11232,7 +11264,7 @@ begin
begin
// left side is a Setter -> RightSide was already inserted as parameter
if AssignContext.RightSide<>nil then
RaiseInconsistency(20170207215544);
RaiseInconsistency(20170207215544,El.left);
Result:=LHS;
end
else
@ -11719,7 +11751,7 @@ Var
begin
Result:=Nil;
if AContext.Access<>caRead then
RaiseInconsistency(20170213213740);
RaiseInconsistency(20170213213740,El);
ForScope:=El.CustomData as TPasForLoopScope; // can be nil!
case El.LoopType of
ltNormal,ltDown: ;
@ -12054,7 +12086,7 @@ begin
// $with1.X = 3;
FuncContext:=TFunctionContext(AContext.GetContextOfType(TFunctionContext));
if FuncContext=nil then
RaiseInconsistency(20170212003759);
RaiseInconsistency(20170212003759,El);
FirstSt:=nil;
LastSt:=nil;
try
@ -12167,7 +12199,7 @@ begin
Result:=false;
if aClass.Parent=nil then exit;
if not aClass.Parent.InheritsFrom(TPasDeclarations) then
RaiseInconsistency(20170412101457);
RaiseInconsistency(20170412101457,aClass);
Decls:=TPasDeclarations(aClass.Parent);
Types:=Decls.Types;
for i:=0 to Types.Count-1 do
@ -12190,11 +12222,6 @@ begin
end;
end;
procedure TPasToJSConverter.RaiseInconsistency(Id: int64);
begin
raise Exception.Create('TPasToJSConverter.RaiseInconsistency['+IntToStr(Id)+']: you found a bug');
end;
function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
var
unary: TJSUnary;
@ -12384,7 +12411,7 @@ begin
begin
if AContext.Resolver=nil then
exit(CreateLiteralUndefined(El));
RaiseInconsistency(20170415185745);
RaiseInconsistency(20170415185745,El);
end;
Result:=ConvertElement(Expr,AContext);
if Result=nil then
@ -12662,7 +12689,7 @@ var
JS: TJSString;
begin
if Lit.Value.ValueType<>jstString then
RaiseInconsistency(20171112020856);
RaiseInconsistency(20171112020856,ErrorEl);
if Lit.Value.CustomValue<>'' then
JS:=Lit.Value.CustomValue
else
@ -12814,7 +12841,7 @@ var
BinExpr: TJSBinaryExpression;
begin
if not (OpCode in [eopEqual,eopNotEqual]) then
RaiseInconsistency(20170401184819);
RaiseInconsistency(20170401184819,El);
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
Call.AddArg(JSArray);
@ -13018,7 +13045,7 @@ begin
// in other unit -> use pas.unitname.$impl
FoundModule:=El.GetModule;
if FoundModule=nil then
RaiseInconsistency(20161024192755);
RaiseInconsistency(20161024192755,El);
Prepend(Result,TransformModuleName(FoundModule,true,AContext)
+'.'+FBuiltInNames[pbivnImplementation]);
end;
@ -13334,7 +13361,7 @@ begin
{$IFDEF VerbosePas2JS}
writeln('TPasToJSConverter.CreateProcedureCallArg FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
{$ENDIF}
RaiseInconsistency(20170213222941);
RaiseInconsistency(20170213222941,El);
end;
// create "{p:Result,get:function(){return this.p.Getter},set:function(v){this.p.Setter(v);}}"
@ -13344,7 +13371,7 @@ begin
begin
// create "{get:function(){return FullGetter;},set:function(v){FullGetter=v;}}"
if (ParamContext.Getter<>nil) and (ParamContext.Getter<>FullGetter) then
RaiseInconsistency(20170213224339);
RaiseInconsistency(20170213224339,El);
GetPath:=String(TJSPrimaryExpressionIdent(FullGetter).Name);
GetDotPos:=PosLast('.',GetPath);
if GetDotPos>0 then
@ -13471,7 +13498,7 @@ begin
else if (SetExpr.ClassType=TJSCallExpression) then
// has already the form Func(v)
else
RaiseInconsistency(20170213225940);
RaiseInconsistency(20170213225940,El);
// add p:GetPathExpr
AddVar(GetPathName,GetPathExpr);
@ -13717,7 +13744,7 @@ begin
if El=nil then
begin
Result:=nil;
RaiseInconsistency(20161024190203);
RaiseInconsistency(20161024190203,El);
end;
C:=El.ClassType;
if (C=TPasConst) then
@ -14067,7 +14094,7 @@ begin
// module.$rtti.$Record("typename",{});
Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewRecord],false,AContext,ObjLit);
if ObjLit=nil then
RaiseInconsistency(20170412124804);
RaiseInconsistency(20170412124804,El);
if El.Members.Count>0 then
begin
// module.$rtti.$Record("typename",{}).addFields(
@ -14168,6 +14195,23 @@ begin
raise E;
end;
procedure TPasToJSConverter.RaiseInconsistency(Id: int64; El: TPasElement);
var
s: String;
begin
s:='TPasToJSConverter.RaiseInconsistency['+IntToStr(Id)+']: you found a bug';
if El<>nil then
begin
s:=s+El.FullName;
if El.Name<>'' then
s:=s+El.Name
else
s:=s+GetElementTypeName(El);
s:=s+' at '+TPas2JSResolver.GetDbgSourcePosStr(El);
end;
raise Exception.Create(s);
end;
function TPasToJSConverter.TransformVariableName(El: TPasElement;
const AName: String; AContext: TConvertContext): String;
var
@ -14176,7 +14220,7 @@ var
begin
if AContext=nil then ;
if Pos('.',AName)>0 then
RaiseInconsistency(20170203164711);
RaiseInconsistency(20170203164711,El);
if UseLowerCase then
Result:=LowerCase(AName)
else
@ -14299,7 +14343,7 @@ begin
Result:='';
El:=AContext.Resolver.ResolveAliasType(El);
if El=nil then
RaiseInconsistency(20170409172756);
RaiseInconsistency(20170409172756,El);
if El=AContext.PasElement then
begin
// referring to itself

View File

@ -26,15 +26,16 @@ Works:
- resolving forward references
- restore resolver scopes
- restore resolved references and access flags
- write+read compiled proc body
ToDo:
- test restoring types
- test restoring expressions
- interface/implementation references
- store converted proc implementation
- store references
- code
- local const
- store only used elements, not unneeded privates
- use stored converted proc implementation
- WPO uses Proc.References
- store converted initialization/finalization
- use stored converted initialization/finalization
- uses section
@ -52,7 +53,7 @@ interface
uses
Classes, Types, SysUtils, contnrs, AVL_Tree, crc,
fpjson, jsonparser, jsonscanner,
PasTree, PScanner, PParser, PasResolveEval, PasResolver, PasUseAnalyzer,
PasTree, PScanner, PParser, PasResolveEval, PasResolver,
Pas2jsFileUtils, FPPas2Js;
const
@ -183,14 +184,15 @@ const
'ObjectChecks'
);
PJUDefaultConvertOptions: TPasToJsConverterOptions = [];
PJUDefaultConvertOptions: TPasToJsConverterOptions = [coStoreProcJS];
PJUConverterOptions: array[TPasToJsConverterOption] of string = (
'LowerCase',
'SwitchStatement',
'EnumNumbers',
'UseStrict',
'NoTypeInfo',
'EliminateDeadCode'
'EliminateDeadCode',
'StoreProcJS'
);
PJUDefaultTargetPlatform = PlatformBrowser;
@ -590,7 +592,7 @@ type
TPJUWriter = class(TPJUFiler)
private
FAnalyzer: TPasAnalyzer;
FConverter: TPasToJSConverter;
FElementIdCounter: integer;
FSourceFilesSorted: TPJUSourceFileArray;
FInImplementation: boolean;
@ -686,13 +688,12 @@ type
constructor Create; override;
destructor Destroy; override;
procedure Clear; override;
procedure WritePJU(aResolver: TPas2JSResolver;
procedure WritePJU(aResolver: TPas2JSResolver; aConverter: TPasToJSConverter;
InitFlags: TPJUInitialFlags; aStream: TStream; Compressed: boolean); virtual;
function WriteJSON(aResolver: TPas2JSResolver;
function WriteJSON(aResolver: TPas2JSResolver; aConverter: TPasToJSConverter;
InitFlags: TPJUInitialFlags): TJSONObject; virtual;
function IndexOfSourceFile(const Filename: string): integer;
property SourceFilesSorted: TPJUSourceFileArray read FSourceFilesSorted;
property Analyzer: TPasAnalyzer read FAnalyzer;
end;
{ TPJUReaderContext }
@ -859,6 +860,7 @@ type
const PropName: string; const DefaultValue: TPasProcedureScopeFlags): TPasProcedureScopeFlags; virtual;
procedure ReadProcedureScope(Obj: TJSONObject; Scope: TPas2JSProcedureScope; aContext: TPJUReaderContext); virtual;
procedure ReadProcScopeReferences(Obj: TJSONObject; ImplScope: TPas2JSProcedureScope); virtual;
procedure ReadProcedureBody(Obj: TJSONObject; El: TPasProcedure; aContext: TPJUReaderContext); virtual;
procedure ReadProcedure(Obj: TJSONObject; El: TPasProcedure; aContext: TPJUReaderContext); virtual;
procedure ReadOperator(Obj: TJSONObject; El: TPasOperator; aContext: TPJUReaderContext); virtual;
// ToDo: procedure ReadExternalReferences(ParentJSON: TJSONObject); virtual;
@ -2857,13 +2859,13 @@ procedure TPJUWriter.WriteProcedure(Obj: TJSONObject; El: TPasProcedure;
var
DefProcMods: TProcedureModifiers;
Scope: TPas2JSProcedureScope;
List: TFPList;
Refs: TFPList;
Arr: TJSONArray;
i: Integer;
PSRef: TPasProcScopeReference;
SubObj: TJSONObject;
DeclProc: TPasProcedure;
DeclScope: TPasProcedureScope;
DeclScope: TPas2JsProcedureScope;
Ref: TPJUFilerElementRef;
begin
WritePasElement(Obj,El,aContext);
@ -2896,40 +2898,49 @@ begin
if (Scope.ImplProc=nil) and (El.Body<>nil) then
begin
// Note: the References are stored in the declaration scope,
// but in the JSON of the implementation scope, so that
// Note: although the References are in the declaration scope,
// they are stored with the implementation scope, so that
// all references can be resolved immediately by the reader
DeclProc:=Scope.DeclarationProc;
if DeclProc=nil then
DeclProc:=El;
DeclScope:=NoNil(DeclProc.CustomData) as TPasProcedureScope;
DeclScope:=NoNil(DeclProc.CustomData) as TPas2JSProcedureScope;
// write references
if DeclScope.References=nil then
Analyzer.AnalyzeProcRefs(DeclProc);
List:=DeclScope.GetReferences;
try
if List.Count>0 then
begin
Arr:=TJSONArray.Create;
Obj.Add('ProcRefs',Arr);
for i:=0 to List.Count-1 do
if DeclScope.References<>nil then
begin
Refs:=DeclScope.GetReferences;
try
if Refs.Count>0 then
begin
PSRef:=TPasProcScopeReference(List[i]);
Ref:=GetElementReference(PSRef.Element);
if (Ref.Id=0) and not (Ref.Element is TPasUnresolvedSymbolRef) then
RaiseMsg(20180221170307,El,GetObjName(Ref.Element));
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
if PSRef.Access<>PJUDefaultPSRefAccess then
SubObj.Add('Access',PJUPSRefAccessNames[PSRef.Access]);
AddReferenceToObj(SubObj,'Id',PSRef.Element);
Arr:=TJSONArray.Create;
Obj.Add('ProcRefs',Arr);
for i:=0 to Refs.Count-1 do
begin
PSRef:=TPasProcScopeReference(Refs[i]);
Ref:=GetElementReference(PSRef.Element);
if (Ref.Id=0) and not (Ref.Element is TPasUnresolvedSymbolRef) then
RaiseMsg(20180221170307,El,GetObjName(Ref.Element));
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
if PSRef.Access<>PJUDefaultPSRefAccess then
SubObj.Add('Access',PJUPSRefAccessNames[PSRef.Access]);
AddReferenceToObj(SubObj,'Id',PSRef.Element);
end;
end;
end;
finally
Analyzer.Clear;
List.Free;
end;
finally
Refs.Free;
end;
end;
// precompiled body
if Scope.BodyJS<>'' then
begin
Obj.Add('Body',Scope.BodyJS);
// ToDo: globals
end;
end;
if (Scope.BodyJS<>'') and (Scope.ImplProc<>nil) then
RaiseMsg(20180228142831,El);
end;
procedure TPJUWriter.WriteOperator(Obj: TJSONObject; El: TPasOperator;
@ -3006,12 +3017,10 @@ end;
constructor TPJUWriter.Create;
begin
inherited Create;
FAnalyzer:=TPasAnalyzer.Create;
end;
destructor TPJUWriter.Destroy;
begin
FreeAndNil(FAnalyzer);
inherited Destroy;
end;
@ -3025,7 +3034,8 @@ begin
end;
procedure TPJUWriter.WritePJU(aResolver: TPas2JSResolver;
InitFlags: TPJUInitialFlags; aStream: TStream; Compressed: boolean);
aConverter: TPasToJSConverter; InitFlags: TPJUInitialFlags; aStream: TStream;
Compressed: boolean);
var
CurIndent: integer;
Spaces: string;
@ -3157,7 +3167,7 @@ var
aJSON: TJSONObject;
begin
CurIndent:=0;
aJSON:=WriteJSON(aResolver,InitFlags);
aJSON:=WriteJSON(aResolver,aConverter,InitFlags);
try
WriteObj(aJSON);
finally
@ -3166,12 +3176,13 @@ begin
end;
function TPJUWriter.WriteJSON(aResolver: TPas2JSResolver;
InitFlags: TPJUInitialFlags): TJSONObject;
aConverter: TPasToJSConverter; InitFlags: TPJUInitialFlags): TJSONObject;
var
Obj, JSMod: TJSONObject;
aContext: TPJUWriterContext;
begin
Result:=nil;
FConverter:=aConverter;
FResolver:=aResolver;
FParser:=Resolver.CurrentParser;
FScanner:=FParser.Scanner;
@ -3180,8 +3191,6 @@ begin
aContext:=nil;
Obj:=TJSONObject.Create;
try
Analyzer.Clear;
Analyzer.Resolver:=aResolver;
WriteHeaderMagic(Obj);
WriteHeaderVersion(Obj);
WriteInitialFlags(Obj);
@ -3200,7 +3209,6 @@ begin
aContext.Free;
if Result=nil then
Obj.Free;
Analyzer.Clear;
end;
end;
@ -5781,6 +5789,19 @@ begin
end;
end;
procedure TPJUReader.ReadProcedureBody(Obj: TJSONObject; El: TPasProcedure;
aContext: TPJUReaderContext);
var
ImplScope: TPas2JSProcedureScope;
s: string;
begin
ImplScope:=TPas2JSProcedureScope(El.CustomData);
if not ReadString(Obj,'Body',s,El) then
RaiseMsg(20180228131232,El);
ImplScope.BodyJS:=s;
if aContext=nil then ;
end;
procedure TPJUReader.ReadProcedure(Obj: TJSONObject; El: TPasProcedure;
aContext: TPJUReaderContext);
var
@ -5848,7 +5869,9 @@ begin
if Obj.Find('ImplProc')=nil then
ReadProcScopeReferences(Obj,Scope);
// ToDo: Body : TProcedureBody;
if Obj.Find('Body')<>nil then
ReadProcedureBody(Obj,El,aContext);
end;
procedure TPJUReader.ReadOperator(Obj: TJSONObject; El: TPasOperator;

View File

@ -40,10 +40,13 @@ type
FPJUWriter: TPJUWriter;
procedure OnFilerGetSrc(Sender: TObject; aFilename: string; out p: PChar;
out Count: integer);
function OnConverterIsElementUsed(Sender: TObject; El: TPasElement): boolean;
function OnConverterIsTypeInfoUsed(Sender: TObject; El: TPasElement): boolean;
protected
procedure SetUp; override;
procedure TearDown; override;
procedure ConvertModule; override;
function CreateConverter: TPasToJSConverter; override;
procedure ParseUnit; override;
procedure WriteReadUnit; virtual;
procedure StartParsing; override;
function CheckRestoredObject(const Path: string; Orig, Rest: TObject): boolean; virtual;
@ -164,12 +167,27 @@ begin
end;
end;
function TCustomTestPrecompile.OnConverterIsElementUsed(Sender: TObject;
El: TPasElement): boolean;
begin
Result:=Analyzer.IsUsed(El);
end;
function TCustomTestPrecompile.OnConverterIsTypeInfoUsed(Sender: TObject;
El: TPasElement): boolean;
begin
Result:=Analyzer.IsTypeInfoUsed(El);
end;
procedure TCustomTestPrecompile.SetUp;
begin
inherited SetUp;
FInitialFlags:=TPJUInitialFlags.Create;
FAnalyzer:=TPasAnalyzer.Create;
Analyzer.Resolver:=Engine;
Analyzer.Options:=Analyzer.Options+[paoProcImplReferences];
Converter.OnIsElementUsed:=@OnConverterIsElementUsed;
Converter.OnIsTypeInfoUsed:=@OnConverterIsTypeInfoUsed;
end;
procedure TCustomTestPrecompile.TearDown;
@ -181,10 +199,16 @@ begin
inherited TearDown;
end;
procedure TCustomTestPrecompile.ConvertModule;
function TCustomTestPrecompile.CreateConverter: TPasToJSConverter;
begin
Result:=inherited CreateConverter;
Result.Options:=Result.Options+[coStoreProcJS];
end;
procedure TCustomTestPrecompile.ParseUnit;
begin
inherited ParseUnit;
Analyzer.AnalyzeModule(Module);
inherited ConvertModule;
end;
procedure TCustomTestPrecompile.WriteReadUnit;
@ -208,7 +232,7 @@ begin
try
try
PJUWriter.OnGetSrc:=@OnFilerGetSrc;
PJUWriter.WritePJU(Engine,InitialFlags,ms,false);
PJUWriter.WritePJU(Engine,Converter,InitialFlags,ms,false);
except
on E: Exception do
begin
@ -484,10 +508,35 @@ end;
procedure TCustomTestPrecompile.CheckRestoredProcScope(const Path: string;
Orig, Rest: TPas2JSProcedureScope);
var
OrigList, RestList: TStringList;
i: Integer;
begin
CheckRestoredReference(Path+'.DeclarationProc',Orig.DeclarationProc,Rest.DeclarationProc);
CheckRestoredReference(Path+'.ImplProc',Orig.ImplProc,Rest.ImplProc);
CheckRestoredProcScopeRefs(Path+'.References',Orig,Rest);
if Orig.BodyJS<>Rest.BodyJS then
begin
writeln('TCustomTestPrecompile.CheckRestoredProcScope ',Path,'.BodyJS diff:');
OrigList:=TStringList.Create;
RestList:=TStringList.Create;
try
OrigList.Text:=Orig.BodyJS;
RestList.Text:=Rest.BodyJS;
for i:=0 to OrigList.Count-1 do
begin
if i>=RestList.Count then
Fail(Path+'.BodyJS RestLine missing: '+OrigList[i]);
writeln(' ',i,': '+OrigList[i]);
end;
if OrigList.Count<RestList.Count then
Fail(Path+'.BodyJS RestLine too much: '+RestList[OrigList.Count]);
finally
OrigList.Free;
RestList.Free;
end;
end;
if Rest.DeclarationProc=nil then
begin
AssertEquals(Path+'.ResultVarName',Orig.ResultVarName,Rest.ResultVarName);
@ -517,6 +566,7 @@ var
i: Integer;
OrigRef, RestRef: TPasProcScopeReference;
begin
// check References of a proc with implementation
CheckRestoredObject(Path,Orig.References,Rest.References);
OrigList:=nil;
RestList:=nil;
@ -1344,6 +1394,9 @@ begin
' j:=Abs(d);',
' Result:=j;',
'end;',
'procedure NotUsed;',
'begin',
'end;',
'']);
WriteReadUnit;
end;

View File

@ -580,6 +580,7 @@ type
function LinesToStr(Args: array of const): string;
function ExtractFileUnitName(aFilename: string): string;
function JSToStr(El: TJSElement): string;
function CheckSrcDiff(Expected, Actual: string; out Msg: string): boolean;
implementation
@ -638,6 +639,158 @@ begin
end;
end;
function CheckSrcDiff(Expected, Actual: string; out Msg: string): boolean;
// search diff, ignore changes in spaces
const
SpaceChars = [#9,#10,#13,' '];
var
ExpectedP, ActualP: PChar;
function FindLineEnd(p: PChar): PChar;
begin
Result:=p;
while not (Result^ in [#0,#10,#13]) do inc(Result);
end;
function FindLineStart(p, MinP: PChar): PChar;
begin
while (p>MinP) and not (p[-1] in [#10,#13]) do dec(p);
Result:=p;
end;
procedure DiffFound;
var
ActLineStartP, ActLineEndP, p, StartPos: PChar;
ExpLine, ActLine: String;
i: Integer;
begin
writeln('Diff found "',Msg,'". Lines:');
// write correct lines
p:=PChar(Expected);
repeat
StartPos:=p;
while not (p^ in [#0,#10,#13]) do inc(p);
ExpLine:=copy(Expected,StartPos-PChar(Expected)+1,p-StartPos);
if p^ in [#10,#13] then
begin
if (p[1] in [#10,#13]) and (p^<>p[1]) then
inc(p,2)
else
inc(p);
end;
if (p<=ExpectedP) and (p^<>#0) then
begin
writeln('= ',ExpLine);
end else begin
// diff line
// write actual line
ActLineStartP:=FindLineStart(ActualP,PChar(Actual));
ActLineEndP:=FindLineEnd(ActualP);
ActLine:=copy(Actual,ActLineStartP-PChar(Actual)+1,ActLineEndP-ActLineStartP);
writeln('- ',ActLine);
// write expected line
writeln('+ ',ExpLine);
// write empty line with pointer ^
for i:=1 to 2+ExpectedP-StartPos do write(' ');
writeln('^');
Msg:='expected "'+ExpLine+'", but got "'+ActLine+'".';
CheckSrcDiff:=false;
exit;
end;
until p^=#0;
writeln('DiffFound Actual:-----------------------');
writeln(Actual);
writeln('DiffFound Expected:---------------------');
writeln(Expected);
writeln('DiffFound ------------------------------');
Msg:='diff found, but lines are the same, internal error';
CheckSrcDiff:=false;
end;
var
IsSpaceNeeded: Boolean;
LastChar, Quote: Char;
begin
Result:=true;
Msg:='';
if Expected='' then Expected:=' ';
if Actual='' then Actual:=' ';
ExpectedP:=PChar(Expected);
ActualP:=PChar(Actual);
repeat
//writeln('TTestModule.CheckDiff Exp="',ExpectedP^,'" Act="',ActualP^,'"');
case ExpectedP^ of
#0:
begin
// check that rest of Actual has only spaces
while ActualP^ in SpaceChars do inc(ActualP);
if ActualP^<>#0 then
begin
DiffFound;
exit;
end;
exit(true);
end;
' ',#9,#10,#13:
begin
// skip space in Expected
IsSpaceNeeded:=false;
if ExpectedP>PChar(Expected) then
LastChar:=ExpectedP[-1]
else
LastChar:=#0;
while ExpectedP^ in SpaceChars do inc(ExpectedP);
if (LastChar in ['a'..'z','A'..'Z','0'..'9','_','$'])
and (ExpectedP^ in ['a'..'z','A'..'Z','0'..'9','_','$']) then
IsSpaceNeeded:=true;
if IsSpaceNeeded and (not (ActualP^ in SpaceChars)) then
begin
DiffFound;
exit;
end;
while ActualP^ in SpaceChars do inc(ActualP);
end;
'''','"':
begin
while ActualP^ in SpaceChars do inc(ActualP);
if ExpectedP^<>ActualP^ then
begin
DiffFound;
exit;
end;
Quote:=ExpectedP^;
repeat
inc(ExpectedP);
inc(ActualP);
if ExpectedP^<>ActualP^ then
begin
DiffFound;
exit;
end;
if (ExpectedP^ in [#0,#10,#13]) then
break
else if (ExpectedP^=Quote) then
begin
inc(ExpectedP);
inc(ActualP);
break;
end;
until false;
end;
else
while ActualP^ in SpaceChars do inc(ActualP);
if ExpectedP^<>ActualP^ then
begin
DiffFound;
exit;
end;
inc(ExpectedP);
inc(ActualP);
end;
until false;
end;
{ TTestEnginePasResolver }
procedure TTestEnginePasResolver.SetModule(AValue: TPasModule);
@ -1217,114 +1370,11 @@ end;
procedure TCustomTestModule.CheckDiff(Msg, Expected, Actual: string);
// search diff, ignore changes in spaces
const
SpaceChars = [#9,#10,#13,' '];
var
ExpectedP, ActualP: PChar;
function FindLineEnd(p: PChar): PChar;
begin
Result:=p;
while not (Result^ in [#0,#10,#13]) do inc(Result);
end;
function FindLineStart(p, MinP: PChar): PChar;
begin
while (p>MinP) and not (p[-1] in [#10,#13]) do dec(p);
Result:=p;
end;
procedure DiffFound;
var
ActLineStartP, ActLineEndP, p, StartPos: PChar;
ExpLine, ActLine: String;
i: Integer;
begin
writeln('Diff found "',Msg,'". Lines:');
// write correct lines
p:=PChar(Expected);
repeat
StartPos:=p;
while not (p^ in [#0,#10,#13]) do inc(p);
ExpLine:=copy(Expected,StartPos-PChar(Expected)+1,p-StartPos);
if p^ in [#10,#13] then
begin
if (p[1] in [#10,#13]) and (p^<>p[1]) then
inc(p,2)
else
inc(p);
end;
if (p<=ExpectedP) and (p^<>#0) then
begin
writeln('= ',ExpLine);
end else begin
// diff line
// write actual line
ActLineStartP:=FindLineStart(ActualP,PChar(Actual));
ActLineEndP:=FindLineEnd(ActualP);
ActLine:=copy(Actual,ActLineStartP-PChar(Actual)+1,ActLineEndP-ActLineStartP);
writeln('- ',ActLine);
// write expected line
writeln('+ ',ExpLine);
// write empty line with pointer ^
for i:=1 to 2+ExpectedP-StartPos do write(' ');
writeln('^');
AssertEquals(Msg,ExpLine,ActLine);
break;
end;
until p^=#0;
writeln('DiffFound Actual:-----------------------');
writeln(Actual);
writeln('DiffFound Expected:---------------------');
writeln(Expected);
writeln('DiffFound ------------------------------');
Fail('diff found, but lines are the same, internal error');
end;
var
IsSpaceNeeded: Boolean;
LastChar: Char;
s: string;
begin
if Expected='' then Expected:=' ';
if Actual='' then Actual:=' ';
ExpectedP:=PChar(Expected);
ActualP:=PChar(Actual);
repeat
//writeln('TTestModule.CheckDiff Exp="',ExpectedP^,'" Act="',ActualP^,'"');
case ExpectedP^ of
#0:
begin
// check that rest of Actual has only spaces
while ActualP^ in SpaceChars do inc(ActualP);
if ActualP^<>#0 then
DiffFound;
exit;
end;
' ',#9,#10,#13:
begin
// skip space in Expected
IsSpaceNeeded:=false;
if ExpectedP>PChar(Expected) then
LastChar:=ExpectedP[-1]
else
LastChar:=#0;
while ExpectedP^ in SpaceChars do inc(ExpectedP);
if (LastChar in ['a'..'z','A'..'Z','0'..'9','_','$'])
and (ExpectedP^ in ['a'..'z','A'..'Z','0'..'9','_','$']) then
IsSpaceNeeded:=true;
if IsSpaceNeeded and (not (ActualP^ in SpaceChars)) then
DiffFound;
while ActualP^ in SpaceChars do inc(ActualP);
end;
else
while ActualP^ in SpaceChars do inc(ActualP);
if ExpectedP^<>ActualP^ then
DiffFound;
inc(ExpectedP);
inc(ActualP);
end;
until false;
if CheckSrcDiff(Expected,Actual,s) then exit;
Fail(Msg+': '+s);
end;
procedure TCustomTestModule.CheckUnit(Filename, ExpectedSrc: string);
@ -5515,7 +5565,6 @@ begin
Add(' end;');
Add('end;');
ConvertUnit;
// ToDo: check use analyzer
CheckSource('TestAsmPas_Impl',
LinesToStr([
'var $impl = $mod.$impl;',