pastojs: writer: external reference queue

git-svn-id: trunk@38564 -
This commit is contained in:
Mattias Gaertner 2018-03-18 13:00:59 +00:00
parent df4d675339
commit afb706b772
7 changed files with 164 additions and 57 deletions

View File

@ -191,6 +191,7 @@ ToDo:
- array+array
- pointer type, ^type, @ operator, [] operator
- type alias type
- set of CharRange
- object
- interfaces
- implements, supports

View File

@ -10052,10 +10052,10 @@ begin
if Value=nil then
RaiseNotSupported(El,AContext,20170910211948);
case Value.Kind of
revkNil:
Result:=CreateLiteralNull(El);
revkBool:
Result:=CreateLiteralBoolean(El,TResEvalBool(Value).B);
revkEnum:
Result:=CreateReferencePathExpr(TResEvalEnum(Value).GetEnumValue,AContext);
revkInt:
Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
revkUInt:
@ -10066,6 +10066,8 @@ begin
Result:=CreateLiteralString(El,TResEvalString(Value).S);
revkUnicodeString:
Result:=CreateLiteralJSString(El,TResEvalUTF16(Value).S);
revkEnum:
Result:=CreateReferencePathExpr(TResEvalEnum(Value).GetEnumValue,AContext);
revkSetOfInt:
if Value.IdentEl is TPasExpr then
Result:=ConvertElement(Value.IdentEl,AContext)

View File

@ -262,6 +262,7 @@ type
procedure HandleEParserError(E: EParserError);
procedure HandleEPasResolve(E: EPasResolve);
procedure HandleEPas2JS(E: EPas2JS);
procedure HandleEPCUReader(E: EPas2JsReadError);
procedure HandleUnknownException(E: Exception);
procedure HandleException(E: Exception);
procedure DoLogMsgAtEl(MsgType: TMessageType; const Msg: string;
@ -1051,6 +1052,20 @@ begin
Compiler.Terminate(ExitCodeConverterError);
end;
procedure TPas2jsCompilerFile.HandleEPCUReader(E: EPas2JsReadError);
var
Reader: TPCUCustomReader;
begin
if E.Owner is TPCUCustomReader then
begin
Reader:=TPCUCustomReader(E.Owner);
Log.Log(mtError,E.Message);
end else begin
Log.Log(mtError,E.Message);
end;
Compiler.Terminate(ExitCodePCUError);
end;
procedure TPas2jsCompilerFile.HandleUnknownException(E: Exception);
begin
if not (E is ECompilerTerminate) then
@ -1073,6 +1088,8 @@ begin
HandleEPasResolve(EPasResolve(E))
else if E is EPas2JS then
HandleEPas2JS(EPas2JS(E))
else if E is EPas2JsReadError then
HandleEPCUReader(EPas2JsReadError(E))
else if E is EFileNotFoundError then
begin
Log.Log(mtFatal,E.Message);

View File

@ -14,7 +14,12 @@
**********************************************************************
Abstract:
Write and read a precompiled module (pcu).
Write and read a precompiled module (pcu, gzipped json).
- Built-In symbols are collected in one array.
- symbols of this module are stored in a tree
- external references are stored in used module trees. They can refer
recursively to other external references, so they are collected in a Queue.
Works:
- store used source files and checksums
@ -191,7 +196,7 @@ const
'ObjectChecks'
);
PCUDefaultConverterOptions: TPasToJsConverterOptions = [coStoreImplJS];
PCUDefaultConverterOptions: TPasToJsConverterOptions = [coUseStrict];
PCUConverterOptions: array[TPasToJsConverterOption] of string = (
'LowerCase',
'SwitchStatement',
@ -539,6 +544,7 @@ type
Pending: TPCUFilerPendingElRef;
Obj: TJSONObject;
Elements: TJSONArray; // for external references
NextNewExt: TPCUFilerElementRef; // next new external reference
procedure AddPending(Item: TPCUFilerPendingElRef);
procedure Clear;
destructor Destroy; override;
@ -570,6 +576,7 @@ type
function GetDefaultExprHasEvalValue(Expr: TPasExpr): boolean; virtual;
function GetSrcCheckSum(aFilename: string): TPCUSourceFileChecksum; virtual;
function GetElementReference(El: TPasElement; AutoCreate: boolean = true): TPCUFilerElementRef;
function CreateElementRef(El: TPasElement): TPCUFilerElementRef; virtual;
procedure AddedBuiltInRef(Ref: TPCUFilerElementRef); virtual;
public
constructor Create; virtual;
@ -645,6 +652,7 @@ type
FInImplementation: boolean;
FBuiltInSymbolsArr: TJSONArray;
protected
FFirstNewExt, FLastNewExt: TPCUFilerElementRef; // not yet stored external references
procedure RaiseMsg(Id: int64; const Msg: string = ''); override; overload;
procedure ResolvePendingElRefs(Ref: TPCUFilerElementRef);
function CheckElScope(El: TPasElement; NotNilId: int64; ScopeClass: TPasScopeClass): TPasScope; virtual;
@ -654,6 +662,7 @@ type
procedure AddReferenceToObj(Obj: TJSONObject; const PropName: string;
El: TPasElement; WriteNil: boolean = false); virtual;
procedure CreateElReferenceId(Ref: TPCUFilerElementRef); virtual;
function CreateElementRef(El: TPasElement): TPCUFilerElementRef; override;
procedure AddedBuiltInRef(Ref: TPCUFilerElementRef); override;
protected
procedure WriteHeaderMagic(Obj: TJSONObject); virtual;
@ -1469,18 +1478,23 @@ end;
procedure TPCUFiler.RaiseMsg(Id: int64; El: TPasElement; const Msg: string);
var
Path, s: String;
CurEl: TPasElement;
begin
Path:='';
while El<>nil do
CurEl:=El;
while CurEl<>nil do
begin
if Path<>'' then Path:='.'+Path;
s:=El.Name;
s:=CurEl.Name;
if s='' then
s:=El.ClassName;
s:=CurEl.ClassName;
Path:=s+Path;
El:=El.Parent;
CurEl:=CurEl.Parent;
end;
RaiseMsg(Id,Path+': '+Msg);
s:=Path+': '+Msg;
if El.GetModule<>Resolver.RootElement then
s:='This='+Resolver.RootElement.Name+' El='+s;
RaiseMsg(Id,s);
end;
function TPCUFiler.GetDefaultMemberVisibility(El: TPasElement
@ -1599,14 +1613,13 @@ begin
end
else if El is TPasUnresolvedSymbolRef then
RaiseMsg(20180215190054,El,GetObjName(El));
Node:=FElementRefs.FindKey(El,@CompareElWithPCUFilerElementRef);
if Node<>nil then
Result:=TPCUFilerElementRef(Node.Data)
else if AutoCreate then
begin
Result:=TPCUFilerElementRef.Create;
Result.Element:=El;
FElementRefs.Add(Result);
Result:=CreateElementRef(El);
if IsBuiltIn then
AddedBuiltInRef(Result);
end
@ -1614,6 +1627,13 @@ begin
Result:=nil;
end;
function TPCUFiler.CreateElementRef(El: TPasElement): TPCUFilerElementRef;
begin
Result:=TPCUFilerElementRef.Create;
Result.Element:=El;
FElementRefs.Add(Result);
end;
procedure TPCUFiler.AddedBuiltInRef(Ref: TPCUFilerElementRef);
begin
if Ref=nil then ;
@ -1801,6 +1821,19 @@ begin
Ref.Obj.Add('Id',Ref.Id);
end;
function TPCUWriter.CreateElementRef(El: TPasElement): TPCUFilerElementRef;
begin
Result:=inherited CreateElementRef(El);
if El.GetModule<>Resolver.RootElement then
begin
if FFirstNewExt=nil then
FFirstNewExt:=Result
else
FLastNewExt.NextNewExt:=Result;
FLastNewExt:=Result;
end;
end;
procedure TPCUWriter.AddedBuiltInRef(Ref: TPCUFilerElementRef);
var
ModuleObj, Obj: TJSONObject;
@ -2092,6 +2125,7 @@ begin
WImplBlock(aModule.FinalizationSection,'Final');
end;
//writeln('TPCUWriter.WriteModule WriteExternalReferences of implementation ',Resolver.RootElement.Name,' aContext.Section=',GetObjName(aContext.Section));
WriteExternalReferences(aContext);
end;
@ -2318,7 +2352,14 @@ begin
WriteDeclarations(Obj,Section,aContext);
if Section is TInterfaceSection then
begin
if aContext.SectionObj<>Obj then
RaiseMsg(20180318112544,Section);
{$IFDEF VerbosePJUFiler}
//writeln('TPCUWriter.WriteSection WriteExternalReferences of Interface ',Section.FullPath);
{$ENDIF}
WriteExternalReferences(aContext);
end;
end;
procedure TPCUWriter.WriteDeclarations(ParentJSON: TJSONObject;
@ -3417,6 +3458,7 @@ begin
begin
if aContext.SectionObj=nil then
RaiseMsg(20180314154428,El);
//writeln('TPCUWriter.WriteExternalReference ',Resolver.RootElement.Name,' Section=',GetObjName(aContext.Section),' IndirectUses=',El.Name);
aContext.IndirectUsesArr:=TJSONArray.Create;
aContext.SectionObj.Add('IndirectUses',aContext.IndirectUsesArr);
end;
@ -3429,25 +3471,26 @@ end;
procedure TPCUWriter.WriteExternalReferences(aContext: TPCUWriterContext);
var
Node: TAVLTreeNode;
Ref: TPCUFilerElementRef;
El: TPasElement;
Data: TObject;
begin
Node:=FElementRefs.FindLowest;
while Node<>nil do
while FFirstNewExt<>nil do
begin
Ref:=TPCUFilerElementRef(Node.Data);
Node:=FElementRefs.FindSuccessor(Node);
Ref:=FFirstNewExt;
FFirstNewExt:=Ref.NextNewExt;
if FFirstNewExt=nil then
FLastNewExt:=nil;
if Ref.Pending=nil then
continue; // not used
continue; // not used, e.g. when a child is written, its parents are
// written too, which might still be in the queue
El:=Ref.Element;
//writeln('TPCUWriter.WriteExternalReferences ',GetObjName(El),' ',El.FullPath);
Data:=El.CustomData;
if Data is TResElDataBuiltInSymbol then
{$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
if El.CustomData is TResElDataBuiltInSymbol then
RaiseMsg(20180314120554,El);
if El.GetModule=Resolver.RootElement then
continue;
RaiseMsg(20180318120511,El);
{$ENDIF}
// external element
if Ref.Obj=nil then
WriteExternalReference(El,aContext);
@ -3468,6 +3511,8 @@ end;
procedure TPCUWriter.Clear;
begin
FFirstNewExt:=nil;
FLastNewExt:=nil;
FInitialFlags:=nil;
FElementIdCounter:=0;
FSourceFilesSorted:=nil;

View File

@ -37,6 +37,7 @@ const
ExitCodeWriteError = 5;
ExitCodeSyntaxError = 6;
ExitCodeConverterError = 7;
ExitCodePCUError = 8;
const
DefaultLogMsgTypes = [mtFatal..mtDebug]; // by default show everything

View File

@ -295,6 +295,7 @@ type
Procedure TestSet_Property;
Procedure TestSet_EnumConst;
Procedure TestSet_AnonymousEnumType;
Procedure TestSet_AnonymousEnumTypeChar; // ToDo
Procedure TestSet_ConstEnum;
Procedure TestSet_ConstChar;
Procedure TestSet_ConstInt;
@ -4209,6 +4210,38 @@ begin
'']));
end;
procedure TTestModule.TestSet_AnonymousEnumTypeChar;
begin
exit;
StartProgram(false);
Add([
'type',
' TAtoZ = ''A''..''Z'';',
' TSetOfAZ = set of TAtoZ;',
'var',
' c: char;',
' a: TAtoZ;',
' s: TSetOfAZ = [''P'',''A''];',
' i: longint;',
'begin',
' Include(s,''S'');',
' Include(s,c);',
' Include(s,a);',
' c:=low(TAtoZ);',
' i:=ord(low(TAtoZ));',
' a:=high(TAtoZ);',
' a:=high(TSetOfAtoZ);',
' s:=[a,c,''M''];',
'']);
ConvertProgram;
CheckSource('TestSet_AnonymousEnumTypeChar',
LinesToStr([ // statements
'']),
LinesToStr([
'']));
end;
procedure TTestModule.TestSet_ConstEnum;
begin
StartProgram(false);
@ -13620,30 +13653,33 @@ end;
procedure TTestModule.TestPointer;
begin
StartProgram(false);
Add('type');
Add(' TObject = class end;');
Add(' TClass = class of TObject;');
Add(' TArrInt = array of longint;');
Add('var');
Add(' v: jsvalue;');
Add(' Obj: tobject;');
Add(' C: tclass;');
Add(' a: tarrint;');
Add(' p: Pointer;');
Add('begin');
Add(' p:=p;');
Add(' p:=nil;');
Add(' if p=nil then;');
Add(' if nil=p then;');
Add(' if Assigned(p) then;');
Add(' p:=Pointer(v);');
Add(' p:=obj;');
Add(' p:=c;');
Add(' p:=a;');
Add(' p:=tobject;');
Add(' obj:=TObject(p);');
Add(' c:=TClass(p);');
Add(' a:=TArrInt(p);');
Add(['type',
' TObject = class end;',
' TClass = class of TObject;',
' TArrInt = array of longint;',
'const',
' n = nil;',
'var',
' v: jsvalue;',
' Obj: tobject;',
' C: tclass;',
' a: tarrint;',
' p: Pointer = nil;',
'begin',
' p:=p;',
' p:=nil;',
' if p=nil then;',
' if nil=p then;',
' if Assigned(p) then;',
' p:=Pointer(v);',
' p:=obj;',
' p:=c;',
' p:=a;',
' p:=tobject;',
' obj:=TObject(p);',
' c:=TClass(p);',
' a:=TArrInt(p);',
' p:=n;']);
ConvertProgram;
CheckSource('TestPointer',
LinesToStr([ // statements
@ -13653,6 +13689,7 @@ begin
' this.$final = function () {',
' };',
'});',
'this.n = null;',
'this.v = undefined;',
'this.Obj = null;',
'this.C = null;',
@ -13673,6 +13710,7 @@ begin
'$mod.Obj = $mod.p;',
'$mod.C = $mod.p;',
'$mod.a = $mod.p;',
'$mod.p = null;',
'']));
end;

View File

@ -39,7 +39,7 @@ type
procedure CheckPrecompile(MainFile, UnitPaths: string;
SharedParams: TStringList = nil;
FirstRunParams: TStringList = nil;
SecondRunParams: TStringList = nil);
SecondRunParams: TStringList = nil; ExpExitCode: integer = 0);
public
constructor Create; override;
property Format: TPas2JSPrecompileFormat read FFormat write FFormat;
@ -70,9 +70,9 @@ end;
{ TCustomTestCLI_Precompile }
procedure TCustomTestCLI_Precompile.CheckPrecompile(MainFile, UnitPaths: string;
SharedParams: TStringList; FirstRunParams: TStringList;
SecondRunParams: TStringList);
procedure TCustomTestCLI_Precompile.CheckPrecompile(MainFile,
UnitPaths: string; SharedParams: TStringList; FirstRunParams: TStringList;
SecondRunParams: TStringList; ExpExitCode: integer);
var
UnitOutputDir, JSFilename, OrigSrc, NewSrc, s: String;
JSFile: TCLIFile;
@ -106,13 +106,16 @@ begin
Params.Assign(SharedParams);
if SecondRunParams<>nil then
Params.AddStrings(SecondRunParams);
Compile([MainFile,'-Jc','-FU'+UnitOutputDir]);
NewSrc:=JSFile.Source;
if not CheckSrcDiff(OrigSrc,NewSrc,s) then
begin
WriteSources;
Fail('test1.js: '+s);
end;
Compile([MainFile,'-Jc','-FU'+UnitOutputDir],ExpExitCode);
if ExpExitCode=0 then
begin
NewSrc:=JSFile.Source;
if not CheckSrcDiff(OrigSrc,NewSrc,s) then
begin
WriteSources;
Fail('test1.js: '+s);
end;
end;
finally
SharedParams.Free;
FirstRunParams.Free;