Repository URL to install this package:
|
Version:
3.2.0 ▾
|
{
This file is part of the Free Component Library (FCL)
Copyright (c) 2018 Mattias Gaertner mattias@freepascal.org
Pascal to Javascript converter class.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************
Abstract:
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
- store compiler flags
- restore module as json
- restore types
- references to built in symbols via Id
- references to module's TPasElement via Id
- resolving forward references
- restore resolver scopes
- restore resolved references and access flags
- useanalyzer: use restored proc references
- write+read compiled proc body
- converter: use precompiled body
- store/restore/use precompiled JS of proc bodies
- store/restore/use precompiled JS of proc local const
- store/restore/use precompiled JS of initialization plus references
- useanalyzer: generate + use initialization/finalization references
- uses section
- indirect used units
- external references
- stop after uses section and continue reading
- WPO uses Proc.References
- gzipped json
- write final switches
ToDo:
- store used GUIDs
- distinguish reader errors in fatal and error
- when pcu is bad, unload and use src
- replace GUID with crc
- srcmaps for precompiled js
}
unit Pas2JsFiler;
{$mode objfpc}{$H+}
interface
uses
Classes, Types, SysUtils, contnrs,
{$ifdef pas2js}
{$else}
zstream, AVL_Tree,
{$endif}
fpjson, jsonparser, jsonscanner,
PasTree, PScanner, PParser, PasResolveEval, PasResolver,
Pas2jsFileUtils, FPPas2Js;
const
PCUMagic = 'Pas2JSCache';
PCUVersion = 5;
{ Version Changes:
1: initial version
2: - TPasProperty.ImplementsFunc:String -> Implements:TPasExprArray
- pcsfAncestorResolved
- removed msIgnoreInterfaces
3: changed records from function to objects (pas2js 1.3)
4: precompiled JS of initialization section now only contains the statements,
not the whole $init function (pas2js 1.5)
5: removed modeswitch ignoreattributes
}
BuiltInNodeName = 'BuiltIn';
PCUDefaultParserOptions: TPOptions = po_Pas2js;
PCUBoolStr: array[boolean] of string = (
'False',
'True'
);
PCUParserOptionNames: array[TPOption] of string = (
'delphi',
'KeepScannerError',
'CAssignments',
'ResolveStandardTypes',
'AsmWhole',
'NoOverloadedProcs',
'KeepClassForward',
'ArrayRangeExpr',
'SelfToken',
'CheckModeSwitches',
'CheckCondFunction',
'StopOnErrorDirective',
'ExtClassConstWithoutExpr',
'StopOnUnitInterface');
PCUDefaultModeSwitches: TModeSwitches = [
msObjfpc,
msClass,
msResult,
msNestedComment,
msRepeatForward,
msInitFinal,
msOut,
msDefaultPara,
msHintDirective,
msProperty,
msExcept,
msDefaultUnicodestring,
msCBlocks];
PCUModeSwitchNames: array[TModeSwitch] of string = (
'None',
'Fpc',
'Objfpc',
'Delphi',
'DelphiUnicode',
'TP7',
'Mac',
'Iso',
'Extpas',
'GPC',
'Class',
'Objpas',
'Result',
'StringPchar',
'CVarSupport',
'NestedComment',
'TPProcVar',
'MacProcVar',
'RepeatForward',
'Pointer2Procedure',
'AutoDeref',
'InitFinal',
'DefaultAnsistring',
'Out',
'DefaultPara',
'HintDirective',
'DuplicateNames',
'Property',
'DefaultInline',
'Except',
'ObjectiveC1',
'ObjectiveC2',
'NestedProcVars',
'NonLocalGoto',
'AdvancedRecords',
'ISOLikeUnaryMinus',
'SystemCodePage',
'FinalFields',
'DefaultUnicodestring',
'TypeHelpers',
'CBlocks',
'ISOLikeIO',
'ISOLikeProgramsPara',
'ISOLikeMod',
'ArrayOperators',
'ExternalClass',
'PrefixedAttributes',
'OmitRTTI',
'MultiHelpers',
'ImplicitFunctionSpecialization'
); // Dont forget to update ModeSwitchToInt !
PCUDefaultBoolSwitches: TBoolSwitches = [
bsHints,
bsNotes,
bsWarnings
];
PCUBoolSwitchNames: array[TBoolSwitch] of string = (
'None',
'Align',
'BoolEval',
'Assertions',
'DebugInfo',
'Extension',
'ImportedData',
'LongStrings',
'IOChecks',
'WriteableConst',
'LocalSymbols',
'TypeInfo',
'Optimization',
'OpenStrings',
'OverflowChecks',
'RangeChecks',
'TypedAddress',
'SafeDivide',
'VarStringChecks',
'Stackframes',
'ExtendedSyntax',
'ReferenceInfo',
'Hints',
'Notes',
'Warnings',
'Macro',
'ScopedEnums',
'ObjectChecks',
'PointerMath',
'Goto'
);
PCUDefaultConverterOptions: TPasToJsConverterOptions = [coUseStrict];
PCUConverterOptions: array[TPasToJsConverterOption] of string = (
'LowerCase',
'SwitchStatement',
'EnumNumbers',
'UseStrict',
'NoTypeInfo',
'EliminateDeadCode',
'StoreImplJS',
'RTLVersionCheckMain',
'RTLVersionCheckSystem',
'RTLVersionCheckUnit'
);
PCUDefaultTargetPlatform = PlatformBrowser;
PCUTargetPlatformNames: array[TPasToJsPlatform] of string = (
'Browser',
'NodeJS'
);
PCUDefaultTargetProcessor = ProcessorECMAScript5;
PCUTargetProcessorNames: array[TPasToJsProcessor] of string = (
'ECMAScript5',
'ECMAScript6'
);
PCUMemberVisibilityNames: array[TPasMemberVisibility] of string = (
'Default',
'Private',
'Protected',
'Public',
'Published',
'Automated',
'StrictPrivate',
'StrictProtected'
);
PCUMemberHintNames: array[TPasMemberHint] of string = (
'Deprecated',
'Library',
'Platform',
'Experimental',
'Unimplemented'
);
PCUDefaultModuleScopeFlags = [pmsfRangeErrorSearched];
PCUModuleScopeFlagNames: array[TPasModuleScopeFlag] of string = (
'AssertSearched',
'RangeErrorNeeded',
'RangeErrorSearched'
) ;
PCUDefaultIdentifierKind = pikSimple;
PCUIdentifierKindNames: array[TPasIdentifierKind] of string = (
'None',
'BaseType',
'BuiltInProc',
'Simple',
'Proc',
'Namespace'
);
PCUVarModifierNames: array[TVariableModifier] of string = (
'CVar',
'External',
'Public',
'Export',
'Class',
'Static'
);
PCUDefaultExprKind = pekIdent;
PCUExprKindNames: array[TPasExprKind] of string = (
'Ident',
'Number',
'String',
'Set',
'Nil',
'Bool',
'Range',
'Unary',
'Binary',
'Func',
'Array',
'List',
'Inherited',
'Self',
'Specialize',
'Procedure');
PCUExprOpCodeNames: array[TExprOpCode] of string = (
'None',
'Add',
'Sub',
'Mul',
'DivF',
'DivI',
'Mod',
'Pow',
'Shr',
'Shl',
'Not',
'And',
'Or',
'Xor',
'Eq',
'NE',
'LT',
'GT',
'LTE',
'GTE',
'In',
'Is',
'As',
'SymDif',
'Addr',
'Deref',
'MemAddr',
'SubId'
);
PCUPackModeNames: array[TPackMode] of string = (
'None',
'Packed',
'BitPacked'
);
PCURESetElKindNames : array[TRESetElKind] of string = (
'None',
'Enum',
'Int',
'Char',
'Bool'
);
PCUObjKindNames: array[TPasObjKind] of string = (
'Object',
'Class',
'Interface',
'ClassHelper',
'RecordHelper',
'TypeHelper',
'DispInterface'
);
PCUClassInterfaceTypeNames: array[TPasClassInterfaceType] of string = (
'COM',
'CORBA'
);
PCUClassScopeFlagNames: array[TPasClassScopeFlag] of string = (
'AncestorResolved',
'Sealed',
'Published'
);
PCUArgumentAccessNames: array[TArgumentAccess] of string = (
'Default',
'Const',
'Var',
'Out',
'ConstRef'
);
PCUCallingConventionNames: array[TCallingConvention] of string = (
'Default',
'Register',
'Pascal',
'CDecl',
'StdCall',
'OldFPCCall',
'SafeCall',
'SysCall'
);
PCUProcTypeModifierNames: array[TProcTypeModifier] of string = (
'OfObject',
'IsNested',
'Static',
'Varargs',
'ReferenceTo'
);
PCUProcedureMessageTypeNames: array[TProcedureMessageType] of string = (
'None',
'Integer',
'String'
);
PCUOperatorTypeNames: array[TOperatorType] of string = (
'Unknown',
'Implicit',
'Explicit',
'Mul',
'Plus',
'Minus',
'Division',
'LessThan',
'Equal',
'GreaterThan',
'Assign',
'NotEqual',
'LessEqualThan',
'GreaterEqualThan',
'Power',
'SymmetricalDifference',
'Inc',
'Dec',
'Mod',
'Negative',
'Positive',
'BitWiseOr',
'Div',
'LeftShift',
'LogicalOr',
'BitwiseAnd',
'bitwiseXor',
'LogicalAnd',
'LogicalNot',
'LogicalXor',
'RightShift',
'Enumerator',
'In'
);
PCUProcedureModifierNames: array[TProcedureModifier] of string = (
'Virtual',
'Dynamic',
'Abstract',
'Override',
'Export',
'Overload',
'Message',
'Reintroduce',
'Inline',
'Assembler',
'Public',
'CompilerProc',
'External',
'Forward',
'DispId',
'NoReturn',
'Far',
'Final'
);
PCUProcedureScopeFlagNames: array[TPasProcedureScopeFlag] of string = (
'GrpOverload',
'ppsfIsSpecialized'
);
PCUDefaultPSRefAccess = psraRead;
PCUPSRefAccessNames: array[TPSRefAccess] of string = (
'None',
'Read',
'Write',
'ReadWrite',
'WriteRead',
'TypeInfo'
);
PCUResolvedRefAccessNames: array[TResolvedRefAccess] of string = (
'None',
'Read',
'Assign',
'ReadAndAssign',
'VarParam',
'OutParam',
'ParamToUnknownProc'
);
PCUResolvedReferenceFlagNames: array[TResolvedReferenceFlag] of string = (
'Dot',
'ImplicitCall',
'NoImplicitCall',
'NewInst',
'FreeInst',
'VMT',
'ConstInh'
);
type
{ TPCUInitialFlags }
TPCUInitialFlags = class
public
ParserOptions: TPOptions;
ModeSwitches: TModeSwitches;
BoolSwitches: TBoolSwitches;
ConverterOptions: TPasToJsConverterOptions;
TargetPlatform: TPasToJsPlatform;
TargetProcessor: TPasToJsProcessor;
// ToDo: defines
constructor Create;
procedure Clear;
end;
type
TPCUSourceFileType = (
sftUnit,
sftInclude
);
TPCUSourceFileKinds = set of TPCUSourceFileType;
const
PCUSourceFileTypeNames: array[TPCUSourceFileType] of string = (
'Unit',
'Include'
);
type
TPCUSourceFileChecksum = cardinal;
EPas2JsFilerError = class(Exception)
public
Owner: TObject;
end;
EPas2JsWriteError = class(EPas2JsFilerError);
EPas2JsReadError = class(EPas2JsFilerError);
{ TPCUSourceFile }
TPCUSourceFile = class
public
FileType: TPCUSourceFileType;
Filename: string;
Checksum: TPCUSourceFileChecksum;
Index: integer;
end;
TPCUSourceFileArray = array of TPCUSourceFile;
TPCUGetSrcEvent = procedure(Sender: TObject; aFilename: string;
out p: PChar; out Count: integer) of object;
{ TPCUFilerContext - base class TPCUWriterContext/TPCUReaderContext }
TPCUFilerContext = class
public
ModeSwitches: TModeSwitches;
BoolSwitches: TBoolSwitches;
end;
{ TPCUFilerPendingElRef }
TPCUFilerPendingElRef = class
public
Next: TPCUFilerPendingElRef;
ErrorEl: TPasElement;
end;
{ TPCUFilerElementRef }
TPCUFilerElementRef = class
public
ParentRef: TPCUFilerElementRef;
Element: TPasElement;
Id: integer; // 0 = pending
Pending: TPCUFilerPendingElRef;
Obj: TJSONObject;
Elements: TJSONArray; // for external references
NextNewExt: TPCUFilerElementRef; // next new external reference
procedure AddPending(Item: TPCUFilerPendingElRef);
procedure Clear;
destructor Destroy; override;
end;
TPCUFilerElementRefArray = array of TPCUFilerElementRef;
{ TPCUFiler - base class TPCUWriter/TPCUReader}
TPCUFiler = class
private
FFileVersion: longint;
FGUID: TGUID;
FInitialFlags: TPCUInitialFlags;
FOnGetSrc: TPCUGetSrcEvent;
FParser: TPasParser;
FResolver: TPas2JSResolver;
FScanner: TPascalScanner;
FSourceFiles: TObjectList;
function GetSourceFiles(Index: integer): TPCUSourceFile;
protected
FElementRefs: TAVLTree; // tree of TPCUFilerElementRef sorted for Element
procedure RaiseMsg(Id: int64; const Msg: string = ''); virtual; abstract; overload;
procedure RaiseMsg(Id: int64; El: TPasElement; const Msg: string = ''); overload;
function GetDefaultMemberVisibility(El: TPasElement): TPasMemberVisibility; virtual;
function GetDefaultPasScopeVisibilityContext(Scope: TPasScope): TPasElement; virtual;
procedure GetDefaultsPasIdentifierProps(El: TPasElement; out Kind: TPasIdentifierKind; out Name: string); virtual;
function GetDefaultClassScopeFlags(Scope: TPas2JSClassScope): TPasClassScopeFlags; virtual;
function GetDefaultProcModifiers(Proc: TPasProcedure): TProcedureModifiers; virtual;
function GetDefaultProcTypeModifiers(ProcType: TPasProcedureType): TProcTypeModifiers; virtual;
function GetDefaultExprHasEvalValue(Expr: TPasExpr): boolean; virtual;
function GetSrcCheckSum(aFilename: string): TPCUSourceFileChecksum; virtual;
function GetDefaultRefName(El: TPasElement): string; virtual;
function GetElementReference(El: TPasElement; AutoCreate: boolean = true): TPCUFilerElementRef;
function CreateElementRef(El: TPasElement): TPCUFilerElementRef; virtual;
procedure AddedBuiltInRef(Ref: TPCUFilerElementRef); virtual;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Clear; virtual;
property Resolver: TPas2JSResolver read FResolver;
property Parser: TPasParser read FParser;
property Scanner: TPascalScanner read FScanner;
property InitialFlags: TPCUInitialFlags read FInitialFlags;
property OnGetSrc: TPCUGetSrcEvent read FOnGetSrc write FOnGetSrc;
function SourceFileCount: integer;
property SourceFiles[Index: integer]: TPCUSourceFile read GetSourceFiles;
property ElementRefs: TAVLTree read FElementRefs;
property GUID: TGUID read FGUID write FGUID;
end;
{ TPCUCustomWriter }
TPCUCustomWriter = class(TPCUFiler)
private
FOnIsElementUsed: TPas2JSIsElementUsedEvent;
public
procedure WritePCU(aResolver: TPas2JSResolver; aConverter: TPasToJSConverter;
InitFlags: TPCUInitialFlags; aStream: TStream; Compressed: boolean); virtual; abstract;
property OnIsElementUsed: TPas2JSIsElementUsedEvent read FOnIsElementUsed write FOnIsElementUsed;
end;
TPCUWriterClass = class of TPCUWriter;
{ TPCUCustomReader }
TPCUCustomReader = class(TPCUFiler)
private
FSourceFilename: string;
public
procedure ReadPCU(aResolver: TPas2JSResolver; aStream: TStream); virtual; abstract;
function ReadContinue: boolean; virtual; abstract; // true=finished
function ReadCanContinue: boolean; virtual; // true=not finished and no pending used interface
property SourceFilename: string read FSourceFilename write FSourceFilename; // default value for TPasElement.SourceFilename
end;
TPCUReaderClass = class of TPCUCustomReader;
{ TPCUWriterContext }
TPCUWriterContext = class(TPCUFilerContext)
public
Section: TPasSection;
SectionObj: TJSONObject;
IndirectUsesArr: TJSONArray;
end;
{ TPCUWriterPendingElRefObj }
TPCUWriterPendingElRefObj = class(TPCUFilerPendingElRef)
public
Obj: TJSONObject;
PropName: string;
end;
{ TPCUWriterPendingElRefArray }
TPCUWriterPendingElRefArray = class(TPCUFilerPendingElRef)
public
Arr: TJSONArray;
Index: integer;
end;
{ TPCUWriter }
TPCUWriter = class(TPCUCustomWriter)
private
FConverter: TPasToJSConverter;
FElementIdCounter: integer;
FJSON: TJSONObject;
FSourceFilesSorted: TPCUSourceFileArray;
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;
procedure AddArrayFlag(Obj: TJSONObject; var Arr: TJSONArray;
const ArrName, Flag: string; Enable: boolean);
procedure AddReferenceToArray(Arr: TJSONArray; El: TPasElement; WriteNull: boolean = true); virtual;
procedure AddReferenceToObj(Obj: TJSONObject; const PropName: string;
El: TPasElement; WriteNil: boolean = false); virtual;
procedure CreateAutoElReferenceId(Ref: TPCUFilerElementRef); virtual;
procedure CreateElReferenceId(Ref: TPCUFilerElementRef); virtual;
function CreateElementRef(El: TPasElement): TPCUFilerElementRef; override;
procedure AddedBuiltInRef(Ref: TPCUFilerElementRef); override;
protected
procedure WriteHeaderMagic(Obj: TJSONObject); virtual;
procedure WriteHeaderVersion(Obj: TJSONObject); virtual;
procedure WriteGUID(Obj: TJSONObject); virtual;
procedure WriteInitialFlags(Obj: TJSONObject); virtual;
procedure WriteFinalFlags(Obj: TJSONObject); virtual;
procedure WriteParserOptions(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TPOptions); virtual;
procedure WriteModeSwitches(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TModeSwitches); virtual;
procedure WriteBoolSwitches(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TBoolSwitches); virtual;
procedure WriteConverterOptions(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TPasToJsConverterOptions); virtual;
procedure WriteSrcFiles(Obj: TJSONObject); virtual;
procedure WriteMemberHints(Obj: TJSONObject; const Value, DefaultValue: TPasMemberHints); virtual;
procedure WritePasScope(Obj: TJSONObject; Scope: TPasScope; aContext: TPCUWriterContext); virtual;
procedure WriteIdentifierScope(Obj: TJSONObject; Scope: TPasIdentifierScope; aContext: TPCUWriterContext); virtual;
procedure WriteModuleScopeFlags(Obj: TJSONObject; const Value, DefaultValue: TPasModuleScopeFlags); virtual;
procedure WriteModuleScope(Obj: TJSONObject; Scope: TPas2JSModuleScope; aContext: TPCUWriterContext); virtual;
procedure WriteSrcPos(Obj: TJSONObject; El: TPasElement; aContext: TPCUWriterContext); virtual;
procedure WritePasElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUWriterContext); virtual;
procedure WriteModule(Obj: TJSONObject; aModule: TPasModule; aContext: TPCUWriterContext); virtual;
procedure WriteSection(ParentJSON: TJSONObject; Section: TPasSection;
const PropName: string; aContext: TPCUWriterContext); virtual;
procedure WriteDeclarations(ParentJSON: TJSONObject; Decls: TPasDeclarations; aContext: TPCUWriterContext); virtual;
procedure WriteElementProperty(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; El: TPasElement; aContext: TPCUWriterContext); virtual;
procedure WriteElementList(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; ListOfElements: TFPList; aContext: TPCUWriterContext;
ReferencesAllowed: boolean = false); virtual;
procedure WriteElementArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; ArrOfElements: TPasElementArray; aContext: TPCUWriterContext;
ReferencesAllowed: boolean = false); virtual;
procedure WriteElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUWriterContext); virtual;
procedure WriteElType(Obj: TJSONObject; El: TPasElement; const PropName: string; aType: TPasType; aContext: TPCUWriterContext); virtual;
procedure WriteVarModifiers(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TVariableModifiers); virtual;
procedure WriteResolvedRefFlags(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TResolvedReferenceFlags); virtual;
procedure WriteResolvedReference(Obj: TJSONObject; Ref: TResolvedReference; ErrorEl: TPasElement); virtual;
procedure WriteExprCustomData(Obj: TJSONObject; Expr: TPasExpr; aContext: TPCUWriterContext); virtual;
procedure WriteExpr(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; Expr: TPasExpr; aContext: TPCUWriterContext); virtual;
procedure WritePasExpr(Obj: TJSONObject; Expr: TPasExpr;
DefaultKind: TPasExprKind; DefaultOpCode: TExprOpCode; aContext: TPCUWriterContext); virtual;
procedure WritePasExprArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; const ExprArr: TPasExprArray; aContext: TPCUWriterContext); virtual;
procedure WriteScopeReferences(Obj: TJSONObject; References: TPasScopeReferences;
const PropName: string; aContext: TPCUWriterContext); virtual;
procedure WriteUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr; aContext: TPCUWriterContext); virtual;
procedure WriteBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr; aContext: TPCUWriterContext); virtual;
procedure WritePrimitiveExpr(Obj: TJSONObject; Expr: TPrimitiveExpr; aContext: TPCUWriterContext); virtual;
procedure WriteBoolConstExpr(Obj: TJSONObject; Expr: TBoolConstExpr; aContext: TPCUWriterContext); virtual;
procedure WriteParamsExpr(Obj: TJSONObject; Expr: TParamsExpr; aContext: TPCUWriterContext); virtual;
procedure WriteRecordValues(Obj: TJSONObject; Expr: TRecordValues; aContext: TPCUWriterContext); virtual;
procedure WriteArrayValues(Obj: TJSONObject; Expr: TArrayValues; aContext: TPCUWriterContext); virtual;
procedure WriteResString(Obj: TJSONObject; El: TPasResString; aContext: TPCUWriterContext); virtual;
procedure WriteGenericTemplateTypes(Obj: TJSONObject; Parent: TPasElement; GenericTemplateTypes: TFPList; aContext: TPCUWriterContext); virtual;
procedure WriteAliasType(Obj: TJSONObject; El: TPasAliasType; aContext: TPCUWriterContext); virtual;
procedure WritePointerType(Obj: TJSONObject; El: TPasPointerType; aContext: TPCUWriterContext); virtual;
procedure WriteSpecializeType(Obj: TJSONObject; El: TPasSpecializeType; aContext: TPCUWriterContext); virtual;
procedure WriteInlineSpecializeExpr(Obj: TJSONObject; Expr: TInlineSpecializeExpr; aContext: TPCUWriterContext); virtual;
procedure WriteRangeType(Obj: TJSONObject; El: TPasRangeType; aContext: TPCUWriterContext); virtual;
procedure WriteArrayType(Obj: TJSONObject; El: TPasArrayType; aContext: TPCUWriterContext); virtual;
procedure WriteFileType(Obj: TJSONObject; El: TPasFileType; aContext: TPCUWriterContext); virtual;
procedure WriteEnumValue(Obj: TJSONObject; El: TPasEnumValue; aContext: TPCUWriterContext); virtual;
procedure WriteEnumTypeScope(Obj: TJSONObject; Scope: TPasEnumTypeScope; aContext: TPCUWriterContext); virtual;
procedure WriteEnumType(Obj: TJSONObject; El: TPasEnumType; aContext: TPCUWriterContext); virtual;
procedure WriteSetType(Obj: TJSONObject; El: TPasSetType; aContext: TPCUWriterContext); virtual;
procedure WriteRecordVariant(Obj: TJSONObject; El: TPasVariant; aContext: TPCUWriterContext); virtual;
procedure WriteRecordTypeScope(Obj: TJSONObject; Scope: TPasRecordScope; aContext: TPCUWriterContext); virtual;
procedure WriteRecordType(Obj: TJSONObject; El: TPasRecordType; aContext: TPCUWriterContext); virtual;
procedure WriteClassScopeFlags(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TPasClassScopeFlags); virtual;
procedure WriteClassIntfMapProcs(Obj: TJSONObject; Map: TPasClassIntfMap); virtual;
procedure WriteClassScope(Obj: TJSONObject; Scope: TPas2JSClassScope; aContext: TPCUWriterContext); virtual;
procedure WriteClassType(Obj: TJSONObject; El: TPasClassType; aContext: TPCUWriterContext); virtual;
procedure WriteArgument(Obj: TJSONObject; El: TPasArgument; aContext: TPCUWriterContext); virtual;
procedure WriteProcTypeModifiers(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TProcTypeModifiers); virtual;
procedure WriteProcedureType(Obj: TJSONObject; El: TPasProcedureType; aContext: TPCUWriterContext); virtual;
procedure WriteResultElement(Obj: TJSONObject; El: TPasResultElement; aContext: TPCUWriterContext); virtual;
procedure WriteFunctionType(Obj: TJSONObject; El: TPasFunctionType; aContext: TPCUWriterContext); virtual;
procedure WriteStringType(Obj: TJSONObject; El: TPasStringType; aContext: TPCUWriterContext); virtual;
procedure WriteVariable(Obj: TJSONObject; El: TPasVariable; aContext: TPCUWriterContext); virtual;
procedure WriteExportSymbol(Obj: TJSONObject; El: TPasExportSymbol; aContext: TPCUWriterContext); virtual;
procedure WriteConst(Obj: TJSONObject; El: TPasConst; aContext: TPCUWriterContext); virtual;
procedure WritePropertyScope(Obj: TJSONObject; Scope: TPasPropertyScope; aContext: TPCUWriterContext); virtual;
procedure WriteProperty(Obj: TJSONObject; El: TPasProperty; aContext: TPCUWriterContext); virtual;
procedure WriteMethodResolution(Obj: TJSONObject; El: TPasMethodResolution; aContext: TPCUWriterContext); virtual;
procedure WriteProcedureNameParts(Obj: TJSONObject; El: TPasProcedure; aContext: TPCUWriterContext); virtual;
procedure WriteProcedureModifiers(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TProcedureModifiers); virtual;
procedure WriteProcScopeFlags(Obj: TJSONObject; const PropName: string; const Value, DefaultValue: TPasProcedureScopeFlags); virtual;
procedure WriteProcedureScope(Obj: TJSONObject; Scope: TPas2JSProcedureScope; aContext: TPCUWriterContext); virtual;
procedure WriteProcedure(Obj: TJSONObject; El: TPasProcedure; aContext: TPCUWriterContext); virtual;
procedure WriteOperator(Obj: TJSONObject; El: TPasOperator; aContext: TPCUWriterContext); virtual;
procedure WriteAttributes(Obj: TJSONObject; El: TPasAttributes; aContext: TPCUWriterContext); virtual;
procedure WriteExtRefSignature(Ref: TPCUFilerElementRef; aContext: TPCUWriterContext); virtual;
function WriteExternalReference(El: TPasElement; aContext: TPCUWriterContext): TPCUFilerElementRef; virtual;
procedure WriteExternalReferences(aContext: TPCUWriterContext); virtual;
public
constructor Create; override;
destructor Destroy; override;
procedure Clear; override;
procedure WritePCU(aResolver: TPas2JSResolver; aConverter: TPasToJSConverter;
InitFlags: TPCUInitialFlags; aStream: TStream; Compressed: boolean); override;
function WriteJSON(aResolver: TPas2JSResolver; aConverter: TPasToJSConverter;
InitFlags: TPCUInitialFlags): TJSONObject; virtual;
function IndexOfSourceFile(const Filename: string): integer;
property SourceFilesSorted: TPCUSourceFileArray read FSourceFilesSorted;
property JSON: TJSONObject read FJSON;
property Converter: TPasToJSConverter read FConverter;
end;
{ TPCUReaderContext }
TPCUReaderContext = class(TPCUFilerContext)
end;
TOnSetElReference = procedure(El: TPasElement; Data: TObject) of object;
{ TPCUReaderPendingElRef }
TPCUReaderPendingElRef = class(TPCUFilerPendingElRef)
public
Data: TObject;
Setter: TOnSetElReference;
end;
TPCUAddRef = {$IFDEF CheckPasTreeRefCount}String{$ELSE}boolean{$ENDIF};
{ TPCUReaderPendingElListRef }
TPCUReaderPendingElListRef = class(TPCUFilerPendingElRef)
public
List: TFPList;
Index: integer;
AddRef: TPCUAddRef;
end;
{ TPCUReaderPendingElArrRef }
TPCUReaderPendingElArrRef = class(TPCUFilerPendingElRef)
public
Arr: TPasElementArray;
Index: integer;
AddRef: TPCUAddRef;
end;
{ TPCUReaderPendingIdentifierScope }
TPCUReaderPendingIdentifierScope = class
public
Scope: TPasIdentifierScope;
Arr: TJSONArray;
end;
{ TPCUReader }
TPCUReader = class(TPCUCustomReader)
private
FElementRefsArray: TPCUFilerElementRefArray; // TPCUFilerElementRef by Id
FJSON: TJSONObject;
FPendingIdentifierScopes: TObjectList; // list of TPCUReaderPendingIdentifierScope
procedure Set_Variable_VarType(RefEl: TPasElement; Data: TObject);
procedure Set_AliasType_DestType(RefEl: TPasElement; Data: TObject);
procedure Set_PointerType_DestType(RefEl: TPasElement; Data: TObject);
procedure Set_ArrayType_ElType(RefEl: TPasElement; Data: TObject);
procedure Set_FileType_ElType(RefEl: TPasElement; Data: TObject);
procedure Set_SetType_EnumType(RefEl: TPasElement; Data: TObject);
procedure Set_Variant_Members(RefEl: TPasElement; Data: TObject);
procedure Set_RecordType_VariantEl(RefEl: TPasElement; Data: TObject);
procedure Set_RecordScope_DefaultProperty(RefEl: TPasElement; Data: TObject);
procedure Set_Argument_ArgType(RefEl: TPasElement; Data: TObject);
procedure Set_ClassScope_NewInstanceFunction(RefEl: TPasElement; Data: TObject);
procedure Set_ClassScope_DirectAncestor(RefEl: TPasElement; Data: TObject);
procedure Set_ClassScope_DefaultProperty(RefEl: TPasElement; Data: TObject);
procedure Set_ClassIntfMap_Intf(RefEl: TPasElement; Data: TObject);
procedure Set_ClassType_AncestorType(RefEl: TPasElement; Data: TObject);
procedure Set_ClassType_HelperForType(RefEl: TPasElement; Data: TObject);
procedure Set_ResultElement_ResultType(RefEl: TPasElement; Data: TObject);
procedure Set_PasScope_VisibilityContext(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_AssertClass(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_AssertDefConstructor(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_AssertMsgConstructor(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_RangeErrorClass(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_RangeErrorConstructor(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_SystemTVarRec(RefEl: TPasElement; Data: TObject);
procedure Set_ModScope_SystemVarRecs(RefEl: TPasElement; Data: TObject);
procedure Set_EnumTypeScope_CanonicalSet(RefEl: TPasElement; Data: TObject);
procedure Set_PropertyScope_AncestorProp(RefEl: TPasElement; Data: TObject);
procedure Set_ProcedureScope_ImplProc(RefEl: TPasElement; Data: TObject);
procedure Set_ProcedureScope_Overridden(RefEl: TPasElement; Data: TObject);
procedure Set_ResolvedReference_Declaration(RefEl: TPasElement; Data: TObject);
procedure Set_ResolvedReference_CtxConstructor(RefEl: TPasElement; Data: TObject);
procedure Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement; Data: TObject);
protected
procedure RaiseMsg(Id: int64; const Msg: string = ''); overload; override;
function CheckJSONArray(Data: TJSONData; El: TPasElement; const PropName: string): TJSONArray;
function CheckJSONObject(Data: TJSONData; Id: int64): TJSONObject;
function CheckJSONString(Data: TJSONData; Id: int64): String;
function ReadString(Obj: TJSONObject; const PropName: string; out s: string; El: TPasElement): boolean;
function ReadInteger(Obj: TJSONObject; const PropName: string; out i: integer; El: TPasElement): boolean;
function ReadBoolean(Obj: TJSONObject; const PropName: string; out b: boolean; El: TPasElement): boolean;
function ReadArray(Obj: TJSONObject; const PropName: string; out Arr: TJSONArray; El: TPasElement): boolean;
function ReadObject(Obj: TJSONObject; const PropName: string; out SubObj: TJSONObject; El: TPasElement): boolean;
function CreateContext: TPCUReaderContext; virtual;
function GetElReference(Id: integer; ErrorEl: TPasElement): TPCUFilerElementRef; virtual;
function AddElReference(Id: integer; ErrorEl: TPasElement; El: TPasElement): TPCUFilerElementRef; virtual;
procedure PromiseSetElReference(Id: integer; const Setter: TOnSetElReference;
Data: TObject; ErrorEl: TPasElement); virtual;
procedure PromiseSetElListReference(Id: integer; List: TFPList; Index: integer;
AddRef: TPCUAddRef; ErrorEl: TPasElement); virtual;
procedure PromiseSetElArrReference(Id: integer; Arr: TPasElementArray; Index: integer;
AddRef: TPCUAddRef; ErrorEl: TPasElement); virtual;
procedure ReadHeaderMagic(Obj: TJSONObject); virtual;
procedure ReadHeaderVersion(Obj: TJSONObject); virtual;
procedure ReadGUID(Obj: TJSONObject); virtual;
procedure ReadHeaderItem(const PropName: string; Data: TJSONData); virtual;
procedure ReadArrayFlags(Data: TJSONData; El: TPasElement; const PropName: string; out Names: TStringDynArray; out Enable: TBooleanDynArray);
function ReadParserOptions(Obj: TJSONObject; El: TPasElement; const PropName: string; const DefaultValue: TPOptions): TPOptions; virtual;
function ReadModeSwitches(Obj: TJSONObject; El: TPasElement; const PropName: string; const DefaultValue: TModeSwitches): TModeSwitches; virtual;
function ReadBoolSwitches(Obj: TJSONObject; El: TPasElement; const PropName: string; const DefaultValue: TBoolSwitches): TBoolSwitches; virtual;
function ReadConverterOptions(Obj: TJSONObject; El: TPasElement; const PropName: string; const DefaultValue: TPasToJsConverterOptions): TPasToJsConverterOptions; virtual;
procedure ReadTargetPlatform(Data: TJSONData); virtual;
procedure ReadTargetProcessor(Data: TJSONData); virtual;
procedure ReadSrcFiles(Data: TJSONData); virtual;
function ReadMemberHints(Obj: TJSONObject; El: TPasElement; const DefaultValue: TPasMemberHints): TPasMemberHints; virtual;
procedure ReadSrcPos(Obj: TJSONObject; El: TPasElement; aContext: TPCUReaderContext); virtual;
procedure ReadPasElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUReaderContext); virtual;
procedure ReadExternalMembers(El: TPasElement; Arr: TJSONArray; Members: TFPList); virtual;
procedure ReadExternalReferences(Obj: TJSONObject; El: TPasElement); virtual;
procedure ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
procedure ReadUsedUnitsFinish(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
procedure ReadSectionScope(Obj: TJSONObject; Scope: TPas2JSSectionScope; aContext: TPCUReaderContext); virtual;
procedure ReadSection(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
procedure ReadDeclarations(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
function CreateElement(AClass: TPTreeElement; const AName: String;
AParent: TPasElement): TPasElement; virtual;
function ReadElement(Obj: TJSONObject; Parent: TPasElement; aContext: TPCUReaderContext): TPasElement; virtual;
function ReadElementProperty(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; BaseClass: TPTreeElement; aContext: TPCUReaderContext): TPasElement; virtual;
procedure ReadElementReference(Obj: TJSONObject; Instance: TPasElementBase;
const PropName: string; const Setter: TOnSetElReference); virtual;
procedure ReadElementList(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; ListOfElements: TFPList; AddRef: TPCUAddRef;
aContext: TPCUReaderContext); virtual;
procedure ReadElementArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; var ArrOfElements: TPasElementArray; AddRef: TPCUAddRef;
aContext: TPCUReaderContext); virtual;
procedure ReadElType(Obj: TJSONObject; const PropName: string; El: TPasElement;
const Setter: TOnSetElReference; aContext: TPCUReaderContext); virtual;
function ReadResolvedRefFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TResolvedReferenceFlags): TResolvedReferenceFlags; virtual;
procedure ReadResolvedReference(Obj: TJSONObject; Ref: TResolvedReference; ErrorEl: TPasElement); virtual;
procedure ReadPasExpr(Obj: TJSONObject; Expr: TPasExpr; DefKind: TPasExprKind; aContext: TPCUReaderContext); virtual;
procedure ReadExprCustomData(Obj: TJSONObject; Expr: TPasExpr; aContext: TPCUReaderContext); virtual;
function ReadExpr(Obj: TJSONObject; Parent: TPasElement; const PropName: string;
aContext: TPCUReaderContext): TPasExpr; virtual;
procedure ReadPasExprArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; var ExprArr: TPasExprArray; aContext: TPCUReaderContext); virtual;
procedure ReadPasScope(Obj: TJSONObject; Scope: TPasScope; aContext: TPCUReaderContext); virtual;
procedure ReadScopeReferences(Obj: TJSONObject; Scope: TPasScope;
const PropName: string; var References: TPasScopeReferences); virtual;
procedure ReadIdentifierScopeArray(Arr: TJSONArray; Scope: TPasIdentifierScope); virtual;
procedure ReadIdentifierScope(Obj: TJSONObject; Scope: TPasIdentifierScope; aContext: TPCUReaderContext); virtual;
function ReadModuleScopeFlags(Obj: TJSONObject; El: TPasElement; const DefaultValue: TPasModuleScopeFlags): TPasModuleScopeFlags; virtual;
procedure ReadModuleScope(Obj: TJSONObject; Scope: TPas2JSModuleScope; aContext: TPCUReaderContext); virtual;
procedure ReadModuleHeader(Data: TJSONData); virtual;
function ReadModule(Obj: TJSONObject; aContext: TPCUReaderContext): boolean; virtual;
procedure ReadUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr; aContext: TPCUReaderContext); virtual;
procedure ReadBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr; aContext: TPCUReaderContext); virtual;
procedure ReadBoolConstExpr(Obj: TJSONObject; Expr: TBoolConstExpr; aContext: TPCUReaderContext); virtual;
procedure ReadParamsExpr(Obj: TJSONObject; Expr: TParamsExpr; aContext: TPCUReaderContext); virtual;
procedure ReadRecordValues(Obj: TJSONObject; Expr: TRecordValues; aContext: TPCUReaderContext); virtual;
procedure ReadArrayValues(Obj: TJSONObject; Expr: TArrayValues; aContext: TPCUReaderContext); virtual;
procedure ReadResString(Obj: TJSONObject; El: TPasResString; aContext: TPCUReaderContext); virtual;
procedure ReadGenericTemplateTypes(Obj: TJSONObject; Parent: TPasElement; var GenericTemplateTypes: TFPList; aContext: TPCUReaderContext); virtual;
procedure ReadAliasType(Obj: TJSONObject; El: TPasAliasType; aContext: TPCUReaderContext); virtual;
procedure ReadPointerType(Obj: TJSONObject; El: TPasPointerType; aContext: TPCUReaderContext); virtual;
procedure ReadSpecializeType(Obj: TJSONObject; El: TPasSpecializeType; aContext: TPCUReaderContext); virtual;
procedure ReadInlineSpecializeExpr(Obj: TJSONObject; Expr: TInlineSpecializeExpr; aContext: TPCUReaderContext); virtual;
procedure ReadRangeType(Obj: TJSONObject; El: TPasRangeType; aContext: TPCUReaderContext); virtual;
procedure ReadArrayType(Obj: TJSONObject; El: TPasArrayType; aContext: TPCUReaderContext); virtual;
procedure ReadFileType(Obj: TJSONObject; El: TPasFileType; aContext: TPCUReaderContext); virtual;
procedure ReadEnumValue(Obj: TJSONObject; El: TPasEnumValue; aContext: TPCUReaderContext); virtual;
procedure ReadEnumTypeScope(Obj: TJSONObject; Scope: TPasEnumTypeScope; aContext: TPCUReaderContext); virtual;
procedure ReadEnumType(Obj: TJSONObject; El: TPasEnumType; aContext: TPCUReaderContext); virtual;
procedure ReadSetType(Obj: TJSONObject; El: TPasSetType; aContext: TPCUReaderContext); virtual;
function ReadPackedMode(Obj: TJSONObject; const PropName: string; ErrorEl: TPasElement): TPackMode; virtual;
procedure ReadRecordVariant(Obj: TJSONObject; El: TPasVariant; aContext: TPCUReaderContext); virtual;
procedure ReadRecordScope(Obj: TJSONObject; Scope: TPasRecordScope; aContext: TPCUReaderContext); virtual;
procedure ReadRecordType(Obj: TJSONObject; El: TPasRecordType; aContext: TPCUReaderContext); virtual;
function ReadClassInterfaceType(Obj: TJSONObject; const PropName: string; ErrorEl: TPasElement; DefaultValue: TPasClassInterfaceType): TPasClassInterfaceType;
function ReadClassScopeFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TPasClassScopeFlags): TPasClassScopeFlags; virtual;
procedure ReadClassScopeAbstractProcs(Obj: TJSONObject; Scope: TPas2JSClassScope); virtual;
procedure ReadClassIntfMapProcs(Obj: TJSONObject; Map: TPasClassIntfMap; OrigIntfType: TPasType); virtual;
procedure ReadClassIntfMap(Obj: TJSONObject; Scope: TPas2JSClassScope; Map: TPasClassIntfMap; OrigIntfType: TPasType); virtual;
procedure ReadClassScopeInterfaces(Obj: TJSONObject; Scope: TPas2JSClassScope); virtual;
procedure ReadClassScopeDispatchProcs(Obj: TJSONObject; Scope: TPas2JSClassScope); virtual;
procedure ReadClassScope(Obj: TJSONObject; Scope: TPas2JSClassScope; aContext: TPCUReaderContext); virtual;
procedure ReadClassType(Obj: TJSONObject; El: TPasClassType; aContext: TPCUReaderContext); virtual;
procedure ReadArgument(Obj: TJSONObject; El: TPasArgument; aContext: TPCUReaderContext); virtual;
function ReadProcTypeModifiers(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TProcTypeModifiers): TProcTypeModifiers; virtual;
procedure ReadProcedureType(Obj: TJSONObject; El: TPasProcedureType; aContext: TPCUReaderContext); virtual;
procedure ReadResultElement(Obj: TJSONObject; El: TPasResultElement; aContext: TPCUReaderContext); virtual;
procedure ReadFunctionType(Obj: TJSONObject; El: TPasFunctionType; aContext: TPCUReaderContext); virtual;
procedure ReadStringType(Obj: TJSONObject; El: TPasStringType; aContext: TPCUReaderContext); virtual;
function ReadVarModifiers(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TVariableModifiers): TVariableModifiers; virtual;
procedure ReadVariable(Obj: TJSONObject; El: TPasVariable; aContext: TPCUReaderContext); virtual;
procedure ReadExportSymbol(Obj: TJSONObject; El: TPasExportSymbol; aContext: TPCUReaderContext); virtual;
procedure ReadConst(Obj: TJSONObject; El: TPasConst; aContext: TPCUReaderContext); virtual;
procedure ReadPropertyScope(Obj: TJSONObject; Scope: TPasPropertyScope; aContext: TPCUReaderContext); virtual;
procedure ReadProperty(Obj: TJSONObject; El: TPasProperty; aContext: TPCUReaderContext); virtual;
procedure ReadMethodResolution(Obj: TJSONObject; El: TPasMethodResolution; aContext: TPCUReaderContext); virtual;
procedure ReadProcedureNameParts(Obj: TJSONObject; El: TPasProcedure; aContext: TPCUReaderContext); virtual;
function ReadProcedureModifiers(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TProcedureModifiers): TProcedureModifiers; virtual;
function ReadProcScopeFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TPasProcedureScopeFlags): TPasProcedureScopeFlags; virtual;
procedure ReadProcedureScope(Obj: TJSONObject; Scope: TPas2JSProcedureScope; aContext: TPCUReaderContext); virtual;
procedure ReadProcScopeReferences(Obj: TJSONObject; ImplScope: TPas2JSProcedureScope); virtual;
procedure ReadProcedureBody(Obj: TJSONObject; El: TPasProcedure; aContext: TPCUReaderContext); virtual;
procedure ReadProcedure(Obj: TJSONObject; El: TPasProcedure; aContext: TPCUReaderContext); virtual;
procedure ReadOperator(Obj: TJSONObject; El: TPasOperator; aContext: TPCUReaderContext); virtual;
procedure ReadAttributes(Obj: TJSONObject; El: TPasAttributes; aContext: TPCUReaderContext); virtual;
procedure ResolvePending; virtual;
procedure ReadBuiltInSymbols(Obj: TJSONObject; ErrorEl: TPasElement); virtual;
public
constructor Create; override;
destructor Destroy; override;
procedure Clear; override;
procedure ReadPCU(aResolver: TPas2JSResolver; aStream: TStream); override; // sets property JSON, reads header and returns
procedure ReadJSONHeader(aResolver: TPas2JSResolver; Obj: TJSONObject); virtual;
function ReadContinue: boolean; override; // true=finished
property FileVersion: longint read FFileVersion;
property JSON: TJSONObject read FJSON;
end;
{ TPas2JSPrecompileFormat }
TPas2JSPrecompileFormat = class
public
Ext: string;
Description: string; // used by -h
ReaderClass: TPCUReaderClass;
WriterClass: TPCUWriterClass;
Enabled: boolean;
end;
{ TPas2JSPrecompileFormats }
TPas2JSPrecompileFormats = class
private
FItems: TObjectList; // list of TObjectList
function GetItems(Index: integer): TPas2JSPrecompileFormat;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function Count: integer;
function Add(aFormat: TPas2JSPrecompileFormat): TPas2JSPrecompileFormats;
function Add(const Ext, Description: string;
const Reader: TPCUReaderClass;
const Writer: TPCUWriterClass
): TPas2JSPrecompileFormat;
function IndexOf(aFormat: TPas2JSPrecompileFormat): integer;
function FindExt(Ext: string): TPas2JSPrecompileFormat;
function Remove(aFormat: TPas2JSPrecompileFormat): integer;
function Delete(Index: integer): TPas2JSPrecompileFormats;
property Items[Index: integer]: TPas2JSPrecompileFormat read GetItems; default;
end;
var
PrecompileFormats: TPas2JSPrecompileFormats = nil;
PCUFormat: TPas2JSPrecompileFormat = nil;
procedure RegisterPCUFormat;
function ComparePointer(Data1, Data2: Pointer): integer;
function ComparePCUSrcFiles(File1, File2: Pointer): integer;
function ComparePCUFilerElementRef(Ref1, Ref2: Pointer): integer;
function CompareElWithPCUFilerElementRef(El, Ref: Pointer): integer;
function EncodeVLQ(i: TMaxPrecInt): string; overload;
function EncodeVLQ(i: TMaxPrecUInt): string; overload;
function DecodeVLQ(const s: string): TMaxPrecInt; // base256 Variable Length Quantity
function DecodeVLQ(var p: PByte): TMaxPrecInt; // base256 Variable Length Quantity
function ComputeChecksum(p: PChar; Cnt: integer): TPCUSourceFileChecksum;
function crc32(crc: cardinal; buf: Pbyte; len: cardinal): cardinal;
function ModeSwitchToInt(ms: TModeSwitch): byte;
function StrToPasIdentifierKind(const s: string): TPasIdentifierKind;
procedure WriteJSON(aData: TJSONData; TargetStream: TStream; Compressed: boolean);
procedure GrowIdToRefsArray(var IdToRefsArray: TPCUFilerElementRefArray; Id: integer);
function dbgmem(const s: string): string; overload;
function dbgmem(p: PChar; Cnt: integer): string; overload;
implementation
procedure RegisterPCUFormat;
begin
if PCUFormat=nil then
PCUFormat:=PrecompileFormats.Add('pcu','all used pcu must match exactly',TPCUReader,TPCUWriter);
end;
function ComparePointer(Data1, Data2: Pointer): integer;
begin
if Data1>Data2 then Result:=-1
else if Data1<Data2 then Result:=1
else Result:=0;
end;
function ComparePCUSrcFiles(File1, File2: Pointer): integer;
var
Src1: TPCUSourceFile absolute File1;
Src2: TPCUSourceFile absolute File2;
begin
Result:=CompareStr(Src1.Filename,Src2.Filename);
end;
function ComparePCUFilerElementRef(Ref1, Ref2: Pointer): integer;
var
Reference1: TPCUFilerElementRef absolute Ref1;
Reference2: TPCUFilerElementRef absolute Ref2;
begin
Result:=ComparePointer(Reference1.Element,Reference2.Element);
end;
function CompareElWithPCUFilerElementRef(El, Ref: Pointer): integer;
var
Element: TPasElement absolute El;
Reference: TPCUFilerElementRef absolute Ref;
begin
Result:=ComparePointer(Element,Reference.Element);
end;
function EncodeVLQ(i: TMaxPrecInt): string;
{ Convert signed number to base256-VLQ:
Each byte has 8bit, where the least significant bit is the continuation bit
(1=there is a next byte).
The first byte contains the sign bit in the last bit
and the 6 most significant bits of the number.
For example:
0 = %00000000 => 0
1 = %00000001 => -0
2 = %00000010 => 1
130 5 = %10000010 %00000101 = 000010 0000101 = 100000101 = 133
}
var
digits: integer;
begin
digits:=0;
if i<0 then
begin
if i=Low(TMaxPrecInt) then
begin
Result:=EncodeVLQ(High(TMaxPrecInt)+1);
Result[1]:=chr(ord(Result[1]) or 1);
exit;
end;
digits:=1;
i:=-i;
end;
inc(digits,(i and %111111) shl 1);
i:=i shr 6;
if i>0 then
inc(digits,%10000000); // need another byte -> set continuation bit
Result:=chr(digits);
while i>0 do
begin
digits:=i and %1111111;
i:=i shr 7;
if i>0 then
inc(digits,%10000000); // need another byte -> set continuation bit
Result:=Result+chr(digits);
end;
end;
function EncodeVLQ(i: TMaxPrecUInt): string;
var
digits: integer;
begin
digits:=(i and %111111) shl 1;
if i>0 then
inc(digits,%10000000); // need another byte -> set continuation bit
Result:=chr(digits);
i:=i shr 6;
while i>0 do
begin
digits:=i and %1111111;
i:=i shr 7;
if i>0 then
inc(digits,%10000000); // need another byte -> set continuation bit
Result:=Result+chr(digits);
end;
end;
function DecodeVLQ(const s: string): TMaxPrecInt;
var
p: PByte;
begin
if s='' then
raise EConvertError.Create('DecodeVLQ empty');
p:=PByte(s);
Result:=DecodeVLQ(p);
if p-PByte(s)<>length(s) then
raise EConvertError.Create('DecodeVLQ waste');
end;
function DecodeVLQ(var p: PByte): TMaxPrecInt;
{ Convert base256-VLQ to signed number,
For the fomat see EncodeVLQ
}
procedure RaiseInvalid;
begin
raise ERangeError.Create('DecodeVLQ');
end;
const
MaxShift = 63; // actually log2(High(TMaxPrecInt))
var
digit, Shift: Integer;
Negated: Boolean;
begin
digit:=p^;
inc(p);
Negated:=(digit and 1)>0;
Result:=(digit shr 1) and %111111;
Shift:=6;
while digit>=%10000000 do
begin
digit:=p^;
inc(p);
if Shift>MaxShift then
RaiseInvalid;
inc(Result,TMaxPrecInt(digit and %1111111) shl Shift);
inc(Shift,7);
end;
if Negated then
Result:=-Result;
end;
function ComputeChecksum(p: PChar; Cnt: integer): TPCUSourceFileChecksum;
var
SrcP, SrcEndP, SrcLineEndP, SrcLineStartP: PChar;
l: PtrInt;
CheckSum, CurLen: Cardinal;
begin
if Cnt=0 then exit(0);
// ignore trailing spaces and unify line endings
SrcP:=p;
SrcEndP:=p+Cnt;
while (SrcEndP>SrcP) and (SrcEndP[-1] in [#9,#10,#13,' ']) do
dec(SrcEndP);
CheckSum:=crc32(0,nil,0);
while SrcP<SrcEndP do
begin
SrcLineStartP:=SrcP;
while (SrcP<SrcEndP) and not (SrcP^ in [#10,#13]) do
inc(SrcP);
SrcLineEndP:=SrcP;
while (SrcLineEndP>SrcLineStartP) and (SrcLineEndP[-1] in [#9,' ']) do
dec(SrcLineEndP);
l:=SrcLineEndP-SrcLineStartP;
while l>0 do
begin
if l<$8000 then
CurLen:=l
else
CurLen:=$8000;
CheckSum:=crc32(CheckSum, PByte(SrcLineStartP), CurLen);
inc(SrcLineStartP,CurLen);
dec(l,CurLen);
end;
while (SrcP<SrcEndP) and (SrcP^ in [#10,#13]) do
inc(SrcP);
end;
Result:=CheckSum;
end;
const
crc32_table : array[Byte] of cardinal = (
$00000000, $77073096, $ee0e612c, $990951ba, $076dc419,
$706af48f, $e963a535, $9e6495a3, $0edb8832, $79dcb8a4,
$e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07,
$90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de,
$1adad47d, $6ddde4eb, $f4d4b551, $83d385c7, $136c9856,
$646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9,
$fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4,
$a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
$35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3,
$45df5c75, $dcd60dcf, $abd13d59, $26d930ac, $51de003a,
$c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599,
$b8bda50f, $2802b89e, $5f058808, $c60cd9b2, $b10be924,
$2f6f7c87, $58684c11, $c1611dab, $b6662d3d, $76dc4190,
$01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f,
$9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e,
$e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
$6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed,
$1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950,
$8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3,
$fbd44c65, $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2,
$4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a,
$346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5,
$aa0a4c5f, $dd0d7cc9, $5005713c, $270241aa, $be0b1010,
$c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
$5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17,
$2eb40d81, $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6,
$03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615,
$73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8,
$e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344,
$8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb,
$196c3671, $6e6b06e7, $fed41b76, $89d32be0, $10da7a5a,
$67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
$d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1,
$a6bc5767, $3fb506dd, $48b2364b, $d80d2bda, $af0a1b4c,
$36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef,
$4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236,
$cc0c7795, $bb0b4703, $220216b9, $5505262f, $c5ba3bbe,
$b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31,
$2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c,
$026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
$95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b,
$e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242,
$68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1,
$18b74777, $88085ae6, $ff0f6a70, $66063bca, $11010b5c,
$8f659eff, $f862ae69, $616bffd3, $166ccf45, $a00ae278,
$d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7,
$4969474d, $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66,
$37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
$bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605,
$cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8,
$5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b,
$2d02ef8d);
function crc32(crc: cardinal; buf: Pbyte; len: cardinal): cardinal;
begin
if buf = nil then
exit(0);
crc := crc xor $FFFFFFFF;
while (len >= 8) do
begin
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
dec(len, 8);
end;
while (len > 0) do
begin
crc := crc32_table[(crc xor buf^) and $ff] xor (crc shr 8);
inc(buf);
dec(len);
end;
result := crc xor $FFFFFFFF;
end;
function ModeSwitchToInt(ms: TModeSwitch): byte;
begin
case ms of
msNone: Result:=0;
msFpc: Result:=1;
msObjfpc: Result:=2;
msDelphi: Result:=3;
msDelphiUnicode: Result:=4;
msTP7: Result:=5;
msMac: Result:=6;
msIso: Result:=7;
msExtpas: Result:=8;
msGPC: Result:=9;
msClass: Result:=10;
msObjpas: Result:=11;
msResult: Result:=12;
msStringPchar: Result:=13;
msCVarSupport: Result:=14;
msNestedComment: Result:=15;
msTPProcVar: Result:=16;
msMacProcVar: Result:=17;
msRepeatForward: Result:=18;
msPointer2Procedure: Result:=19;
msAutoDeref: Result:=20;
msInitFinal: Result:=21;
msDefaultAnsistring: Result:=22;
msOut: Result:=23;
msDefaultPara: Result:=24;
msHintDirective: Result:=25;
msDuplicateNames: Result:=26;
msProperty: Result:=27;
msDefaultInline: Result:=28;
msExcept: Result:=29;
msObjectiveC1: Result:=30;
msObjectiveC2: Result:=31;
msNestedProcVars: Result:=32;
msNonLocalGoto: Result:=33;
msAdvancedRecords: Result:=34;
msISOLikeUnaryMinus: Result:=35;
msSystemCodePage: Result:=36;
msFinalFields: Result:=37;
msDefaultUnicodestring: Result:=38;
msTypeHelpers: Result:=39;
msCBlocks: Result:=40;
msISOLikeIO: Result:=41;
msISOLikeProgramsPara: Result:=42;
msISOLikeMod: Result:=43;
msExternalClass: Result:=44;
msPrefixedAttributes: Result:=45;
// msIgnoreInterfaces: Result:=46;
// msIgnoreAttributes: Result:=47;
msOmitRTTI: Result:=48;
msMultiHelpers: Result:=49;
msImplicitFunctionSpec: Result:=50;
end;
end;
function StrToPasIdentifierKind(const s: string): TPasIdentifierKind;
var
Kind: TPasIdentifierKind;
begin
for Kind in TPasIdentifierKind do
if s=PCUIdentifierKindNames[Kind] then
exit(Kind);
Result:=pikNone;
end;
procedure WriteJSON(aData: TJSONData; TargetStream: TStream; Compressed: boolean
);
var
CurIndent: integer;
Spaces: string;
procedure WriteString(const s: string);
begin
if s='' then exit;
TargetStream.Write(s[1],length(s));
end;
procedure WriteChar(const c: char);
begin
TargetStream.Write(c,1);
end;
procedure WriteLine;
begin
WriteString(sLineBreak);
if CurIndent>0 then
TargetStream.Write(Spaces[1],CurIndent);
end;
procedure Indent;
begin
if Compressed then exit;
inc(CurIndent,2);
if CurIndent>length(Spaces) then
Spaces:=Spaces+' ';
end;
procedure Unindent;
begin
if Compressed then exit;
dec(CurIndent,2);
end;
procedure WriteData(Data: TJSONData); forward;
procedure WriteObj(Obj: TJSONObject);
var
i: Integer;
Name: String;
begin
WriteChar('{');
if not Compressed then
begin
Indent;
WriteLine;
end;
for i:=0 to Obj.Count-1 do
begin
if i>0 then
begin
WriteChar(',');
if not Compressed then
WriteLine;
end;
Name:=Obj.Names[i];
WriteChar('"');
if IsValidIdent(Name) then
WriteString(Name)
else
WriteString(StringToJSONString(Name,false));
WriteString('":');
WriteData(Obj.Elements[Name]);
end;
if not Compressed then
begin
Unindent;
WriteLine;
end;
WriteChar('}');
end;
procedure WriteArray(Arr: TJSONArray);
var
i: Integer;
begin
WriteChar('[');
if not Compressed then
begin
Indent;
WriteLine;
end;
for i:=0 to Arr.Count-1 do
begin
if i>0 then
begin
WriteChar(',');
if not Compressed then
WriteLine;
end;
WriteData(Arr[i]);
end;
if not Compressed then
begin
Unindent;
WriteLine;
end;
WriteChar(']');
end;
procedure WriteData(Data: TJSONData);
var
C: TClass;
begin
C:=Data.ClassType;
if C=TJSONObject then
WriteObj(TJSONObject(Data))
else if C=TJSONArray then
WriteArray(TJSONArray(Data))
else if C.InheritsFrom(TJSONNumber)
or (C=TJSONBoolean)
then
WriteString(Data.AsString)
else if (C=TJSONNull) then
WriteString('null')
else if C=TJSONString then
begin
WriteChar('"');
WriteString(StringToJSONString(Data.AsString));
WriteChar('"');
end
else
raise EPas2JsWriteError.Create('unknown JSON data '+GetObjName(Data));
end;
begin
CurIndent:=0;
WriteData(aData);
end;
procedure GrowIdToRefsArray(var IdToRefsArray: TPCUFilerElementRefArray; Id: integer);
var
OldCapacity, NewCapacity: Integer;
begin
OldCapacity:=length(IdToRefsArray);
if Id>=OldCapacity then
begin
// grow
NewCapacity:=OldCapacity;
if NewCapacity=0 then NewCapacity:=100;
while NewCapacity<Id+1 do NewCapacity:=NewCapacity*2;
SetLength(IdToRefsArray,NewCapacity);
FillByte(IdToRefsArray[OldCapacity],SizeOf(Pointer)*(NewCapacity-OldCapacity),0);
end;
end;
function dbgmem(const s: string): string;
begin
if s='' then exit('');
Result:=dbgmem(PChar(s),length(s));
end;
function dbgmem(p: PChar; Cnt: integer): string;
procedure AddLine(const Line: string);
begin
if Result<>'' then
Result:=Result+LineEnding;
Result:=Result+Line;
end;
var
c: Char;
IsTxt: boolean;
Line: String;
i: Integer;
begin
Result:='';
if (p=nil) or (Cnt<=0) then exit;
Line:='';
IsTxt:=false;
for i:=0 to Cnt-1 do
begin
c:=p[i];
if c in ['a'..'z','A'..'Z','_','/','0'..'9'] then
begin
if not IsTxt then
begin
Line:=Line+'''';
IsTxt:=true;
end;
Line:=Line+c;
end
else
begin
if IsTxt then
begin
Line:=Line+'''';
IsTxt:=false;
end;
Line:=Line+'#'+HexStr(ord(c),2);
end;
if length(Line)>78 then
begin
AddLine(Line);
Line:='';
end;
end;
if Line<>'' then
AddLine(Line);
end;
{ TPCUCustomReader }
function TPCUCustomReader.ReadCanContinue: boolean;
var
Module: TPasModule;
Section: TPasSection;
Scope: TPas2JSSectionScope;
begin
Result:=false;
Module:=Resolver.RootElement;
if Module=nil then exit(true); // not yet started
Section:=Resolver.GetLastSection;
if Section=nil then exit(true); // only header
Scope:=Section.CustomData as TPas2JSSectionScope;
if Scope.Finished then exit(false); // finished
Result:=Section.PendingUsedIntf=nil;
end;
{ TPCUFilerElementRef }
procedure TPCUFilerElementRef.AddPending(Item: TPCUFilerPendingElRef);
begin
Item.Next:=Pending;
Pending:=Item;
end;
procedure TPCUFilerElementRef.Clear;
var
Ref, NextRef: TPCUFilerPendingElRef;
begin
Elements:=nil;
Ref:=Pending;
while Ref<>nil do
begin
NextRef:=Ref.Next;
Ref.Next:=nil;
Ref.Free;
Ref:=NextRef;
end;
Pending:=nil;
end;
destructor TPCUFilerElementRef.Destroy;
begin
Clear;
inherited Destroy;
end;
{ TPCUFiler }
function TPCUFiler.GetSourceFiles(Index: integer): TPCUSourceFile;
begin
Result:=TPCUSourceFile(FSourceFiles[Index]);
end;
procedure TPCUFiler.RaiseMsg(Id: int64; El: TPasElement; const Msg: string);
var
Path, s: String;
CurEl: TPasElement;
begin
Path:='';
CurEl:=El;
while CurEl<>nil do
begin
if Path<>'' then Path:='.'+Path;
s:=CurEl.Name;
if s='' then
s:=CurEl.ClassName;
Path:=s+Path;
CurEl:=CurEl.Parent;
end;
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
): TPasMemberVisibility;
var
aClass: TPasClassType;
begin
if El=nil then ;
Result:=visDefault;
if El.Parent is TPasClassType then
begin
aClass:=TPasClassType(El.Parent);
case aClass.ObjKind of
okInterface: Result:=visPublic;
end;
end;
end;
function TPCUFiler.GetDefaultPasScopeVisibilityContext(Scope: TPasScope
): TPasElement;
var
El: TPasElement;
begin
El:=Scope.Element;
if El is TPasMembersType then
Result:=El
else if El is TPasModule then
Result:=El
else if (Scope is TPasProcedureScope) and (Scope.Element.Parent is TPasMembersType) then
Result:=Scope.Element.Parent
else
Result:=nil;
end;
procedure TPCUFiler.GetDefaultsPasIdentifierProps(El: TPasElement; out
Kind: TPasIdentifierKind; out Name: string);
begin
Kind:=PCUDefaultIdentifierKind;
if El is TPasProcedure then
Kind:=pikProc;
Name:=El.Name;
end;
function TPCUFiler.GetDefaultClassScopeFlags(Scope: TPas2JSClassScope
): TPasClassScopeFlags;
begin
if FFileVersion<2 then
Result:=[]
else
Result:=[pcsfAncestorResolved];
if Scope.AncestorScope<>nil then
begin
if pcsfPublished in Scope.AncestorScope.Flags then
Include(Result,pcsfPublished);
end;
end;
function TPCUFiler.GetDefaultProcModifiers(Proc: TPasProcedure
): TProcedureModifiers;
begin
Result:=[];
if Proc.Parent is TPasClassType then
begin
if TPasClassType(Proc.Parent).IsExternal then
Include(Result,pmExternal);
end;
end;
function TPCUFiler.GetDefaultProcTypeModifiers(ProcType: TPasProcedureType
): TProcTypeModifiers;
var
Proc: TPasProcedure;
begin
Result:=[];
if ProcType.Parent is TPasProcedure then
begin
Proc:=TPasProcedure(ProcType.Parent);
if Proc.Parent is TPasClassType then
Include(Result,ptmOfObject);
end;
end;
function TPCUFiler.GetDefaultExprHasEvalValue(Expr: TPasExpr): boolean;
var
C: TClass;
begin
C:=Expr.Parent.ClassType;
if C.InheritsFrom(TPasExpr) then exit(false);
if (C=TPasAliasType)
or (C=TPasTypeAliasType)
or (C=TPasPointerType)
or (C=TPasProperty)
then
exit(false);
C:=Expr.ClassType;
if C=TArrayValues then exit(false);
if C=TRecordValues then exit(false);
Result:=not Resolver.ExprEvaluator.IsSimpleExpr(Expr);
end;
function TPCUFiler.GetSrcCheckSum(aFilename: string): TPCUSourceFileChecksum;
var
p: PChar;
Cnt: integer;
begin
OnGetSrc(Self,aFilename,p,Cnt);
Result:=ComputeChecksum(p,Cnt);
end;
function TPCUFiler.GetDefaultRefName(El: TPasElement): string;
var
C: TClass;
begin
Result:=El.Name;
if Result<>'' then exit;
// some elements without name can be referred to:
C:=El.ClassType;
if C=TInterfaceSection then
Result:='Interface'
else if C=TPasArrayType then
Result:='Array' // anonymous array
else if C.InheritsFrom(TPasProcedureType) and (El.Parent is TPasProcedure) then
Result:='Type'
else
Result:='';
end;
function TPCUFiler.GetElementReference(El: TPasElement; AutoCreate: boolean
): TPCUFilerElementRef;
var
Node: TAVLTreeNode;
MyEl: TPasElement;
IsBuiltIn: boolean;
begin
{$IFDEF VerbosePCUFiler}
//writeln('TPCUFiler.GetElementReference ',GetObjName(El));
{$ENDIF}
IsBuiltIn:=El.CustomData is TResElDataBuiltInSymbol;
if IsBuiltIn then
begin
// built-in symbol -> redirect to symbol of this module
MyEl:=Resolver.FindLocalBuiltInSymbol(El);
if MyEl=nil then
RaiseMsg(20180207121004,El,GetObjName(El.CustomData));
El:=MyEl;
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:=CreateElementRef(El);
if IsBuiltIn then
AddedBuiltInRef(Result);
end
else
Result:=nil;
end;
function TPCUFiler.CreateElementRef(El: TPasElement): TPCUFilerElementRef;
{$IFDEF MemCheck}
var
Node: TAVLTreeNode;
{$ENDIF}
begin
Result:=TPCUFilerElementRef.Create;
Result.Element:=El;
{$IFDEF MemCheck}
Node:=FElementRefs.Add(Result);
if Node<>FElementRefs.FindKey(El,@CompareElWithPCUFilerElementRef) then
RaiseMsg(20180711222046,El);
{$ELSE}
FElementRefs.Add(Result);
{$ENDIF}
end;
procedure TPCUFiler.AddedBuiltInRef(Ref: TPCUFilerElementRef);
begin
if Ref=nil then ;
end;
constructor TPCUFiler.Create;
begin
FFileVersion:=PCUVersion;
FSourceFiles:=TObjectList.Create(true);
FElementRefs:=TAVLTree.Create(@ComparePCUFilerElementRef);
FElementRefs.SetNodeManager(TAVLTreeNodeMemManager.Create,true); // no shared manager, needed for multithreading
end;
destructor TPCUFiler.Destroy;
begin
Clear;
FreeAndNil(FSourceFiles);
FreeAndNil(FElementRefs);
inherited Destroy;
end;
procedure TPCUFiler.Clear;
begin
FElementRefs.FreeAndClear;
FSourceFiles.Clear;
FResolver:=nil;
FParser:=nil;
FScanner:=nil;
end;
function TPCUFiler.SourceFileCount: integer;
begin
Result:=FSourceFiles.Count;
end;
{ TPCUInitialFlags }
constructor TPCUInitialFlags.Create;
begin
Clear;
end;
procedure TPCUInitialFlags.Clear;
begin
ParserOptions:=PCUDefaultParserOptions;
ModeSwitches:=PCUDefaultModeSwitches;
BoolSwitches:=PCUDefaultBoolSwitches;
ConverterOptions:=PCUDefaultConverterOptions;
TargetPlatform:=PCUDefaultTargetPlatform;
TargetProcessor:=PCUDefaultTargetProcessor;
end;
{ TPCUWriter }
procedure TPCUWriter.ResolvePendingElRefs(Ref: TPCUFilerElementRef);
var
RefItem: TPCUFilerPendingElRef;
RefObj: TPCUWriterPendingElRefObj;
RefArr: TPCUWriterPendingElRefArray;
begin
if Ref.Pending=nil then exit;
// this element is referenced
if Ref.Id=0 then
CreateElReferenceId(Ref);
// resolve all pending references
while Ref.Pending<>nil do
begin
RefItem:=Ref.Pending;
if RefItem is TPCUWriterPendingElRefObj then
begin
RefObj:=TPCUWriterPendingElRefObj(RefItem);
RefObj.Obj.Add(RefObj.PropName,Ref.Id);
end
else if RefItem is TPCUWriterPendingElRefArray then
begin
RefArr:=TPCUWriterPendingElRefArray(RefItem);
RefArr.Arr.Integers[RefArr.Index]:=Ref.Id;
end
else
RaiseMsg(20180207113335,RefItem.ClassName);
Ref.Pending:=RefItem.Next;
RefItem.Next:=nil;
RefItem.Free;
end;
end;
procedure TPCUWriter.RaiseMsg(Id: int64; const Msg: string);
var
E: EPas2JsWriteError;
begin
E:=EPas2JsWriteError.Create('['+IntToStr(Id)+'] '+Msg);
E.Owner:=Self;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.RaiseMsg ',E.Message);
{$ENDIF}
raise E;
end;
function TPCUWriter.CheckElScope(El: TPasElement; NotNilId: int64;
ScopeClass: TPasScopeClass): TPasScope;
var
Data: TObject;
begin
Data:=El.CustomData;
if Data=nil then
begin
if NotNilId>0 then
RaiseMsg(NotNilId);
exit(nil);
end;
if Data.ClassType<>ScopeClass then
RaiseMsg(20180206113601,'expected '+ScopeClass.ClassName+', but found '+Data.ClassName);
Result:=TPasScope(Data);
if Result.Element<>El then
RaiseMsg(20180206113723,'El='+GetObjName(El)+' Scope.Element='+GetObjName(Result.Element));
if Result.Owner<>Resolver then
RaiseMsg(20180206113750,El,GetObjName(Result));
end;
procedure TPCUWriter.AddArrayFlag(Obj: TJSONObject; var Arr: TJSONArray;
const ArrName, Flag: string; Enable: boolean);
begin
if Arr=nil then
begin
Arr:=TJSONArray.Create;
Obj.Add(ArrName,Arr);
end;
if Enable then
Arr.Add(Flag)
else
Arr.Add('-'+Flag);
end;
procedure TPCUWriter.AddReferenceToArray(Arr: TJSONArray; El: TPasElement;
WriteNull: boolean);
var
Ref: TPCUFilerElementRef;
Item: TPCUWriterPendingElRefArray;
begin
if El=nil then
begin
if WriteNull then
Arr.Add(CreateJSON);
exit;
end;
Ref:=GetElementReference(El);
if (Ref.Obj<>nil) and (Ref.Id=0) then
CreateElReferenceId(Ref);
Arr.Add(Ref.Id);
if Ref.Id<>0 then
exit;
// Element was not yet written -> add a pending item to the queue
Item:=TPCUWriterPendingElRefArray.Create;
Item.ErrorEl:=El;
Item.Arr:=Arr;
Item.Index:=Arr.Count-1;
Ref.AddPending(Item);
end;
procedure TPCUWriter.AddReferenceToObj(Obj: TJSONObject;
const PropName: string; El: TPasElement; WriteNil: boolean);
var
Ref: TPCUFilerElementRef;
Item: TPCUWriterPendingElRefObj;
begin
if El=nil then
begin
if WriteNil then
Obj.Add(PropName,0);
exit;
end;
Ref:=GetElementReference(El);
if (Ref.Obj<>nil) and (Ref.Id=0) then
CreateElReferenceId(Ref);
if Ref.Id<>0 then
Obj.Add(PropName,Ref.Id)
else
begin
// Element was not yet written -> add a pending item to the queue
Item:=TPCUWriterPendingElRefObj.Create;
Item.ErrorEl:=El;
Item.Obj:=Obj;
Item.PropName:=PropName;
Ref.AddPending(Item);
end;
end;
procedure TPCUWriter.CreateAutoElReferenceId(Ref: TPCUFilerElementRef);
begin
if Ref.Id<>0 then
RaiseMsg(20180207114300,Ref.Element,IntToStr(Ref.Id));
inc(FElementIdCounter);
Ref.Id:=FElementIdCounter;
end;
procedure TPCUWriter.CreateElReferenceId(Ref: TPCUFilerElementRef);
begin
CreateAutoElReferenceId(Ref);
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;
{$IF defined(VerbosePCUFiler) or defined(VerbosePJUFiler) or defined(VerbosePas2JS)}
if (El.Name='') and (GetDefaultRefName(El)='') then
RaiseMsg(20180623091608,El);
{$ENDIF}
end;
end;
procedure TPCUWriter.AddedBuiltInRef(Ref: TPCUFilerElementRef);
var
ModuleObj, Obj: TJSONObject;
El: TPasElement;
Data: TObject;
begin
El:=Ref.Element;
// add built-in symbol to BuiltIn array
if El<>Resolver.FindLocalBuiltInSymbol(El) then
RaiseMsg(20180207124914,El);
if FBuiltInSymbolsArr=nil then
begin
ModuleObj:=JSON.Find('Module') as TJSONObject;
FBuiltInSymbolsArr:=TJSONArray.Create;
ModuleObj.Add(BuiltInNodeName,FBuiltInSymbolsArr);
end;
Obj:=TJSONObject.Create;
FBuiltInSymbolsArr.Add(Obj);
Obj.Add('Name',El.Name);
// Ref.Id is written in ResolvePendingElRefs
Data:=El.CustomData;
if Data is TResElDataBuiltInProc then
case TResElDataBuiltInProc(Data).BuiltIn of
bfStrFunc: Obj.Add('Type','Func');
end;
Ref.Obj:=Obj;
ResolvePendingElRefs(Ref);
end;
procedure TPCUWriter.WriteHeaderMagic(Obj: TJSONObject);
begin
Obj.Add('FileType',PCUMagic);
end;
procedure TPCUWriter.WriteHeaderVersion(Obj: TJSONObject);
begin
Obj.Add('Version',PCUVersion);
end;
procedure TPCUWriter.WriteGUID(Obj: TJSONObject);
begin
Obj.Add('GUID',GUIDToString(GUID));
end;
procedure TPCUWriter.WriteInitialFlags(Obj: TJSONObject);
begin
WriteParserOptions(Obj,'InitParserOpts',InitialFlags.ParserOptions,PCUDefaultParserOptions);
WriteModeSwitches(Obj,'InitModeSwitches',InitialFlags.Modeswitches,PCUDefaultModeSwitches);
WriteBoolSwitches(Obj,'InitBoolSwitches',InitialFlags.BoolSwitches,PCUDefaultBoolSwitches);
WriteConverterOptions(Obj,'InitConverterOpts',InitialFlags.ConverterOptions,PCUDefaultConverterOptions);
if InitialFlags.TargetPlatform<>PCUDefaultTargetPlatform then
Obj.Add('TargetPlatform',PCUTargetPlatformNames[InitialFlags.TargetPlatform]);
if InitialFlags.TargetProcessor<>PCUDefaultTargetProcessor then
Obj.Add('TargetProcessor',PCUTargetProcessorNames[InitialFlags.TargetProcessor]);
// ToDo: write initial flags: used defines, used macros
end;
procedure TPCUWriter.WriteFinalFlags(Obj: TJSONObject);
begin
WriteParserOptions(Obj,'FinalParserOpts',Parser.Options,InitialFlags.ParserOptions);
WriteModeSwitches(Obj,'FinalModeSwitches',Scanner.CurrentModeSwitches,InitialFlags.Modeswitches);
WriteBoolSwitches(Obj,'FinalBoolSwitches',Scanner.CurrentBoolSwitches,InitialFlags.BoolSwitches);
if InitialFlags.ConverterOptions<>Converter.Options then
RaiseMsg(20180314185555,'InitialFlags='+dbgs(InitialFlags.ConverterOptions)+' Converter='+dbgs(Converter.Options));
// ToDo: write final flags: used defines, used macros
end;
procedure TPCUWriter.WriteParserOptions(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TPOptions);
var
Arr: TJSONArray;
f: TPOption;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TPOptions do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUParserOptionNames[f],f in Value);
end;
procedure TPCUWriter.WriteModeSwitches(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TModeSwitches);
var
Arr: TJSONArray;
f: TModeSwitch;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TModeSwitch do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUModeSwitchNames[f],f in Value);
end;
procedure TPCUWriter.WriteBoolSwitches(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TBoolSwitches);
var
Arr: TJSONArray;
f: TBoolSwitch;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TBoolSwitch do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUBoolSwitchNames[f],f in Value);
end;
procedure TPCUWriter.WriteConverterOptions(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TPasToJsConverterOptions);
var
Arr: TJSONArray;
f: TPasToJsConverterOption;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TPasToJsConverterOption do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUConverterOptions[f],f in Value);
end;
procedure TPCUWriter.WriteSrcFiles(Obj: TJSONObject);
var
CurFile: TPCUSourceFile;
List: TFPList;
i: Integer;
SourcesArr: TJSONArray;
Src: TJSONObject;
begin
List:=TFPList.Create;
try
// get files from scanner
for i:=0 to Scanner.Files.Count-1 do
begin
CurFile:=TPCUSourceFile.Create;
CurFile.Index:=i;
CurFile.Filename:=Scanner.Files[i];
if i=0 then
CurFile.FileType:=sftUnit
else
CurFile.FileType:=sftInclude;
FSourceFiles.Add(CurFile);
CurFile.Checksum:=GetSrcCheckSum(CurFile.Filename);
List.Add(CurFile);
end;
// create FSourceFilesSorted
List.Sort(@ComparePCUSrcFiles);
SetLength(FSourceFilesSorted,List.Count);
for i:=0 to List.Count-1 do
FSourceFilesSorted[i]:=TPCUSourceFile(List[i]);
// write
SourcesArr:=TJSONArray.Create;
Obj.Add('Sources',SourcesArr);
for i:=0 to FSourceFiles.Count-1 do
begin
CurFile:=TPCUSourceFile(FSourceFiles[i]);
Src:=TJSONObject.Create;
SourcesArr.Add(Src);
if (i=0) then
// the first file is the unit source, no need to write Kind
else if (CurFile.FileType=sftInclude) then
// the default file type is include, no need to write Kind
else
Src.Add('Type',PCUSourceFileTypeNames[CurFile.FileType]);
Src.Add('File',CurFile.Filename);
Src.Add('CheckSum',CurFile.Checksum);
end;
finally
List.Free;
end;
end;
procedure TPCUWriter.WriteMemberHints(Obj: TJSONObject; const Value,
DefaultValue: TPasMemberHints);
var
Arr: TJSONArray;
f: TPasMemberHint;
begin
Arr:=nil;
for f in TPasMemberHints do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,'Hints',PCUMemberHintNames[f],f in Value);
end;
procedure TPCUWriter.WritePasElement(Obj: TJSONObject; El: TPasElement;
aContext: TPCUWriterContext);
var
DefHints: TPasMemberHints;
DefVisibility: TPasMemberVisibility;
Ref: TPCUFilerElementRef;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WritePasElement ',GetObjName(El));
{$ENDIF}
if El.Name<>'' then
Obj.Add('Name',Resolver.GetOverloadName(El));
// Id
Ref:=GetElementReference(El);
Ref.Obj:=Obj;
ResolvePendingElRefs(Ref);
WriteSrcPos(Obj,El,aContext);
DefVisibility:=GetDefaultMemberVisibility(El);
if El.Visibility<>DefVisibility then
Obj.Add('Visibility',PCUMemberVisibilityNames[El.Visibility]);
DefHints:=[];
if El.Parent<>nil then
DefHints:=El.Parent.Hints;
WriteMemberHints(Obj,El.Hints,DefHints);
if El.HintMessage<>'' then
Obj.Add('HintMessage',El.HintMessage);
// not needed El.DocComment
if aContext<>nil then ;
end;
procedure TPCUWriter.WriteModuleScopeFlags(Obj: TJSONObject; const Value,
DefaultValue: TPasModuleScopeFlags);
var
Arr: TJSONArray;
f: TPasModuleScopeFlag;
begin
Arr:=nil;
for f in TPasModuleScopeFlags do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,'ScopeFlags',PCUModuleScopeFlagNames[f],f in Value);
end;
procedure TPCUWriter.WriteModule(Obj: TJSONObject; aModule: TPasModule;
aContext: TPCUWriterContext);
procedure WSection(Section: TPasSection; const PropName: string);
begin
if Section=nil then exit;
if Section.Parent<>aModule then
RaiseMsg(20180205153912,aModule,PropName);
aContext.Section:=Section; // set Section before calling virtual method
aContext.SectionObj:=nil;
aContext.IndirectUsesArr:=nil;
WriteSection(Obj,Section,PropName,aContext);
end;
procedure WImplBlock(Block: TPasImplBlock; const PropPrefix: string);
var
Scope: TPas2JSInitialFinalizationScope;
begin
if Block=nil then exit;
Scope:=Block.CustomData as TPas2JSInitialFinalizationScope;
if Scope.JS<>'' then
Obj.Add(PropPrefix+'JS',Scope.JS);
WriteScopeReferences(Obj,Scope.References,PropPrefix+'Refs',aContext);
end;
procedure RaisePending(Ref: TPCUFilerElementRef);
{$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
var
PendObj: TPCUWriterPendingElRefObj;
PendArr: TPCUWriterPendingElRefArray;
{$ENDIF}
begin
{$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
{AllowWriteln}
writeln('TPCUWriter.WriteModule Ref.Element=',GetElementDbgPath(Ref.Element),' Pending=',GetObjName(Ref.Pending),' ErrorEl=',GetElementDbgPath(Ref.Pending.ErrorEl));
if Ref.Pending is TPCUWriterPendingElRefObj then
begin
PendObj:=TPCUWriterPendingElRefObj(Ref.Pending);
writeln(' Obj=',PendObj.Obj<>nil,' PropName=',PendObj.PropName);
end
else if Ref.Pending is TPCUWriterPendingElRefArray then
begin
PendArr:=TPCUWriterPendingElRefArray(Ref.Pending);
writeln(' Arr=',PendArr.Arr<>nil,' Index=',PendArr.Index);
end;
{AllowWriteln-}
{$ENDIF}
RaiseMsg(20180318225558,Ref.Element,GetObjName(Ref.Pending));
end;
var
ModScope: TPas2JSModuleScope;
Node: TAVLTreeNode;
Ref: TPCUFilerElementRef;
begin
FInImplementation:=false;
WritePasElement(Obj,aModule,aContext);
if aModule.ClassType=TPasModule then
Obj.Add('Type','Unit')
else if aModule.ClassType=TPasProgram then
Obj.Add('Type','Program')
else if aModule.ClassType=TPasLibrary then
Obj.Add('Type','Library')
else
RaiseMsg(20180203163923);
// module scope
ModScope:=TPas2JSModuleScope(CheckElScope(aModule,20180206113855,TPas2JSModuleScope));
WriteModuleScope(Obj,ModScope,aContext);
// write sections
if aModule.ClassType=TPasProgram then
begin
WSection(TPasProgram(aModule).ProgramSection,'Program');
WImplBlock(aModule.InitializationSection,'begin');
end
else if aModule.ClassType=TPasLibrary then
begin
WSection(TPasLibrary(aModule).LibrarySection,'Library');
WImplBlock(aModule.InitializationSection,'begin');
end
else
begin
WSection(aModule.InterfaceSection,'Interface');
FInImplementation:=true;
WSection(aModule.ImplementationSection,'Implementation');
WImplBlock(aModule.InitializationSection,'Init');
WImplBlock(aModule.FinalizationSection,'Final');
end;
//writeln('TPCUWriter.WriteModule WriteExternalReferences of implementation ',Resolver.RootElement.Name,' aContext.Section=',GetObjName(aContext.Section));
WriteExternalReferences(aContext);
// consistency check
Node:=FElementRefs.FindLowest;
while Node<>nil do
begin
Ref:=TPCUFilerElementRef(Node.Data);
if Ref.Pending<>nil then
RaisePending(Ref);
Node:=FElementRefs.FindSuccessor(Node);
end;
end;
procedure TPCUWriter.WritePasScope(Obj: TJSONObject; Scope: TPasScope;
aContext: TPCUWriterContext);
var
DefVisibilityContext: TPasElement;
begin
if aContext=nil then ;
DefVisibilityContext:=GetDefaultPasScopeVisibilityContext(Scope);
if Scope.VisibilityContext<>DefVisibilityContext then
AddReferenceToObj(Obj,'VisibilityContext',Scope.VisibilityContext,true);
end;
procedure TPCUWriter.WriteIdentifierScope(Obj: TJSONObject;
Scope: TPasIdentifierScope; aContext: TPCUWriterContext);
var
Arr: TJSONArray;
procedure WriteItem(Item: TPasIdentifier);
var
DefKind: TPasIdentifierKind;
DefName: string;
Sub: TJSONObject;
begin
GetDefaultsPasIdentifierProps(Item.Element,DefKind,DefName);
if (Item.Kind=DefKind) and (Item.Identifier=DefName) then
begin
// add the element Id
AddReferenceToArray(Arr,Item.Element);
end
else begin
// add a json object
Sub:=TJSONObject.Create;
Arr.Add(Sub);
if Item.Kind<>DefKind then
Sub.Add('Kind',PCUIdentifierKindNames[Item.Kind]);
if Item.Identifier<>DefName then
Sub.Add('Name',Item.Identifier);
AddReferenceToObj(Sub,'El',Item.Element);
end;
end;
var
Locals: TFPList;
i, p: Integer;
Item: TPasIdentifier;
Ordered: TPasIdentifierArray;
begin
WritePasScope(Obj,Scope,aContext);
Arr:=nil;
if aContext=nil then ;
Locals:=Scope.GetLocalIdentifiers;
try
p:=0;
Ordered:=nil;
for i:=0 to Locals.Count-1 do
begin
if Arr=nil then
begin
Arr:=TJSONArray.Create;
Obj.Add('SItems',Arr);
end;
Item:=TPasIdentifier(Locals[i]);
if Item.NextSameIdentifier=nil then
WriteItem(Item)
else
begin
// write in declaration order (i.e. reverse)
p:=0;
while Item<>nil do
begin
if length(Ordered)<=p then
SetLength(Ordered,length(Ordered)+4);
Ordered[p]:=Item;
inc(p);
Item:=Item.NextSameIdentifier;
end;
while p>0 do
begin
dec(p);
WriteItem(Ordered[p]);
end;
end;
end;
finally
Locals.Free;
end;
end;
procedure TPCUWriter.WriteModuleScope(Obj: TJSONObject;
Scope: TPas2JSModuleScope; aContext: TPCUWriterContext);
var
aModule: TPasModule;
begin
aModule:=Scope.Element as TPasModule;
if Scope.FirstName<>FirstDottedIdentifier(aModule.Name) then
RaiseMsg(20180206114233,aModule);
// write not needed: Scope.FirstName
WriteModuleScopeFlags(Obj,Scope.Flags,PCUDefaultModuleScopeFlags);
WriteBoolSwitches(Obj,'BoolSwitches',Scope.BoolSwitches,aContext.BoolSwitches);
AddReferenceToObj(Obj,'AssertClass',Scope.AssertClass);
AddReferenceToObj(Obj,'AssertDefConstructor',Scope.AssertDefConstructor);
AddReferenceToObj(Obj,'AssertMsgConstructor',Scope.AssertMsgConstructor);
AddReferenceToObj(Obj,'RangeErrorClass',Scope.RangeErrorClass);
AddReferenceToObj(Obj,'RangeErrorConstructor',Scope.RangeErrorConstructor);
AddReferenceToObj(Obj,'SystemTVarRec',Scope.SystemTVarRec);
AddReferenceToObj(Obj,'SystemVarRecs',Scope.SystemVarRecs);
WritePasScope(Obj,Scope,aContext);
end;
procedure TPCUWriter.WriteSrcPos(Obj: TJSONObject; El: TPasElement;
aContext: TPCUWriterContext);
var
LastLine, LastCol, i, CurLine, CurCol: Integer;
s: String;
begin
if aContext=nil then ;
if (El.Parent=nil) or (El.Parent.SourceFilename<>El.SourceFilename) then
begin
if El.SourceFilename<>'' then
begin
i:=IndexOfSourceFile(El.SourceFilename);
if i<0 then
RaiseMsg(20180205110259,El,El.SourceFilename);
end
else
i:=-1;
Obj.Add('File',i);
end;
if El.Parent=nil then
begin
LastLine:=1;
LastCol:=1;
end
else
Resolver.UnmangleSourceLineNumber(El.Parent.SourceLinenumber,LastLine,LastCol);
Resolver.UnmangleSourceLineNumber(El.SourceLinenumber,CurLine,CurCol);
s:='';
if LastLine<>CurLine then
s:=IntToStr(CurLine);
if LastCol<>CurCol then
s:=s+','+IntToStr(CurCol);
if s<>'' then
Obj.Add('Pos',s);
// not needed: El.SourceEndLinenumber
end;
procedure TPCUWriter.WriteSection(ParentJSON: TJSONObject;
Section: TPasSection; const PropName: string; aContext: TPCUWriterContext);
var
Obj, SubObj: TJSONObject;
Scope, UsesScope: TPas2JSSectionScope;
i, j: Integer;
Arr: TJSONArray;
UsesUnit: TPasUsesUnit;
Name, InFilename: String;
Ref: TPCUFilerElementRef;
begin
if Section=nil then exit;
Obj:=TJSONObject.Create;
ParentJSON.Add(PropName,Obj);
aContext.SectionObj:=Obj;
aContext.IndirectUsesArr:=nil;
WritePasElement(Obj,Section,aContext);
Scope:=TPas2JSSectionScope(CheckElScope(Section,20180206121825,TPas2JSSectionScope));
if not Scope.Finished then
RaiseMsg(20180206130333,Section);
WriteBoolSwitches(Obj,'BoolSwitches',Scope.BoolSwitches,aContext.BoolSwitches);
aContext.BoolSwitches:=Scope.BoolSwitches;
WriteModeSwitches(Obj,'ModeSwitches',Scope.ModeSwitches,aContext.ModeSwitches);
aContext.ModeSwitches:=Scope.ModeSwitches;
if Scope.UsesScopes.Count<>length(Section.UsesClause) then
RaiseMsg(20180206122222,Section);
Arr:=nil;
for i:=0 to Scope.UsesScopes.Count-1 do
begin
UsesUnit:=Section.UsesClause[i];
UsesScope:=TPas2JSSectionScope(Scope.UsesScopes[i]);
if UsesScope.Element<>TPasModule(UsesUnit.Module).InterfaceSection then
RaiseMsg(20180206122459,Section,'usesscope '+IntToStr(i)+' UsesScope.Element='+GetObjName(UsesScope.Element)+' Module='+GetObjName(Section.UsesClause[i].Module));
if Arr=nil then
begin
Arr:=TJSONArray.Create;
Obj.Add('Uses',Arr);
end;
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
if UsesUnit.Expr<>nil then
Name:=DotExprToName(UsesUnit.Expr)
else
begin
// implicit unit, e.g. system
Name:=UsesUnit.Module.Name;
for j:=0 to Parser.ImplicitUses.Count-1 do
if CompareText(Parser.ImplicitUses[i],Name)=0 then
begin
Name:=Parser.ImplicitUses[i];
break;
end;
end;
if Name='' then
RaiseMsg(20180307091654,UsesUnit.Expr);
SubObj.Add('Name',Name);
if UsesUnit.InFilename<>nil then
begin
InFilename:=Resolver.GetUsesUnitInFilename(UsesUnit.InFilename);
if InFilename='' then
RaiseMsg(20180307094723,UsesUnit.InFilename);
SubObj.Add('In',InFilename);
end;
if CompareText(UsesUnit.Module.Name,Name)<>0 then
SubObj.Add('UnitName',UsesUnit.Module.Name);
// ref object for uses
Ref:=GetElementReference(UsesUnit);
Ref.Obj:=SubObj;
if OnIsElementUsed(Self,UsesUnit.Module) then
begin
// ref object for module
Ref:=GetElementReference(UsesUnit.Module);
if Ref.Obj=nil then
begin
Ref.Obj:=TJSONObject.Create;
SubObj.Add('Module',Ref.Obj);
end;
end;
end;
WriteIdentifierScope(Obj,Scope,aContext);
// not needed: Scope ElevatedLocals
// not needed: Scope Helpers
if (length(Scope.Helpers)>0) and not (Scope.Element is TInterfaceSection) then
RaiseMsg(20190119122007,Section);
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 ',GetElementFullPath(Section));
{$ENDIF}
WriteExternalReferences(aContext);
end;
end;
procedure TPCUWriter.WriteDeclarations(ParentJSON: TJSONObject;
Decls: TPasDeclarations; aContext: TPCUWriterContext);
var
i: Integer;
Decl: TPasElement;
Arr: TJSONArray;
DeclObj: TJSONObject;
begin
Arr:=nil;
for i:=0 to Decls.Declarations.Count-1 do
begin
Decl:=TPasElement(Decls.Declarations[i]);
if Decl.Parent<>Decls then
RaiseMsg(20180208221915,Decl,'['+IntToStr(i)+']='+GetObjName(Decl)+': '+GetObjName(Decls)+'<>'+GetObjName(Decl.Parent));
if Arr=nil then
begin
Arr:=TJSONArray.Create;
ParentJSON.Add('Declarations',Arr);
end;
DeclObj:=TJSONObject.Create;
Arr.Add(DeclObj);
WriteElement(DeclObj,Decl,aContext);
end;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteDeclarations END ',GetObjName(Decls));
{$ENDIF}
end;
procedure TPCUWriter.WriteElementProperty(Obj: TJSONObject;
Parent: TPasElement; const PropName: string; El: TPasElement;
aContext: TPCUWriterContext);
var
SubObj: TJSONObject;
begin
if El=nil then exit;
if (Parent<>El.Parent) then
RaiseMsg(20180208221751,El,GetObjName(Parent)+'<>'+GetObjName(El.Parent));
SubObj:=TJSONObject.Create;
Obj.Add(PropName,SubObj);
WriteElement(SubObj,El,aContext);
end;
procedure TPCUWriter.WriteElementList(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; ListOfElements: TFPList; aContext: TPCUWriterContext;
ReferencesAllowed: boolean);
var
Arr: TJSONArray;
i: Integer;
SubObj: TJSONObject;
Item: TPasElement;
begin
if (ListOfElements=nil) or (ListOfElements.Count=0) then exit;
Arr:=TJSONArray.Create;
Obj.Add(PropName,Arr);
for i:=0 to ListOfElements.Count-1 do
begin
Item:=TPasElement(ListOfElements[i]);
if Item.Parent<>Parent then
begin
if not ReferencesAllowed then
RaiseMsg(20180209191444,Item,GetObjName(Parent)+'<>'+GetObjName(Item.Parent));
AddReferenceToArray(Arr,Item);
end
else
begin
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
WriteElement(SubObj,Item,aContext);
end;
end;
end;
procedure TPCUWriter.WriteElementArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; ArrOfElements: TPasElementArray;
aContext: TPCUWriterContext; ReferencesAllowed: boolean);
var
Arr: TJSONArray;
i: Integer;
SubObj: TJSONObject;
Item: TPasElement;
begin
if length(ArrOfElements)=0 then exit;
Arr:=TJSONArray.Create;
Obj.Add(PropName,Arr);
for i:=0 to length(ArrOfElements)-1 do
begin
Item:=ArrOfElements[i];
if Item.Parent<>Parent then
begin
if not ReferencesAllowed then
RaiseMsg(20180209191444,Item,GetObjName(Parent)+'<>'+GetObjName(Item.Parent));
AddReferenceToArray(Arr,Item);
end
else
begin
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
WriteElement(SubObj,Item,aContext);
end;
end;
end;
procedure TPCUWriter.WriteElement(Obj: TJSONObject;
El: TPasElement; aContext: TPCUWriterContext);
var
C: TClass;
Kind: TPasExprKind;
begin
C:=El.ClassType;
if C=TUnaryExpr then
begin
Obj.Add('Type','Unary');
WriteUnaryExpr(Obj,TUnaryExpr(El),aContext);
end
else if C=TBinaryExpr then
begin
Obj.Add('Type','Binary');
WriteBinaryExpr(Obj,TBinaryExpr(El),aContext);
end
else if C=TPrimitiveExpr then
begin
Kind:=TPrimitiveExpr(El).Kind;
if not (Kind in [pekIdent,pekNumber,pekString]) then
RaiseMsg(20180210153604,El,PCUExprKindNames[Kind]);
Obj.Add('Type',PCUExprKindNames[Kind]);
WritePrimitiveExpr(Obj,TPrimitiveExpr(El),aContext);
end
else if C=TBoolConstExpr then
begin
if El.CustomData=nil then
begin
Obj.Add('Type',PCUBoolStr[TBoolConstExpr(El).Value]);
WritePasExpr(Obj,TBoolConstExpr(El),pekBoolConst,eopNone,aContext);
end
else
begin
Obj.Add('Type','Bool');
WriteBoolConstExpr(Obj,TBoolConstExpr(El),aContext);
end;
end
else if C=TNilExpr then
begin
Obj.Add('Type','Nil');
WritePasExpr(Obj,TNilExpr(El),pekNil,eopNone,aContext);
end
else if C=TInheritedExpr then
begin
Obj.Add('Type','Inherited');
WritePasExpr(Obj,TInheritedExpr(El),pekInherited,eopNone,aContext);
end
else if C=TSelfExpr then
begin
Obj.Add('Type','Self');
WritePasExpr(Obj,TSelfExpr(El),pekSelf,eopNone,aContext);
end
else if C=TParamsExpr then
begin
case TParamsExpr(El).Kind of
pekArrayParams: Obj.Add('Type','A[]');
pekFuncParams: Obj.Add('Type','F()');
pekSet: Obj.Add('Type','[]');
else
RaiseMsg(20190222012727,El,ExprKindNames[TParamsExpr(El).Kind]);
end;
WriteParamsExpr(Obj,TParamsExpr(El),aContext);
end
else if C=TRecordValues then
begin
Obj.Add('Type','RecValues');
WriteRecordValues(Obj,TRecordValues(El),aContext);
end
else if C=TArrayValues then
begin
Obj.Add('Type','ArrValues');
WriteArrayValues(Obj,TArrayValues(El),aContext);
end
else if C=TPasResString then
begin
Obj.Add('Type','ResString');
WriteResString(Obj,TPasResString(El),aContext);
end
else if C=TPasAliasType then
begin
Obj.Add('Type','Alias');
WriteAliasType(Obj,TPasAliasType(El),aContext);
end
else if C=TPasPointerType then
begin
Obj.Add('Type','Pointer');
WritePointerType(Obj,TPasPointerType(El),aContext);
end
else if C=TPasTypeAliasType then
begin
Obj.Add('Type','TypeAlias');
WriteAliasType(Obj,TPasTypeAliasType(El),aContext);
end
else if C=TPasClassOfType then
begin
Obj.Add('Type','ClassOf');
WriteAliasType(Obj,TPasClassOfType(El),aContext);
end
else if C=TPasSpecializeType then
begin
Obj.Add('Type','Specialize');
WriteSpecializeType(Obj,TPasSpecializeType(El),aContext);
end
else if C=TInlineSpecializeExpr then
begin
Obj.Add('Type','InlineSpecialize');
WriteInlineSpecializeExpr(Obj,TInlineSpecializeExpr(El),aContext);
end
else if C=TPasRangeType then
begin
Obj.Add('Type','RangeType');
WriteRangeType(Obj,TPasRangeType(El),aContext);
end
else if C=TPasArrayType then
begin
Obj.Add('Type','ArrType');
WriteArrayType(Obj,TPasArrayType(El),aContext);
end
else if C=TPasFileType then
begin
Obj.Add('Type','File');
WriteFileType(Obj,TPasFileType(El),aContext);
end
else if C=TPasEnumValue then
begin
Obj.Add('Type','EnumV');
WriteEnumValue(Obj,TPasEnumValue(El),aContext);
end
else if C=TPasEnumType then
begin
Obj.Add('Type','EnumType');
WriteEnumType(Obj,TPasEnumType(El),aContext);
end
else if C=TPasSetType then
begin
Obj.Add('Type','SetType');
WriteSetType(Obj,TPasSetType(El),aContext);
end
else if C=TPasVariant then
begin
Obj.Add('Type','RecVariant');
WriteRecordVariant(Obj,TPasVariant(El),aContext);
end
else if C=TPasRecordType then
begin
Obj.Add('Type','Record');
WriteRecordType(Obj,TPasRecordType(El),aContext);
end
else if C=TPasClassType then
begin
Obj.Add('Type',PCUObjKindNames[TPasClassType(El).ObjKind]);
WriteClassType(Obj,TPasClassType(El),aContext);
end
else if C=TPasArgument then
begin
Obj.Add('Type','Arg');
WriteArgument(Obj,TPasArgument(El),aContext);
end
else if C=TPasProcedureType then
begin
Obj.Add('Type','ProcType');
WriteProcedureType(Obj,TPasProcedureType(El),aContext);
end
else if C=TPasResultElement then
begin
Obj.Add('Type','Result');
WriteResultElement(Obj,TPasResultElement(El),aContext);
end
else if C=TPasFunctionType then
begin
Obj.Add('Type','FuncType');
WriteFunctionType(Obj,TPasFunctionType(El),aContext);
end
else if C=TPasStringType then
begin
Obj.Add('Type','StringType');
WriteStringType(Obj,TPasStringType(El),aContext);
end
else if C=TPasVariable then
begin
Obj.Add('Type','Var');
WriteVariable(Obj,TPasVariable(El),aContext);
end
else if C=TPasExportSymbol then
begin
Obj.Add('Type','Export');
WriteExportSymbol(Obj,TPasExportSymbol(El),aContext);
end
else if C=TPasConst then
begin
Obj.Add('Type','Const');
WriteConst(Obj,TPasConst(El),aContext);
end
else if C=TPasProperty then
begin
Obj.Add('Type','Property');
WriteProperty(Obj,TPasProperty(El),aContext);
end
else if C=TPasMethodResolution then
begin
Obj.Add('Type','MethodRes');
WriteMethodResolution(Obj,TPasMethodResolution(El),aContext);
end
else if C.InheritsFrom(TPasProcedure) then
begin
if C.InheritsFrom(TPasOperator) then
begin
if C=TPasOperator then
Obj.Add('Type','Operator')
else if C=TPasClassOperator then
Obj.Add('Type','ClassOperator')
else
RaiseMsg(20180210130142,El);
WriteOperator(Obj,TPasOperator(El),aContext);
exit;
end;
if C=TPasProcedure then
Obj.Add('Type','Procedure')
else if C=TPasClassProcedure then
Obj.Add('Type','ClassProcedure')
else if C=TPasFunction then
Obj.Add('Type','Function')
else if C=TPasClassFunction then
Obj.Add('Type','ClassFunction')
else if C=TPasConstructor then
Obj.Add('Type','Constructor')
else if C=TPasClassConstructor then
Obj.Add('Type','ClassConstructor')
else if C=TPasDestructor then
Obj.Add('Type','Destructor')
else if C=TPasClassDestructor then
Obj.Add('Type','Class Destructor')
else
RaiseMsg(20180210130202,El);
WriteProcedure(Obj,TPasProcedure(El),aContext);
end
else if C=TPasAttributes then
begin
Obj.Add('Type','Attributes');
WriteAttributes(Obj,TPasAttributes(El),aContext);
end
else
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteElement ',GetObjName(El));
{$ENDIF}
RaiseMsg(20180205154041,El,GetObjName(El));
end;
end;
procedure TPCUWriter.WriteElType(Obj: TJSONObject; El: TPasElement;
const PropName: string; aType: TPasType; aContext: TPCUWriterContext);
begin
if aType=nil then exit;
if (aType.Name='') or (aType.Parent=El) then
begin
// anonymous type
WriteElementProperty(Obj,El,PropName,aType,aContext);
end
else
begin
// reference
AddReferenceToObj(Obj,PropName,aType);
end;
end;
procedure TPCUWriter.WriteVarModifiers(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TVariableModifiers);
var
Arr: TJSONArray;
f: TVariableModifier;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TVariableModifier do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUVarModifierNames[f],f in Value);
end;
procedure TPCUWriter.WriteResolvedRefFlags(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TResolvedReferenceFlags);
var
Arr: TJSONArray;
f: TResolvedReferenceFlag;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TResolvedReferenceFlag do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUResolvedReferenceFlagNames[f],f in Value);
end;
procedure TPCUWriter.WriteResolvedReference(Obj: TJSONObject;
Ref: TResolvedReference; ErrorEl: TPasElement);
var
Ctx: TResolvedRefContext;
begin
WriteResolvedRefFlags(Obj,'RefFlags',Ref.Flags,[]);
if Ref.Access<>rraRead then
Obj.Add('RefAccess',PCUResolvedRefAccessNames[Ref.Access]);
if Ref.WithExprScope<>nil then
RaiseMsg(20180215132828,ErrorEl);
if Ref.Context<>nil then
begin
Ctx:=Ref.Context;
if Ctx.ClassType=TResolvedRefCtxConstructor then
begin
if TResolvedRefCtxConstructor(Ctx).Typ=nil then
RaiseMsg(20190222011342,ErrorEl);
AddReferenceToObj(Obj,'RefConstructorType',TResolvedRefCtxConstructor(Ctx).Typ);
end
else if Ctx.ClassType=TResolvedRefCtxAttrProc then
begin
if TResolvedRefCtxAttrProc(Ctx).Proc=nil then
RaiseMsg(20190222011427,ErrorEl);
AddReferenceToObj(Obj,'RefAttrProc',TResolvedRefCtxAttrProc(Ctx).Proc);
end
else
RaiseMsg(20180215132849,ErrorEl,GetObjName(Ref.Context));
end;
AddReferenceToObj(Obj,'RefDecl',Ref.Declaration);
end;
procedure TPCUWriter.WriteExprCustomData(Obj: TJSONObject; Expr: TPasExpr;
aContext: TPCUWriterContext);
procedure CheckNext(Data: TObject);
var
Value: TResEvalValue;
DefHasEvalValue: Boolean;
begin
DefHasEvalValue:=GetDefaultExprHasEvalValue(Expr);
//writeln('TPCUWriter.WriteExprCustomData.CheckNext Expr=',GetObjName(Expr),' Parent=',GetObjName(Expr.Parent),' Def=',DefHasEvalValue,' Data=',GetObjName(Data));
if Data=nil then
begin
if DefHasEvalValue then
Obj.Add('Eval',false);
end
else if Data is TResEvalValue then
begin
Value:=TResEvalValue(Data);
if not DefHasEvalValue then
Obj.Add('Eval',true);
// value is not stored
if Value.CustomData<>nil then
RaiseMsg(20180215143045,Expr,GetObjName(Data));
end
else
RaiseMsg(20180215143108,Expr,GetObjName(Data));
end;
var
Ref: TResolvedReference;
begin
if Expr.CustomData is TResolvedReference then
begin
Ref:=TResolvedReference(Expr.CustomData);
WriteResolvedReference(Obj,Ref,Expr);
CheckNext(Ref.CustomData);
end
else
CheckNext(Expr.CustomData);
if aContext<>nil then ;
end;
procedure TPCUWriter.WriteExpr(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; Expr: TPasExpr; aContext: TPCUWriterContext);
var
SubObj: TJSONObject;
begin
if Expr=nil then exit;
if Parent<>Expr.Parent then
RaiseMsg(20180208221051,Parent,PropName+' Expr='+GetObjName(Expr)+' Parent='+GetObjName(Parent)+'<>'+GetObjName(Expr.Parent)+'=Expr.Parent');
// ToDo: write simple expressions in a compact format
SubObj:=TJSONObject.Create;
Obj.Add(PropName,SubObj);
WriteElement(SubObj,Expr,aContext);
WriteExprCustomData(SubObj,Expr,aContext);
end;
procedure TPCUWriter.WritePasExpr(Obj: TJSONObject; Expr: TPasExpr;
DefaultKind: TPasExprKind; DefaultOpCode: TExprOpCode;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,Expr,aContext);
if Expr.Kind<>DefaultKind then
Obj.Add('Kind',PCUExprKindNames[Expr.Kind]);
if Expr.OpCode<>DefaultOpCode then
Obj.Add('Op',PCUExprOpCodeNames[Expr.OpCode]);
WriteExpr(Obj,Expr,'Format1',Expr.format1,aContext);
WriteExpr(Obj,Expr,'Format2',Expr.format2,aContext);
end;
procedure TPCUWriter.WritePasExprArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; const ExprArr: TPasExprArray;
aContext: TPCUWriterContext);
var
Arr: TJSONArray;
i: Integer;
Expr: TPasExpr;
SubObj: TJSONObject;
begin
if length(ExprArr)=0 then exit;
Arr:=TJSONArray.Create;
Obj.Add(PropName,Arr);
for i:=0 to length(ExprArr)-1 do
begin
Expr:=ExprArr[i];
if Expr.Parent<>Parent then
RaiseMsg(20180209191444,Expr,GetObjName(Parent)+'<>'+GetObjName(Expr.Parent));
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
WriteElement(SubObj,Expr,aContext);
WriteExprCustomData(SubObj,Expr,aContext);
end;
end;
procedure TPCUWriter.WriteScopeReferences(Obj: TJSONObject;
References: TPasScopeReferences; const PropName: string;
aContext: TPCUWriterContext);
var
Refs: TFPList;
Arr: TJSONArray;
i: Integer;
PSRef: TPasScopeReference;
SubObj: TJSONObject;
begin
if References=nil then exit;
Refs:=References.GetList;
try
if Refs.Count>0 then
begin
Arr:=TJSONArray.Create;
Obj.Add(PropName,Arr);
for i:=0 to Refs.Count-1 do
begin
PSRef:=TPasScopeReference(Refs[i]);
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
if PSRef.Access<>PCUDefaultPSRefAccess then
SubObj.Add('Access',PCUPSRefAccessNames[PSRef.Access]);
AddReferenceToObj(SubObj,'Id',PSRef.Element);
end;
end;
finally
Refs.Free;
end;
if aContext=nil then ;
end;
procedure TPCUWriter.WriteUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr;
aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,pekUnary,eopAdd,aContext);
WriteExpr(Obj,Expr,'Operand',Expr.Operand,aContext);
end;
procedure TPCUWriter.WriteBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr;
aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,pekBinary,eopAdd,aContext);
WriteExpr(Obj,Expr,'Left',Expr.left,aContext);
WriteExpr(Obj,Expr,'Right',Expr.right,aContext);
end;
procedure TPCUWriter.WritePrimitiveExpr(Obj: TJSONObject; Expr: TPrimitiveExpr;
aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,Expr.Kind,eopNone,aContext);
if Expr.Value<>'' then
Obj.Add('Value',Expr.Value);
end;
procedure TPCUWriter.WriteBoolConstExpr(Obj: TJSONObject; Expr: TBoolConstExpr;
aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,pekBoolConst,eopNone,aContext);
if Expr.Value then
Obj.Add('Value',true);
end;
procedure TPCUWriter.WriteParamsExpr(Obj: TJSONObject; Expr: TParamsExpr;
aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,Expr.Kind,eopNone,aContext);
WriteExpr(Obj,Expr,'Value',Expr.Value,aContext);
WritePasExprArray(Obj,Expr,'Params',Expr.Params,aContext);
end;
procedure TPCUWriter.WriteRecordValues(Obj: TJSONObject; Expr: TRecordValues;
aContext: TPCUWriterContext);
var
Arr: TJSONArray;
i: Integer;
SubObj: TJSONObject;
RecValue: TRecordValuesItem;
begin
WritePasExpr(Obj,Expr,pekListOfExp,eopNone,aContext);
if length(Expr.Fields)>0 then
begin
Arr:=TJSONArray.Create;
Obj.Add('Fields',Arr);
for i:=0 to length(Expr.Fields)-1 do
begin
RecValue:=Expr.Fields[i];
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
SubObj.Add('Name',RecValue.Name);
if (RecValue.ValueExp<>nil) and (RecValue.ValueExp.Name<>'') then
RaiseMsg(20180209192240,RecValue.ValueExp);
WriteElement(SubObj,RecValue.ValueExp,aContext);
end;
end;
end;
procedure TPCUWriter.WriteArrayValues(Obj: TJSONObject; Expr: TArrayValues;
aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,pekListOfExp,eopNone,aContext);
WritePasExprArray(Obj,Expr,'Values',Expr.Values,aContext);
end;
procedure TPCUWriter.WriteResString(Obj: TJSONObject; El: TPasResString;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteExpr(Obj,El,'Expr',El.Expr,aContext);
end;
procedure TPCUWriter.WriteGenericTemplateTypes(Obj: TJSONObject;
Parent: TPasElement; GenericTemplateTypes: TFPList;
aContext: TPCUWriterContext);
var
Arr: TJSONArray;
i: Integer;
Templ: TPasGenericTemplateType;
TemplObj: TJSONObject;
begin
if (GenericTemplateTypes=nil) or (GenericTemplateTypes.Count=0) then exit;
Arr:=TJSONArray.Create;
Obj.Add('GenericTemplateTypes',Arr);
for i:=0 to GenericTemplateTypes.Count-1 do
begin
Templ:=TPasGenericTemplateType(GenericTemplateTypes[i]);
TemplObj:=TJSONObject.Create;
Arr.Add(TemplObj);
TemplObj.Add('Name',Templ.Name);
WriteElementArray(TemplObj,Parent,'Constraints',Templ.Constraints,aContext,true);
end;
end;
procedure TPCUWriter.WriteAliasType(Obj: TJSONObject; El: TPasAliasType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElType(Obj,El,'Dest',El.DestType,aContext);
WriteExpr(Obj,El,'Expr',El.Expr,aContext);
end;
procedure TPCUWriter.WritePointerType(Obj: TJSONObject; El: TPasPointerType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElType(Obj,El,'Dest',El.DestType,aContext);
end;
procedure TPCUWriter.WriteSpecializeType(Obj: TJSONObject;
El: TPasSpecializeType; aContext: TPCUWriterContext);
begin
WriteAliasType(Obj,El,aContext);
WriteElementList(Obj,El,'Params',El.Params,aContext);
end;
procedure TPCUWriter.WriteInlineSpecializeExpr(Obj: TJSONObject;
Expr: TInlineSpecializeExpr; aContext: TPCUWriterContext);
begin
WritePasExpr(Obj,Expr,pekSpecialize,eopNone,aContext);
WriteExpr(Obj,Expr,'Name',Expr.NameExpr,aContext);
WriteElementList(Obj,Expr,'Params',Expr.Params,aContext);
end;
procedure TPCUWriter.WriteRangeType(Obj: TJSONObject; El: TPasRangeType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteExpr(Obj,El,'Range',El.RangeExpr,aContext);
end;
procedure TPCUWriter.WriteArrayType(Obj: TJSONObject; El: TPasArrayType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
WritePasExprArray(Obj,El,'Ranges',El.Ranges,aContext);
if El.PackMode<>pmNone then
Obj.Add('Packed',PCUPackModeNames[El.PackMode]);
WriteElType(Obj,El,'ElType',El.ElType,aContext);
end;
procedure TPCUWriter.WriteFileType(Obj: TJSONObject; El: TPasFileType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElType(Obj,El,'ElType',El.ElType,aContext);
end;
procedure TPCUWriter.WriteEnumValue(Obj: TJSONObject; El: TPasEnumValue;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteExpr(Obj,El,'Value',El.Value,aContext);
end;
procedure TPCUWriter.WriteEnumTypeScope(Obj: TJSONObject;
Scope: TPasEnumTypeScope; aContext: TPCUWriterContext);
begin
WriteIdentifierScope(Obj,Scope,aContext);
WriteElType(Obj,Scope.Element,'CanonicalSet',Scope.CanonicalSet,aContext);
end;
procedure TPCUWriter.WriteEnumType(Obj: TJSONObject; El: TPasEnumType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElementList(Obj,El,'Values',El.Values,aContext);
WriteEnumTypeScope(Obj,EL.CustomData as TPasEnumTypeScope,aContext);
end;
procedure TPCUWriter.WriteSetType(Obj: TJSONObject; El: TPasSetType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElType(Obj,El,'EnumType',El.EnumType,aContext);
if El.IsPacked then
Obj.Add('Packed',true);
end;
procedure TPCUWriter.WriteRecordVariant(Obj: TJSONObject; El: TPasVariant;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElementList(Obj,El,'Values',El.Values,aContext);
WriteElType(Obj,El,'Members',El.Members,aContext);
end;
procedure TPCUWriter.WriteRecordTypeScope(Obj: TJSONObject;
Scope: TPasRecordScope; aContext: TPCUWriterContext);
begin
AddReferenceToObj(Obj,'DefaultProperty',Scope.DefaultProperty);
WriteIdentifierScope(Obj,Scope,aContext);
end;
procedure TPCUWriter.WriteRecordType(Obj: TJSONObject; El: TPasRecordType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
if El.PackMode<>pmNone then
Obj.Add('Packed',PCUPackModeNames[El.PackMode]);
WriteElementList(Obj,El,'Members',El.Members,aContext);
// VariantEl: TPasElement can be TPasVariable or TPasType
if El.VariantEl is TPasType then
WriteElType(Obj,El,'VariantEl',TPasType(El.VariantEl),aContext)
else
WriteElementProperty(Obj,El,'VariantEl',El.VariantEl,aContext);
WriteElementList(Obj,El,'Variants',El.Variants,aContext);
WriteRecordTypeScope(Obj,El.CustomData as TPasRecordScope,aContext);
end;
procedure TPCUWriter.WriteClassScopeFlags(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TPasClassScopeFlags);
var
Arr: TJSONArray;
f: TPasClassScopeFlag;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TPasClassScopeFlag do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUClassScopeFlagNames[f],f in Value);
end;
procedure TPCUWriter.WriteClassIntfMapProcs(Obj: TJSONObject;
Map: TPasClassIntfMap);
var
Procs: TFPList;
Arr: TJSONArray;
i: Integer;
begin
Procs:=Map.Procs;
if Procs<>nil then
begin
Arr:=TJSONArray.Create;
Obj.Add('Procs',Arr);
for i:=0 to Procs.Count-1 do
AddReferenceToArray(Arr,TPasProcedure(Procs[i]));
end;
end;
procedure TPCUWriter.WriteClassScope(Obj: TJSONObject;
Scope: TPas2JSClassScope; aContext: TPCUWriterContext);
procedure WriteMap(SubObj: TJSONObject; Map: TPasClassIntfMap);
var
AncObj: TJSONObject;
begin
if Map.Element=nil then
RaiseMsg(20180325131134,Scope.Element);
if Map.Intf=nil then
RaiseMsg(20180325131135,Scope.Element);
AddReferenceToObj(SubObj,'Intf',Map.Intf);
WriteClassIntfMapProcs(SubObj,Map);
if Map.AncestorMap<>nil then
begin
AncObj:=TJSONObject.Create;
SubObj.Add('AncestorMap',AncObj);
WriteMap(AncObj,Map.AncestorMap);
end;
end;
var
Arr: TJSONArray;
i: Integer;
aClass: TPasClassType;
CanonicalClassOf: TPasClassOfType;
ScopeIntf: TFPList;
o: TObject;
SubObj: TJSONObject;
Ref: TPCUFilerElementRef;
begin
WriteIdentifierScope(Obj,Scope,aContext);
aClass:=Scope.Element as TPasClassType;
AddReferenceToObj(Obj,'NewInstanceFunction',Scope.NewInstanceFunction);
// AncestorScope can be derived from DirectAncestor
// CanonicalClassOf is autogenerated
CanonicalClassOf:=Scope.CanonicalClassOf;
if aClass.ObjKind in ([okClass]+okAllHelpers) then
begin
if CanonicalClassOf=nil then
RaiseMsg(20180217143821,aClass);
if CanonicalClassOf.Name<>'Self' then
RaiseMsg(20180217143822,aClass);
if CanonicalClassOf.DestType<>aClass then
RaiseMsg(20180217143834,aClass);
if CanonicalClassOf.Visibility<>visStrictPrivate then
RaiseMsg(20180217143844,aClass);
if CanonicalClassOf.SourceFilename<>aClass.SourceFilename then
RaiseMsg(20180217143857,aClass);
if CanonicalClassOf.SourceLinenumber<>aClass.SourceLinenumber then
RaiseMsg(20180217143905,aClass);
Ref:=GetElementReference(CanonicalClassOf);
CreateAutoElReferenceId(Ref);
Obj.Add('ClassOf',Ref.Id);
ResolvePendingElRefs(Ref);
end
else if CanonicalClassOf<>nil then
RaiseMsg(20180329110817,aClass,GetObjName(CanonicalClassOf));
AddReferenceToObj(Obj,'DirectAncestor',Scope.DirectAncestor);
AddReferenceToObj(Obj,'DefaultProperty',Scope.DefaultProperty);
WriteClassScopeFlags(Obj,'SFlags',Scope.Flags,GetDefaultClassScopeFlags(Scope));
if length(Scope.AbstractProcs)>0 then
begin
Arr:=TJSONArray.Create;
Obj.Add('AbstractProcs',Arr);
for i:=0 to length(Scope.AbstractProcs)-1 do
AddReferenceToArray(Arr,Scope.AbstractProcs[i]);
end;
if Scope.DispatchField<>'' then
Obj.Add('DispatchField',Scope.DispatchField);
if Scope.DispatchStrField<>'' then
Obj.Add('DispatchStrField',Scope.DispatchStrField);
if Scope.GUID<>'' then
Obj.Add('SGUID',Scope.GUID);
ScopeIntf:=Scope.Interfaces;
if (ScopeIntf<>nil) and (ScopeIntf.Count>0) then
begin
Arr:=TJSONArray.Create;
Obj.Add('SInterfaces',Arr);
for i:=0 to ScopeIntf.Count-1 do
begin
o:=TObject(ScopeIntf[i]);
if o is TPasProperty then
begin
// delegation
AddReferenceToArray(Arr,TPasProperty(o));
end
else if o is TPasClassIntfMap then
begin
// method resolution
SubObj:=TJSONObject.Create;
Arr.Add(SubObj);
WriteMap(SubObj,TPasClassIntfMap(o));
end
else
RaiseMsg(20180325111939,aClass,IntToStr(i)+':'+GetObjName(TObject(aClass.Interfaces[i]))+' '+GetObjName(o));
end;
end;
end;
procedure TPCUWriter.WriteClassType(Obj: TJSONObject; El: TPasClassType;
aContext: TPCUWriterContext);
var
Arr: TJSONArray;
i: Integer;
Ref: TResolvedReference;
Scope: TPas2JSClassScope;
begin
WritePasElement(Obj,El,aContext);
WriteGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
if El.PackMode<>pmNone then
Obj.Add('Packed',PCUPackModeNames[El.PackMode]);
// ObjKind is the 'Type'
if El.InterfaceType<>citCom then
Obj.Add('IntfType',PCUClassInterfaceTypeNames[El.InterfaceType]);
WriteElType(Obj,El,'Ancestor',El.AncestorType,aContext);
WriteElType(Obj,El,'HelperFor',El.HelperForType,aContext);
if El.IsForward then
Obj.Add('Forward',true);
if El.IsExternal then
Obj.Add('External',true);
// not needed IsShortDefinition: Boolean; -> class(anchestor); without end
WriteExpr(Obj,El,'GUID',El.GUIDExpr,aContext);
if El.Modifiers.Count>0 then
begin
Arr:=TJSONArray.Create;
Obj.Add('Modifiers',Arr);
for i:=0 to El.Modifiers.Count-1 do
Arr.Add(El.Modifiers[i]);
end;
if El.ExternalNameSpace<>'' then
Obj.Add('ExternalNameSpace',El.ExternalNameSpace);
if El.ExternalName<>'' then
Obj.Add('ExternalName',El.ExternalName);
if El.IsForward then
begin
Ref:=TResolvedReference(El.CustomData);
WriteResolvedReference(Obj,Ref,El);
end
else
begin
Scope:=El.CustomData as TPas2JSClassScope;
WriteElementList(Obj,El,'Interfaces',El.Interfaces,aContext,true);
WriteElementList(Obj,El,'Members',El.Members,aContext);
if Scope<>nil then
WriteClassScope(Obj,Scope,aContext)
else
Obj.Add('Scope',false); // msIgnoreInterfaces
end;
end;
procedure TPCUWriter.WriteArgument(Obj: TJSONObject; El: TPasArgument;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
if El.Access<>argDefault then
Obj.Add('Access',PCUArgumentAccessNames[El.Access]);
if El.ArgType<>nil then
begin
if El.ArgType.Parent=El then
WriteElementProperty(Obj,El,'ArgType',El.ArgType,aContext)
else
AddReferenceToObj(Obj,'ArgType',El.ArgType);
end;
WriteExpr(Obj,El,'Value',El.ValueExpr,aContext)
end;
procedure TPCUWriter.WriteProcTypeModifiers(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TProcTypeModifiers);
var
Arr: TJSONArray;
f: TProcTypeModifier;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TProcTypeModifier do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUProcTypeModifierNames[f],f in Value);
end;
procedure TPCUWriter.WriteProcedureType(Obj: TJSONObject;
El: TPasProcedureType; aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
WriteElementList(Obj,El,'Args',El.Args,aContext);
if El.CallingConvention<>ccDefault then
Obj.Add('Call',PCUCallingConventionNames[El.CallingConvention]);
WriteProcTypeModifiers(Obj,'Modifiers',El.Modifiers,GetDefaultProcTypeModifiers(El));
end;
procedure TPCUWriter.WriteResultElement(Obj: TJSONObject;
El: TPasResultElement; aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteElType(Obj,El,'Result',El.ResultType,aContext);
end;
procedure TPCUWriter.WriteFunctionType(Obj: TJSONObject; El: TPasFunctionType;
aContext: TPCUWriterContext);
begin
WriteProcedureType(Obj,El,aContext);
WriteElementProperty(Obj,El,'Result',El.ResultEl,aContext);
end;
procedure TPCUWriter.WriteStringType(Obj: TJSONObject; El: TPasStringType;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
Obj.Add('Length',El.LengthExpr);
end;
procedure TPCUWriter.WriteVariable(Obj: TJSONObject; El: TPasVariable;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
if El.VarType<>nil then
begin
if El.VarType.Parent=El then
// anonymous type
WriteElementProperty(Obj,El,'VarType',El.VarType,aContext)
else
// reference
AddReferenceToObj(Obj,'VarType',El.VarType);
end;
WriteVarModifiers(Obj,'VarMods',El.VarModifiers,[]);
WriteExpr(Obj,El,'Library',El.LibraryName,aContext);
WriteExpr(Obj,El,'Export',El.ExportName,aContext);
WriteExpr(Obj,El,'Absolute',El.AbsoluteExpr,aContext);
WriteExpr(Obj,El,'Expr',El.Expr,aContext);
end;
procedure TPCUWriter.WriteExportSymbol(Obj: TJSONObject; El: TPasExportSymbol;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WriteExpr(Obj,El,'ExportName',El.ExportName,aContext);
WriteExpr(Obj,El,'ExportIndex',El.ExportIndex,aContext);
end;
procedure TPCUWriter.WriteConst(Obj: TJSONObject; El: TPasConst;
aContext: TPCUWriterContext);
begin
WriteVariable(Obj,El,aContext);
if El.IsConst<>(El.VarType=nil) then
Obj.Add('IsConst',El.IsConst);
end;
procedure TPCUWriter.WritePropertyScope(Obj: TJSONObject;
Scope: TPasPropertyScope; aContext: TPCUWriterContext);
begin
WriteIdentifierScope(Obj,Scope,aContext);
AddReferenceToObj(Obj,'AncestorProp',Scope.AncestorProp);
end;
procedure TPCUWriter.WriteProperty(Obj: TJSONObject; El: TPasProperty;
aContext: TPCUWriterContext);
var
Scope: TPasPropertyScope;
begin
Scope:=El.CustomData as TPasPropertyScope;
WriteVariable(Obj,El,aContext);
WriteExpr(Obj,El,'Index',El.IndexExpr,aContext);
WriteExpr(Obj,El,'Read',El.ReadAccessor,aContext);
WriteExpr(Obj,El,'Write',El.WriteAccessor,aContext);
WritePasExprArray(Obj,El,'Implements',El.Implements,aContext);
WriteExpr(Obj,El,'DispId',El.DispIDExpr,aContext);
WriteExpr(Obj,El,'Stored',El.StoredAccessor,aContext);
WriteExpr(Obj,El,'DefaultValue',El.DefaultExpr,aContext);
WriteElementList(Obj,El,'Args',El.Args,aContext);
//ReadAccessorName: string; // not used by resolver
//WriteAccessorName: string; // not used by resolver
//ImplementsName: string; // not used by resolver
//StoredAccessorName: string; // not used by resolver
if El.DispIDReadOnly then
Obj.Add('ReadOnly',true);
if El.isDefault then
Obj.Add('Default',true);
if El.IsNodefault then
Obj.Add('NoDefault',true);
if Scope<>nil then
WritePropertyScope(Obj,Scope,aContext)
else
Obj.Add('Scope',false); // msIgnoreInterfaces
end;
procedure TPCUWriter.WriteMethodResolution(Obj: TJSONObject;
El: TPasMethodResolution; aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
if El.ProcClass=TPasProcedure then
Obj.Add('ProcClass','procedure')
else if El.ProcClass=TPasFunction then
// default value
else
RaiseMsg(20180329104205,El);
WriteExpr(Obj,El,'InterfaceName',El.InterfaceName,aContext);
WriteExpr(Obj,El,'InterfaceProc',El.InterfaceProc,aContext);
WriteExpr(Obj,El,'ImplementationProc',El.ImplementationProc,aContext);
end;
procedure TPCUWriter.WriteProcedureNameParts(Obj: TJSONObject;
El: TPasProcedure; aContext: TPCUWriterContext);
var
Arr, TemplArr: TJSONArray;
NamePartObj, TemplObj: TJSONObject;
i, j: Integer;
GenType: TPasGenericTemplateType;
NameParts: TProcedureNameParts;
begin
NameParts:=El.NameParts;
if (NameParts=nil) or (NameParts.Count=0) then exit;
Arr:=TJSONArray.Create;
Obj.Add('NameParts',Arr);
for i:=0 to NameParts.Count-1 do
begin
NamePartObj:=TJSONObject.Create;
Arr.Add(NamePartObj);
with TProcedureNamePart(NameParts[i]) do
begin
NamePartObj.Add('Name',Name);
if Templates<>nil then
begin
TemplArr:=TJSONArray.Create;
NamePartObj.Add('Templates',TemplArr);
for j:=0 to Templates.Count-1 do
begin
GenType:=TPasGenericTemplateType(Templates[j]);
TemplObj:=TJSONObject.Create;
TemplArr.Add(TemplObj);
TemplObj.Add('Name',GenType.Name);
WriteElementArray(TemplObj,El,'Constraints',GenType.Constraints,aContext,true);
end;
end;
end;
end;
end;
procedure TPCUWriter.WriteProcedureModifiers(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TProcedureModifiers);
var
Arr: TJSONArray;
f: TProcedureModifier;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TProcedureModifier do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUProcedureModifierNames[f],f in Value);
end;
procedure TPCUWriter.WriteProcScopeFlags(Obj: TJSONObject;
const PropName: string; const Value, DefaultValue: TPasProcedureScopeFlags);
var
Arr: TJSONArray;
f: TPasProcedureScopeFlag;
begin
if Value=DefaultValue then exit;
Arr:=nil;
for f in TPasProcedureScopeFlag do
if (f in Value)<>(f in DefaultValue) then
AddArrayFlag(Obj,Arr,PropName,PCUProcedureScopeFlagNames[f],f in Value);
end;
procedure TPCUWriter.WriteProcedureScope(Obj: TJSONObject;
Scope: TPas2JSProcedureScope; aContext: TPCUWriterContext);
begin
// Not needed, contains only local stuff: WriteIdentifierScope(Obj,Scope,aContext);
if Scope.ResultVarName<>'' then
Obj.Add('ResultVarName',Scope.ResultVarName);
// Scope.OverloadName is stored as 'Name' and ReadProcedureScope reverts it
if Scope.DeclarationProc<>nil then
RaiseMsg(20180219135933,Scope.Element);
AddReferenceToObj(Obj,'ImplProc',Scope.ImplProc);
AddReferenceToObj(Obj,'Overridden',Scope.OverriddenProc);
// ClassOrRecordScope: TPasClassScope; auto derived
if Scope.SelfArg<>nil then
RaiseMsg(20180211180457,Scope.Element); // SelfArg only valid for method implementation
// Mode: TModeSwitch: auto derived
WriteProcScopeFlags(Obj,'SFlags',Scope.Flags,[]);
WriteBoolSwitches(Obj,'BoolSwitches',Scope.BoolSwitches,aContext.BoolSwitches);
WriteModeSwitches(Obj,'ModeSwitches',Scope.ModeSwitches,aContext.ModeSwitches);
end;
procedure TPCUWriter.WriteProcedure(Obj: TJSONObject; El: TPasProcedure;
aContext: TPCUWriterContext);
var
DefProcMods: TProcedureModifiers;
Scope: TPas2JSProcedureScope;
Arr: TJSONArray;
i: Integer;
DeclProc: TPasProcedure;
DeclScope: TPas2JsProcedureScope;
begin
WritePasElement(Obj,El,aContext);
Scope:=El.CustomData as TPas2JSProcedureScope;
//writeln('TPCUWriter.WriteProcedure ',GetObjName(El),' ',GetObjName(Scope),' ',Resolver.GetElementSourcePosStr(El));
if Scope.DeclarationProc=nil then
begin
// declaration
WriteProcedureNameParts(Obj,El,aContext);
WriteElementProperty(Obj,El,'ProcType',El.ProcType,aContext);
WriteExpr(Obj,El,'Public',El.PublicName,aContext);
// e.g. external LibraryExpr name LibrarySymbolName;
WriteExpr(Obj,El,'Lib',El.LibraryExpr,aContext);
WriteExpr(Obj,El,'LibName',El.LibrarySymbolName,aContext);
WriteExpr(Obj,El,'DispId',El.DispIDExpr,aContext);
if El.AliasName<>'' then
Obj.Add('Alias',El.AliasName);
DefProcMods:=GetDefaultProcModifiers(El);
WriteProcedureModifiers(Obj,'PMods',El.Modifiers,DefProcMods);
WriteExpr(Obj,El,'Msg',El.MessageExpr,aContext);
if (El.MessageName<>'') or (El.MessageType<>pmtNone) then
begin
Obj.Add('Message',El.MessageName);
if El.MessageType<>pmtInteger then
Obj.Add('MessageType',PCUProcedureMessageTypeNames[El.MessageType]);
end;
WriteProcedureScope(Obj,Scope,aContext);
end
else
begin
// implementation
AddReferenceToObj(Obj,'DeclarationProc',Scope.DeclarationProc);
end;
if (Scope.ImplProc=nil) and (El.Body<>nil) then
begin
// 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 TPas2JSProcedureScope;
WriteScopeReferences(Obj,DeclScope.References,'Refs',aContext);
// precompiled body
if Scope.BodyJS<>'' then
begin
if Scope.GlobalJS<>nil then
begin
Arr:=TJSONArray.Create;
Obj.Add('Globals',Arr);
for i:=0 to Scope.GlobalJS.Count-1 do
Arr.Add(Scope.GlobalJS[i]);
end;
Obj.Add('Body',Scope.BodyJS);
Obj.Add('Empty',Scope.EmptyJS);
end;
end;
if (Scope.BodyJS<>'') and (Scope.ImplProc<>nil) then
RaiseMsg(20180228142831,El);
end;
procedure TPCUWriter.WriteOperator(Obj: TJSONObject; El: TPasOperator;
aContext: TPCUWriterContext);
begin
WriteProcedure(Obj,El,aContext);
Obj.Add('Operator',PCUOperatorTypeNames[El.OperatorType]);
if El.TokenBased then
Obj.Add('TokenBased',El.TokenBased);
end;
procedure TPCUWriter.WriteAttributes(Obj: TJSONObject; El: TPasAttributes;
aContext: TPCUWriterContext);
begin
WritePasElement(Obj,El,aContext);
WritePasExprArray(Obj,El,'Calls',El.Calls,aContext);
end;
procedure TPCUWriter.WriteExtRefSignature(Ref: TPCUFilerElementRef;
aContext: TPCUWriterContext);
procedure WriteMemberIndex(Members: TFPList; Member: TPasElement; Obj: TJSONObject);
var
i, Index: Integer;
begin
for i:=0 to Members.Count-1 do
if TPasElement(Members[i])=Member then
begin
Index:=i;
break;
end;
if Index<0 then
RaiseMsg(20180309184111,Member);
Obj.Add('MId',Index);
end;
var
Parent, El: TPasElement;
C: TClass;
begin
//writeln('TPCUWriter.WriteExtRefSignature START ',GetObjName(Ref.Element));
if aContext=nil then ;
// write member index
El:=Ref.Element;
Parent:=El.Parent;
C:=Parent.ClassType;
if C.InheritsFrom(TPasDeclarations) then
WriteMemberIndex(TPasDeclarations(Parent).Declarations,Ref.Element,Ref.Obj)
else if (C=TPasClassType)
or (C=TPasRecordType) then
WriteMemberIndex(TPasMembersType(Parent).Members,Ref.Element,Ref.Obj)
else if C=TPasEnumType then
WriteMemberIndex(TPasEnumType(Parent).Values,Ref.Element,Ref.Obj)
else if C.InheritsFrom(TPasModule) then
begin
if Ref.Element is TInterfaceSection then
else
RaiseMsg(20180310104857,Parent,GetObjName(Ref.Element));
end
else
RaiseMsg(20180310104810,Parent,GetObjName(Ref.Element));
//writeln('TPCUWriter.WriteExtRefSignature END ',GetObjName(Ref.Element));
end;
function TPCUWriter.WriteExternalReference(El: TPasElement;
aContext: TPCUWriterContext): TPCUFilerElementRef;
var
ParentRef, Ref: TPCUFilerElementRef;
Parent: TPasElement;
Name: String;
begin
Result:=nil;
if El=nil then exit;
// check if already written
Ref:=GetElementReference(El);
if Ref.Obj<>nil then
exit(Ref);
//writeln('TPCUWriter.WriteExternalReference ',GetObjName(El));
// check that is written
Parent:=El.Parent;
ParentRef:=WriteExternalReference(Parent,aContext);
if ParentRef=nil then
if not (El is TPasModule) then
RaiseMsg(20180308174440,El,GetObjName(El));
// check name
Name:=Resolver.GetOverloadName(El);
if Name='' then
begin
Name:=GetDefaultRefName(El);
if Name='' then
RaiseMsg(20180308174850,El,GetObjName(El));
end;
// write
Ref.Obj:=TJSONObject.Create;
Ref.Obj.Add('Name',Name);
if ParentRef<>nil then
begin
Ref.ParentRef:=ParentRef;
// add to parent
if ParentRef.Elements=nil then
begin
ParentRef.Elements:=TJSONArray.Create;
ParentRef.Obj.Add('El',ParentRef.Elements);
end;
ParentRef.Elements.Add(Ref.Obj);
//writeln('TPCUWriter.WriteExternalReference ',GetObjName(El),' WriteExtRefSignature...');
WriteExtRefSignature(Ref,aContext);
end
else if (El.ClassType=TPasModule) or (El is TPasUnitModule) then
begin
// indirect used unit
if aContext.IndirectUsesArr=nil then
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;
aContext.IndirectUsesArr.Add(Ref.Obj);
end
else
RaiseMsg(20180314153224,El);
Result:=Ref;
end;
procedure TPCUWriter.WriteExternalReferences(aContext: TPCUWriterContext);
var
Ref: TPCUFilerElementRef;
El: TPasElement;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteExternalReferences START aContext.Section=',GetObjName(aContext.Section));
{$ENDIF}
while FFirstNewExt<>nil do
begin
Ref:=FFirstNewExt;
FFirstNewExt:=Ref.NextNewExt;
if FFirstNewExt=nil then
FLastNewExt:=nil;
if Ref.Pending=nil then
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),' ',GetElementFullPath(El));
{$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
if El.CustomData is TResElDataBuiltInSymbol then
RaiseMsg(20180314120554,El);
if El.GetModule=Resolver.RootElement then
RaiseMsg(20180318120511,El);
{$ENDIF}
// external element
if Ref.Obj=nil then
WriteExternalReference(El,aContext);
// Ref.Id is written in ResolvePendingElRefs
ResolvePendingElRefs(Ref);
end;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteExternalReferences END aContext.Section=',GetObjName(aContext.Section));
{$ENDIF}
end;
constructor TPCUWriter.Create;
begin
inherited Create;
end;
destructor TPCUWriter.Destroy;
begin
inherited Destroy;
end;
procedure TPCUWriter.Clear;
begin
FFirstNewExt:=nil;
FLastNewExt:=nil;
FInitialFlags:=nil;
FElementIdCounter:=0;
FSourceFilesSorted:=nil;
FInImplementation:=false;
inherited Clear;
end;
procedure TPCUWriter.WritePCU(aResolver: TPas2JSResolver;
aConverter: TPasToJSConverter; InitFlags: TPCUInitialFlags; aStream: TStream;
Compressed: boolean);
var
TargetStream: TStream;
var
aJSON: TJSONObject;
Comp: Tcompressionstream;
begin
aJSON:=WriteJSON(aResolver,aConverter,InitFlags);
TargetStream:=aStream;
try
if Compressed then
TargetStream:=TMemoryStream.Create;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WritePCU create js');
{$ENDIF}
Pas2jsFiler.WriteJSON(aJSON,TargetStream,Compressed);
if Compressed then
try
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WritePCU zip...');
{$ENDIF}
Comp:=Tcompressionstream.create(cldefault,aStream);
try
Comp.WriteDWord(TargetStream.Size);
Comp.Write(TMemoryStream(TargetStream).Memory^,TargetStream.Size);
finally
Comp.Free;
end;
except
on E: Ecompressionerror do
RaiseMsg(20180704163113,'compression error: '+E.Message);
end;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WritePCU END');
{$ENDIF}
finally
if TargetStream<>aStream then
TargetStream.Free;
aJSON.Free;
end;
end;
function TPCUWriter.WriteJSON(aResolver: TPas2JSResolver;
aConverter: TPasToJSConverter; InitFlags: TPCUInitialFlags): TJSONObject;
var
Obj, JSMod: TJSONObject;
aContext: TPCUWriterContext;
begin
Result:=nil;
FConverter:=aConverter;
FResolver:=aResolver;
FParser:=Resolver.CurrentParser;
FScanner:=FParser.Scanner;
FInitialFlags:=InitFlags;
aContext:=nil;
Obj:=TJSONObject.Create;
try
FJSON:=Obj;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteJSON header ...');
{$ENDIF}
WriteHeaderMagic(Obj);
WriteHeaderVersion(Obj);
WriteGUID(Obj);
WriteInitialFlags(Obj);
WriteSrcFiles(Obj);
// ToDo: WriteUsedModulesPrecompiledChecksums
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteJSON module ...');
{$ENDIF}
aContext:=TPCUWriterContext.Create;
aContext.ModeSwitches:=InitialFlags.ModeSwitches;
aContext.BoolSwitches:=InitialFlags.BoolSwitches;
JSMod:=TJSONObject.Create;
Obj.Add('Module',JSMod);
WriteModule(JSMod,aResolver.RootElement,aContext);
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteJSON footer ...');
{$ENDIF}
WriteFinalFlags(Obj);
Result:=Obj;
finally
FJSON:=nil;
aContext.Free;
if Result=nil then
Obj.Free;
end;
{$IFDEF VerbosePCUFiler}
writeln('TPCUWriter.WriteJSON END');
{$ENDIF}
end;
function TPCUWriter.IndexOfSourceFile(const Filename: string): integer;
var
l, r, m, cmp: Integer;
begin
l:=0;
r:=length(FSourceFilesSorted)-1;
while l<=r do
begin
m:=(l+r) div 2;
cmp:=CompareStr(Filename,FSourceFilesSorted[m].Filename);
if cmp<0 then
r:=m-1
else if cmp>0 then
l:=m+1
else
exit(FSourceFilesSorted[m].Index);
end;
Result:=-1;
end;
{ TPCUReader }
procedure TPCUReader.Set_Variable_VarType(RefEl: TPasElement; Data: TObject);
var
El: TPasVariable absolute Data;
begin
if RefEl is TPasType then
begin
El.VarType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasVariable.VarType'){$ENDIF};
end
else
RaiseMsg(20180211121809,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_AliasType_DestType(RefEl: TPasElement; Data: TObject);
var
El: TPasAliasType absolute Data;
begin
if RefEl is TPasType then
begin
El.DestType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasAliasType.DestType'){$ENDIF};
end
else
RaiseMsg(20180211121801,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_PointerType_DestType(RefEl: TPasElement; Data: TObject
);
var
El: TPasPointerType absolute Data;
begin
if RefEl is TPasType then
begin
El.DestType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasPointerType.DestType'){$ENDIF};
end
else
RaiseMsg(20180211121757,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ArrayType_ElType(RefEl: TPasElement; Data: TObject);
var
El: TPasArrayType absolute Data;
begin
if RefEl is TPasType then
begin
El.ElType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasArrayType.ElType'){$ENDIF};
end
else
RaiseMsg(20180211121732,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_FileType_ElType(RefEl: TPasElement; Data: TObject);
var
El: TPasFileType absolute Data;
begin
if RefEl is TPasType then
begin
El.ElType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasFileType.ElType'){$ENDIF};
end
else
RaiseMsg(20180211121726,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_SetType_EnumType(RefEl: TPasElement; Data: TObject);
var
El: TPasSetType absolute Data;
begin
if RefEl is TPasType then
begin
El.EnumType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasSetType.EnumType'){$ENDIF};
end
else
RaiseMsg(20180211121714,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_Variant_Members(RefEl: TPasElement; Data: TObject);
var
El: TPasVariant absolute Data;
begin
if RefEl is TPasRecordType then
begin
El.Members:=TPasRecordType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasVariant.Members'){$ENDIF};
end
else
RaiseMsg(20180211121657,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_RecordType_VariantEl(RefEl: TPasElement; Data: TObject
);
var
El: TPasRecordType absolute Data;
begin
if (RefEl is TPasType) or (RefEl.ClassType=TPasVariable) then
begin
El.VariantEl:=RefEl;
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasRecordType.VariantEl'){$ENDIF};
end
else
RaiseMsg(20180210205031,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_RecordScope_DefaultProperty(RefEl: TPasElement;
Data: TObject);
var
Scope: TPasRecordScope absolute Data;
begin
if RefEl is TPasProperty then
Scope.DefaultProperty:=TPasProperty(RefEl) // no AddRef
else
RaiseMsg(20190106213412,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_Argument_ArgType(RefEl: TPasElement; Data: TObject);
var
El: TPasArgument absolute Data;
begin
if RefEl is TPasType then
begin
El.ArgType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasArgument.ArgType'){$ENDIF};
end
else
RaiseMsg(20180211121643,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ClassScope_NewInstanceFunction(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSClassScope absolute Data;
begin
if RefEl is TPasClassFunction then
Scope.NewInstanceFunction:=TPasClassFunction(RefEl)
else
RaiseMsg(20180214114043,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ClassScope_DirectAncestor(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSClassScope absolute Data;
AncestorScope: TPas2JSClassScope;
aClassAncestor: TPasType;
begin
if not (RefEl is TPasType) then
RaiseMsg(20180214114823,Scope.Element,GetObjName(RefEl));
Scope.DirectAncestor:=TPasType(RefEl);
if Scope.DirectAncestor=nil then exit;
// set AncestorScope
aClassAncestor:=Resolver.ResolveAliasType(Scope.DirectAncestor);
if not (aClassAncestor is TPasClassType) then
RaiseMsg(20180214114322,Scope.Element,GetObjName(RefEl));
AncestorScope:=aClassAncestor.CustomData as TPas2JSClassScope;
Scope.AncestorScope:=AncestorScope;
if (AncestorScope<>nil) and (pcsfPublished in Scope.AncestorScope.Flags) then
Include(Scope.Flags,pcsfPublished);
end;
procedure TPCUReader.Set_ClassScope_DefaultProperty(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSClassScope absolute Data;
begin
if RefEl is TPasProperty then
Scope.DefaultProperty:=TPasProperty(RefEl) // no AddRef
else
RaiseMsg(20180214115044,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ClassIntfMap_Intf(RefEl: TPasElement; Data: TObject);
var
Map: TPasClassIntfMap absolute Data;
begin
if RefEl is TPasClassType then
Map.Intf:=TPasClassType(RefEl) // no AddRef
else
RaiseMsg(20180325125418,Map.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ClassType_AncestorType(RefEl: TPasElement;
Data: TObject);
var
El: TPasClassType absolute Data;
begin
if RefEl is TPasType then
begin
El.AncestorType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasClassType.AncestorType'){$ENDIF};
end
else
RaiseMsg(20180211121632,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ClassType_HelperForType(RefEl: TPasElement;
Data: TObject);
var
El: TPasClassType absolute Data;
begin
if RefEl is TPasType then
begin
El.HelperForType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasClassType.HelperForType'){$ENDIF};
end
else
RaiseMsg(20180211121612,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ResultElement_ResultType(RefEl: TPasElement; Data: TObject
);
var
El: TPasResultElement absolute Data;
begin
if RefEl is TPasType then
begin
El.ResultType:=TPasType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasResultElement.ResultType'){$ENDIF};
end
else
RaiseMsg(20180211121537,El,GetObjName(RefEl));
end;
procedure TPCUReader.Set_PasScope_VisibilityContext(RefEl: TPasElement;
Data: TObject);
var
Scope: TPasScope absolute Data;
begin
Scope.VisibilityContext:=RefEl;
end;
procedure TPCUReader.Set_ModScope_AssertClass(RefEl: TPasElement; Data: TObject
);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasClassType then
Scope.AssertClass:=TPasClassType(RefEl)
else
RaiseMsg(20180211121441,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ModScope_AssertDefConstructor(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasConstructor then
Scope.AssertDefConstructor:=TPasConstructor(RefEl)
else
RaiseMsg(20180211123001,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ModScope_AssertMsgConstructor(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasConstructor then
Scope.AssertMsgConstructor:=TPasConstructor(RefEl)
else
RaiseMsg(20180211123020,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ModScope_RangeErrorClass(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasClassType then
Scope.RangeErrorClass:=TPasClassType(RefEl)
else
RaiseMsg(20180211123041,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ModScope_RangeErrorConstructor(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasConstructor then
Scope.RangeErrorConstructor:=TPasConstructor(RefEl)
else
RaiseMsg(20180211123100,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ModScope_SystemTVarRec(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasRecordType then
Scope.SystemTVarRec:=TPasRecordType(RefEl)
else
RaiseMsg(20190215230826,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ModScope_SystemVarRecs(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSModuleScope absolute Data;
begin
if RefEl is TPasFunction then
Scope.SystemVarRecs:=TPasFunction(RefEl)
else
RaiseMsg(20190215230857,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_EnumTypeScope_CanonicalSet(RefEl: TPasElement;
Data: TObject);
var
El: TPasEnumType absolute Data;
Scope: TPasEnumTypeScope;
begin
if RefEl is TPasSetType then
begin
Scope:=El.CustomData as TPasEnumTypeScope;
Scope.CanonicalSet:=TPasSetType(RefEl);
if RefEl.Parent<>El then
RefEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasEnumTypeScope.CanonicalSet'){$ENDIF};
end
else
RaiseMsg(20180316215238,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_PropertyScope_AncestorProp(RefEl: TPasElement;
Data: TObject);
var
Scope: TPasPropertyScope absolute Data;
begin
if RefEl is TPasProperty then
Scope.AncestorProp:=TPasProperty(RefEl)
else
RaiseMsg(20180213214723,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ProcedureScope_ImplProc(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSProcedureScope absolute Data;
begin
if RefEl is TPasProcedure then
Scope.ImplProc:=TPasProcedure(RefEl) // no AddRef
else
RaiseMsg(20180219140043,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ProcedureScope_Overridden(RefEl: TPasElement;
Data: TObject);
var
Scope: TPas2JSProcedureScope absolute Data;
begin
if RefEl is TPasProcedure then
Scope.OverriddenProc:=TPasProcedure(RefEl) // no AddRef
else
RaiseMsg(20180213215959,Scope.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ResolvedReference_Declaration(RefEl: TPasElement;
Data: TObject);
var
Ref: TResolvedReference absolute Data;
begin
Ref.Declaration:=RefEl;
end;
procedure TPCUReader.Set_ResolvedReference_CtxConstructor(RefEl: TPasElement;
Data: TObject);
var
Ref: TResolvedReference absolute Data;
begin
if RefEl is TPasType then
TResolvedRefCtxConstructor(Ref.Context).Typ:=TPasType(RefEl) // no AddRef
else
RaiseMsg(20190222010314,Ref.Element,GetObjName(RefEl));
end;
procedure TPCUReader.Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement;
Data: TObject);
var
Ref: TResolvedReference absolute Data;
begin
if RefEl is TPasConstructor then
TResolvedRefCtxAttrProc(Ref.Context).Proc:=TPasConstructor(RefEl) // no AddRef
else
RaiseMsg(20190222010821,Ref.Element,GetObjName(RefEl));
end;
procedure TPCUReader.RaiseMsg(Id: int64; const Msg: string);
var
E: EPas2JsReadError;
begin
E:=EPas2JsReadError.Create('['+IntToStr(Id)+'] '+Msg);
E.Owner:=Self;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.RaiseMsg ',E.Message);
{$ENDIF}
raise E;
end;
function TPCUReader.CheckJSONArray(Data: TJSONData; El: TPasElement;
const PropName: string): TJSONArray;
begin
if Data is TJSONArray then exit(TJSONArray(Data));
if Data=nil then
RaiseMsg(20180205140943,El,PropName+': nil')
else
RaiseMsg(20180205140358,El,PropName+': '+Data.ClassName);
Result:=nil;
end;
function TPCUReader.CheckJSONObject(Data: TJSONData; Id: int64): TJSONObject;
begin
if Data is TJSONObject then exit(TJSONObject(Data));
RaiseMsg(Id);
Result:=nil;
end;
function TPCUReader.CheckJSONString(Data: TJSONData; Id: int64): String;
begin
if Data is TJSONString then
exit(String(Data.AsString));
RaiseMsg(Id);
Result:='';
end;
function TPCUReader.ReadString(Obj: TJSONObject; const PropName: string; out
s: string; El: TPasElement): boolean;
var
C: TClass;
Data: TJSONData;
begin
s:='';
Data:=Obj.Find(PropName);
if Data=nil then exit(false);
C:=Data.ClassType;
if C=TJSONString then
begin
s:=String(Data.AsString);
exit(true);
end;
RaiseMsg(20180205133227,El,PropName+':'+Data.ClassName);
Result:=false;
end;
function TPCUReader.ReadInteger(Obj: TJSONObject; const PropName: string; out
i: integer; El: TPasElement): boolean;
var
C: TClass;
Data: TJSONData;
begin
i:=0;
Data:=Obj.Find(PropName);
if Data=nil then exit(false);
C:=Data.ClassType;
if C=TJSONIntegerNumber then
begin
i:=Data.AsInteger;
exit(true);
end;
RaiseMsg(20180205133132,El,PropName+':'+Data.ClassName);
Result:=false;
end;
function TPCUReader.ReadBoolean(Obj: TJSONObject; const PropName: string; out
b: boolean; El: TPasElement): boolean;
var
C: TClass;
Data: TJSONData;
begin
b:=false;
Data:=Obj.Find(PropName);
if Data=nil then exit(false);
C:=Data.ClassType;
if C=TJSONBoolean then
begin
b:=Data.AsBoolean;
exit(true);
end;
RaiseMsg(20180207183730,El,PropName+':'+Data.ClassName);
Result:=false;
end;
function TPCUReader.ReadArray(Obj: TJSONObject; const PropName: string; out
Arr: TJSONArray; El: TPasElement): boolean;
var
Data: TJSONData;
begin
Arr:=nil;
Data:=Obj.Find(PropName);
if Data=nil then exit(false);
if not (Data is TJSONArray) then
RaiseMsg(20180207144507,El,PropName+':'+Data.ClassName);
Arr:=TJSONArray(Data);
Result:=true;
end;
function TPCUReader.ReadObject(Obj: TJSONObject; const PropName: string; out
SubObj: TJSONObject; El: TPasElement): boolean;
var
Data: TJSONData;
begin
SubObj:=nil;
Data:=Obj.Find(PropName);
if Data=nil then exit(false);
if not (Data is TJSONObject) then
RaiseMsg(20180210212719,El,PropName+':'+Data.ClassName);
SubObj:=TJSONObject(Data);
Result:=true;
end;
function TPCUReader.CreateContext: TPCUReaderContext;
begin
Result:=TPCUReaderContext.Create;
Result.ModeSwitches:=InitialFlags.ModeSwitches;
Result.BoolSwitches:=InitialFlags.BoolSwitches;
end;
function TPCUReader.GetElReference(Id: integer; ErrorEl: TPasElement
): TPCUFilerElementRef;
begin
if Id<=0 then
RaiseMsg(20180221171721,ErrorEl);
if Id>=length(FElementRefsArray) then
RaiseMsg(20180221171741,ErrorEl);
Result:=FElementRefsArray[Id];
end;
function TPCUReader.AddElReference(Id: integer; ErrorEl: TPasElement;
El: TPasElement): TPCUFilerElementRef;
var
Ref: TPCUFilerElementRef;
RefItem: TPCUFilerPendingElRef;
PendingElRef: TPCUReaderPendingElRef;
PendingElListRef: TPCUReaderPendingElListRef;
PendingElArrRef: TPCUReaderPendingElArrRef;
{$IF defined(VerbosePCUFiler) or defined(memcheck)}
Node: TAVLTreeNode;
{$ENDIF}
begin
if Id<=0 then
RaiseMsg(20180207151233,ErrorEl);
if Id>1000000 then
RaiseMsg(20180316090216,ErrorEl,IntToStr(Id));
if Id>=length(FElementRefsArray) then
GrowIdToRefsArray(FElementRefsArray,Id);
Ref:=FElementRefsArray[Id];
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.AddElReference Id=',Id,' El=',GetObjName(El),' ErrorEl=',GetObjName(ErrorEl),' OldRef=',GetObjName(Ref));
{$ENDIF}
if Ref=nil then
begin
// new target element
if El<>nil then
begin
Ref:=GetElementReference(El,true);
if Ref.Id=0 then
Ref.Id:=Id
else if Ref.Id<>Id then
RaiseMsg(20180207152251,ErrorEl,IntToStr(Ref.Id)+'<>'+IntToStr(Id));
end
else
begin
Ref:=TPCUFilerElementRef.Create;
Ref.Id:=Id;
end;
{$IF defined(VerbosePCUFiler) or defined(memcheck)}
if FElementRefsArray[Id]<>nil then
RaiseMsg(20180711212859,ErrorEl,IntToStr(Id)+' is not FElementRefsArray[Id]');
{$ENDIF}
FElementRefsArray[Id]:=Ref;
end;
Result:=Ref;
if El=nil then
exit
else if Ref.Element=nil then
begin
Ref.Element:=El;
{$IF defined(VerbosePCUFiler) or defined(memcheck)}
Node:=FElementRefs.FindKey(El,@CompareElWithPCUFilerElementRef);
if Node<>nil then
RaiseMsg(20180711231646,El,GetObjName(TPCUFilerElementRef(Node.Data).Element));
{$ENDIF}
FElementRefs.Add(Ref);
if Ref.Pending<>nil then
begin
// resolve pending references
while Ref.Pending<>nil do
begin
RefItem:=Ref.Pending;
if RefItem is TPCUReaderPendingElRef then
begin
PendingElRef:=TPCUReaderPendingElRef(RefItem);
PendingElRef.Setter(Ref.Element,PendingElRef.Data);
end
else if RefItem is TPCUReaderPendingElListRef then
begin
PendingElListRef:=TPCUReaderPendingElListRef(RefItem);
PendingElListRef.List[PendingElListRef.Index]:=Ref.Element;
if PendingElListRef.AddRef{$IFDEF CheckPasTreeRefCount}<>''{$ENDIF} then
Ref.Element.AddRef{$IFDEF CheckPasTreeRefCount}(PendingElListRef.AddRef){$ENDIF};
end
else if RefItem is TPCUReaderPendingElArrRef then
begin
PendingElArrRef:=TPCUReaderPendingElArrRef(RefItem);
PendingElArrRef.Arr[PendingElArrRef.Index]:=Ref.Element;
if PendingElArrRef.AddRef{$IFDEF CheckPasTreeRefCount}<>''{$ENDIF} then
Ref.Element.AddRef{$IFDEF CheckPasTreeRefCount}(PendingElArrRef.AddRef){$ENDIF};
end
else
RaiseMsg(20180207153056,ErrorEl,RefItem.ClassName);
Ref.Pending:=RefItem.Next;
RefItem.Next:=nil;
RefItem.Free;
end;
end;
end
else if El<>Ref.Element then
RaiseMsg(20180207194919,ErrorEl,'Duplicate Id='+IntToStr(Id)+' El='+GetObjName(El)+' Ref.Element='+GetObjName(Ref.Element));
end;
procedure TPCUReader.PromiseSetElReference(Id: integer;
const Setter: TOnSetElReference; Data: TObject; ErrorEl: TPasElement);
var
Ref: TPCUFilerElementRef;
PendingItem: TPCUReaderPendingElRef;
begin
Ref:=AddElReference(Id,ErrorEl,nil);
if Ref.Element<>nil then
begin
// element was already created -> execute Setter immediately
Setter(Ref.Element,Data);
end
else
begin
// element was not yet created -> store Setter
PendingItem:=TPCUReaderPendingElRef.Create;
PendingItem.Setter:=Setter;
PendingItem.Data:=Data;
PendingItem.ErrorEl:=ErrorEl;
Ref.AddPending(PendingItem);
end;
end;
procedure TPCUReader.PromiseSetElListReference(Id: integer; List: TFPList;
Index: integer; AddRef: TPCUAddRef; ErrorEl: TPasElement);
var
Ref: TPCUFilerElementRef;
PendingItem: TPCUReaderPendingElListRef;
begin
Ref:=AddElReference(Id,ErrorEl,nil);
if Ref.Element<>nil then
begin
// element was already created -> set list item immediately
List[Index]:=Ref.Element;
if AddRef{$IFDEF CheckPasTreeRefCount}<>''{$ENDIF} then
Ref.Element.AddRef{$IFDEF CheckPasTreeRefCount}(AddRef){$ENDIF};
end
else
begin
// element was not yet created -> store
PendingItem:=TPCUReaderPendingElListRef.Create;
PendingItem.List:=List;
PendingItem.Index:=Index;
PendingItem.AddRef:=AddRef;
PendingItem.ErrorEl:=ErrorEl;
Ref.AddPending(PendingItem);
end;
end;
procedure TPCUReader.PromiseSetElArrReference(Id: integer;
Arr: TPasElementArray; Index: integer; AddRef: TPCUAddRef;
ErrorEl: TPasElement);
var
Ref: TPCUFilerElementRef;
PendingItem: TPCUReaderPendingElArrRef;
begin
Ref:=AddElReference(Id,ErrorEl,nil);
if Ref.Element<>nil then
begin
// element was already created -> set list item immediately
Arr[Index]:=Ref.Element;
if AddRef{$IFDEF CheckPasTreeRefCount}<>''{$ENDIF} then
Ref.Element.AddRef{$IFDEF CheckPasTreeRefCount}(AddRef){$ENDIF};
end
else
begin
// element was not yet created -> store
PendingItem:=TPCUReaderPendingElArrRef.Create;
PendingItem.Arr:=Arr;
PendingItem.Index:=Index;
PendingItem.AddRef:=AddRef;
PendingItem.ErrorEl:=ErrorEl;
Ref.AddPending(PendingItem);
end;
end;
procedure TPCUReader.ReadHeaderMagic(Obj: TJSONObject);
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadHeaderMagic ',Obj.Get('FileType',''));
{$ENDIF}
if Obj.Get('FileType','')<>PCUMagic then
RaiseMsg(20180130201710,'not a PCU file');
end;
procedure TPCUReader.ReadHeaderVersion(Obj: TJSONObject);
begin
FFileVersion:=Obj.Get('Version',0);
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadHeaderVersion ',FFileVersion);
{$ENDIF}
if FFileVersion<1 then
RaiseMsg(20180130201801,'invalid PCU file version');
if FFileVersion>PCUVersion then
RaiseMsg(20180130201822,'pcu file was created by a newer compiler.');
end;
procedure TPCUReader.ReadGUID(Obj: TJSONObject);
var
s: string;
begin
if ReadString(Obj,'GUID',s,nil) then
FGUID:=StringToGUID(s);
end;
procedure TPCUReader.ReadHeaderItem(const PropName: string; Data: TJSONData);
begin
RaiseMsg(20180202151706,'unknown property "'+PropName+'" '+GetObjName(Data));
end;
procedure TPCUReader.ReadArrayFlags(Data: TJSONData; El: TPasElement;
const PropName: string; out Names: TStringDynArray; out
Enable: TBooleanDynArray);
const
IdentStart = ['a'..'z','A'..'Z','_'];
var
Arr: TJSONArray;
Cnt, i: Integer;
s: String;
begin
Names:=nil;
Enable:=nil;
if Data=nil then exit;
Arr:=CheckJSONArray(Data,El,PropName);
Cnt:=Arr.Count;
if Cnt=0 then exit;
SetLength(Names,Cnt);
SetLength(Enable,Cnt);
for i:=0 to Cnt-1 do
begin
Data:=Arr[i];
if not (Data is TJSONString) then
RaiseMsg(20180202132350,El,PropName+' elements must be string');
s:=String(TJSONString(Data).AsString);
if s='' then
RaiseMsg(20180202133605,El,PropName+' elements must be string');
if s[1]='-' then
begin
Enable[i]:=false;
system.Delete(s,1,1);
end
else
Enable[i]:=true;
if not (s[1] in IdentStart) then
RaiseMsg(20180202133605,El,PropName+' elements must be identifiers');
Names[i]:=s;
end;
end;
function TPCUReader.ReadParserOptions(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TPOptions): TPOptions;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TPOption;
Found: Boolean;
i: Integer;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadParserOptions START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TPOption do
if s=PCUParserOptionNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180202144009,El,'unknown ParserOption "'+s+'"');
end;
end;
function TPCUReader.ReadModeSwitches(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TModeSwitches): TModeSwitches;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TModeSwitch;
Found: Boolean;
i: Integer;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadModeSwitches START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
if (FileVersion<5) and (SameText(s,'multiplescopehelpers')) then
s:=PCUModeSwitchNames[msMultiHelpers];
for f in TModeSwitch do
if s=PCUModeSwitchNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
begin
if (FileVersion<5) and (SameText(s,'ignoreinterfaces')) then
// ignore old switch
else
RaiseMsg(20180202144054,El,'unknown ModeSwitch "'+s+'"');
end;
end;
end;
function TPCUReader.ReadBoolSwitches(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TBoolSwitches): TBoolSwitches;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TBoolSwitch;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadBoolSwitches START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TBoolSwitch do
if s=PCUBoolSwitchNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180202144116,El,'unknown BoolSwitch "'+s+'"');
end;
end;
function TPCUReader.ReadConverterOptions(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TPasToJsConverterOptions
): TPasToJsConverterOptions;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TPasToJsConverterOption;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadConverterOptions START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TPasToJsConverterOption do
if s=PCUConverterOptions[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180202144136,'unknown ConverterOption "'+s+'"');
end;
end;
procedure TPCUReader.ReadTargetPlatform(Data: TJSONData);
var
p: TPasToJsPlatform;
s: String;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadTargetPlatform START');
{$ENDIF}
s:=CheckJSONString(Data,20180203100215);
for p in TPasToJsPlatform do
if s=PCUTargetPlatformNames[p] then
begin
InitialFlags.TargetPlatform:=p;
exit;
end;
RaiseMsg(20180202145542,'invalid TargetPlatform');
end;
procedure TPCUReader.ReadTargetProcessor(Data: TJSONData);
var
p: TPasToJsProcessor;
s: String;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadTargetProcessor START');
{$ENDIF}
s:=CheckJSONString(Data,20180203100235);
for p in TPasToJsProcessor do
if s=PCUTargetProcessorNames[p] then
begin
InitialFlags.TargetProcessor:=p;
exit;
end;
RaiseMsg(20180202145623,'invalid TargetProcessor');
end;
procedure TPCUReader.ReadSrcFiles(Data: TJSONData);
var
SourcesArr: TJSONArray;
i, j: Integer;
Src: TJSONObject;
CurFile: TPCUSourceFile;
Found: Boolean;
ft: TPCUSourceFileType;
s: TJSONStringType;
CurFilename, PropName: string;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadSrcFiles START ');
{$ENDIF}
SourcesArr:=CheckJSONArray(Data,nil,'Sources');
for i:=0 to SourcesArr.Count-1 do
begin
Src:=CheckJSONObject(SourcesArr[i],20180203100307);
CurFile:=TPCUSourceFile.Create;
FSourceFiles.Add(CurFile);
if i=0 then
CurFile.FileType:=sftUnit
else
CurFile.FileType:=sftInclude;
for j:=0 to Src.Count-1 do
begin
PropName:=Src.Names[j];
Data:=Src.Elements[PropName];
case PropName of
'Type':
begin
s:=CheckJSONString(Data,20180203101322);
Found:=false;
for ft in TPCUSourceFileType do
if s=PCUSourceFileTypeNames[ft] then
begin
Found:=true;
CurFile.FileType:=ft;
break;
end;
if not Found then
RaiseMsg(20180202144347,'unknown filetype "'+s+'"');
end;
'File':
begin
CurFilename:=CheckJSONString(Data,20180203100410);
if CurFilename='' then
RaiseMsg(20180130203605);
if length(CurFilename)>MAX_PATH then
RaiseMsg(20180130203624);
DoDirSeparators(CurFilename);
if CurFilename<>ResolveDots(CurFilename) then
RaiseMsg(20180130203841);
if ExtractFilenameOnly(CurFilename)='' then
RaiseMsg(20180130203924);
CurFile.Filename:=CurFilename;
end;
'CheckSum':
CurFile.Checksum:=Data.AsInt64;
else
RaiseMsg(20180202152628,'unknown file property "'+PropName+'"');
end;
end;
end;
end;
function TPCUReader.ReadMemberHints(Obj: TJSONObject; El: TPasElement;
const DefaultValue: TPasMemberHints): TPasMemberHints;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TPasMemberHint;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadMemberHints START');
{$ENDIF}
Data:=Obj.Find('Hints');
if Data=nil then exit;
ReadArrayFlags(Data,El,'Hints',Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TPasMemberHint do
if s=PCUMemberHintNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180205134551,'unknown element Hints "'+s+'"');
end;
end;
procedure TPCUReader.ReadSrcPos(Obj: TJSONObject; El: TPasElement;
aContext: TPCUReaderContext);
var
i, LastLine, LastCol: integer;
s: string;
CurLine, CurCol: LongInt;
p: SizeInt;
begin
if aContext=nil then ;
if ReadInteger(Obj,'File',i,El) then
begin
if i>=0 then
El.SourceFilename:=SourceFiles[i].Filename
else
El.SourceFilename:='';
end
else if El.Parent<>nil then
El.SourceFilename:=El.Parent.SourceFilename
else
El.SourceFilename:='';
if El.Parent<>nil then
Resolver.UnmangleSourceLineNumber(El.Parent.SourceLinenumber,LastLine,LastCol)
else
begin
LastLine:=1;
LastCol:=1;
end;
if ReadString(Obj,'Pos',s,El) then
begin
p:=Pos(',',s);
if p>0 then
begin
CurLine:=StrToIntDef(LeftStr(s,p-1),LastLine);
CurCol:=StrToIntDef(copy(s,p+1,length(s)),LastCol);
end
else
begin
CurLine:=StrToIntDef(s,LastLine);
CurCol:=LastCol;
end;
El.SourceLinenumber:=Resolver.MangleSourceLineNumber(CurLine,CurCol);
end
else
El.SourceLinenumber:=Resolver.MangleSourceLineNumber(LastLine,LastCol);
end;
procedure TPCUReader.ReadPasElement(Obj: TJSONObject; El: TPasElement;
aContext: TPCUReaderContext);
function StrToMemberVisibility(const s: string): TPasMemberVisibility;
var
vis: TPasMemberVisibility;
begin
for vis in TPasMemberVisibility do
if PCUMemberVisibilityNames[vis]=s then
exit(vis);
RaiseMsg(20180205134334,El,s);
end;
var
Id: integer;
s: string;
DefHints: TPasMemberHints;
begin
if ReadInteger(Obj,'Id',Id,El) then
AddElReference(Id,El,El);
ReadSrcPos(Obj,El,aContext);
if ReadString(Obj,'Visibility',s,El) then
El.Visibility:=StrToMemberVisibility(s)
else
El.Visibility:=GetDefaultMemberVisibility(El);
DefHints:=[];
if El.Parent<>nil then
DefHints:=El.Parent.Hints;
El.Hints:=ReadMemberHints(Obj,El,DefHints);
if ReadString(Obj,'HintMessage',s,El) then
El.HintMessage:=s;
if aContext<>nil then ;
end;
procedure TPCUReader.ReadExternalMembers(El: TPasElement; Arr: TJSONArray;
Members: TFPList);
var
i, Index: Integer;
Data: TJSONData;
SubObj: TJSONObject;
Name: string;
ChildEl: TPasElement;
begin
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180309173351,El);
SubObj:=TJSONObject(Data);
// search element
if not ReadString(SubObj,'Name',Name,El) then
RaiseMsg(20180309180233,El,IntToStr(i));
if not ReadInteger(SubObj,'MId',Index,El) then
RaiseMsg(20180309184629,El,IntToStr(i));
if (Index<0) or (Index>=Members.Count) then
RaiseMsg(20180309184718,El,IntToStr(Index)+' out of bounds 0-'+IntToStr(Members.Count));
ChildEl:=TPasElement(Members[Index]);
if Resolver.GetOverloadName(ChildEl)<>Name then
RaiseMsg(20180309200800,El,'Expected="'+Name+'", but found "'+Resolver.GetOverloadName(ChildEl)+'" ('+ChildEl.Name+')');
// read child declarations
ReadExternalReferences(SubObj,ChildEl);
end;
end;
procedure TPCUReader.ReadExternalReferences(Obj: TJSONObject; El: TPasElement);
var
Arr: TJSONArray;
Id: Integer;
Data: TJSONData;
SubObj: TJSONObject;
Intf: TInterfaceSection;
Name: string;
Ref: TPCUFilerElementRef;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadExtRefs ',GetObjName(El));
{$ENDIF}
if ReadInteger(Obj,'Id',Id,El) then
begin
Ref:=AddElReference(Id,El,El);
Ref.Obj:=Obj;
end;
if ReadArray(Obj,'El',Arr,El) then
begin
if El is TPasDeclarations then
ReadExternalMembers(El,Arr,TPasDeclarations(El).Declarations)
else if El is TPasMembersType then
ReadExternalMembers(El,Arr,TPasMembersType(El).Members)
else if El is TPasEnumType then
ReadExternalMembers(El,Arr,TPasEnumType(El).Values)
else if El is TPasModule then
begin
// a Module has only the Interface as child
if Arr.Count<>1 then
RaiseMsg(20180309180715,El,IntToStr(Arr.Count));
Data:=Arr[0];
if not (Data is TJSONObject) then
RaiseMsg(20180309180745,El);
SubObj:=TJSONObject(Data);
if not ReadString(SubObj,'Name',Name,El) then
RaiseMsg(20180309180749,El);
if Name<>'Interface' then
RaiseMsg(20180309180806,El);
Intf:=TPasModule(El).InterfaceSection;
if Intf=nil then
RaiseMsg(20180309180856,El);
ReadExternalReferences(SubObj,Intf);
end
else
RaiseMsg(20180309180610,El);
end;
end;
procedure TPCUReader.ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection;
aContext: TPCUReaderContext);
// Note: can be called twice for each section if there are pending used interfaces
var
Arr: TJSONArray;
i, Id: Integer;
Data: TJSONData;
UsesObj: TJSONObject;
Name, InFilename, ModuleName: string;
Use: TPasUsesUnit;
Module: TPasModule;
begin
// fetch used units
if ReadArray(Obj,'Uses',Arr,Section) then
begin
SetLength(Section.UsesClause,Arr.Count);
for i:=0 to length(Section.UsesClause)-1 do
Section.UsesClause[i]:=nil;
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180307103518,Section,GetObjName(Data));
UsesObj:=TJSONObject(Data);
if not ReadString(UsesObj,'Name',Name,Section) then
RaiseMsg(20180307103629,Section);
if not IsValidIdent(Name,true,true) then
RaiseMsg(20180307103937,Section,Name);
ReadString(UsesObj,'In',InFilename,Section);
ReadString(UsesObj,'UnitName',ModuleName,Section);
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadUsedUnits ',i,' Name="',Name,'" In="',InFilename,'" ModuleName="',ModuleName,'"');
{$ENDIF}
Use:=TPasUsesUnit(CreateElement(TPasUsesUnit,Name,Section));
Section.UsesClause[i]:=Use;
// Use.Expr is not needed
if InFilename<>'' then
begin
Use.InFilename:=TPrimitiveExpr(CreateElement(TPrimitiveExpr,'',Use));
Use.InFilename.Kind:=pekString;
Use.InFilename.Value:=InFilename;
end;
if ModuleName='' then ModuleName:=Name;
Module:=Resolver.FindModule(Name,Use.Expr,Use.InFilename);
if Module=nil then
RaiseMsg(20180307231247,Use);
Use.Module:=Module;
Module.AddRef{$IFDEF CheckPasTreeRefCount}('TPasUsesUnit.Module'){$ENDIF};
if ReadInteger(UsesObj,'Id',Id,Use) then
AddElReference(Id,Use,Use);
end;
Resolver.CheckPendingUsedInterface(Section);
end;
if aContext=nil then ;
end;
procedure TPCUReader.ReadUsedUnitsFinish(Obj: TJSONObject;
Section: TPasSection; aContext: TPCUReaderContext);
var
Arr: TJSONArray;
Scope, UsedScope: TPas2JSSectionScope;
i: Integer;
Use: TPasUsesUnit;
Module: TPasModule;
Data: TJSONData;
UsesObj, ModuleObj: TJSONObject;
Name: string;
begin
Scope:=Section.CustomData as TPas2JSSectionScope;
// read external refs from used units
if ReadArray(Obj,'Uses',Arr,Section) then
begin
Scope:=Section.CustomData as TPas2JSSectionScope;
if Scope.UsesFinished then
RaiseMsg(20180313133931,Section);
if Section.PendingUsedIntf<>nil then
RaiseMsg(20180313134142,Section,GetObjName(Section.PendingUsedIntf));
if Arr.Count<>length(Section.UsesClause) then
RaiseMsg(20180313134338,IntToStr(Arr.Count)+'<>'+IntToStr(length(Section.UsesClause)));
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180313134409,Section,GetObjName(Data));
UsesObj:=TJSONObject(Data);
Use:=Section.UsesClause[i];
Module:=Use.Module as TPasModule;
UsedScope:=Module.InterfaceSection.CustomData as TPas2JSSectionScope;
Scope.UsesScopes.Add(UsedScope);
if ReadObject(UsesObj,'Module',ModuleObj,Use) then
ReadExternalReferences(ModuleObj,Module);
end;
end;
// read external refs from indirectly used units
if ReadArray(Obj,'IndirectUses',Arr,Section) then
begin
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180314155716,Section,GetObjName(Data));
UsesObj:=TJSONObject(Data);
if not ReadString(UsesObj,'Name',Name,Section) then
RaiseMsg(20180314155756,Section);
if not IsValidIdent(Name,true,true) then
RaiseMsg(20180314155800,Section,Name);
Module:=Resolver.FindModule(Name,nil,nil);
if Module=nil then
RaiseMsg(20180314155840,Section,Name);
if Module.InterfaceSection=nil then
RaiseMsg(20180314155953,Section,'indirect unit "'+Name+'"');
UsedScope:=Module.InterfaceSection.CustomData as TPas2JSSectionScope;
if not UsedScope.Finished then
RaiseMsg(20180314155953,Section,'indirect unit "'+Name+'"');
ReadExternalReferences(UsesObj,Module);
end;
end;
Scope.UsesFinished:=true;
if aContext=nil then ;
end;
procedure TPCUReader.ReadSectionScope(Obj: TJSONObject;
Scope: TPas2JSSectionScope; aContext: TPCUReaderContext);
begin
ReadIdentifierScope(Obj,Scope,aContext);
// not needed: Scope ElevatedLocals
// not needed: Scope Helpers, autogenerated in ReadClassType
Scope.BoolSwitches:=ReadBoolSwitches(Obj,Scope.Element,'BoolSwitches',aContext.BoolSwitches);
Scope.ModeSwitches:=ReadModeSwitches(Obj,Scope.Element,'ModeSwitches',aContext.ModeSwitches);
end;
procedure TPCUReader.ReadSection(Obj: TJSONObject; Section: TPasSection;
aContext: TPCUReaderContext);
// Note: can be called twice for each section if there are pending used interfaces
var
Scope: TPas2JSSectionScope;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadSection ',GetObjName(Section));
{$ENDIF}
if Section.CustomData=nil then
begin
ReadPasElement(Obj,Section,aContext);
Scope:=TPas2JSSectionScope(Resolver.CreateScope(Section,TPas2JSSectionScope));
ReadUsedUnitsInit(Obj,Section,aContext);
if Section.PendingUsedIntf<>nil then exit;
end
else
begin
Scope:=Section.CustomData as TPas2JSSectionScope;
if Scope.Finished then
RaiseMsg(20180308160336,Section);
if Section.PendingUsedIntf<>nil then
RaiseMsg(20180308160639,Section,GetObjName(Section.PendingUsedIntf));
end;
// read external references
ReadUsedUnitsFinish(Obj,Section,aContext);
// read scope, needs external refs
ReadSectionScope(Obj,Scope,aContext);
aContext.BoolSwitches:=Scope.BoolSwitches;
aContext.ModeSwitches:=Scope.ModeSwitches;
// read declarations, needs external refs
ReadDeclarations(Obj,Section,aContext);
Scope.Finished:=true;
if Section is TInterfaceSection then
begin
ResolvePending;
Resolver.NotifyPendingUsedInterfaces;
end;
end;
procedure TPCUReader.ReadDeclarations(Obj: TJSONObject; Section: TPasSection;
aContext: TPCUReaderContext);
var
Arr: TJSONArray;
i: Integer;
Data: TJSONData;
El: TPasElement;
C: TClass;
begin
if not ReadArray(Obj,'Declarations',Arr,Section) then exit;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadDeclarations ',GetObjName(Section),' ',Arr.Count);
{$ENDIF}
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180207182304,Section,IntToStr(i)+' '+GetObjName(Data));
El:=ReadElement(TJSONObject(Data),Section,aContext);
Section.Declarations.Add(El);
C:=El.ClassType;
if C=TPasResString then
Section.ResStrings.Add(El)
else if C=TPasConst then
Section.Consts.Add(El)
else if (C=TPasClassType) or (C=TPasRecordType) then
Section.Classes.Add(El)
else if C.InheritsFrom(TPasType) then
// not TPasClassType, TPasRecordType !
Section.Types.Add(El)
else if C.InheritsFrom(TPasProcedure) then
Section.Functions.Add(El)
else if C=TPasVariable then
Section.Variables.Add(El)
else if C=TPasProperty then
Section.Properties.Add(El)
else if C=TPasExportSymbol then
Section.ExportSymbols.Add(El);
end;
end;
function TPCUReader.CreateElement(AClass: TPTreeElement; const AName: String;
AParent: TPasElement): TPasElement;
begin
Result:=AClass.Create(AName,AParent);
Result.SourceFilename:=SourceFilename;
{$IFDEF CheckPasTreeRefCount}Result.RefIds.Add('CreateElement');{$ENDIF}
end;
function TPCUReader.ReadElement(Obj: TJSONObject; Parent: TPasElement;
aContext: TPCUReaderContext): TPasElement;
procedure ReadPrimitive(Kind: TPasExprKind);
var
Prim: TPrimitiveExpr;
Value: string;
begin
ReadString(Obj,'Value',Value,Parent);
Prim:=TPrimitiveExpr(CreateElement(TPrimitiveExpr,'',Parent));
Prim.Kind:=Kind;
Prim.Value:=Value;
Result:=Prim;
Prim.Name:='';
ReadPasExpr(Obj,Prim,Kind,aContext);
end;
procedure ReadParams(Kind: TPasExprKind);
begin
Result:=CreateElement(TParamsExpr,'',Parent);
TParamsExpr(Result).Kind:=Kind;
ReadParamsExpr(Obj,TParamsExpr(Result),aContext);
end;
procedure CreateClassType(Kind: TPasObjKind; const aName: string);
begin
Result:=CreateElement(TPasClassType,aName,Parent);
TPasClassType(Result).ObjKind:=Kind;
ReadClassType(Obj,TPasClassType(Result),aContext);
end;
procedure ReadProc(aClass: TPasProcedureClass; const aName: string);
begin
Result:=CreateElement(aClass,aName,Parent);
ReadProcedure(Obj,TPasProcedure(Result),aContext);
end;
procedure ReadOper(aClass: TPasProcedureClass; const aName: string);
begin
Result:=CreateElement(aClass,aName,Parent);
ReadOperator(Obj,TPasOperator(Result),aContext);
end;
var
aType, Name: string;
ok: Boolean;
begin
Result:=nil;
if not ReadString(Obj,'Type',aType,Parent) then
RaiseMsg(20180210143327,Parent);
if not ReadString(Obj,'Name',Name,Parent) then
Name:='';
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadElement ',GetObjName(Parent),' Type="',aType,'" Name="',Name,'"');
{$ENDIF}
ok:=false;
try
case aType of
'Unary':
begin
Result:=CreateElement(TUnaryExpr,Name,Parent);
ReadUnaryExpr(Obj,TUnaryExpr(Result),aContext);
end;
'Binary':
begin
Result:=CreateElement(TBinaryExpr,Name,Parent);
TBinaryExpr(Result).Kind:=pekBinary;
TBinaryExpr(Result).OpCode:=eopAdd;
ReadBinaryExpr(Obj,TBinaryExpr(Result),aContext);
end;
'Ident': ReadPrimitive(pekIdent);
'Number': ReadPrimitive(pekNumber);
'String': ReadPrimitive(pekString);
'Bool':
begin
Result:=CreateElement(TBoolConstExpr,'',Parent);
TBoolConstExpr(Result).Kind:=pekBoolConst;
TBoolConstExpr(Result).Value:=false;
ReadBoolConstExpr(Obj,TBoolConstExpr(Result),aContext);
end;
'False','True':
begin
Result:=CreateElement(TBoolConstExpr,'',Parent);
TBoolConstExpr(Result).Kind:=pekBoolConst;
TBoolConstExpr(Result).Value:=aType='True';
ReadPasExpr(Obj,TBoolConstExpr(Result),pekBoolConst,aContext);
end;
'Nil':
begin
Result:=CreateElement(TNilExpr,'nil',Parent);
TNilExpr(Result).Kind:=pekNil;
ReadPasExpr(Obj,TNilExpr(Result),pekNil,aContext);
end;
'Inherited':
begin
Result:=CreateElement(TInheritedExpr,'',Parent);
TInheritedExpr(Result).Kind:=pekInherited;
ReadPasExpr(Obj,TInheritedExpr(Result),pekInherited,aContext);
end;
'Self':
begin
Result:=CreateElement(TSelfExpr,'',Parent);
TSelfExpr(Result).Kind:=pekSelf;
ReadPasExpr(Obj,TSelfExpr(Result),pekSelf,aContext);
end;
'A[]':
ReadParams(pekArrayParams);
'F()':
ReadParams(pekFuncParams);
'[]':
ReadParams(pekSet);
'RecValues':
begin
Result:=CreateElement(TRecordValues,'',Parent);
TRecordValues(Result).Kind:=pekListOfExp;
ReadRecordValues(Obj,TRecordValues(Result),aContext);
end;
'ArrValues':
begin
Result:=CreateElement(TArrayValues,'',Parent);
TArrayValues(Result).Kind:=pekListOfExp;
ReadArrayValues(Obj,TArrayValues(Result),aContext);
end;
'ResString':
begin
Result:=CreateElement(TPasResString,Name,Parent);
ReadResString(Obj,TPasResString(Result),aContext);
end;
'Alias':
begin
Result:=CreateElement(TPasAliasType,Name,Parent);
ReadAliasType(Obj,TPasAliasType(Result),aContext);
end;
'Pointer':
begin
Result:=CreateElement(TPasPointerType,Name,Parent);
ReadPointerType(Obj,TPasPointerType(Result),aContext);
end;
'TypeAlias':
begin
Result:=CreateElement(TPasTypeAliasType,Name,Parent);
ReadAliasType(Obj,TPasTypeAliasType(Result),aContext);
end;
'ClassOf':
begin
Result:=CreateElement(TPasClassOfType,Name,Parent);
ReadAliasType(Obj,TPasClassOfType(Result),aContext);
end;
'Specialize':
begin
Result:=CreateElement(TPasSpecializeType,Name,Parent);
ReadSpecializeType(Obj,TPasSpecializeType(Result),aContext);
end;
'InlineSpecialize':
begin
Result:=CreateElement(TInlineSpecializeExpr,Name,Parent);
ReadInlineSpecializeExpr(Obj,TInlineSpecializeExpr(Result),aContext);
end;
'RangeType':
begin
Result:=CreateElement(TPasRangeType,Name,Parent);
ReadRangeType(Obj,TPasRangeType(Result),aContext);
end;
'ArrType':
begin
Result:=CreateElement(TPasArrayType,Name,Parent);
ReadArrayType(Obj,TPasArrayType(Result),aContext);
end;
'File':
begin
Result:=CreateElement(TPasFileType,Name,Parent);
ReadFileType(Obj,TPasFileType(Result),aContext);
end;
'EnumV':
begin
Result:=CreateElement(TPasEnumValue,Name,Parent);
ReadEnumValue(Obj,TPasEnumValue(Result),aContext);
end;
'EnumType':
begin
Result:=CreateElement(TPasEnumType,Name,Parent);
ReadEnumType(Obj,TPasEnumType(Result),aContext);
end;
'SetType':
begin
Result:=CreateElement(TPasSetType,Name,Parent);
ReadSetType(Obj,TPasSetType(Result),aContext);
end;
'RecVariant':
begin
Result:=CreateElement(TPasVariant,Name,Parent);
ReadRecordVariant(Obj,TPasVariant(Result),aContext);
end;
'Record':
begin
Result:=CreateElement(TPasRecordType,Name,Parent);
ReadRecordType(Obj,TPasRecordType(Result),aContext);
end;
'Object': CreateClassType(okObject,Name);
'Class': CreateClassType(okClass,Name);
'Interface': CreateClassType(okInterface,Name);
'ClassHelper': CreateClassType(okClassHelper,Name);
'RecordHelper': CreateClassType(okRecordHelper,Name);
'TypeHelper': CreateClassType(okTypeHelper,Name);
'DispInterface': CreateClassType(okDispInterface,Name);
'Arg':
begin
Result:=CreateElement(TPasArgument,Name,Parent);
ReadArgument(Obj,TPasArgument(Result),aContext);
end;
'ProcType':
begin
Result:=CreateElement(TPasProcedureType,Name,Parent);
ReadProcedureType(Obj,TPasProcedureType(Result),aContext);
end;
'Result':
begin
Result:=CreateElement(TPasResultElement,Name,Parent);
ReadResultElement(Obj,TPasResultElement(Result),aContext);
end;
'FuncType':
begin
Result:=CreateElement(TPasFunctionType,Name,Parent);
ReadFunctionType(Obj,TPasFunctionType(Result),aContext);
end;
'StringType':
begin
Result:=CreateElement(TPasStringType,Name,Parent);
ReadStringType(Obj,TPasStringType(Result),aContext);
end;
'Var':
begin
Result:=CreateElement(TPasVariable,Name,Parent);
ReadVariable(Obj,TPasVariable(Result),aContext);
end;
'Export':
begin
Result:=CreateElement(TPasExportSymbol,Name,Parent);
ReadExportSymbol(Obj,TPasExportSymbol(Result),aContext);
end;
'Const':
begin
Result:=CreateElement(TPasConst,Name,Parent);
ReadConst(Obj,TPasConst(Result),aContext);
end;
'Property':
begin
Result:=CreateElement(TPasProperty,Name,Parent);
ReadProperty(Obj,TPasProperty(Result),aContext);
end;
'MethodRes':
begin
Result:=CreateElement(TPasMethodResolution,Name,Parent);
ReadMethodResolution(Obj,TPasMethodResolution(Result),aContext);
end;
'Procedure': ReadProc(TPasProcedure,Name);
'ClassProcedure': ReadProc(TPasClassProcedure,Name);
'Function': ReadProc(TPasFunction,Name);
'ClassFunction': ReadProc(TPasClassFunction,Name);
'Constructor': ReadProc(TPasConstructor,Name);
'ClassConstructor': ReadProc(TPasClassConstructor,Name);
'Destructor': ReadProc(TPasDestructor,Name);
'ClassDestructor': ReadProc(TPasClassDestructor,Name);
'Operator': ReadOper(TPasConstructor,Name);
'ClassOperator': ReadOper(TPasClassConstructor,Name);
'Attributes':
begin
Result:=CreateElement(TPasAttributes,Name,Parent);
ReadAttributes(Obj,TPasAttributes(Result),aContext);
end;
else
RaiseMsg(20180210143758,Parent,'unknown type "'+LeftStr(aType,100)+'"');
end;
ok:=true;
finally
if not ok then
if Result<>nil then
begin
Result.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
Result:=nil;
end;
end;
end;
function TPCUReader.ReadElementProperty(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; BaseClass: TPTreeElement; aContext: TPCUReaderContext
): TPasElement;
var
SubObj: TJSONObject;
s: String;
begin
if not ReadObject(Obj,PropName,SubObj,Parent) then exit;
Result:=ReadElement(SubObj,Parent,aContext);
if (Result is BaseClass) then exit;
s:=GetObjName(Result);
Result.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};;
Result:=nil;
RaiseMsg(20180211105744,Parent,PropName+' is '+s);
end;
procedure TPCUReader.ReadElementReference(Obj: TJSONObject;
Instance: TPasElementBase; const PropName: string;
const Setter: TOnSetElReference);
var
Data: TJSONData;
ErrorEl: TPasElement;
Id: Integer;
begin
Data:=Obj.Find(PropName);
if Data=nil then exit;
if Instance is TPasElement then
ErrorEl:=TPasElement(Instance)
else if Instance is TResolveData then
ErrorEl:=TResolveData(Instance).Element
else
RaiseMsg(20180211120642,GetObjName(Instance)+'.'+PropName);
if Data is TJSONIntegerNumber then
begin
Id:=Data.AsInteger;
PromiseSetElReference(Id,Setter,Instance,ErrorEl);
end
else
RaiseMsg(20180211120300,ErrorEl,PropName+' is '+GetObjName(Data));
end;
procedure TPCUReader.ReadElementList(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; ListOfElements: TFPList; AddRef: TPCUAddRef;
aContext: TPCUReaderContext);
var
Arr: TJSONArray;
i, Id: Integer;
Data: TJSONData;
SubObj: TJSONObject;
SubEl: TPasElement;
begin
if not ReadArray(Obj,PropName,Arr,Parent) then exit;
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if Data is TJSONIntegerNumber then
begin
// reference
Id:=Data.AsInteger;
ListOfElements.Add(nil);
PromiseSetElListReference(Id,ListOfElements,i,AddRef,Parent);
end
else if Data is TJSONObject then
begin
SubObj:=TJSONObject(Data);
SubEl:=ReadElement(SubObj,Parent,aContext);
ListOfElements.Add(SubEl);
end
else
RaiseMsg(20180210201001,Parent,'['+IntToStr(i)+'] is '+GetObjName(Data));
end;
end;
procedure TPCUReader.ReadElementArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; var ArrOfElements: TPasElementArray;
AddRef: TPCUAddRef; aContext: TPCUReaderContext);
var
Arr: TJSONArray;
i, Id: Integer;
Data: TJSONData;
SubObj: TJSONObject;
SubEl: TPasElement;
begin
if not ReadArray(Obj,PropName,Arr,Parent) then exit;
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if Data is TJSONIntegerNumber then
begin
// reference
Id:=Data.AsInteger;
SetLength(ArrOfElements,i+1);
ArrOfElements[i]:=nil;
PromiseSetElArrReference(Id,ArrOfElements,i,AddRef,Parent);
end
else if Data is TJSONObject then
begin
SubObj:=TJSONObject(Data);
SubEl:=ReadElement(SubObj,Parent,aContext);
SetLength(ArrOfElements,i+1);
ArrOfElements[i]:=SubEl;
end
else
RaiseMsg(20180210201001,Parent,'['+IntToStr(i)+'] is '+GetObjName(Data));
end;
end;
procedure TPCUReader.ReadElType(Obj: TJSONObject; const PropName: string;
El: TPasElement; const Setter: TOnSetElReference; aContext: TPCUReaderContext
);
var
Data: TJSONData;
Id: Integer;
SubEl: TPasElement;
s: String;
begin
if aContext=nil then ;
Data:=Obj.Find(PropName);
if Data=nil then exit;
if Data is TJSONIntegerNumber then
begin
// reference
Id:=Data.AsInteger;
PromiseSetElReference(Id,Setter,El,El);
end
else if Data is TJSONObject then
begin
// anonymous type
SubEl:=ReadElement(TJSONObject(Data),El,aContext);
if not (SubEl is TPasType) then
begin
s:=GetObjName(SubEl);
if SubEl<>nil then
SubEl.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
RaiseMsg(20180210150730,El,PropName+', expected type, but got '+s);
end;
Setter(SubEl,El);
end
else
RaiseMsg(20180207185313,El,PropName+':'+GetObjName(Data));
end;
function TPCUReader.ReadResolvedRefFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TResolvedReferenceFlags
): TResolvedReferenceFlags;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TResolvedReferenceFlag;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadResolvedRefFlags START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TResolvedReferenceFlag do
if s=PCUResolvedReferenceFlagNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180215134501,'unknown resolvedreference flag "'+s+'"');
end;
end;
procedure TPCUReader.ReadResolvedReference(Obj: TJSONObject;
Ref: TResolvedReference; ErrorEl: TPasElement);
var
Found: Boolean;
s: string;
a: TResolvedRefAccess;
begin
ReadElementReference(Obj,Ref,'RefDecl',@Set_ResolvedReference_Declaration);
Ref.Flags:=ReadResolvedRefFlags(Obj,ErrorEl,'RefFlags',[]);
Ref.Access:=rraRead;
if ReadString(Obj,'RefAccess',s,ErrorEl) then
begin
Found:=false;
for a in TResolvedRefAccess do
if s=PCUResolvedRefAccessNames[a] then
begin
Ref.Access:=a;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180215134804,ErrorEl,s);
end;
if Obj.Find('RefConstructorType')<>nil then
begin
Ref.Context:=TResolvedRefCtxConstructor.Create;
ReadElementReference(Obj,Ref,'RefConstructorType',@Set_ResolvedReference_CtxConstructor);
end
else if Obj.Find('RefAttrProc')<>nil then
begin
Ref.Context:=TResolvedRefCtxAttrProc.Create;
ReadElementReference(Obj,Ref,'RefAttrProc',@Set_ResolvedReference_CtxAttrProc);
end;
end;
procedure TPCUReader.ReadPasExpr(Obj: TJSONObject; Expr: TPasExpr;
DefKind: TPasExprKind; aContext: TPCUReaderContext);
var
Kind: TPasExprKind;
s: string;
Op: TExprOpCode;
Found: Boolean;
begin
Expr.Kind:=DefKind;
if ReadString(Obj,'Kind',s,Expr) then
begin
Found:=false;
for Kind in TPasExprKind do
if s=PCUExprKindNames[Kind] then
begin
Expr.Kind:=Kind;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180208074859,Expr,s);
end;
if ReadString(Obj,'Op',s,Expr) then
begin
Found:=false;
for Op in TExprOpCode do
if s=PCUExprOpCodeNames[Op] then
begin
Expr.OpCode:=Op;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180208074950,Expr,s);
end;
Expr.format1:=ReadExpr(Obj,Expr,'format1',aContext);
Expr.format2:=ReadExpr(Obj,Expr,'format2',aContext);
ReadPasElement(Obj,Expr,aContext);
end;
procedure TPCUReader.ReadExprCustomData(Obj: TJSONObject; Expr: TPasExpr;
aContext: TPCUReaderContext);
var
Ref: TResolvedReference;
NeedEvalValue: Boolean;
Value: TResEvalValue;
begin
Ref:=TResolvedReference(Expr.CustomData);
if Obj.Find('RefDecl')<>nil then
begin
Ref:=TResolvedReference.Create;
Resolver.AddResolveData(Expr,Ref,lkModule);
ReadResolvedReference(Obj,Ref,Expr);
end;
if not ReadBoolean(Obj,'Eval',NeedEvalValue,Expr) then
NeedEvalValue:=GetDefaultExprHasEvalValue(Expr);
//writeln('TPCUReader.ReadExprCustomData ',GetElementFullPath(Expr),' ',GetObjName(Expr),' NeedEvalValue=',NeedEvalValue);
if NeedEvalValue then
begin
Value:=Resolver.Eval(Expr,[refAutoConst]);
if Value<>nil then
ReleaseEvalValue(Value);
end;
if aContext=nil then ;
end;
function TPCUReader.ReadExpr(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; aContext: TPCUReaderContext): TPasExpr;
var
Data: TJSONData;
s: string;
SubObj: TJSONObject;
El: TPasElement;
begin
Data:=Obj.Find(PropName);
if Data=nil then exit(nil);
if Data is TJSONObject then
begin
SubObj:=TJSONObject(Data);
El:=ReadElement(SubObj,Parent,aContext);
if not (El is TPasExpr) then
begin
s:=GetObjName(El);
if El<>nil then
El.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
RaiseMsg(20180210152134,Parent,PropName+' got '+s);
end;
Result:=TPasExpr(El);
ReadExprCustomData(SubObj,Result,aContext);
end
else
RaiseMsg(20180207190200,Parent,PropName+':'+GetObjName(Data));
end;
procedure TPCUReader.ReadPasExprArray(Obj: TJSONObject; Parent: TPasElement;
const PropName: string; var ExprArr: TPasExprArray;
aContext: TPCUReaderContext);
var
Arr: TJSONArray;
i: Integer;
Data: TJSONData;
SubEl: TPasElement;
SubObj: TJSONObject;
Expr: TPasExpr;
begin
if not ReadArray(Obj,PropName,Arr,Parent) then exit;
SetLength(ExprArr,Arr.Count);
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180210173026,Parent,'['+IntToStr(i)+'] is '+GetObjName(Data));
SubObj:=TJSONObject(Data);
SubEl:=ReadElement(SubObj,Parent,aContext);
if not (SubEl is TPasExpr) then
RaiseMsg(20180210173026,Parent,'['+IntToStr(i)+'] is '+GetObjName(SubEl));
Expr:=TPasExpr(SubEl);
ExprArr[i]:=Expr;
ReadExprCustomData(SubObj,Expr,aContext);
end;
end;
procedure TPCUReader.ReadPasScope(Obj: TJSONObject; Scope: TPasScope;
aContext: TPCUReaderContext);
var
Data: TJSONData;
Id: Integer;
begin
Data:=Obj.Find('VisibilityContext');
if Data=nil then
Scope.VisibilityContext:=GetDefaultPasScopeVisibilityContext(Scope)
else
begin
Id:=Data.AsInteger;
if Id=0 then
Scope.VisibilityContext:=nil
else
ReadElementReference(Obj,Scope,'VisibilityContext',@Set_PasScope_VisibilityContext);
end;
if aContext=nil then ;
end;
procedure TPCUReader.ReadScopeReferences(Obj: TJSONObject; Scope: TPasScope;
const PropName: string; var References: TPasScopeReferences);
var
Arr: TJSONArray;
i, Id: Integer;
Data: TJSONData;
SubObj: TJSONObject;
Ref: TPCUFilerElementRef;
s: string;
Found: Boolean;
Access: TPSRefAccess;
El: TPasElement;
begin
El:=Scope.Element;
if References<>nil then
RaiseMsg(20180302145101,El);
if not ReadArray(Obj,PropName,Arr,El) then exit;
References:=TPasScopeReferences.Create(Scope);
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180221164800,El,GetObjName(Data));
SubObj:=TJSONObject(Data);
Data:=SubObj.Find('Id');
if not (Data is TJSONIntegerNumber) then
RaiseMsg(20180221171546,El,GetObjName(Data));
Id:=Data.AsInteger;
Ref:=GetElReference(Id,El);
if Ref=nil then
RaiseMsg(20180221171940,El,IntToStr(Id));
if Ref.Element=nil then
RaiseMsg(20180221171940,El,IntToStr(Id));
if ReadString(SubObj,'Access',s,El) then
begin
Found:=false;
for Access in TPSRefAccess do
if s=PCUPSRefAccessNames[Access] then
begin
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180221172333,El,'Access "'+s+'"');
end
else
Access:=PCUDefaultPSRefAccess;
References.Add(Ref.Element,Access);
end;
end;
procedure TPCUReader.ReadIdentifierScopeArray(Arr: TJSONArray;
Scope: TPasIdentifierScope);
// called after reading module, i.e. all elements are created
function GetElRef(Id: integer; out DefKind: TPasIdentifierKind;
out DefName: string): TPCUFilerElementRef;
begin
Result:=GetElReference(Id,Scope.Element);
if (Result=nil) or (Result.Element=nil) then
RaiseMsg(20180207161358,Scope.Element,'Id not found: '+IntToStr(Id));
GetDefaultsPasIdentifierProps(Result.Element,DefKind,DefName);
end;
var
i, Id: Integer;
Data: TJSONData;
ItemObj: TJSONObject;
s, Name, DefName: string;
Kind, DefKind: TPasIdentifierKind;
Ref: TPCUFilerElementRef;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadIdentifierScope ',Arr.Count);
{$ENDIF}
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if Data is TJSONIntegerNumber then
begin
Id:=Data.AsInteger;
Ref:=GetElRef(Id,DefKind,DefName);
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadIdentifierScope Id=',Id,' ',DefName,' ',DefKind,' ',GetObjName(Ref.Element));
{$ENDIF}
Scope.AddIdentifier(DefName,Ref.Element,DefKind);
end
else if Data is TJSONObject then
begin
ItemObj:=TJSONObject(Data);
if not ReadInteger(ItemObj,'El',Id,Scope.Element) then
RaiseMsg(20180207162015,Scope.Element,'missing El:integer');
Ref:=GetElRef(Id,DefKind,DefName);
if ReadString(ItemObj,'Kind',s,Scope.Element) then
Kind:=StrToPasIdentifierKind(s)
else
Kind:=DefKind;
if not ReadString(ItemObj,'Name',Name,Scope.Element) then
Name:=DefName;
if Name='' then
RaiseMsg(20180207162358,Scope.Element,IntToStr(Id));
Scope.AddIdentifier(Name,Ref.Element,Kind);
end
else
RaiseMsg(20180207154839,Scope.Element,GetObjName(Data));
end;
end;
procedure TPCUReader.ReadIdentifierScope(Obj: TJSONObject;
Scope: TPasIdentifierScope; aContext: TPCUReaderContext);
var
Arr: TJSONArray;
Pending: TPCUReaderPendingIdentifierScope;
begin
if ReadArray(Obj,'SItems',Arr,Scope.Element) then
begin
Pending:=TPCUReaderPendingIdentifierScope.Create;
Pending.Scope:=Scope;
Pending.Arr:=Arr;
FPendingIdentifierScopes.Add(Pending);
end;
ReadPasScope(Obj,Scope,aContext);
end;
function TPCUReader.ReadModuleScopeFlags(Obj: TJSONObject; El: TPasElement;
const DefaultValue: TPasModuleScopeFlags): TPasModuleScopeFlags;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TPasModuleScopeFlag;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadModuleScopeFlags START');
{$ENDIF}
Data:=Obj.Find('ScopeFlags');
if Data=nil then exit;
ReadArrayFlags(Data,El,'ScopeFlags',Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TPasModuleScopeFlag do
if s=PCUModuleScopeFlagNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180206114404,'unknown ModuleScopeFlag "'+s+'"');
end;
end;
procedure TPCUReader.ReadModuleScope(Obj: TJSONObject;
Scope: TPas2JSModuleScope; aContext: TPCUReaderContext);
var
aModule: TPasModule;
begin
aModule:=Scope.Element as TPasModule;
Scope.FirstName:=FirstDottedIdentifier(aModule.Name);
Scope.Flags:=ReadModuleScopeFlags(Obj,aModule,PCUDefaultModuleScopeFlags);
Scope.BoolSwitches:=ReadBoolSwitches(Obj,aModule,'BoolSwitches',aContext.BoolSwitches);
ReadElementReference(Obj,Scope,'AssertClass',@Set_ModScope_AssertClass);
ReadElementReference(Obj,Scope,'AssertDefConstructor',@Set_ModScope_AssertDefConstructor);
ReadElementReference(Obj,Scope,'AssertMsgConstructor',@Set_ModScope_AssertMsgConstructor);
ReadElementReference(Obj,Scope,'RangeErrorClass',@Set_ModScope_RangeErrorClass);
ReadElementReference(Obj,Scope,'RangeErrorConstructor',@Set_ModScope_RangeErrorConstructor);
ReadElementReference(Obj,Scope,'SystemTVarRec',@Set_ModScope_SystemTVarRec);
ReadElementReference(Obj,Scope,'SystemVarRecs',@Set_ModScope_SystemVarRecs);
ReadPasScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadModuleHeader(Data: TJSONData);
var
Obj: TJSONObject;
aName, aType: String;
aModule: TPasModule;
ModScope: TPas2JSModuleScope;
aContext: TPCUReaderContext;
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadModuleHeader START');
{$ENDIF}
CheckJSONObject(Data,20180308140357);
Obj:=TJSONObject(Data);
aName:=String(Obj.Get('Name',''));
aType:=String(Obj.Get('Type',''));
case aType of
'Unit': aModule:=TPasModule(CreateElement(TPasModule,aName,nil));
'Program': aModule:=TPasProgram(CreateElement(TPasProgram,aName,nil));
'Library': aModule:=TPasLibrary(CreateElement(TPasLibrary,aName,nil));
else
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadModuleHeader Type="',aType,'"');
{$ENDIF}
RaiseMsg(20180203100748);
end;
Resolver.RootElement:=aModule;
aContext:=CreateContext;
try
ReadPasElement(Obj,aModule,aContext);
ModScope:=TPas2JSModuleScope(Resolver.CreateScope(aModule,Resolver.ScopeClass_Module));
ReadModuleScope(Obj,ModScope,aContext);
ReadBuiltInSymbols(Obj,aModule);
finally
aContext.Free;
end;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadModuleHeader END');
{$ENDIF}
end;
function TPCUReader.ReadModule(Obj: TJSONObject; aContext: TPCUReaderContext
): boolean;
var
aModule: TPasModule;
function CreateOrContinueSection(const PropName: string; var Section: TPasSection;
SectionClass: TPasSectionClass): boolean;
var
SubObj: TJSONObject;
begin
if not ReadObject(Obj,PropName,SubObj,aModule) then
RaiseMsg(20180308142146,aModule);
if Section=nil then
Section:=TPasSection(CreateElement(SectionClass,'',aModule));
ReadSection(SubObj,Section,aContext);
Result:=Section.PendingUsedIntf=nil;
end;
procedure ReadInitialFinal(Obj: TJSONObject; Block: TPasImplBlock;
const PropPrefix: string);
var
Scope: TPas2JSInitialFinalizationScope;
s: string;
begin
Scope:=TPas2JSInitialFinalizationScope(Resolver.CreateScope(Block,Resolver.ScopeClass_InitialFinalization));
Block.CustomData:=Scope;
if not ReadString(Obj,PropPrefix+'JS',s,Block) then exit;
Scope.JS:=s;
ReadScopeReferences(Obj,Scope,PropPrefix+'Refs',Scope.References);
end;
var
ModScope: TPas2JSModuleScope;
OldBoolSwitches: TBoolSwitches;
Prog: TPasProgram;
Lib: TPasLibrary;
OldModeSwitches: TModeSwitches;
begin
Result:=false;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadModule START ');
{$ENDIF}
aModule:=Resolver.RootElement;
ModScope:=aModule.CustomData as TPas2JSModuleScope;
OldBoolSwitches:=aContext.BoolSwitches;
aContext.BoolSwitches:=ModScope.BoolSwitches;
OldModeSwitches:=aContext.ModeSwitches;
try
// read sections
if aModule.ClassType=TPasProgram then
begin
// start or continue ProgramSection
Prog:=TPasProgram(aModule);
if not CreateOrContinueSection('Program',TPasSection(Prog.ProgramSection),
TProgramSection) then
exit; // pending uses interfaces -> pause
end
else if aModule.ClassType=TPasLibrary then
begin
// start or continue LibrarySection
Lib:=TPasLibrary(aModule);
if not CreateOrContinueSection('Library',TPasSection(Lib.LibrarySection),
TLibrarySection) then
exit; // pending uses interfaces -> pause
end
else
begin
// unit
if aModule.ImplementationSection=nil then
begin
// start or continue unit Interface
if not CreateOrContinueSection('Interface',TPasSection(aModule.InterfaceSection),
TInterfaceSection) then
exit; // pending uses interfaces -> pause
end;
// start or continue unit Implementation
if not CreateOrContinueSection('Implementation',TPasSection(aModule.ImplementationSection),
TImplementationSection) then
exit; // pending uses interfaces -> pause
end;
if Obj.Find('InitJS')<>nil then
begin
aModule.InitializationSection:=TInitializationSection(CreateElement(TInitializationSection,'',aModule));
ReadInitialFinal(Obj,aModule.InitializationSection,'Init');
end;
if Obj.Find('FinalJS')<>nil then
begin
aModule.FinalizationSection:=TFinalizationSection(CreateElement(TFinalizationSection,'',aModule));
ReadInitialFinal(Obj,aModule.FinalizationSection,'Final');
end;
finally
aContext.BoolSwitches:=OldBoolSwitches;
aContext.ModeSwitches:=OldModeSwitches;
end;
ResolvePending;
Result:=true;
end;
procedure TPCUReader.ReadUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr;
aContext: TPCUReaderContext);
begin
Expr.OpCode:=eopAdd;
Expr.Kind:=pekUnary;
ReadPasExpr(Obj,Expr,pekUnary,aContext);
Expr.Operand:=ReadExpr(Obj,Expr,'Operand',aContext);
end;
procedure TPCUReader.ReadBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr;
aContext: TPCUReaderContext);
begin
ReadPasExpr(Obj,Expr,pekBinary,aContext);
Expr.left:=ReadExpr(Obj,Expr,'Left',aContext);
Expr.right:=ReadExpr(Obj,Expr,'Right',aContext);
end;
procedure TPCUReader.ReadBoolConstExpr(Obj: TJSONObject; Expr: TBoolConstExpr;
aContext: TPCUReaderContext);
begin
ReadPasExpr(Obj,Expr,pekBoolConst,aContext);
ReadBoolean(Obj,'Value',Expr.Value,Expr);
end;
procedure TPCUReader.ReadParamsExpr(Obj: TJSONObject; Expr: TParamsExpr;
aContext: TPCUReaderContext);
begin
ReadPasExpr(Obj,Expr,Expr.Kind,aContext);
Expr.Value:=ReadExpr(Obj,Expr,'Value',aContext);
ReadPasExprArray(Obj,Expr,'Params',Expr.Params,aContext);
end;
procedure TPCUReader.ReadRecordValues(Obj: TJSONObject; Expr: TRecordValues;
aContext: TPCUReaderContext);
var
Arr: TJSONArray;
i: Integer;
Data: TJSONData;
SubObj: TJSONObject;
SubEl: TPasElement;
aName: string;
begin
ReadPasExpr(Obj,Expr,pekListOfExp,aContext);
if ReadArray(Obj,'Fields',Arr,Expr) then
begin
SetLength(Expr.Fields,Arr.Count);
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180210173636,Expr,'['+IntToStr(i)+'] is '+GetObjName(Data));
SubObj:=TJSONObject(Data);
if ReadString(SubObj,'Name',aName,Expr) then
Expr.Fields[i].Name:=aName;
SubEl:=ReadElement(TJSONObject(Data),Expr,aContext);
if not (SubEl is TPasExpr) then
RaiseMsg(20180210174041,Expr,'['+IntToStr(i)+'] is '+GetObjName(SubEl));
Expr.Fields[i].ValueExp:=TPasExpr(SubEl);
end;
end;
end;
procedure TPCUReader.ReadArrayValues(Obj: TJSONObject; Expr: TArrayValues;
aContext: TPCUReaderContext);
begin
ReadPasExpr(Obj,Expr,pekListOfExp,aContext);
ReadPasExprArray(Obj,Expr,'Values',Expr.Values,aContext);
end;
procedure TPCUReader.ReadResString(Obj: TJSONObject; El: TPasResString;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
El.Expr:=ReadExpr(Obj,El,'Expr',aContext);
end;
procedure TPCUReader.ReadGenericTemplateTypes(Obj: TJSONObject;
Parent: TPasElement; var GenericTemplateTypes: TFPList;
aContext: TPCUReaderContext);
var
TemplArr: TJSONArray;
i: Integer;
TemplObj: TJSONObject;
GenTypeName: string;
GenType: TPasGenericTemplateType;
begin
if not ReadArray(Obj,'GenericTemplateTypes',TemplArr,Parent) then exit;
if GenericTemplateTypes=nil then
GenericTemplateTypes:=TFPList.Create;
for i:=0 to TemplArr.Count-1 do
begin
TemplObj:=CheckJSONObject(TemplArr[i],20190720224105);
if not ReadString(TemplObj,'Name',GenTypeName,Parent) or (GenTypeName='') then
RaiseMsg(20190720224130,Parent,IntToStr(i));
GenType:=TPasGenericTemplateType(CreateElement(TPasGenericTemplateType,GenTypeName,Parent));
GenericTemplateTypes.Add(GenType);
ReadElementArray(TemplObj,Parent,'Constraints',GenType.Constraints,
{$IFDEF CheckPasTreeRefCount}'TPasGenericTemplateType.Constraints'{$ELSE}true{$ENDIF},
aContext);
end;
end;
procedure TPCUReader.ReadAliasType(Obj: TJSONObject; El: TPasAliasType;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElType(Obj,'Dest',El,@Set_AliasType_DestType,aContext);
El.Expr:=ReadExpr(Obj,El,'Expr',aContext);
end;
procedure TPCUReader.ReadPointerType(Obj: TJSONObject; El: TPasPointerType;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElType(Obj,'Dest',El,@Set_PointerType_DestType,aContext);
end;
procedure TPCUReader.ReadSpecializeType(Obj: TJSONObject;
El: TPasSpecializeType; aContext: TPCUReaderContext);
begin
ReadAliasType(Obj,El,aContext);
ReadElementList(Obj,El,'Params',El.Params,
{$IFDEF CheckPasTreeRefCount}'TPasSpecializeType.Params'{$ELSE}true{$ENDIF},
aContext);
end;
procedure TPCUReader.ReadInlineSpecializeExpr(Obj: TJSONObject;
Expr: TInlineSpecializeExpr; aContext: TPCUReaderContext);
begin
Expr.Kind:=pekSpecialize;
Expr.NameExpr:=ReadExpr(Obj,Expr,'Name',aContext);
ReadElementList(Obj,Expr,'Params',Expr.Params,
{$IFDEF CheckPasTreeRefCount}'TInlineSpecializeExpr.Params'{$ELSE}true{$ENDIF},
aContext);
end;
procedure TPCUReader.ReadRangeType(Obj: TJSONObject; El: TPasRangeType;
aContext: TPCUReaderContext);
var
Expr: TPasExpr;
s: String;
begin
ReadPasElement(Obj,El,aContext);
Expr:=ReadExpr(Obj,El,'Range',aContext);
if not (Expr is TBinaryExpr) then
begin
s:=GetObjName(Expr);
if Expr<>nil then
Expr.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
RaiseMsg(20180216204042,El,s);
end;
El.RangeExpr:=TBinaryExpr(Expr);
end;
procedure TPCUReader.ReadArrayType(Obj: TJSONObject; El: TPasArrayType;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
ReadPasExprArray(Obj,El,'Ranges',El.Ranges,aContext);
if El.PackMode<>pmNone then
Obj.Add('Packed',PCUPackModeNames[El.PackMode]);
ReadElType(Obj,'ElType',El,@Set_ArrayType_ElType,aContext);
end;
procedure TPCUReader.ReadFileType(Obj: TJSONObject; El: TPasFileType;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElType(Obj,'ElType',El,@Set_FileType_ElType,aContext);
end;
procedure TPCUReader.ReadEnumValue(Obj: TJSONObject; El: TPasEnumValue;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
El.Value:=ReadExpr(Obj,El,'Value',aContext);
end;
procedure TPCUReader.ReadEnumTypeScope(Obj: TJSONObject;
Scope: TPasEnumTypeScope; aContext: TPCUReaderContext);
begin
ReadElType(Obj,'CanonicalSet',Scope.Element,@Set_EnumTypeScope_CanonicalSet,aContext);
ReadIdentifierScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadEnumType(Obj: TJSONObject; El: TPasEnumType;
aContext: TPCUReaderContext);
var
Scope: TPasEnumTypeScope;
begin
Scope:=TPasEnumTypeScope(Resolver.CreateScope(El,TPasEnumTypeScope));
El.CustomData:=Scope;
ReadPasElement(Obj,El,aContext);
ReadEnumTypeScope(Obj,Scope,aContext);
ReadElementList(Obj,El,'Values',El.Values,
{$IFDEF CheckPasTreeRefCount}'TPasEnumType.Values'{$ELSE}true{$ENDIF},
aContext);
end;
procedure TPCUReader.ReadSetType(Obj: TJSONObject; El: TPasSetType;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElType(Obj,'EnumType',El,@Set_SetType_EnumType,aContext);
ReadBoolean(Obj,'Packed',El.IsPacked,El);
end;
function TPCUReader.ReadPackedMode(Obj: TJSONObject; const PropName: string;
ErrorEl: TPasElement): TPackMode;
var
p: TPackMode;
s: string;
begin
Result:=pmNone;
if not ReadString(Obj,PropName,s,ErrorEl) then exit;
for p in TPackMode do
if s=PCUPackModeNames[p] then
exit(p);
RaiseMsg(20180210210038,ErrorEl,PropName+' "'+s+'"');
end;
procedure TPCUReader.ReadRecordVariant(Obj: TJSONObject; El: TPasVariant;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElementList(Obj,El,'Values',El.Values,
{$IFDEF CheckPasTreeRefCount}'TPasVariant.Values'{$ELSE}true{$ENDIF},
aContext);
ReadElType(Obj,'Members',El,@Set_Variant_Members,aContext);
end;
procedure TPCUReader.ReadRecordScope(Obj: TJSONObject; Scope: TPasRecordScope;
aContext: TPCUReaderContext);
begin
ReadElementReference(Obj,Scope,'DefaultProperty',@Set_RecordScope_DefaultProperty);
ReadIdentifierScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadRecordType(Obj: TJSONObject; El: TPasRecordType;
aContext: TPCUReaderContext);
var
Data: TJSONData;
Id: Integer;
Scope: TPasRecordScope;
begin
if FileVersion<3 then
RaiseMsg(20190109214718,El,'record format changed');
Scope:=TPasRecordScope(Resolver.CreateScope(El,TPasRecordScope));
El.CustomData:=Scope;
ReadPasElement(Obj,El,aContext);
ReadGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
El.PackMode:=ReadPackedMode(Obj,'Packed',El);
ReadElementList(Obj,El,'Members',El.Members,
{$IFDEF CheckPasTreeRefCount}'TPasRecordType.Members'{$ELSE}true{$ENDIF},
aContext);
// VariantEl: TPasElement can be TPasVariable or TPasType
Data:=Obj.Find('VariantEl');
if Data is TJSONIntegerNumber then
begin
Id:=Data.AsInteger;
PromiseSetElReference(Id,@Set_RecordType_VariantEl,El,El);
end
else if Data is TJSONObject then
El.VariantEl:=ReadElement(TJSONObject(Data),El,aContext);
ReadElementList(Obj,El,'Variants',El.Variants,
{$IFDEF CheckPasTreeRefCount}'TPasRecordType.Variants'{$ELSE}true{$ENDIF},
aContext);
ReadRecordScope(Obj,Scope,aContext);
end;
function TPCUReader.ReadClassInterfaceType(Obj: TJSONObject;
const PropName: string; ErrorEl: TPasElement;
DefaultValue: TPasClassInterfaceType): TPasClassInterfaceType;
var
s: string;
cit: TPasClassInterfaceType;
begin
if ReadString(Obj,PropName,s,ErrorEl) then
begin
for cit in TPasClassInterfaceType do
if s=PCUClassInterfaceTypeNames[cit] then
exit(cit);
RaiseMsg(20180329105126,ErrorEl,PropName+'='+s);
end
else
Result:=DefaultValue;
end;
function TPCUReader.ReadClassScopeFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TPasClassScopeFlags
): TPasClassScopeFlags;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TPasClassScopeFlag;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadClassScopeFlags START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TPasClassScopeFlag do
if s=PCUClassScopeFlagNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180214115647,'unknown class scope flag "'+s+'"');
end;
end;
procedure TPCUReader.ReadClassScopeAbstractProcs(Obj: TJSONObject;
Scope: TPas2JSClassScope);
var
Arr: TJSONArray;
Data: TJSONData;
Id, i: Integer;
Ref: TPCUFilerElementRef;
begin
if not ReadArray(Obj,'AbstractProcs',Arr,Scope.Element) then exit;
SetLength(Scope.AbstractProcs,Arr.Count);
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if Data is TJSONIntegerNumber then
begin
Id:=Data.AsInteger;
Ref:=GetElReference(Id,Scope.Element);
if (Ref=nil) or (Ref.Element=nil) then
RaiseMsg(20180214121727,Scope.Element,'['+IntToStr(i)+'] missing Id '+IntToStr(Id));
if Ref.Element is TPasProcedure then
Scope.AbstractProcs[i]:=TPasProcedure(Ref.Element) // no AddRef
else
RaiseMsg(20180214121902,Scope.Element,'['+IntToStr(i)+'] is '+GetObjName(Ref.Element));
end
else
RaiseMsg(20180214121627,Scope.Element,'['+IntToStr(i)+'] is '+GetObjName(Data));
end;
end;
procedure TPCUReader.ReadClassIntfMapProcs(Obj: TJSONObject;
Map: TPasClassIntfMap; OrigIntfType: TPasType);
var
aClass: TPasClassType;
Arr: TJSONArray;
i, Id: Integer;
Data: TJSONData;
IntfMember: TPasElement;
Ref: TPCUFilerElementRef;
begin
aClass:=Map.Element as TPasClassType;
if ReadArray(Obj,'Procs',Arr,aClass) then
begin
if Map.Procs<>nil then
RaiseMsg(20180329143122,aClass);
Map.Procs:=TFPList.Create;
if Arr.Count<>Map.Intf.Members.Count then
RaiseMsg(20180325130318,aClass,Map.Intf.FullPath+' Expected='+IntToStr(Map.Intf.Members.Count)+', but found '+IntToStr(Arr.Count));
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
IntfMember:=TPasElement(Map.Intf.Members[i]);
if (Data is TJSONIntegerNumber) then
begin
Id:=Data.AsInteger;
Ref:=AddElReference(Id,aClass,nil);
if Ref.Element=nil then
RaiseMsg(20180325125930,aClass,'missing method resolution of interface '+OrigIntfType.Name);
if not (Ref.Element is TPasProcedure) then
RaiseMsg(20180325130108,aClass,'['+IntToStr(i)+']='+OrigIntfType.Name+'.'+GetObjName(IntfMember)+' method expected, but found '+GetObjName(Ref.Element));
if not (IntfMember is TPasProcedure) then
RaiseMsg(20180329134354,aClass,'['+IntToStr(i)+']='+OrigIntfType.Name+'.'+GetObjName(IntfMember)+' intf member is not method, mapped proc='+GetObjName(Ref.Element));
Map.Procs.Add(Ref.Element);
end
else if Data is TJSONNull then
begin
if IntfMember is TPasProcedure then
RaiseMsg(20180329132957,aClass,'['+IntToStr(i)+']='+OrigIntfType.Name+'.'+GetObjName(IntfMember)+' intf method expects implementation');
Map.Procs.Add(nil);
end
else
RaiseMsg(20180325125851,aClass,IntToStr(i)+' '+GetObjName(Data));
end;
end
else if Map.Intf.Members.Count>0 then
RaiseMsg(20180325130720,aClass,Map.Intf.FullPath+' Expected='+IntToStr(Map.Intf.Members.Count)+', but found 0');
end;
procedure TPCUReader.ReadClassIntfMap(Obj: TJSONObject; Scope: TPas2JSClassScope;
Map: TPasClassIntfMap; OrigIntfType: TPasType);
var
aClass: TPasClassType;
Id: Integer;
Data: TJSONData;
Ref: TPCUFilerElementRef;
AncObj: TJSONObject;
begin
aClass:=Scope.Element as TPasClassType;
Map.Element:=aClass;
// Intf
Data:=Obj.Find('Intf');
if not (Data is TJSONIntegerNumber) then
RaiseMsg(20180325130226,aClass,OrigIntfType.Name);
Id:=Data.AsInteger;
Ref:=AddElReference(Id,aClass,nil);
if not (Ref.Element is TPasClassType) then
RaiseMsg(20180325131020,aClass,OrigIntfType.Name+' '+GetObjName(Ref.Element));
Map.Intf:=TPasClassType(Ref.Element);
// Procs
ReadClassIntfMapProcs(Obj,Map,OrigIntfType);
// AncestorMap
if ReadObject(Obj,'AncestorMap',AncObj,aClass) then
begin
Map.AncestorMap:=TPasClassIntfMap.Create;
ReadClassIntfMap(AncObj,Scope,Map.AncestorMap,OrigIntfType);
end;
end;
procedure TPCUReader.ReadClassScopeInterfaces(Obj: TJSONObject;
Scope: TPas2JSClassScope);
var
aClass: TPasClassType;
Arr: TJSONArray;
i, Id: Integer;
Data: TJSONData;
Ref: TPCUFilerElementRef;
OrigIntfType, IntfType: TPasType;
SubObj: TJSONObject;
Map: TPasClassIntfMap;
begin
aClass:=Scope.Element as TPasClassType;
if ReadArray(Obj,'SInterfaces',Arr,aClass) then
begin
if Arr.Count<>aClass.Interfaces.Count then
RaiseMsg(20180325124134,aClass);
if Scope.Interfaces=nil then
Scope.Interfaces:=TFPList.Create;
if Scope.Interfaces.Count>0 then
RaiseMsg(20180325124546,aClass);
for i:=0 to Arr.Count-1 do
begin
OrigIntfType:=TPasType(aClass.Interfaces[i]);
IntfType:=Resolver.ResolveAliasType(OrigIntfType);
if not (IntfType is TPasClassType) then
RaiseMsg(20180325124401,aClass,IntToStr(i)+' '+GetObjName(IntfType));
Data:=Arr[i];
if Data is TJSONIntegerNumber then
begin
// property, interface delegation
Id:=Data.AsInteger;
Ref:=AddElReference(Id,aClass,nil);
if Ref.Element=nil then
RaiseMsg(20180325124421,aClass,'missing delegation property of interface '+OrigIntfType.Name);
if not (Ref.Element is TPasProperty) then
RaiseMsg(20180325124616,aClass,OrigIntfType.Name+' delegate: '+GetObjName(Ref.Element));
Scope.Interfaces.Add(Ref.Element);
end
else if Data is TJSONObject then
begin
// map
SubObj:=TJSONObject(Data);
Map:=TPasClassIntfMap.Create;
Scope.Interfaces.Add(Map);
ReadClassIntfMap(SubObj,Scope,Map,OrigIntfType);
end
else
RaiseMsg(20180325124206,aClass,OrigIntfType.Name);
end;
end
else if aClass.Interfaces.Count>0 then
begin
RaiseMsg(20180325131248,aClass);
end;
end;
procedure TPCUReader.ReadClassScopeDispatchProcs(Obj: TJSONObject;
Scope: TPas2JSClassScope);
var
El: TPasClassType;
begin
El:=TPasClassType(Scope.Element);
ReadString(Obj,'DispatchField',Scope.DispatchField,El);
ReadString(Obj,'DispatchStrField',Scope.DispatchStrField,El);
end;
procedure TPCUReader.ReadClassScope(Obj: TJSONObject; Scope: TPas2JSClassScope;
aContext: TPCUReaderContext);
var
aClass: TPasClassType;
CanonicalClassOf: TPasClassOfType;
CanonicalClassOfId: integer;
begin
aClass:=Scope.Element as TPasClassType;
if aClass.ObjKind in ([okClass]+okAllHelpers) then
begin
CanonicalClassOf:=TPasClassOfType(CreateElement(TPasClassOfType,'Self',aClass));
Scope.CanonicalClassOf:=CanonicalClassOf;
CanonicalClassOf.Visibility:=visStrictPrivate;
CanonicalClassOf.SourceFilename:=aClass.SourceFilename;
CanonicalClassOf.SourceLinenumber:=aClass.SourceLinenumber;
CanonicalClassOf.DestType:=aClass;
aClass.AddRef{$IFDEF CheckPasTreeRefCount}('TPasClassScope.CanonicalClassOf'){$ENDIF};
if ReadInteger(Obj,'ClassOf',CanonicalClassOfId,CanonicalClassOf) then
AddElReference(CanonicalClassOfId,CanonicalClassOf,CanonicalClassOf);
end;
ReadElementReference(Obj,Scope,'NewInstanceFunction',@Set_ClassScope_NewInstanceFunction);
ReadElementReference(Obj,Scope,'DirectAncestor',@Set_ClassScope_DirectAncestor);
ReadElementReference(Obj,Scope,'DefaultProperty',@Set_ClassScope_DefaultProperty);
Scope.Flags:=ReadClassScopeFlags(Obj,Scope.Element,'SFlags',GetDefaultClassScopeFlags(Scope));
if not ReadString(Obj,'SGUID',Scope.GUID,aClass) then
Scope.GUID:='';
ReadIdentifierScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadClassType(Obj: TJSONObject; El: TPasClassType;
aContext: TPCUReaderContext);
var
Arr: TJSONArray;
i: Integer;
Data: TJSONData;
Scope: TPas2JSClassScope;
Ref: TResolvedReference;
Parent: TPasElement;
SectionScope: TPasSectionScope;
begin
ReadBoolean(Obj,'Forward',El.IsForward,El);
if El.IsForward then
begin
Scope:=nil;
Ref:=TResolvedReference.Create;
Resolver.AddResolveData(El,Ref,lkModule);
ReadResolvedReference(Obj,Ref,El);
end
else
begin
if Obj.Find('Scope') is TJSONBoolean then
Scope:=nil // msIgnoreInterfaces
else
begin
Scope:=TPas2JSClassScope(Resolver.CreateScope(El,Resolver.ScopeClass_Class));
El.CustomData:=Scope;
end;
end;
ReadPasElement(Obj,El,aContext);
ReadGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
El.PackMode:=ReadPackedMode(Obj,'Packed',El);
// ObjKind is the 'Type'
El.InterfaceType:=ReadClassInterfaceType(Obj,'IntfType',El,citCom);
ReadElType(Obj,'Ancestor',El,@Set_ClassType_AncestorType,aContext);
ReadElType(Obj,'HelperFor',El,@Set_ClassType_HelperForType,aContext);
ReadBoolean(Obj,'External',El.IsExternal,El);
// not needed IsShortDefinition: Boolean; -> class(anchestor); without end
El.GUIDExpr:=ReadExpr(Obj,El,'GUID',aContext);
// Modifiers
if ReadArray(Obj,'Modifiers',Arr,El) then
begin
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONString) then
RaiseMsg(20180210211250,El,'Modifiers['+IntToStr(i)+'] '+GetObjName(Data));
El.Modifiers.Add(String(Data.AsString));
end;
end;
ReadElementList(Obj,El,'Interfaces',El.Interfaces,
{$IFDEF CheckPasTreeRefCount}'TPasClassType.Interfaces'{$ELSE}true{$ENDIF},
aContext);
ReadString(Obj,'ExternalNameSpace',El.ExternalNameSpace,El);
ReadString(Obj,'ExternalName',El.ExternalName,El);
if Scope<>nil then
ReadClassScope(Obj,Scope,aContext);
// read Members
ReadElementList(Obj,El,'Members',El.Members,
{$IFDEF CheckPasTreeRefCount}'TPasClassType.Members'{$ELSE}true{$ENDIF},
aContext);
if Scope<>nil then
begin
ReadClassScopeAbstractProcs(Obj,Scope);
ReadClassScopeInterfaces(Obj,Scope);
ReadClassScopeDispatchProcs(Obj,Scope);
if El.ObjKind in okAllHelpers then
begin
// restore cached helpers in interface
Parent:=El.Parent;
while Parent<>nil do
begin
if Parent.ClassType=TInterfaceSection then
begin
SectionScope:=Parent.CustomData as TPasSectionScope;
Resolver.AddHelper(El,SectionScope.Helpers);
break;
end;
Parent:=Parent.Parent;
end;
end;
end;
end;
procedure TPCUReader.ReadArgument(Obj: TJSONObject; El: TPasArgument;
aContext: TPCUReaderContext);
var
s: string;
Found: Boolean;
Arg: TArgumentAccess;
begin
ReadPasElement(Obj,El,aContext);
if ReadString(Obj,'Access',s,El) then
begin
Found:=false;
for Arg in TArgumentAccess do
if s=PCUArgumentAccessNames[Arg] then
begin
El.Access:=Arg;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180210205544,El,'Access "'+s+'"');
end;
ReadElType(Obj,'ArgType',El,@Set_Argument_ArgType,aContext);
El.ValueExpr:=ReadExpr(Obj,El,'Value',aContext);
end;
function TPCUReader.ReadProcTypeModifiers(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TProcTypeModifiers
): TProcTypeModifiers;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TProcTypeModifier;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadProcTypeModifiers START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TProcTypeModifier do
if s=PCUProcTypeModifierNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180210212015,'unknown procedure modifier "'+s+'"');
end;
end;
procedure TPCUReader.ReadProcedureType(Obj: TJSONObject; El: TPasProcedureType;
aContext: TPCUReaderContext);
var
s: string;
Found: Boolean;
c: TCallingConvention;
begin
ReadPasElement(Obj,El,aContext);
ReadGenericTemplateTypes(Obj,El,El.GenericTemplateTypes,aContext);
ReadElementList(Obj,El,'Args',El.Args,
{$IFDEF CheckPasTreeRefCount}'TPasProcedureType.Args'{$ELSE}true{$ENDIF},
aContext);
if ReadString(Obj,'Call',s,El) then
begin
Found:=false;
for c in TCallingConvention do
if s=PCUCallingConventionNames[c] then
begin
El.CallingConvention:=c;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180210212130,El,'Call "'+s+'"');
end;
El.Modifiers:=ReadProcTypeModifiers(Obj,El,'Modifiers',GetDefaultProcTypeModifiers(El));
end;
procedure TPCUReader.ReadResultElement(Obj: TJSONObject; El: TPasResultElement;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElType(Obj,'Result',El,@Set_ResultElement_ResultType,aContext);
end;
procedure TPCUReader.ReadFunctionType(Obj: TJSONObject; El: TPasFunctionType;
aContext: TPCUReaderContext);
begin
ReadProcedureType(Obj,El,aContext);
El.ResultEl:=TPasResultElement(ReadElementProperty(Obj,El,'Result',TPasResultElement,aContext));
end;
procedure TPCUReader.ReadStringType(Obj: TJSONObject; El: TPasStringType;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadString(Obj,'Length',El.LengthExpr,El);
end;
function TPCUReader.ReadVarModifiers(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TVariableModifiers
): TVariableModifiers;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TVariableModifier;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadVarModifiers START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TVariableModifier do
if s=PCUVarModifierNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180207184723,'unknown var modifier "'+s+'"');
end;
end;
procedure TPCUReader.ReadVariable(Obj: TJSONObject; El: TPasVariable;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadElType(Obj,'VarType',El,@Set_Variable_VarType,aContext);
El.VarModifiers:=ReadVarModifiers(Obj,El,'VarMods',[]);
El.LibraryName:=ReadExpr(Obj,El,'Library',aContext);
El.ExportName:=ReadExpr(Obj,El,'Export',aContext);
El.AbsoluteExpr:=ReadExpr(Obj,El,'Absolute',aContext);
El.Expr:=ReadExpr(Obj,El,'Expr',aContext);
end;
procedure TPCUReader.ReadExportSymbol(Obj: TJSONObject; El: TPasExportSymbol;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
El.ExportName:=ReadExpr(Obj,El,'ExportName',aContext);
El.ExportIndex:=ReadExpr(Obj,El,'ExportIndex',aContext);
end;
procedure TPCUReader.ReadConst(Obj: TJSONObject; El: TPasConst;
aContext: TPCUReaderContext);
begin
ReadVariable(Obj,El,aContext);
if not ReadBoolean(Obj,'IsConst',El.IsConst,El) then
El.IsConst:=Obj.Find('VarType')=nil;
end;
procedure TPCUReader.ReadPropertyScope(Obj: TJSONObject;
Scope: TPasPropertyScope; aContext: TPCUReaderContext);
begin
ReadElementReference(Obj,Scope,'AncestorProp',@Set_PropertyScope_AncestorProp);
ReadIdentifierScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadProperty(Obj: TJSONObject; El: TPasProperty;
aContext: TPCUReaderContext);
var
Scope: TPasPropertyScope;
Expr: TPasExpr;
begin
if Obj.Find('Scope') is TJSONBoolean then
Scope:=nil // msIgnoreInterfaces
else
begin
Scope:=TPasPropertyScope(Resolver.CreateScope(El,TPasPropertyScope));
El.CustomData:=Scope;
end;
ReadVariable(Obj,El,aContext);
El.IndexExpr:=ReadExpr(Obj,El,'Index',aContext);
El.ReadAccessor:=ReadExpr(Obj,El,'Read',aContext);
El.WriteAccessor:=ReadExpr(Obj,El,'Write',aContext);
if FileVersion<2 then
begin
if Obj.Find('Implements')<>nil then
begin
Expr:=ReadExpr(Obj,El,'Implements',aContext);
SetLength(El.Implements,1);
El.Implements[0]:=Expr;
end;
end
else
ReadPasExprArray(Obj,El,'Implements',El.Implements,aContext);
El.DispIDExpr:=ReadExpr(Obj,El,'DispId',aContext);
El.StoredAccessor:=ReadExpr(Obj,El,'Stored',aContext);
El.DefaultExpr:=ReadExpr(Obj,El,'DefaultValue',aContext);
ReadElementList(Obj,El,'Args',El.Args,
{$IFDEF CheckPasTreeRefCount}'TPasProperty.Args'{$ELSE}true{$ENDIF},
aContext);
//ReadAccessorName: string; // not used by resolver
//WriteAccessorName: string; // not used by resolver
//ImplementsName: string; // not used by resolver
//StoredAccessorName: string; // not used by resolver
ReadBoolean(Obj,'ReadOnly',El.DispIDReadOnly,El);
ReadBoolean(Obj,'Default',El.IsDefault,El);
ReadBoolean(Obj,'NoDefault',El.IsNodefault,El);
if Scope<>nil then
ReadPropertyScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadMethodResolution(Obj: TJSONObject;
El: TPasMethodResolution; aContext: TPCUReaderContext);
var
s: string;
begin
ReadPasElement(Obj,El,aContext);
if ReadString(Obj,'ProcClass',s,El) then
case s of
'procedure': El.ProcClass:=TPasProcedure;
else
RaiseMsg(20180329104616,El,s);
end
else
El.ProcClass:=TPasFunction;
El.InterfaceProc:=ReadExpr(Obj,El,'InterfaceProc',aContext);
El.InterfaceName:=ReadExpr(Obj,El,'InterfaceName',aContext);
El.ImplementationProc:=ReadExpr(Obj,El,'ImplementationProc',aContext);
end;
procedure TPCUReader.ReadProcedureNameParts(Obj: TJSONObject;
El: TPasProcedure; aContext: TPCUReaderContext);
var
Arr, TemplArr: TJSONArray;
i, j: Integer;
NamePartObj, TemplObj: TJSONObject;
GenTypeName: string;
GenType: TPasGenericTemplateType;
NamePart: TProcedureNamePart;
begin
ReleaseProcNameParts(El.NameParts);
if ReadArray(Obj,'NameParts',Arr,El) then
begin
if El.NameParts=nil then
El.NameParts:=TProcedureNameParts.Create
else
El.NameParts.Clear;
for i:=0 to Arr.Count-1 do
begin
NamePartObj:=CheckJSONObject(Arr[i],20190718113441);
NamePart:=TProcedureNamePart.Create;
El.NameParts.Add(NamePart);
with NamePart do
begin
if not ReadString(NamePartObj,'Name',Name,El) then
RaiseMsg(20190718113739,El,IntToStr(i));
if not ReadArray(NamePartObj,'Templates',TemplArr,El) then
continue; // Templates=nil
Templates:=TFPList.Create;
for j:=0 to TemplArr.Count-1 do
begin
TemplObj:=CheckJSONObject(TemplArr[j],20190718114058);
if not ReadString(TemplObj,'Name',GenTypeName,El) or (GenTypeName='') then
RaiseMsg(20190718114244,El,IntToStr(i)+','+IntToStr(j));
GenType:=TPasGenericTemplateType(CreateElement(TPasGenericTemplateType,GenTypeName,El));
Templates.Add(GenType);
ReadElementArray(TemplObj,El,'Constraints',GenType.Constraints,
{$IFDEF CheckPasTreeRefCount}'TPasGenericTemplateType.Constraints'{$ELSE}true{$ENDIF},
aContext);
end;
end;
end;
end;
if aContext=nil then ;
end;
function TPCUReader.ReadProcedureModifiers(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TProcedureModifiers
): TProcedureModifiers;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TProcedureModifier;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadProcedureModifiers START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TProcedureModifier do
if s=PCUProcedureModifierNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180211110407,'unknown proc modifier "'+s+'"');
end;
end;
function TPCUReader.ReadProcScopeFlags(Obj: TJSONObject; El: TPasElement;
const PropName: string; const DefaultValue: TPasProcedureScopeFlags
): TPasProcedureScopeFlags;
var
Names: TStringDynArray;
Enable: TBooleanDynArray;
s: String;
f: TPasProcedureScopeFlag;
i: Integer;
Found: Boolean;
Data: TJSONData;
begin
Result:=DefaultValue;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadProcedureScopeFlags START');
{$ENDIF}
Data:=Obj.Find(PropName);
if Data=nil then exit;
ReadArrayFlags(Data,El,PropName,Names,Enable);
for i:=0 to length(Names)-1 do
begin
s:=Names[i];
Found:=false;
for f in TPasProcedureScopeFlag do
if s=PCUProcedureScopeFlagNames[f] then
begin
if Enable[i] then
Include(Result,f)
else
Exclude(Result,f);
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180213220601,'unknown proc scope flag "'+s+'"');
end;
end;
procedure TPCUReader.ReadProcedureScope(Obj: TJSONObject;
Scope: TPas2JSProcedureScope; aContext: TPCUReaderContext);
var
Proc: TPasProcedure;
begin
Proc:=Scope.Element as TPasProcedure;
ReadString(Obj,'ResultVarName',Scope.ResultVarName,Proc);
// Scope.OverloadName is already set in ReadProcedure
ReadElementReference(Obj,Scope,'ImplProc',@Set_ProcedureScope_ImplProc);
ReadElementReference(Obj,Scope,'Overridden',@Set_ProcedureScope_Overridden);
if Proc.Parent is TPasMembersType then
Scope.ClassRecScope:=Proc.Parent.CustomData as TPasClassOrRecordScope // no AddRef
else
; // set via Set_ProcedureScope_ImplProc
// Scope.SelfArg only valid for method implementation
Scope.Flags:=ReadProcScopeFlags(Obj,Proc,'SFlags',[]);
Scope.BoolSwitches:=ReadBoolSwitches(Obj,Proc,'BoolSwitches',aContext.BoolSwitches);
Scope.ModeSwitches:=ReadModeSwitches(Obj,Proc,'ModeSwitches',aContext.ModeSwitches);
//ReadIdentifierScope(Obj,Scope,aContext);
end;
procedure TPCUReader.ReadProcScopeReferences(Obj: TJSONObject;
ImplScope: TPas2JSProcedureScope);
var
DeclScope: TPasProcedureScope;
DeclProc: TPasProcedure;
begin
// Note: the References are stored in the scope object of the declaration proc,
// But TPCUWriter stores them in the implementation scope, so that all
// references can be resolved immediately.
if ImplScope.ImplProc<>nil then
RaiseMsg(20180318212631,ImplScope.Element);
DeclProc:=ImplScope.DeclarationProc;
if DeclProc=nil then
DeclProc:=ImplScope.Element as TPasProcedure;
DeclScope:=DeclProc.CustomData as TPasProcedureScope;
if DeclScope.References<>nil then
RaiseMsg(20180221172403,DeclProc);
ReadScopeReferences(Obj,DeclScope,'Refs',DeclScope.References);
end;
procedure TPCUReader.ReadProcedureBody(Obj: TJSONObject; El: TPasProcedure;
aContext: TPCUReaderContext);
var
ImplScope: TPas2JSProcedureScope;
s: string;
Arr: TJSONArray;
i: Integer;
Data: TJSONData;
begin
ImplScope:=TPas2JSProcedureScope(El.CustomData);
if ImplScope.BodyJS<>'' then
RaiseMsg(20180228231510,El);
if ImplScope.GlobalJS<>nil then
RaiseMsg(20180228231511,El);
if not ReadString(Obj,'Body',s,El) then
RaiseMsg(20180228131232,El);
ReadBoolean(Obj,'Empty',ImplScope.EmptyJS,El);
ImplScope.BodyJS:=s;
if ReadArray(Obj,'Globals',Arr,El) then
begin
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONString) then
RaiseMsg(20180228231555,El,IntToStr(i)+':'+GetObjName(Data));
ImplScope.AddGlobalJS(Data.AsString);
end;
end;
if aContext=nil then ;
end;
procedure TPCUReader.ReadProcedure(Obj: TJSONObject; El: TPasProcedure;
aContext: TPCUReaderContext);
var
DefProcMods: TProcedureModifiers;
t: TProcedureMessageType;
s: string;
Found: Boolean;
Scope: TPas2JSProcedureScope;
DeclProcId: integer;
Ref: TPCUFilerElementRef;
DeclProc: TPasProcedure;
p: SizeInt;
begin
if Obj.Find('Scope') is TJSONBoolean then
Scope:=nil // msIgnoreInterfaces
else
begin
Scope:=TPas2JSProcedureScope(Resolver.CreateScope(El,Resolver.ScopeClass_Procedure));
El.CustomData:=Scope;
p:=Pos('$',El.Name);
if p>0 then
begin
// overload proc name$2 was stored in 'Name'
Scope.OverloadName:=El.Name;
El.Name:=LeftStr(El.Name,p-1);
end;
end;
ReadPasElement(Obj,El,aContext);
if ReadInteger(Obj,'DeclarationProc',DeclProcId,El) then
begin
// ImplProc
Ref:=GetElReference(DeclProcId,El);
if (Ref=nil) or (Ref.Element=nil) then
RaiseMsg(20180219140423,El,'missing DeclarationProc '+IntToStr(DeclProcId));
if not (Ref.Element is TPasProcedure) then
RaiseMsg(20180219140547,El,'DeclarationProc='+GetObjName(Ref.Element));
DeclProc:=TPasProcedure(Ref.Element);
Scope.DeclarationProc:=DeclProc; // no AddRef
El.ProcType:=TPasProcedureType(CreateElement(TPasProcedureTypeClass(DeclProc.ProcType.ClassType),'',DeclProc));
end
else
begin
// declarationproc
ReadProcedureNameParts(Obj,El,aContext);
El.PublicName:=ReadExpr(Obj,El,'Public',aContext);
// e.g. external LibraryExpr name LibrarySymbolName;
El.LibraryExpr:=ReadExpr(Obj,El,'Lib',aContext);
El.LibrarySymbolName:=ReadExpr(Obj,El,'LibName',aContext);
El.DispIDExpr:=ReadExpr(Obj,El,'DispId',aContext);
ReadString(Obj,'Alias',El.AliasName,El);
El.MessageExpr:=ReadExpr(Obj,El,'Msg',aContext);
if ReadString(Obj,'Message',s,El) then
begin
El.MessageName:=s;
El.MessageType:=pmtInteger;
if ReadString(Obj,'MessageType',s,El) then
begin
Found:=false;
for t in TProcedureMessageType do
if s=PCUProcedureMessageTypeNames[t] then
begin
El.MessageType:=t;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180211104537,El,'MessageType "'+s+'"');
end;
end;
DefProcMods:=GetDefaultProcModifiers(El);
El.Modifiers:=ReadProcedureModifiers(Obj,El,'PMods',DefProcMods);
// read ProcType after El.Modifiers
El.ProcType:=TPasProcedureType(ReadElementProperty(
Obj,El,'ProcType',TPasProcedureType,aContext));
if Scope<>nil then
ReadProcedureScope(Obj,Scope,aContext);
end;
if (Scope<>nil) and (Obj.Find('ImplProc')=nil) then
ReadProcScopeReferences(Obj,Scope);
if Obj.Find('Body')<>nil then
ReadProcedureBody(Obj,El,aContext);
end;
procedure TPCUReader.ReadOperator(Obj: TJSONObject; El: TPasOperator;
aContext: TPCUReaderContext);
var
s: string;
Found, b: Boolean;
t: TOperatorType;
begin
ReadProcedure(Obj,El,aContext);
if ReadString(Obj,'Operator',s,El) then
begin
Found:=false;
for t in TOperatorType do
if s=PCUOperatorTypeNames[t] then
begin
El.OperatorType:=t;
Found:=true;
break;
end;
if not Found then
RaiseMsg(20180211110647,El,'Operator "'+s+'"');
end;
if ReadBoolean(Obj,'TokenBased',b,El) then
El.TokenBased:=b;
end;
procedure TPCUReader.ReadAttributes(Obj: TJSONObject; El: TPasAttributes;
aContext: TPCUReaderContext);
begin
ReadPasElement(Obj,El,aContext);
ReadPasExprArray(Obj,El,'Calls',El.Calls,aContext);
end;
procedure TPCUReader.ResolvePending;
var
i: Integer;
PendingIdentifierScope: TPCUReaderPendingIdentifierScope;
Node: TAVLTreeNode;
Ref: TPCUFilerElementRef;
begin
for i:=0 to FPendingIdentifierScopes.Count-1 do
begin
PendingIdentifierScope:=TPCUReaderPendingIdentifierScope(FPendingIdentifierScopes[i]);
ReadIdentifierScopeArray(PendingIdentifierScope.Arr,PendingIdentifierScope.Scope);
end;
FPendingIdentifierScopes.Clear;
Node:=FElementRefs.FindLowest;
while Node<>nil do
begin
Ref:=TPCUFilerElementRef(Node.Data);
Node:=FElementRefs.FindSuccessor(Node);
if Ref.Pending<>nil then
begin
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ResolvePending Ref.Id=',Ref.Id,' Ref.Element=',GetObjName(Ref.Element));
{$ENDIF}
if Ref.Pending.ErrorEl<>nil then
RaiseMsg(20180207194340,Ref.Pending.ErrorEl,IntToStr(Ref.Id))
else
RaiseMsg(20180207194341,Ref.Element,IntToStr(Ref.Id))
end;
end;
end;
procedure TPCUReader.ReadBuiltInSymbols(Obj: TJSONObject; ErrorEl: TPasElement);
var
Arr: TJSONArray;
Data: TJSONData;
SubObj: TJSONObject;
aName, s: string;
bt: TResolverBaseType;
El: TPasElement;
Id, i: integer;
Found: Boolean;
BuiltInProc: TResElDataBuiltInProc;
bp: TResolverBuiltInProc;
pbt: TPas2jsBaseType;
begin
if not ReadArray(Obj,BuiltInNodeName,Arr,ErrorEl) then exit;
for i:=0 to Arr.Count-1 do
begin
Data:=Arr[i];
if not (Data is TJSONObject) then
RaiseMsg(20180215152600,ErrorEl);
SubObj:=TJSONObject(Data);
if not ReadString(SubObj,'Name',aName,ErrorEl) then
RaiseMsg(20180215153027,ErrorEl);
if not ReadInteger(SubObj,'Id',Id,ErrorEl) then
RaiseMsg(20180215153028,ErrorEl,aName);
Found:=false;
for bt in TResolverBaseType do
begin
El:=Resolver.BaseTypes[bt];
if (El<>nil) and (CompareText(El.Name,aName)=0) then
begin
AddElReference(Id,ErrorEl,El);
Found:=true;
break;
end;
end;
if not Found then
begin
for bp in TResolverBuiltInProc do
begin
BuiltInProc:=Resolver.BuiltInProcs[bp];
if BuiltInProc=nil then continue;
El:=BuiltInProc.Element;
if (CompareText(El.Name,aName)=0) then
begin
if bp in [bfStrProc,bfStrFunc] then
begin
if not ReadString(SubObj,'Type',s,ErrorEl) then
s:='Proc';
if (s='Func')<>(bp=bfStrFunc) then continue;
end;
AddElReference(Id,ErrorEl,El);
Found:=true;
break;
end;
end;
end;
if not Found then
begin
for pbt in TPas2jsBaseType do
begin
El:=Resolver.JSBaseTypes[pbt];
if El=nil then continue;
if (CompareText(El.Name,aName)=0) then
begin
Found:=true;
AddElReference(Id,ErrorEl,El);
break;
end;
end;
end;
if not Found then
RaiseMsg(20180216231551,ErrorEl,aName);
end;
end;
constructor TPCUReader.Create;
begin
inherited Create;
FInitialFlags:=TPCUInitialFlags.Create;
FPendingIdentifierScopes:=TObjectList.Create(true);
end;
destructor TPCUReader.Destroy;
begin
FreeAndNil(FJSON);
inherited Destroy;
FreeAndNil(FPendingIdentifierScopes);
FreeAndNil(FInitialFlags);
end;
procedure TPCUReader.Clear;
var
i: Integer;
begin
for i:=0 to length(FElementRefsArray)-1 do
if (FElementRefsArray[i]<>nil) and (FElementRefsArray[i].Element=nil) then
FElementRefsArray[i].Free;
FElementRefsArray:=nil;
FPendingIdentifierScopes.Clear;
inherited Clear;
FInitialFlags.Clear;
end;
procedure TPCUReader.ReadPCU(aResolver: TPas2JSResolver; aStream: TStream);
var
JParser: TJSONParser;
Data: TJSONData;
FirstBytes: string;
Compressed: Boolean;
Decomp: Tdecompressionstream;
Count: Cardinal;
Src: TStream;
begin
FirstBytes:='';
SetLength(FirstBytes,4);
if aStream.Read(FirstBytes[1],4)<4 then
RaiseMsg(20180313232754,nil);
aStream.Seek(-4,soCurrent);
Compressed:=(FirstBytes[1]<>'{') and (FirstBytes<>UTF8BOM+'{');
JParser:=nil;
Src:=nil;
try
if Compressed then
begin
try
Decomp:=Tdecompressionstream.create(aStream);
try
Count:=Decomp.ReadDWord;
if Count>123456789 then
RaiseMsg(20180313233209,'too big, invalid format');
Src:=TMemoryStream.Create;
Src.Size:=Count;
Decomp.read(TMemoryStream(Src).Memory^,Src.Size);
finally
Decomp.Free;
end;
except
on E: Edecompressionerror do
RaiseMsg(20180704162214,'decompression error, file corrupt: '+E.Message);
end;
Src.Position:=0;
end
else
Src:=aStream;
{$IFDEF VerbosePCUUncompressed}
{AllowWriteln}
writeln('TPCUReader.ReadPCU SRC START====================================');
SetLength(FirstBytes,Src.Size);
Src.read(FirstBytes[1],length(FirstBytes));
writeln(FirstBytes);
Src.Position:=0;
writeln('TPCUReader.ReadPCU SRC END======================================');
{AllowWriteln-}
{$ENDIF}
JParser:=TJSONParser.Create(Src,[joUTF8,joStrict]);
Data:=JParser.Parse;
if not (Data is TJSONObject) then
RaiseMsg(20180202130727,'expected JSON object, but found '+JSONTypeName(Data.JSONType));
finally
if Src<>aStream then
Src.Free;
JParser.Free;
end;
ReadJSONHeader(aResolver,TJSONObject(Data));
end;
procedure TPCUReader.ReadJSONHeader(aResolver: TPas2JSResolver;
Obj: TJSONObject);
var
aName: String;
Data: TJSONData;
i: Integer;
begin
FResolver:=aResolver;
FParser:=Resolver.CurrentParser;
FScanner:=FParser.Scanner;
FJSON:=Obj;
{$IF defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
writeln('TPCUReader.ReadJSONHeader START ');
{$ENDIF}
ReadHeaderMagic(Obj);
ReadHeaderVersion(Obj);
ReadGUID(Obj);
for i:=0 to Obj.Count-1 do
begin
aName:=Obj.Names[i];
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadJSONHeader ',aName);
{$ENDIF}
Data:=Obj.Elements[aName];
case aName of
'FileType': ; // done in ReadHeaderMagic
'Version': ; // done in ReadHeaderVersion
'GUID': ; // done in ReadGUID
'TargetPlatform': ReadTargetPlatform(Data);
'TargetProcessor': ReadTargetProcessor(Data);
'Sources': ReadSrcFiles(Data);
'InitParserOpts': InitialFlags.ParserOptions:=ReadParserOptions(Obj,nil,aName,PCUDefaultParserOptions);
'InitModeSwitches': InitialFlags.ModeSwitches:=ReadModeSwitches(Obj,nil,aName,PCUDefaultModeSwitches);
'InitBoolSwitches': InitialFlags.BoolSwitches:=ReadBoolSwitches(Obj,nil,aName,PCUDefaultBoolSwitches);
'InitConverterOpts': InitialFlags.ConverterOptions:=ReadConverterOptions(Obj,nil,aName,PCUDefaultConverterOptions);
'FinalParserOpts': Parser.Options:=ReadParserOptions(Obj,nil,aName,InitialFlags.ParserOptions);
'FinalModeSwitches': Scanner.CurrentModeSwitches:=ReadModeSwitches(Obj,nil,aName,InitialFlags.ModeSwitches);
'FinalBoolSwitches': Scanner.CurrentBoolSwitches:=ReadBoolSwitches(Obj,nil,aName,InitialFlags.BoolSwitches);
'Module': ReadModuleHeader(Data);
else
ReadHeaderItem(aName,Data);
end;
end;
{$IFDEF VerbosePCUFiler}
writeln('TPCUReader.ReadJSONHeader END');
{$ENDIF}
end;
function TPCUReader.ReadContinue: boolean;
var
Obj, SubObj: TJSONObject;
aContext: TPCUReaderContext;
begin
{$IF defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
writeln('TPCUReader.ReadContinue START ',Resolver.RootElement.Name);
{$ENDIF}
Obj:=JSON;
if not ReadObject(Obj,'Module',SubObj,nil) then
RaiseMsg(20180307114005,'missing Module');
aContext:=CreateContext;
try
Result:=ReadModule(SubObj,aContext);
finally
aContext.Free;
end;
{$IF defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
writeln('TPCUReader.ReadContinue END');
{$ENDIF}
end;
{ TPas2JSPrecompileFormats }
function TPas2JSPrecompileFormats.GetItems(Index: integer
): TPas2JSPrecompileFormat;
begin
Result:=TPas2JSPrecompileFormat(FItems[Index]);
end;
constructor TPas2JSPrecompileFormats.Create;
begin
FItems:=TObjectList.Create(true);
end;
destructor TPas2JSPrecompileFormats.Destroy;
begin
Clear;
FreeAndNil(FItems);
inherited Destroy;
end;
procedure TPas2JSPrecompileFormats.Clear;
begin
if (PCUFormat<>nil) and (FItems.IndexOf(PCUFormat)>=0) then
PCUFormat:=nil;
FItems.Clear;
end;
function TPas2JSPrecompileFormats.Count: integer;
begin
Result:=FItems.Count;
end;
function TPas2JSPrecompileFormats.Add(aFormat: TPas2JSPrecompileFormat
): TPas2JSPrecompileFormats;
begin
if FindExt(aFormat.Ext)<>nil then
begin
aFormat.Free;
raise Exception.Create('pas2js precompile extension already exists');
end;
FItems.Add(aFormat);
Result:=Self;
end;
function TPas2JSPrecompileFormats.Add(const Ext, Description: string;
const Reader: TPCUReaderClass; const Writer: TPCUWriterClass
): TPas2JSPrecompileFormat;
begin
Result:=TPas2JSPrecompileFormat.Create;
Result.Ext:=Ext;
Result.Description:=Description;
Result.ReaderClass:=Reader;
Result.WriterClass:=Writer;
Result.Enabled:=true;
Add(Result);
end;
function TPas2JSPrecompileFormats.IndexOf(aFormat: TPas2JSPrecompileFormat
): integer;
begin
Result:=FItems.IndexOf(aFormat);
end;
function TPas2JSPrecompileFormats.FindExt(Ext: string): TPas2JSPrecompileFormat;
var
i: Integer;
begin
Result:=nil;
if (Ext='') then exit;
if Ext[1]='.' then
begin
system.Delete(Ext,1,1);
if Ext='' then exit;
end;
for i:=0 to Count-1 do
if CompareText(Ext,Items[i].Ext)=0 then
exit(Items[i]);
end;
function TPas2JSPrecompileFormats.Remove(aFormat: TPas2JSPrecompileFormat
): integer;
begin
Result:=IndexOf(aFormat);
if Result>=0 then
FItems.Delete(Result);
end;
function TPas2JSPrecompileFormats.Delete(Index: integer): TPas2JSPrecompileFormats;
begin
FItems.Delete(Index);
Result:=Self;
end;
initialization
PrecompileFormats:=TPas2JSPrecompileFormats.Create;
finalization
PrecompileFormats.Free;
PrecompileFormats:=nil;
end.