diff --git a/Source/DelphiAST.Classes.pas b/Source/DelphiAST.Classes.pas index 183c8eb9..3f5d46a5 100644 --- a/Source/DelphiAST.Classes.pas +++ b/Source/DelphiAST.Classes.pas @@ -19,46 +19,52 @@ EParserException = class(Exception) property Line: Integer read FLine; property Col: Integer read FCol; end; - + TAttributeEntry = TPair; PAttributeEntry = ^TAttributeEntry; TSyntaxNodeClass = class of TSyntaxNode; TSyntaxNode = class + public + function HasAttribute(const Key: TAttributeName): Boolean; inline; private FCol: Integer; FLine: Integer; FFileName: string; - function GetHasChildren: Boolean; - function GetHasAttributes: Boolean; - function TryGetAttributeEntry(const Key: TAttributeName; var AttributeEntry: PAttributeEntry): boolean; + function GetHasChildren: Boolean; inline; + function TryGetAttributeEntry(const Key: TAttributeName; out AttributeEntry: PAttributeEntry): boolean; + function GetChildCount: cardinal; inline; + function GetChildNode(index: cardinal): TSyntaxNode; inline; + procedure RemoveAttribute(const Key: TAttributeName); protected FAttributes: TArray; FChildNodes: TArray; FTyp: TSyntaxNodeType; FParentNode: TSyntaxNode; + FAttributesInUse: TAttributeNames; public constructor Create(Typ: TSyntaxNodeType); destructor Destroy; override; function Clone: TSyntaxNode; virtual; procedure AssignPositionFrom(const Node: TSyntaxNode); - + function GetAttribute(const Key: TAttributeName): string; - function HasAttribute(const Key: TAttributeName): Boolean; procedure SetAttribute(const Key: TAttributeName; const Value: string); procedure ClearAttributes; + function AddChild(Typ: TSyntaxNodeType): TSyntaxNode; overload; inline; + procedure AddChildren(Nodes: TArray); function AddChild(Node: TSyntaxNode): TSyntaxNode; overload; - function AddChild(Typ: TSyntaxNodeType): TSyntaxNode; overload; - procedure DeleteChild(Node: TSyntaxNode); - procedure ExtractChild(Node: TSyntaxNode); + procedure DeleteChild(Node: TSyntaxNode); inline; + function ExtractChild(Node: TSyntaxNode): TSyntaxNode; overload; + function ExtractChild(Typ: TSyntaxNodeType): TSyntaxNode; overload; - function FindNode(Typ: TSyntaxNodeType): TSyntaxNode; + function FindNode(Typ: TSyntaxNodeType): TSyntaxNode; overload; + function FindNode(const Types: TSyntaxNodeTypes): TSyntaxNode; overload; property Attributes: TArray read FAttributes; property ChildNodes: TArray read FChildNodes; - property HasAttributes: Boolean read GetHasAttributes; property HasChildren: Boolean read GetHasChildren; property Typ: TSyntaxNodeType read FTyp; property ParentNode: TSyntaxNode read FParentNode; @@ -66,6 +72,9 @@ TSyntaxNode = class property Col: Integer read FCol write FCol; property Line: Integer read FLine write FLine; property FileName: string read FFileName write FFileName; + property ChildNode[index: cardinal]:TSyntaxNode read GetChildNode; + property ChildCount: cardinal read GetChildCount; + property Attribute[const Key: TAttributeName]: string read GetAttribute write SetAttribute; end; TCompoundSyntaxNode = class(TSyntaxNode) @@ -122,15 +131,16 @@ TOperatorInfo = record TOperators = class strict private - class function GetItem(Typ: TSyntaxNodeType): TOperatorInfo; static; + class function GetItem(Typ: TSyntaxNodeType): TOperatorInfo; inline; static; public class function IsOpName(Typ: TSyntaxNodeType): Boolean; class property Items[Typ: TSyntaxNodeType]: TOperatorInfo read GetItem; default; end; const - OperatorsInfo: array [0..27] of TOperatorInfo = + OperatorsInfo: array [ntAddr..ntIs] of TOperatorInfo = ((Typ: ntAddr; Priority: 1; Kind: okUnary; AssocType: atRight), + (Typ: ntDoubleAddr; Priority: 1; Kind: okUnary; AssocType: atRight), (Typ: ntDeref; Priority: 1; Kind: okUnary; AssocType: atLeft), (Typ: ntGeneric; Priority: 1; Kind: okBinary; AssocType: atRight), (Typ: ntIndexed; Priority: 1; Kind: okUnary; AssocType: atLeft), @@ -162,22 +172,15 @@ TOperators = class { TOperators } class function TOperators.GetItem(Typ: TSyntaxNodeType): TOperatorInfo; -var - i: Integer; begin - for i := 0 to High(OperatorsInfo) do - if OperatorsInfo[i].Typ = Typ then - Exit(OperatorsInfo[i]); + Assert(Typ = OperatorsInfo[Typ].Typ); + Assert(Typ in [ntAddr..ntIs]); + Result:= OperatorsInfo[Typ]; //don't use exit in inline routines. end; class function TOperators.IsOpName(Typ: TSyntaxNodeType): Boolean; -var - i: Integer; begin - for i := 0 to High(OperatorsInfo) do - if OperatorsInfo[i].Typ = Typ then - Exit(True); - Result := False; + Result:= (Typ in [ntAddr..ntIs]); end; function IsRoundClose(Typ: TSyntaxNodeType): Boolean; inline; @@ -349,39 +352,108 @@ class procedure TExpressionTools.RawNodeListToTree(RawParentNode: TSyntaxNode; R { TSyntaxNode } + +function TSyntaxNode.HasAttribute(const Key: TAttributeName): Boolean; +begin + Result := Key in FAttributesInUse; +end; + +procedure TSyntaxNode.ClearAttributes; +begin + SetLength(FAttributes, 0); + FAttributesInUse:= []; +end; + +function TSyntaxNode.GetHasChildren: Boolean; +begin + Result := Length(FChildNodes) > 0; +end; + +function TSyntaxNode.GetChildCount: cardinal; +begin + Result:= Length(FChildNodes); +end; + +function TSyntaxNode.AddChild(Typ: TSyntaxNodeType): TSyntaxNode; +begin + Result := AddChild(TSyntaxNode.Create(Typ)); +end; + +function TSyntaxNode.GetChildNode(index: cardinal): TSyntaxNode; +begin + Assert(index < ChildCount); + Result:= FChildNodes[index]; +end; + +procedure TSyntaxNode.DeleteChild(Node: TSyntaxNode); +begin + ExtractChild(Node); + Node.Free; +end; + procedure TSyntaxNode.SetAttribute(const Key: TAttributeName; const Value: string); var AttributeEntry: PAttributeEntry; len: Integer; begin - if not TryGetAttributeEntry(Key, AttributeEntry) then + if not HasAttribute(Key) then begin + if (Value = '') then Exit; //no action needed len := Length(FAttributes); SetLength(FAttributes, len + 1); AttributeEntry := @FAttributes[len]; AttributeEntry^.Key := Key; + Include(FAttributesInUse, Key); end; + if (Value = '') then RemoveAttribute(Key); AttributeEntry^.Value := Value; end; -function TSyntaxNode.TryGetAttributeEntry(const Key: TAttributeName; var AttributeEntry: PAttributeEntry): boolean; +procedure TSyntaxNode.RemoveAttribute(const Key: TAttributeName); +const + Size = SizeOf(TAttributeEntry); +var + Entry: PAttributeEntry; + Index: integer; +begin + if HasAttribute(Key) then begin + TryGetAttributeEntry(Key, Entry); + Index:= (NativeUInt(Entry) - NativeUInt(@FAttributes[0])) + Size; + Move(Entry^, Pointer(NativeUInt(Entry)+Size)^, (High(FAttributes) * Size) - Index); + Exclude(FAttributesInUse, Key); + end; +end; + +function SameText(const Needle: string; const HayStack: array of string): boolean; overload; +var + S: string; +begin + for S in HayStack do begin + if (SameText(Needle, S)) then exit(true); + end; + Result:= false; +end; + +function TSyntaxNode.TryGetAttributeEntry(const Key: TAttributeName; out AttributeEntry: PAttributeEntry): boolean; var i: integer; begin - for i := 0 to High(FAttributes) do + Result:= false; + if not(Key in FAttributesInUse) then begin + //Do not allow the AttributeEntry to be undefined. + AttributeEntry:= nil; + end else for i := 0 to High(FAttributes) do begin if FAttributes[i].Key = Key then begin AttributeEntry := @FAttributes[i]; Exit(True); end; - - Result := False; + end; end; function TSyntaxNode.AddChild(Node: TSyntaxNode): TSyntaxNode; begin Assert(Assigned(Node)); - SetLength(FChildNodes, Length(FChildNodes) + 1); FChildNodes[Length(FChildNodes) - 1] := Node; @@ -390,9 +462,18 @@ function TSyntaxNode.AddChild(Node: TSyntaxNode): TSyntaxNode; Result := Node; end; -function TSyntaxNode.AddChild(Typ: TSyntaxNodeType): TSyntaxNode; +procedure TSyntaxNode.AddChildren(Nodes: TArray); +var + Node: TSyntaxNode; + OldLength: integer; begin - Result := AddChild(TSyntaxNode.Create(Typ)); + OldLength:= Length(FChildNodes); + SetLength(FChildNodes, OldLength + Length(Nodes)); + for Node in Nodes do begin + FChildNodes[OldLength]:= Node; + Inc(OldLength); + Node.FParentNode:= Self; + end; end; function TSyntaxNode.Clone: TSyntaxNode; @@ -409,6 +490,7 @@ function TSyntaxNode.Clone: TSyntaxNode; end; Result.FAttributes := Copy(FAttributes); + Result.FAttributesInUse:= FAttributesInUse; Result.AssignPositionFrom(Self); end; @@ -418,13 +500,16 @@ constructor TSyntaxNode.Create(Typ: TSyntaxNodeType); FTyp := Typ; end; -procedure TSyntaxNode.ExtractChild(Node: TSyntaxNode); + +function TSyntaxNode.ExtractChild(Node: TSyntaxNode): TSyntaxNode; var i: integer; begin + Result:= nil; //do not allow undefined result for i := 0 to High(FChildNodes) do if FChildNodes[i] = Node then begin + Result:= Node; if i < High(FChildNodes) then Move(FChildNodes[i + 1], FChildNodes[i], SizeOf(TSyntaxNode) * (Length(FChildNodes) - i - 1)); SetLength(FChildNodes, High(FChildNodes)); @@ -432,12 +517,6 @@ procedure TSyntaxNode.ExtractChild(Node: TSyntaxNode); end; end; -procedure TSyntaxNode.DeleteChild(Node: TSyntaxNode); -begin - ExtractChild(Node); - Node.Free; -end; - destructor TSyntaxNode.Destroy; var i: integer; @@ -447,6 +526,19 @@ destructor TSyntaxNode.Destroy; inherited; end; +function TSyntaxNode.ExtractChild(Typ: TSyntaxNodeType): TSyntaxNode; +var + Child: TSyntaxNode; +begin + for Child in FChildNodes do begin + if (Child.Typ = Typ) then begin + ExtractChild(Child); + Exit(Child); + end; + end; + Result:= nil; +end; + function TSyntaxNode.FindNode(Typ: TSyntaxNodeType): TSyntaxNode; var i: Integer; @@ -457,6 +549,16 @@ function TSyntaxNode.FindNode(Typ: TSyntaxNodeType): TSyntaxNode; Result := nil; end; +function TSyntaxNode.FindNode(const Types: TSyntaxNodeTypes): TSyntaxNode; +var + i: integer; +begin + for i:= 0 to High(FChildNodes) do begin + if (FChildNodes[i].Typ in Types) then Exit(FChildNodes[i]); + end; + Result:= nil; +end; + function TSyntaxNode.GetAttribute(const Key: TAttributeName): string; var AttributeEntry: PAttributeEntry; @@ -467,28 +569,6 @@ function TSyntaxNode.GetAttribute(const Key: TAttributeName): string; Result := ''; end; -function TSyntaxNode.GetHasAttributes: Boolean; -begin - Result := Length(FAttributes) > 0; -end; - -function TSyntaxNode.GetHasChildren: Boolean; -begin - Result := Length(FChildNodes) > 0; -end; - -function TSyntaxNode.HasAttribute(const Key: TAttributeName): Boolean; -var - AttributeEntry: PAttributeEntry; -begin - Result := TryGetAttributeEntry(Key, AttributeEntry); -end; - -procedure TSyntaxNode.ClearAttributes; -begin - SetLength(FAttributes, 0); -end; - procedure TSyntaxNode.AssignPositionFrom(const Node: TSyntaxNode); begin FCol := Node.Col; @@ -534,4 +614,5 @@ constructor EParserException.Create(Line, Col: Integer; const FileName, Msg: str FCol := Col; end; + end. \ No newline at end of file diff --git a/Source/DelphiAST.Consts.pas b/Source/DelphiAST.Consts.pas index 8532446b..d500535d 100644 --- a/Source/DelphiAST.Consts.pas +++ b/Source/DelphiAST.Consts.pas @@ -4,101 +4,129 @@ interface type TSyntaxNodeType = ( - ntUnknown, - ntAdd, ntAddr, - ntAlignmentParam, + ntDoubleAddr, + ntDeref, + ntGeneric, + ntIndexed, + ntDot, + ntCall, + ntUnaryMinus, + ntNot, + ntMul, + ntFDiv, + ntDiv, + ntMod, ntAnd, + ntShl, + ntShr, + ntAs, + ntAdd, + ntSub, + ntOr, + ntXor, + ntEqual, + ntNotEqual, + ntLower, + ntGreater, + ntLowerEqual, + ntGreaterEqual, + ntIn, + ntIs, + + //Allow the use of [ntStrictPrivate..ntAutomated]. + ntStrictPrivate, + ntPrivate, + ntStrictProtected, + ntProtected, + ntPublic, + ntPublished, + ntAutomated, + + ntUnknown, + ntAlignmentParam, ntAnonymousMethod, + ntAnonymousMethodType, ntArguments, - ntAs, + ntAsmFragment, + ntAsmStatement, ntAssign, ntAt, ntAttribute, ntAttributes, ntBounds, - ntCall, ntCase, ntCaseElse, ntCaseLabel, ntCaseLabels, ntCaseSelector, ntClassConstraint, + ntCompilerDirective, ntConstant, ntConstants, ntConstraints, ntConstructorConstraint, ntContains, ntDefault, - ntDeref, + ntDependency, + ntDeprecated, ntDimension, - ntDiv, - ntDot, ntDownTo, ntElement, ntElse, ntEmptyStatement, ntEnum, - ntEqual, ntExcept, + ntExceptElse, ntExceptionHandler, + ntExperimental, ntExports, ntExpression, ntExpressions, ntExternal, - ntFDiv, + ntExternalName, ntField, ntFields, ntFinalization, ntFinally, ntFor, ntFrom, - ntGeneric, ntGoto, - ntGreater, - ntGreaterEqual, ntGuid, ntHelper, ntIdentifier, ntIf, ntImplementation, ntImplements, - ntIn, ntIndex, - ntIndexed, ntInherited, ntInitialization, ntInterface, - ntIs, ntLabel, + ntLabeledStatement, ntLHS, + ntLibrary, ntLiteral, - ntLower, - ntLowerEqual, ntMessage, ntMethod, - ntMod, - ntMul, ntName, ntNamedArgument, - ntNotEqual, - ntNot, - ntOr, ntPackage, ntParameter, ntParameters, - ntPath, + {ntPath,} + ntPlatform, ntPositionalArgument, - ntProtected, - ntPrivate, + ntProgram, ntProperty, - ntPublic, - ntPublished, ntRaise, ntRead, + ntRecordConstant, ntRecordConstraint, + ntRecordVariant, ntRepeat, ntRequires, + ntResident, ntResolutionClause, ntResourceString, ntReturnType, @@ -106,13 +134,8 @@ interface ntRoundClose, ntRoundOpen, ntSet, - ntShl, - ntShr, ntStatement, ntStatements, - ntStrictPrivate, - ntStrictProtected, - ntSub, ntSubrange, ntThen, ntTo, @@ -126,8 +149,8 @@ interface ntValue, ntVariable, ntVariables, - ntXor, - ntUnaryMinus, + ntVariantSection, + ntVariantTag, ntUnit, ntUses, ntWhile, @@ -139,6 +162,8 @@ interface ntSlashesComment ); + TSyntaxNodeTypes = set of TSyntaxNodeType; + TAttributeName = ( anType, anClass, @@ -155,143 +180,162 @@ interface anInline ); -const - SyntaxNodeNames: array [TSyntaxNodeType] of string = ( - 'unknown', - 'add', - 'addr', - 'alignmentparam', - 'and', - 'anonymousmethod', - 'arguments', - 'as', - 'assign', - 'at', - 'attribute', - 'attributes', - 'bounds', - 'call', - 'case', - 'caseelse', - 'caselabel', - 'caselabels', - 'caseselector', - 'classconstraint', - 'constant', - 'constants', - 'constraints', - 'constructorconstraint', - 'contains', - 'default', - 'deref', - 'dimension', - 'div', - 'dot', - 'downto', - 'element', - 'else', - 'emptystatement', - 'enum', - 'equal', - 'except', - 'exceptionhandler', - 'exports', - 'expression', - 'expressions', - 'external', - 'fdiv', - 'field', - 'fields', - 'finalization', - 'finally', - 'for', - 'from', - 'generic', - 'goto', - 'greater', - 'greaterequal', - 'guid', - 'helper', - 'identifier', - 'if', - 'implementation', - 'implements', - 'in', - 'index', - 'indexed', - 'inherited', - 'initialization', - 'interface', - 'is', - 'label', - 'lhs', - 'literal', - 'lower', - 'lowerequal', - 'message', - 'method', - 'mod', - 'mul', - 'name', - 'namedargument', - 'notequal', - 'not', - 'or', - 'package', - 'parameter', - 'parameters', - 'path', - 'positionalargument', - 'protected', - 'private', - 'property', - 'public', - 'published', - 'raise', - 'read', - 'recordconstraint', - 'repeat', - 'requires', - 'resolutionclause', - 'resourcestring', - 'returntype', - 'rhs', - 'roundclose', - 'roundopen', - 'set', - 'shl', - 'shr', - 'statement', - 'statements', - 'strictprivate', - 'strictprotected', - 'sub', - 'subrange', - 'then', - 'to', - 'try', - 'type', - 'typeargs', - 'typedecl', - 'typeparam', - 'typeparams', - 'typesection', - 'value', - 'variable', - 'variables', - 'xor', - 'unaryminus', - 'unit', - 'uses', - 'while', - 'with', - 'write', + TAttributeNames = set of TAttributeName; - 'ansicomment', - 'borlandcomment', - 'slashescomment' - ); +type + SyntaxNodeNames = class + strict private + class var FData: array[TSyntaxNodeType] of string; + class function GetItem(const index: TSyntaxNodeType): string; static; inline; + class constructor Init; + public + class property Items[const index: TSyntaxNodeType]: string read GetItem; default; + end; + + + +//const +// OldSyntaxNodeNames: array [TSyntaxNodeType] of string = ( +// 'addr', //ntAddr, +// 'deref', //ntDeref, +// 'generic', //ntGeneric, +// 'indexed', //ntIndexed, +// 'dot', //ntDot, +// 'call', //ntCall, +// 'unaryMinus', //ntUnaryMinus, +// 'not', //ntNot, +// 'mul', //ntMul, +// 'fdiv', //ntFDiv, +// 'div', //ntDiv, +// 'mod', //ntMod, +// 'and', //ntAnd, +// 'shl', //ntShl, +// 'shr', //ntShr, +// 'as', //ntAs, +// 'add', //ntAdd, +// 'sub', //ntSub, +// 'or', //ntOr, +// 'xor', //ntXor, +// 'equal', //ntEqual, +// 'notEqual', //ntNotEqual, +// 'lower', //ntLower, +// 'greater', //ntGreater, +// 'lowerEqual', //ntLowerEqual, +// 'greaterEqual', //ntGreaterEqual, +// 'in', //ntIn, +// 'is', //ntIs, +// +// 'unknown', //ntUnknown, +// 'alignmentparam', //ntAlignmentParam, +// 'anonymousmethod', //ntAnonymousMethod, +// 'anonymousmethodtype', //ntAnonymousMethodType, +// 'arguments', //ntArguments, +// 'assign', //ntAssign, +// 'at', //ntAt, +// 'attribute', //ntAttribute, +// 'attributes', //ntAttributes, +// 'bounds', //ntBounds, +// 'case', //ntCase, +// 'caseelse', //ntCaseElse, +// 'caselabel', //ntCaseLabel, +// 'caselabels', //ntCaseLabels, +// 'caseselector', //ntCaseSelector, +// 'classconstraint', //ntClassConstraint, +// 'constant', //ntConstant, +// 'constants', //ntConstants, +// 'constraints', //ntConstraints, +// 'constructorconstraint', //ntConstructorConstraint, +// 'contains', //ntContains, +// 'default', //ntDefault, +// 'dimension', //ntDimension, +// 'downto', //ntDownTo, +// 'element', //ntElement, +// 'else', //ntElse, +// 'emptystatement', //ntEmptyStatement, +// 'enum', //ntEnum, +// 'except', //ntExcept, +// 'exceptelse', //ntExceptElse, +// 'exceptionhandler', //ntExceptionHandler, +// 'exports', //ntExports, +// 'expression', //ntExpression, +// 'expressions', //ntExpressions, +// 'external', //ntExternal, +// 'field', //ntField, +// 'fields', //ntFields, +// 'finalization', //ntFinalization, +// 'finally', //ntFinally, +// 'for', //ntFor, +// 'from', //ntFrom, +// 'goto', //ntGoto, +// 'guid', //ntGuid, +// 'helper', //ntHelper, +// 'identifier', //ntIdentifier, +// 'if', //ntIf, +// 'implementation', //ntImplementation, +// 'implements', //ntImplements, +// 'index', //ntIndex, +// 'inherited', //ntInherited, +// 'initialization', //ntInitialization, +// 'interface', //ntInterface, +// 'label', //ntLabel, +// 'labeledstatement', //ntLabeledStatement, +// 'lhs', //ntLHS, +// 'literal', //ntLiteral, +// 'message', //ntMessage, +// 'method', //ntMethod, +// 'name', //ntName, +// 'namedargument', //ntNamedArgument, +// 'package', //ntPackage, +// 'parameter', //ntParameter, +// 'parameters', //ntParameters, +// 'path', //ntPath, +// 'positionalargument', //ntPositionalArgument, +// 'protected', //ntProtected, +// 'private', //ntPrivate, +// 'property', //ntProperty, +// 'public', //ntPublic, +// 'published', //ntPublished, +// 'raise', //ntRaise, +// 'read', //ntRead, +// 'recordconstraint', //ntRecordConstraint, +// 'repeat', //ntRepeat, +// 'requires', //ntRequires, +// 'resolutionclause', //ntResolutionClause, +// 'resourcestring', //ntResourceString, +// 'returntype', //ntReturnType, +// 'rhs', //ntRHS, +// 'roundclose', //ntRoundClose, +// 'roundopen', //ntRoundOpen, +// 'set', //ntSet, +// 'statement', //ntStatement, +// 'statements', //ntStatements, +// 'strictprivate', //ntStrictPrivate, +// 'strictprotected', //ntStrictProtected, +// 'subrange', //ntSubrange, +// 'then', //ntThen, +// 'to', //ntTo, +// 'try', //ntTry, +// 'type', //ntType, +// 'typeargs', //ntTypeArgs, +// 'typedecl', //ntTypeDecl, +// 'typeparam', //ntTypeParam, +// 'typeparams', //ntTypeParams, +// 'typesection', //ntTypeSection, +// 'value', //ntValue, +// 'variable', //ntVariable, +// 'variables', //ntVariables, +// 'unit', //ntUnit, +// 'uses', //ntUses, +// 'while', //ntWhile, +// 'with', //ntWith, +// 'write', //ntWrite, +// +// 'ansicomment', //ntAnsiComment, +// 'borlandcomment', //ntBorComment, +// 'slashescomment' //ntSlashesComment +// ); +const AttributeNameStrings: array[TAttributeName] of string = ( 'type', 'class', @@ -310,4 +354,22 @@ interface implementation +uses + SysUtils, TypInfo; + +{ TSyntaxNodeNames } + +class function SyntaxNodeNames.GetItem(const index: TSyntaxNodeType): string; +begin + Result:= FData[index]; +end; + +class constructor SyntaxNodeNames.Init; +var + value: TSyntaxNodeType; +begin + for value := Low(TSyntaxNodeType) to High(TSyntaxNodeType) do + FData[value] := Copy(LowerCase(GetEnumName(TypeInfo(TSyntaxNodeType), Ord(value))), 3); +end; + end. diff --git a/Source/DelphiAST.pas b/Source/DelphiAST.pas index c8b23dda..d2aecb36 100644 --- a/Source/DelphiAST.pas +++ b/Source/DelphiAST.pas @@ -27,9 +27,9 @@ TPasLexer = class FOnHandleString: TStringEvent; function GetToken: string; inline; function GetPosXY: TTokenPoint; inline; - function GetFileName: string; + function GetFileName: string; inline; public - constructor Create(const ALexer: TmwPasLex; AOnHandleString: TStringEvent); + constructor Create(const Lexer: TmwPasLex; OnHandleString: TStringEvent); property FileName: string read GetFileName; property PosXY: TTokenPoint read GetPosXY; @@ -41,7 +41,7 @@ TNodeStack = class FLexer: TPasLexer; FStack: TStack; - function GetCount: Integer; + function GetCount: Integer; inline; public constructor Create(Lexer: TPasLexer); destructor Destroy; override; @@ -50,9 +50,9 @@ TNodeStack = class function AddChild(Node: TSyntaxNode): TSyntaxNode; overload; function AddValuedChild(Typ: TSyntaxNodeType; const Value: string): TSyntaxNode; - procedure Clear; - function Peek: TSyntaxNode; - function Pop: TSyntaxNode; + procedure Clear; inline; + function Peek: TSyntaxNode; inline; + function Pop: TSyntaxNode; inline; function Push(Typ: TSyntaxNodeType): TSyntaxNode; overload; function Push(Node: TSyntaxNode): TSyntaxNode; overload; @@ -71,13 +71,14 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure ParserMessage(Sender: TObject; const Typ: TMessageEventType; const Msg: string; X, Y: Integer); function NodeListToString(NamesNode: TSyntaxNode): string; procedure MoveMembersToVisibilityNodes(TypeNode: TSyntaxNode); - procedure CallInheritedConstantExpression; - procedure CallInheritedExpression; - procedure CallInheritedFormalParameterList; - procedure CallInheritedPropertyParameterList; - procedure SetCurrentCompoundNodesEndPosition; + procedure CallInheritedConstantExpression; inline; + procedure CallInheritedExpression; inline; + procedure CallInheritedFormalParameterList; inline; + procedure CallInheritedPropertyParameterList; inline; + procedure SetCurrentCompoundNodesEndPosition; inline; procedure DoOnComment(Sender: TObject; const Text: string); procedure DoHandleString(var s: string); inline; + function GetMainSection(Node: TSyntaxNode): TSyntaxNode; protected FStack: TNodeStack; FComments: TObjectList; @@ -89,10 +90,17 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure AddressOp; override; procedure AlignmentParameter; override; procedure AnonymousMethod; override; + procedure AnonymousMethodType; override; + procedure AnonymousMethodTypeFunction; override; + procedure AnonymousMethodTypeProcedure; override; procedure ArrayBounds; override; procedure ArrayConstant; override; procedure ArrayDimension; override; + procedure ArrayOfConst; override; + procedure AsmFragment; override; + procedure AsmLabelAt; override; procedure AsmStatement; override; + procedure AsmStatements; override; procedure AsOp; override; procedure AssignOp; override; procedure AtExpression; override; @@ -102,7 +110,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure CaseSelector; override; procedure CaseStatement; override; procedure ClassClass; override; - procedure ClassConstraint; override; + procedure ClassConstraint; override; procedure ClassField; override; procedure ClassForward; override; procedure ClassFunctionHeading; override; @@ -114,6 +122,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure ClassProperty; override; procedure ClassReferenceType; override; procedure ClassType; override; + procedure CompilerDirective; override; procedure CompoundStatement; override; procedure ConstParameter; override; procedure ConstantDeclaration; override; @@ -127,11 +136,19 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure ConstructorName; override; procedure ContainsClause; override; procedure DestructorName; override; + procedure DirectiveAbstract; override; procedure DirectiveBinding; override; procedure DirectiveBindingMessage; override; procedure DirectiveCalling; override; + procedure DirectiveDeprecated; override; + procedure DirectiveExperimental; override; procedure DirectiveInline; override; + procedure DirectiveLibrary; override; + procedure DirectivePlatform; override; + procedure DirectiveSealed; override; + procedure DirectiveVarargs; override; procedure DispInterfaceForward; override; + procedure DoubleAddressOp; override; procedure DotOp; override; procedure ElseStatement; override; procedure EmptyStatement; override; @@ -140,6 +157,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure ExceptionBlockElseBranch; override; procedure ExceptionHandler; override; procedure ExceptionVariable; override; + procedure ExplicitType; override; procedure ExportedHeading; override; procedure ExportsClause; override; procedure ExportsElement; override; @@ -148,6 +166,8 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure Expression; override; procedure ExpressionList; override; procedure ExternalDirective; override; + procedure ExternalDependency; override; + procedure FieldList; override; procedure FieldName; override; procedure FinalizationSection; override; procedure FinallyBlock; override; @@ -157,6 +177,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure ForStatementFrom; override; procedure ForStatementIn; override; procedure ForStatementTo; override; + procedure ForwardDeclaration; override; procedure FunctionHeading; override; procedure FunctionMethodName; override; procedure FunctionProcedureName; override; @@ -174,30 +195,44 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure InterfaceGUID; override; procedure InterfaceSection; override; procedure InterfaceType; override; + procedure LabelDeclarationSection; override; + procedure LabeledStatement; override; procedure LabelId; override; + procedure LibraryFile; override; procedure MainUsesClause; override; procedure MainUsedUnitStatement; override; procedure MethodKind; override; procedure MultiplicativeOperator; override; + procedure NameSpecifier; override; procedure NotOp; override; procedure NilToken; override; procedure Number; override; + procedure ObjectField; override; + procedure ObjectForward; override; procedure ObjectNameOfMethod; override; + procedure ObjectType; override; procedure OutParameter; override; + procedure PackageFile; override; procedure ParameterFormal; override; procedure ParameterName; override; procedure PointerSymbol; override; procedure PointerType; override; + procedure ProceduralDirectiveOf; override; procedure ProceduralType; override; procedure ProcedureHeading; override; procedure ProcedureDeclarationSection; override; procedure ProcedureProcedureName; override; + procedure ProgramFile; override; procedure PropertyName; override; procedure PropertyParameterList; override; procedure RaiseStatement; override; procedure RecordConstraint; override; + procedure RecordConstant; override; procedure RecordFieldConstant; override; procedure RecordType; override; + procedure RecordVariant; override; + procedure RecordVariantSection; override; + procedure RecordVariantTag; override; procedure RelativeOperator; override; procedure RepeatStatement; override; procedure ResourceDeclaration; override; @@ -205,6 +240,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure RequiresClause; override; procedure RequiresIdentifier; override; procedure RequiresIdentifierId; override; + procedure Resident; override; procedure ReturnType; override; procedure RoundClose; override; procedure RoundOpen; override; @@ -219,6 +255,8 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure StringStatement; override; procedure StructuredType; override; procedure SubrangeType; override; + procedure TagField; override; + procedure TagFieldTypeName; override; procedure ThenStatement; override; procedure TryStatement; override; procedure TypeArgs; override; @@ -234,16 +272,18 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) procedure UnitId; override; procedure UsesClause; override; procedure UsedUnitName; override; + procedure VarAbsolute; override; procedure VarDeclaration; override; procedure VarName; override; procedure VarParameter; override; procedure VarSection; override; + procedure VisibilityAutomated; override; procedure VisibilityPrivate; override; procedure VisibilityProtected; override; procedure VisibilityPublic; override; procedure VisibilityPublished; override; procedure VisibilityStrictPrivate; override; - procedure VisibilityStrictProtected; override; + procedure VisibilityStrictProtected; override; procedure WhileStatement; override; procedure WithExpressionList; override; procedure WithStatement; override; @@ -273,7 +313,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasPar) implementation uses - TypInfo; + TypInfo, StrUtils; {$IFDEF FPC} type @@ -306,19 +346,25 @@ TStringStreamHelper = class helper for TStringStream // do not use const strings here to prevent allocating new strings every time type - TAttributeValue = (atAsm, atTrue, atFunction, atProcedure, atClassOf, atClass, + TAttributeValue = (atAsm, atTrue, atFunction, atProcedure, atOperator, atClass_Of, atClass, atConst, atConstructor, atDestructor, atEnum, atInterface, atNil, atNumeric, - atOut, atPointer, atName, atString, atSubRange, atVar, atDispInterface); - + atOut, atPointer, atName, atString, atSubRange, atVar, atDispInterface, atType{ExplicitType}, + atObject, atSealed, atAbstract, atBegin, atOf_Object{procedure of object}, + atVarargs, atExternal{Varargs and external are mutually exclusive}, + atStatic, atAbsolute); var AttributeValues: array[TAttributeValue] of string; procedure InitAttributeValues; var value: TAttributeValue; + AttributeStr: string; begin - for value := Low(TAttributeValue) to High(TAttributeValue) do - AttributeValues[value] := Copy(LowerCase(GetEnumName(TypeInfo(TAttributeValue), Ord(value))), 3); + for value := Low(TAttributeValue) to High(TAttributeValue) do begin + AttributeStr:= Copy(LowerCase(GetEnumName(TypeInfo(TAttributeValue), Ord(value))), 3); + AttributeStr:= StringReplace(AttributeStr, '_', ' ', [rfReplaceAll]); + AttributeValues[value] := AttributeStr; + end; end; procedure AssignLexerPositionToNode(const Lexer: TPasLexer; const Node: TSyntaxNode); @@ -330,11 +376,11 @@ procedure AssignLexerPositionToNode(const Lexer: TPasLexer; const Node: TSyntaxN { TPasLexer } -constructor TPasLexer.Create(const ALexer: TmwPasLex; AOnHandleString: TStringEvent); +constructor TPasLexer.Create(const Lexer: TmwPasLex; OnHandleString: TStringEvent); begin inherited Create; - FLexer := ALexer; - FOnHandleString := AOnHandleString; + FLexer := Lexer; + FOnHandleString := OnHandleString; end; function TPasLexer.GetFileName: string; @@ -485,7 +531,7 @@ procedure TPasSyntaxTreeBuilder.AlignmentParameter; procedure TPasSyntaxTreeBuilder.AnonymousMethod; begin - FStack.Push(ntAnonymousMethod); + FStack.Push(ntAnonymousMethod).Attribute[anKind]:= Lexer.Token; //function or procedure try inherited; finally @@ -493,6 +539,26 @@ procedure TPasSyntaxTreeBuilder.AnonymousMethod; end; end; +procedure TPasSyntaxTreeBuilder.AnonymousMethodType; +begin + FStack.Push(ntAnonymousMethodType); + try + inherited; + finally + FStack.Pop + end; +end; + +procedure TPasSyntaxTreeBuilder.AnonymousMethodTypeProcedure; +begin + FStack.Peek.Attribute[anKind]:= Lexer.Token; //procedure +end; + +procedure TPasSyntaxTreeBuilder.AnonymousMethodTypeFunction; +begin + FStack.Peek.Attribute[anKind]:= Lexer.Token; //function +end; + procedure TPasSyntaxTreeBuilder.ArrayBounds; begin FStack.Push(ntBounds); @@ -523,9 +589,57 @@ procedure TPasSyntaxTreeBuilder.ArrayDimension; end; end; +procedure TPasSyntaxTreeBuilder.ArrayOfConst; +begin + //do not fill the name attribute. const is a keyword, not a type. + FStack.Push(ntType).Attribute[anKind]:= AttributeValues[atConst]; + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.AsmFragment; +begin + FStack.AddValuedChild(ntAsmFragment, Lexer.Token); + inherited; +end; + +procedure TPasSyntaxTreeBuilder.AsmLabelAt; +begin + FStack.AddValuedChild(ntAsmFragment, Lexer.Token); + inherited; +end; + procedure TPasSyntaxTreeBuilder.AsmStatement; +var + Node, Child: TSyntaxNode; + ValuedNode: TValuedSyntaxNode absolute Node; + ValuedChild: TValuedSyntaxNode absolute Child; + Optional: string; + Previous: char; +begin + Node:= FStack.PushValuedNode(ntAsmStatement,''); + try + inherited; + Optional:= ''; + Previous:= ' '; + for Child in Node.ChildNodes do begin + //Store the whole statement as well as the parts. + if (ValuedChild.Value[1] in [',', '+', '*', ']', ')', ' ','-',':']) or (Previous in ['(','[',',','+','*','-','@']) then Optional:= ''; + Previous:= ValuedChild.Value[1]; + ValuedNode.Value:= ValuedNode.Value + Optional + ValuedChild.Value; + Optional:= ' '; + end; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.AsmStatements; begin - FStack.PushCompoundSyntaxNode(ntStatements).SetAttribute(anType, AttributeValues[atAsm]); + FStack.PushCompoundSyntaxNode(ntStatements).Attribute[anKind]:= AttributeValues[atAsm]; try inherited; SetCurrentCompoundNodesEndPosition; @@ -578,7 +692,8 @@ procedure TPasSyntaxTreeBuilder.AttributeArgumentExpression; procedure TPasSyntaxTreeBuilder.AttributeArgumentName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntName).Attribute[anName]:= Lexer.Token; inherited; end; @@ -594,7 +709,8 @@ procedure TPasSyntaxTreeBuilder.AttributeArguments; procedure TPasSyntaxTreeBuilder.AttributeName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntname).Attribute[anName]:= Lexer.Token; inherited; end; @@ -657,10 +773,64 @@ procedure TPasSyntaxTreeBuilder.BuildExpressionTree( end; end; +//ExtractChild causes corruption of the childlist. need to investigate why. +//procedure TPasSyntaxTreeBuilder.BuildParametersList( +// ParametersListMethod: TTreeBuilderMethod); +//var +// Params, Temp: TSyntaxNode; +// Attributes: TSyntaxNode; +// ParamList, Param, TypeInfo, ParamExpr: TSyntaxNode; +// ParamKind: string; +//begin +// Params := TSyntaxNode.Create(ntUnknown); +// try +// FStack.Push(ntParameters); +// +// FStack.Push(Params); +// try +// ParametersListMethod; +// finally +// FStack.Pop; +// end; +// +// for ParamList in Params.ChildNodes do +// begin +// TypeInfo := ParamList.ExtractChild(ntType); +// ParamKind := ParamList.Attribute[anKind]; +// ParamExpr := ParamList.ExtractChild(ntExpression); +// Attributes:= ParamList.ExtractChild(ntAttributes); +// +// for Param in ParamList.ChildNodes do +// begin +// if Param.Typ = ntName then begin +// +// Temp:= FStack.Push(ntParameter); +// if ParamKind <> '' then Temp.Attribute[anKind]:= ParamKind; +// +// Temp.Col:= Param.Col; +// Temp.Line:= Param.Line; +// +// if Assigned(Attributes) then FStack.AddChild(Attributes); +// +// FStack.AddChild(Param.Clone); +// if Assigned(TypeInfo) then FStack.AddChild(TypeInfo); +// +// if Assigned(ParamExpr) then FStack.AddChild(ParamExpr); +// +// FStack.Pop; +// end; +// end; +// end; +// FStack.Pop; +// finally +// Params.Free; +// end; +//end; + procedure TPasSyntaxTreeBuilder.BuildParametersList( ParametersListMethod: TTreeBuilderMethod); var - Params, Temp: TSyntaxNode; + Params, Temp, Attributes: TSyntaxNode; ParamList, Param, TypeInfo, ParamExpr: TSyntaxNode; ParamKind: string; begin @@ -678,8 +848,9 @@ procedure TPasSyntaxTreeBuilder.BuildParametersList( for ParamList in Params.ChildNodes do begin TypeInfo := ParamList.FindNode(ntType); - ParamKind := ParamList.GetAttribute(anKind); + ParamKind := ParamList.Attribute[anKind]; ParamExpr := ParamList.FindNode(ntExpression); + Attributes:= ParamList.FindNode(ntAttributes); for Param in ParamList.ChildNodes do begin @@ -688,11 +859,14 @@ procedure TPasSyntaxTreeBuilder.BuildParametersList( Temp := FStack.Push(ntParameter); if ParamKind <> '' then - Temp.SetAttribute(anKind, ParamKind); + Temp.Attribute[anKind]:= ParamKind; Temp.Col := Param.Col; Temp.Line := Param.Line; + if Assigned(Attributes) then + FStack.AddChild(Attributes.Clone); + FStack.AddChild(Param.Clone); if Assigned(TypeInfo) then FStack.AddChild(TypeInfo.Clone); @@ -759,9 +933,19 @@ procedure TPasSyntaxTreeBuilder.CaseStatement; end; end; +procedure TPasSyntaxTreeBuilder.RecordVariant; +begin + FStack.Push(ntRecordVariant); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.ClassClass; begin - FStack.Peek.SetAttribute(anClass, AttributeValues[atTrue]); + FStack.Peek.Attribute[anClass]:= AttributeValues[atTrue]; inherited; end; @@ -769,7 +953,51 @@ procedure TPasSyntaxTreeBuilder.ClassField; var Fields, Temp: TSyntaxNode; Field, TypeInfo, TypeArgs: TSyntaxNode; + IsClassVarSection: boolean; +begin + IsClassVarSection:= FStack.Peek.HasAttribute(anClass); + Fields := TSyntaxNode.Create(ntFields); + try + FStack.Push(Fields); + try + inherited; + finally + FStack.Pop; + end; + + TypeInfo := Fields.FindNode(ntType); + TypeArgs := Fields.FindNode(ntTypeArgs); + for Field in Fields.ChildNodes do + begin + if Field.Typ <> ntName then + Continue; + + Temp := FStack.Push(ntField); + if (IsClassVarSection) then Temp.Attribute[anClass]:= AttributeValues[atTrue]; + try + Temp.AssignPositionFrom(Field); + + FStack.AddChild(Field.Clone); + TypeInfo := TypeInfo.Clone; + if Assigned(TypeArgs) then + TypeInfo.AddChild(TypeArgs.Clone); + FStack.AddChild(TypeInfo); + finally + FStack.Pop; + end; + end; + finally + Fields.Free; + end; +end; + +procedure TPasSyntaxTreeBuilder.ObjectField; +var + Fields, Temp: TSyntaxNode; + Field, TypeInfo, TypeArgs: TSyntaxNode; + IsClassVarSection: boolean; begin + IsClassVarSection:= FStack.Peek.HasAttribute(anClass); Fields := TSyntaxNode.Create(ntFields); try FStack.Push(Fields); @@ -787,6 +1015,7 @@ procedure TPasSyntaxTreeBuilder.ClassField; Continue; Temp := FStack.Push(ntField); + if (IsClassVarSection) then Temp.Attribute[anClass]:= AttributeValues[atTrue]; try Temp.AssignPositionFrom(Field); @@ -806,13 +1035,15 @@ procedure TPasSyntaxTreeBuilder.ClassField; procedure TPasSyntaxTreeBuilder.ClassForward; begin - FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]); - inherited ClassForward; + FStack.Peek.Attribute[anForwarded]:= AttributeValues[atTrue]; + FStack.Peek.Attribute[anType]:= AttributeValues[atClass]; + inherited; end; procedure TPasSyntaxTreeBuilder.ClassFunctionHeading; begin - FStack.Peek.SetAttribute(anKind, AttributeValues[atFunction]); + if (FLexer.Token = 'operator') then FStack.Peek.Attribute[anKind]:= AttributeValues[atOperator] + else FStack.Peek.Attribute[anKind]:= AttributeValues[atFunction]; inherited; end; @@ -828,12 +1059,16 @@ procedure TPasSyntaxTreeBuilder.ClassHelper; procedure TPasSyntaxTreeBuilder.ClassMethod; begin - FStack.Peek.SetAttribute(anClass, AttributeValues[atTrue]); + FStack.Peek.Attribute[anClass]:= AttributeValues[atTrue]; inherited; end; procedure TPasSyntaxTreeBuilder.ClassMethodResolution; +var + PrevNode: TSyntaxNode; begin + PrevNode:= FStack.Peek; //Get the ntMethod node above + PrevNode.Attribute[anKind]:= FLexer.Token; FStack.Push(ntResolutionClause); try inherited; @@ -855,7 +1090,7 @@ procedure TPasSyntaxTreeBuilder.ClassMethodHeading; procedure TPasSyntaxTreeBuilder.ClassProcedureHeading; begin - FStack.Peek.SetAttribute(anKind, AttributeValues[atProcedure]); + FStack.Peek.Attribute[anKind]:= AttributeValues[atProcedure]; inherited; end; @@ -871,7 +1106,7 @@ procedure TPasSyntaxTreeBuilder.ClassProperty; procedure TPasSyntaxTreeBuilder.ClassReferenceType; begin - FStack.Push(ntType).SetAttribute(anType, AttributeValues[atClassof]); + FStack.Push(ntType).Attribute[anType]:= AttributeValues[atClass_of]; try inherited; finally @@ -881,7 +1116,7 @@ procedure TPasSyntaxTreeBuilder.ClassReferenceType; procedure TPasSyntaxTreeBuilder.ClassType; begin - FStack.Push(ntType).SetAttribute(anType, AttributeValues[atClass]); + FStack.Push(ntType).Attribute[anType]:= AttributeValues[atClass]; try inherited; finally @@ -916,7 +1151,7 @@ procedure TPasSyntaxTreeBuilder.MoveMembersToVisibilityNodes(TypeNode: TSyntaxNo procedure TPasSyntaxTreeBuilder.ConstParameter; begin - FStack.Push(ntParameters).SetAttribute(anKind, AttributeValues[atConst]); + FStack.Push(ntParameters).Attribute[anKind]:= AttributeValues[atConst]; try inherited; finally @@ -929,14 +1164,64 @@ procedure TPasSyntaxTreeBuilder.ConstructorName; Temp: TSyntaxNode; begin Temp := FStack.Peek; - Temp.SetAttribute(anKind, AttributeValues[atConstructor]); - Temp.SetAttribute(anName, Lexer.Token); + Temp.Attribute[anKind]:= AttributeValues[atConstructor]; + Temp.Attribute[anName]:= Lexer.Token; + inherited; +end; + +function TPasSyntaxTreeBuilder.GetMainSection(Node: TSyntaxNode): TSyntaxNode; +var + Temp: TSyntaxNode; +begin + If Node.Typ = ntUnknown then begin + //Get the next item on the stack. + Temp:= FStack.Pop; + Node:= FStack.Peek; + FStack.Push(Temp); + end; + if not(Assigned(Node.ParentNode)) then Exit(Node); //return the root node. + while Assigned(Node.ParentNode.ParentNode) do Node:= Node.ParentNode; + if (Node.ParentNode.Typ in [ntProgram, ntLibrary, ntPackage]) then Exit(Node.ParentNode); + Result:= Node; +end; + +procedure TPasSyntaxTreeBuilder.CompilerDirective; +var + Directive: string; + Node: TValuedSyntaxNode; + Part2: integer; + Root: TSyntaxNode; +begin + Directive:= Uppercase(Lexer.Token); + //Always place the compiler directive directly under the `ntInterface` or `ntImplementation` node + //or in the main section in a library, program or package. + Root:= GetMainSection(FStack.Peek); + Node:= TValuedSyntaxNode.Create(ntCompilerDirective); + AssignLexerPositionToNode(Lexer, Node); + Node.Value:= Directive; + Root.AddChild(Node); + //Parse the directive + if (Directive.StartsWith('(*$')) then begin + Delete(Directive, 1, 3); + StringReplace(Directive,'*)','}',[]); + end else begin + Delete(Directive, 1, 2); + end; + Part2:= 1; + while not CharInSet(Directive[Part2],[' ', '+', '-', '}']) do begin + Inc(Part2); + end; + Node.Attribute[anType]:= LeftStr(Directive, Part2-1); + Delete(Directive, 1, Part2-1); + Delete(Directive, Length(Directive), 1); + Directive:= Trim(Directive); + Node.Attribute[anKind]:= Directive; inherited; end; procedure TPasSyntaxTreeBuilder.CompoundStatement; begin - FStack.PushCompoundSyntaxNode(ntStatements); + FStack.PushCompoundSyntaxNode(ntStatements).Attribute[anKind]:= AttributeValues[atBegin]; try inherited; SetCurrentCompoundNodesEndPosition; @@ -975,7 +1260,8 @@ procedure TPasSyntaxTreeBuilder.CallInheritedConstantExpression; procedure TPasSyntaxTreeBuilder.ConstantName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntName).Attribute[anName]:= Lexer.Token; inherited; end; @@ -1016,7 +1302,7 @@ procedure TPasSyntaxTreeBuilder.ClassConstraint; inherited; finally FStack.Pop; - end; + end; end; procedure TPasSyntaxTreeBuilder.ConstructorConstraint; @@ -1026,7 +1312,17 @@ procedure TPasSyntaxTreeBuilder.ConstructorConstraint; inherited; finally FStack.Pop; - end; + end; +end; + +procedure TPasSyntaxTreeBuilder.RecordConstant; +begin + FStack.Push(ntRecordConstant); + try + inherited; + finally + FStack.Pop; + end; end; procedure TPasSyntaxTreeBuilder.RecordConstraint; @@ -1036,7 +1332,7 @@ procedure TPasSyntaxTreeBuilder.RecordConstraint; inherited; finally FStack.Pop; - end; + end; end; procedure TPasSyntaxTreeBuilder.ConstSection; @@ -1046,11 +1342,11 @@ procedure TPasSyntaxTreeBuilder.ConstSection; begin ConstSect := TSyntaxNode.Create(ntConstants); try - FStack.Push(ntConstants); + FStack.Push(ntConstants).Attribute[anKind]:= Lexer.Token; //resourcestring or const FStack.Push(ConstSect); try - inherited ConstSection; + inherited; finally FStack.Pop; end; @@ -1122,34 +1418,43 @@ procedure TPasSyntaxTreeBuilder.DestructorName; Temp: TSyntaxNode; begin Temp := FStack.Peek; - Temp.SetAttribute(anKind, AttributeValues[atDestructor]); - Temp.SetAttribute(anName, Lexer.Token); + Temp.Attribute[anKind]:= AttributeValues[atDestructor]; + Temp.Attribute[anName]:= Lexer.Token; + inherited; +end; + +procedure TPasSyntaxTreeBuilder.DirectiveAbstract; +begin + //anAbstract Attribute can contain either 'sealed' or 'abstract' or `final` + FStack.Peek.Attribute[anAbstract]:= Lexer.Token; inherited; end; procedure TPasSyntaxTreeBuilder.DirectiveBinding; var - token: string; + Token: string; begin token := Lexer.Token; // Method bindings: - if SameText(token, 'override') or SameText(token, 'virtual') - or SameText(token, 'dynamic') + if SameText(Token, 'override') or SameText(token, 'virtual') + or SameText(Token, 'dynamic') or SameText(Token, 'static') then - FStack.Peek.SetAttribute(anMethodBinding, token) + FStack.Peek.Attribute[anMethodBinding]:= Token // Other directives else if SameText(token, 'reintroduce') then - FStack.Peek.SetAttribute(anReintroduce, AttributeValues[atTrue]) - else if SameText(token, 'overload') then - FStack.Peek.SetAttribute(anOverload, AttributeValues[atTrue]) - else if SameText(token, 'abstract') then - FStack.Peek.SetAttribute(anAbstract, AttributeValues[atTrue]); + FStack.Peek.Attribute[anReintroduce]:= AttributeValues[atTrue] + else if SameText(Token, 'overload') then + FStack.Peek.Attribute[anOverload]:= AttributeValues[atTrue] + else if SameText(Token, 'abstract') or SameText(Token, 'final') then + FStack.Peek.Attribute[anAbstract]:= Token; inherited; end; procedure TPasSyntaxTreeBuilder.DirectiveBindingMessage; begin + //message is a method binding directive, for correctness we should record this. + FStack.Peek.Attribute[anMethodBinding]:= 'message'; FStack.Push(ntMessage); try inherited; @@ -1160,19 +1465,78 @@ procedure TPasSyntaxTreeBuilder.DirectiveBindingMessage; procedure TPasSyntaxTreeBuilder.DirectiveCalling; begin - FStack.Peek.SetAttribute(anCallingConvention, Lexer.Token); + FStack.Peek.Attribute[anCallingConvention]:= Lexer.Token; inherited; end; +procedure TPasSyntaxTreeBuilder.DirectiveDeprecated; +begin + FStack.Push(ntDeprecated); + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.DirectiveExperimental; +begin + FStack.Push(ntExperimental); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.DirectiveInline; begin - FStack.Peek.SetAttribute(anInline, AttributeValues[atTrue]); + //'inline' and 'assembler' are both inline directives. + FStack.Peek.Attribute[anInline]:= Lexer.Token; inherited; end; +procedure TPasSyntaxTreeBuilder.DirectiveLibrary; +begin + FStack.Push(ntLibrary); + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.DirectivePlatForm; +begin + FStack.Push(ntPlatform); + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.DirectiveSealed; +begin + //hack, must go to a better attributeType, however sealed, abstract cannot coexist + //Perhaps sealed, abstract and final should all share a attribute type called anInheritance + FStack.Peek.Attribute[anAbstract]:= Lexer.Token; + inherited; +end; + +procedure TPasSyntaxTreeBuilder.DirectiveVarargs; +begin + FStack.Push(ntExternal).Attribute[anKind]:= AttributeValues[atVarArgs]; + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.DispInterfaceForward; begin - FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]); + FStack.Peek.Attribute[anForwarded]:= AttributeValues[atTrue]; inherited; end; @@ -1182,6 +1546,16 @@ procedure TPasSyntaxTreeBuilder.DotOp; inherited; end; +procedure TPasSyntaxTreeBuilder.DoubleAddressOp; +begin + FStack.Push(ntDoubleAddr); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.ElseStatement; begin FStack.Push(ntElse); @@ -1208,9 +1582,9 @@ procedure TPasSyntaxTreeBuilder.EnumeratedType; begin TypeNode := FStack.Push(ntType); try - TypeNode.SetAttribute(anName, AttributeValues[atEnum]); + TypeNode.Attribute[anType]:= AttributeValues[atEnum]; if ScopedEnums then - TypeNode.SetAttribute(anVisibility, 'scoped'); + TypeNode.Attribute[anVisibility]:= 'scoped'; inherited; finally FStack.Pop; @@ -1229,7 +1603,7 @@ procedure TPasSyntaxTreeBuilder.ExceptBlock; procedure TPasSyntaxTreeBuilder.ExceptionBlockElseBranch; begin - FStack.Push(ntElse); + FStack.Push(ntExceptElse); //#223 try inherited; finally @@ -1250,7 +1624,8 @@ procedure TPasSyntaxTreeBuilder.ExceptionHandler; procedure TPasSyntaxTreeBuilder.ExceptionVariable; begin FStack.Push(ntVariable); - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntName).Attribute[anName]:= Lexer.Token; try inherited; finally @@ -1258,6 +1633,12 @@ procedure TPasSyntaxTreeBuilder.ExceptionVariable; end; end; +procedure TPasSyntaxTreeBuilder.ExplicitType; //#220+#181 +begin + FStack.Peek.Attribute[anKind]:= AttributeValues[atType]; + inherited; +end; + procedure TPasSyntaxTreeBuilder.ExportedHeading; begin FStack.PushCompoundSyntaxNode(ntMethod); @@ -1302,7 +1683,7 @@ procedure TPasSyntaxTreeBuilder.ExportsName; FStack.Pop; end; - FStack.Peek.SetAttribute(anName, NodeListToString(NamesNode)); + FStack.Peek.Attribute[anName]:= NodeListToString(NamesNode); finally NamesNode.Free; end; @@ -1310,7 +1691,7 @@ procedure TPasSyntaxTreeBuilder.ExportsName; procedure TPasSyntaxTreeBuilder.ExportsNameId; begin - FStack.AddChild(ntUnknown).SetAttribute(anName, Lexer.Token); + FStack.AddChild(ntUnknown).Attribute[anName]:= Lexer.Token; inherited; end; @@ -1352,9 +1733,19 @@ procedure TPasSyntaxTreeBuilder.ExpressionList; end; end; +procedure TPasSyntaxTreeBuilder.ExternalDependency; +begin + FStack.Push(ntDependency); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.ExternalDirective; begin - FStack.Push(ntExternal); + FStack.Push(ntExternal).Attribute[anKind]:= AttributeValues[atExternal]; try inherited; finally @@ -1362,9 +1753,52 @@ procedure TPasSyntaxTreeBuilder.ExternalDirective; end; end; +procedure TPasSyntaxTreeBuilder.FieldList; +var + Fields, Temp: TSyntaxNode; + Field, TypeInfo, TypeArgs: TSyntaxNode; + IsClassVarSection: boolean; +begin + IsClassVarSection:= FStack.Peek.HasAttribute(anClass); + Fields := TSyntaxNode.Create(ntFields); + try + FStack.Push(Fields); + try + inherited; + finally + FStack.Pop; + end; + + TypeInfo := Fields.FindNode(ntType); + TypeArgs := Fields.FindNode(ntTypeArgs); + for Field in Fields.ChildNodes do + begin + if Field.Typ <> ntName then + Continue; + + Temp := FStack.Push(ntField); + if (IsClassVarSection) then Temp.Attribute[anClass]:= AttributeValues[atTrue]; + try + Temp.AssignPositionFrom(Field); + + FStack.AddChild(Field.Clone); + TypeInfo := TypeInfo.Clone; + if Assigned(TypeArgs) then + TypeInfo.AddChild(TypeArgs.Clone); + FStack.AddChild(TypeInfo); + finally + FStack.Pop; + end; + end; + finally + Fields.Free; + end; +end; + procedure TPasSyntaxTreeBuilder.FieldName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntname).Attribute[anName]:= Lexer.Token; inherited; end; @@ -1376,7 +1810,7 @@ procedure TPasSyntaxTreeBuilder.FinalizationSection; SetCurrentCompoundNodesEndPosition; finally FStack.Pop; - end; + end; end; procedure TPasSyntaxTreeBuilder.FinallyBlock; @@ -1447,61 +1881,61 @@ procedure TPasSyntaxTreeBuilder.ForStatementTo; end; end; +procedure TPasSyntaxTreeBuilder.ForwardDeclaration; +begin + if FStack.Peek.ParentNode.Typ = ntImplementation then begin //#166 + FStack.Peek.Attribute[anForwarded]:= AttributeValues[atTrue]; + end; + inherited; +end; + procedure TPasSyntaxTreeBuilder.FunctionHeading; begin - FStack.Peek.SetAttribute(anKind, AttributeValues[atFunction]); + FStack.Peek.Attribute[anKind]:= AttributeValues[atFunction]; inherited; end; procedure TPasSyntaxTreeBuilder.FunctionMethodName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntName).Attribute[anName]:= Lexer.Token; inherited; end; -procedure TPasSyntaxTreeBuilder.FunctionProcedureName; +procedure TPasSyntaxTreeBuilder.FunctionProcedureName; //#221 record method type params explicitly, keep the full name as well. var - ChildNode, NameNode, TypeParam, TypeNode, Temp: TSyntaxNode; - FullName, TypeParams: string; -begin - FStack.Push(ntName); - NameNode := FStack.Peek; - try - inherited; - for ChildNode in NameNode.ChildNodes do - begin - if ChildNode.Typ = ntTypeParams then - begin - TypeParams := ''; - - for TypeParam in ChildNode.ChildNodes do - begin - TypeNode := TypeParam.FindNode(ntType); - if Assigned(TypeNode) then - begin - if TypeParams <> '' then - TypeParams := TypeParams + ','; - TypeParams := TypeParams + TypeNode.GetAttribute(anName); - end; - end; - - FullName := FullName + '<' + TypeParams + '>'; - Continue; - end; - - if FullName <> '' then - FullName := FullName + '.'; - FullName := FullName + TValuedSyntaxNode(ChildNode).Value; - end; - finally - FStack.Pop; - Temp := FStack.Peek; - DoHandleString(FullName); - Temp.SetAttribute(anName, FullName); - Temp.DeleteChild(NameNode); - end; + ChildNode, NameNode, TypeParam: TSyntaxNode; + FullName, Dot, Comma: string; +begin + //Temp:= FStack.Peek; + NameNode:= FStack.Push(ntName); + try + inherited; + finally + FStack.Pop; + end; + //Traverse the name node and reconstruct the full name + Assert(NameNode.HasChildren); + Dot:= ''; + for ChildNode in NameNode.ChildNodes do begin + case ChildNode.Typ of + ntName: begin + FullName:= Fullname + Dot + ChildNode.Attribute[anName]; + Dot:= '.'; + end; {ntName} + ntTypeParams: begin + Comma:= ''; + Fullname:= Fullname + '<'; + for TypeParam in ChildNode.ChildNodes do begin + FullName:= FullName + Comma + TypeParam.FindNode(ntType).Attribute[anName]; + Comma:= ','; + end; {for} + Fullname:= Fullname + '>'; + end; {ntTypeParams:} + end; {case} + end; {for ChildNode} + NameNode.Attribute[anName]:= FullName; end; - procedure TPasSyntaxTreeBuilder.GotoStatement; begin FStack.Push(ntGoto); @@ -1514,7 +1948,7 @@ procedure TPasSyntaxTreeBuilder.GotoStatement; procedure TPasSyntaxTreeBuilder.Identifier; begin - FStack.AddChild(ntIdentifier).SetAttribute(anName, Lexer.Token); + FStack.AddChild(ntIdentifier).Attribute[anName]:= Lexer.Token; inherited; end; @@ -1597,12 +2031,12 @@ procedure TPasSyntaxTreeBuilder.InitializationSection; SetCurrentCompoundNodesEndPosition; finally FStack.Pop; - end; + end; end; procedure TPasSyntaxTreeBuilder.InterfaceForward; begin - FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]); + FStack.Peek.Attribute[anForwarded]:= AttributeValues[atTrue]; inherited InterfaceForward; end; @@ -1630,22 +2064,60 @@ procedure TPasSyntaxTreeBuilder.InterfaceSection; procedure TPasSyntaxTreeBuilder.InterfaceType; begin case TokenID of - ptInterface: - FStack.Push(ntType).SetAttribute(anType, AttributeValues[atInterface]); - ptDispInterface: - FStack.Push(ntType).SetAttribute(anType, AttributeValues[atDispInterface]); + ptInterface: FStack.Push(ntType).SetAttribute(anType, AttributeValues[atInterface]); + ptDispInterface: FStack.Push(ntType).SetAttribute(anType, AttributeValues[atDispInterface]); + end; {case} + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.LabeledStatement; +var + Node, Name: TSyntaxNode; +begin + Node:= FStack.Push(ntLabeledStatement); + Name:= Node.AddChild(ntName); + Name.Attribute[anName]:= Lexer.Token; + try + inherited; + finally + FStack.Pop; end; +end; + +procedure TPasSyntaxTreeBuilder.LabelDeclarationSection; +begin + FStack.Push(ntLabel); try inherited; finally FStack.Pop; end; end; + procedure TPasSyntaxTreeBuilder.LabelId; +var + Node, Name: TSyntaxNode; +begin + FStack.Push(ntName).Attribute[anName]:= Lexer.Token; + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.LibraryFile; begin - FStack.AddValuedChild(ntLabel, Lexer.Token); + //Assert(FStack.Peek.ParentNode = nil); + FStack.Push(TSyntaxNode.Create(ntLibrary)); + AssignLexerPositionToNode(Lexer, FStack.Peek); inherited; + //Stack.pop is done in `Run` end; procedure TPasSyntaxTreeBuilder.MainUsedUnitStatement; @@ -1661,7 +2133,7 @@ procedure TPasSyntaxTreeBuilder.MainUsedUnitStatement; if Assigned(NameNode) then begin Temp := FStack.Peek; - Temp.SetAttribute(anName, NameNode.GetAttribute(anName)); + Temp.Attribute[anName]:= NameNode.Attribute[anName]; Temp.DeleteChild(NameNode); end; @@ -1673,7 +2145,7 @@ procedure TPasSyntaxTreeBuilder.MainUsedUnitStatement; PathLiteralNode := PathNode.FindNode(ntLiteral); if PathLiteralNode is TValuedSyntaxNode then - FStack.Peek.SetAttribute(anPath, TValuedSyntaxNode(PathLiteralNode).Value); + FStack.Peek.Attribute[anPath]:= TValuedSyntaxNode(PathLiteralNode).Value; finally PathNode.Free; end; @@ -1698,9 +2170,8 @@ procedure TPasSyntaxTreeBuilder.MethodKind; var value: string; begin - value := LowerCase(Lexer.Token); DoHandleString(value); - FStack.Peek.SetAttribute(anKind, value); + FStack.Peek.Attribute[anKind]:= Lexer.Token; inherited; end; @@ -1738,9 +2209,22 @@ procedure TPasSyntaxTreeBuilder.NamedArgument; end; end; +procedure TPasSyntaxTreeBuilder.NameSpecifier; +begin + FStack.Push(ntExternalName); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.NilToken; +var + Node: TSyntaxNode; begin - FStack.AddChild(ntLiteral).SetAttribute(anType, AttributeValues[atNil]); + Node:= FStack.AddValuedChild(ntLiteral, AttributeValues[atNil]); + Node.Attribute[anType]:= AttributeValues[atNil]; inherited; end; @@ -1755,16 +2239,34 @@ procedure TPasSyntaxTreeBuilder.Number; Node: TSyntaxNode; begin Node := FStack.AddValuedChild(ntLiteral, Lexer.Token); - Node.SetAttribute(anType, AttributeValues[atNumeric]); + Node.Attribute[anType]:= AttributeValues[atNumeric]; + inherited; +end; + +procedure TPasSyntaxTreeBuilder.ObjectForward; +begin + FStack.Peek.Attribute[anForwarded]:= AttributeValues[atTrue]; + FStack.Peek.Attribute[anType]:= AttributeValues[atObject]; inherited; end; procedure TPasSyntaxTreeBuilder.ObjectNameOfMethod; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntName).Attribute[anName]:= Lexer.Token; inherited; end; +procedure TPasSyntaxTreeBuilder.ObjectType; +begin + FStack.Push(ntType).Attribute[anType]:= AttributeValues[atObject]; + try + inherited; + finally + MoveMembersToVisibilityNodes(FStack.Pop); + end; +end; + procedure TPasSyntaxTreeBuilder.DoOnComment(Sender: TObject; const Text: string); var Node: TCommentNode; @@ -1792,7 +2294,7 @@ procedure TPasSyntaxTreeBuilder.ParserMessage(Sender: TObject; procedure TPasSyntaxTreeBuilder.OutParameter; begin - FStack.Push(ntParameters).SetAttribute(anKind, AttributeValues[atOut]); + FStack.Push(ntParameters).Attribute[anKind]:= AttributeValues[atOut]; try inherited; finally @@ -1800,6 +2302,15 @@ procedure TPasSyntaxTreeBuilder.OutParameter; end; end; +procedure TPasSyntaxTreeBuilder.PackageFile; +begin + //Assert(FStack.Peek.ParentNode = nil); + FStack.Push(TSyntaxNode.Create(ntPackage)); + AssignLexerPositionToNode(Lexer, FStack.Peek); + inherited; + //Stack.pop is done in `Run` +end; + procedure TPasSyntaxTreeBuilder.ParameterFormal; begin FStack.Push(ntParameters); @@ -1812,7 +2323,8 @@ procedure TPasSyntaxTreeBuilder.ParameterFormal; procedure TPasSyntaxTreeBuilder.ParameterName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntname).Attribute[anName]:= Lexer.Token; inherited; end; @@ -1824,7 +2336,7 @@ procedure TPasSyntaxTreeBuilder.PointerSymbol; procedure TPasSyntaxTreeBuilder.PointerType; begin - FStack.Push(ntType).SetAttribute(anType, AttributeValues[atPointer]); + FStack.Push(ntType).Attribute[anType]:= AttributeValues[atPointer]; try inherited; finally @@ -1842,9 +2354,20 @@ procedure TPasSyntaxTreeBuilder.PositionalArgument; end; end; +procedure TPasSyntaxTreeBuilder.ProceduralDirectiveOf; +begin + //anType is already used for set/enum/subrange/class/record/interface/object. + //It could be reused for this data, but it's a directive, not a type as such. + //And it's to close to `object` proper. + //It should not be a subnode, because only 'of object' is allowed. + FStack.Peek.Attribute[anKind]:= AttributeValues[atOf_Object]; + inherited; +end; + procedure TPasSyntaxTreeBuilder.ProceduralType; begin - FStack.Push(ntType).SetAttribute(anName, Lexer.Token); + //procedure/function is a reserved word, so it cannot be the same as an identifier. + FStack.Push(ntType).Attribute[anType]:= Lexer.Token; try inherited; finally @@ -1865,19 +2388,28 @@ procedure TPasSyntaxTreeBuilder.ProcedureDeclarationSection; procedure TPasSyntaxTreeBuilder.ProcedureHeading; begin - FStack.Peek.SetAttribute(anKind, AttributeValues[atProcedure]); + FStack.Peek.Attribute[anKind]:= AttributeValues[atProcedure]; inherited; end; procedure TPasSyntaxTreeBuilder.ProcedureProcedureName; begin - FStack.Peek.SetAttribute(anName, Lexer.Token); + //FStack.Peek.Attribute[anName, Lexer.Token); + inherited; +end; + +procedure TPasSyntaxTreeBuilder.ProgramFile; +begin + //Assert(FStack.Peek.ParentNode = nil); + FStack.Push(TSyntaxNode.Create(ntProgram)); + AssignLexerPositionToNode(Lexer, FStack.Peek); inherited; + //Stack.pop is done in `Run` end; procedure TPasSyntaxTreeBuilder.PropertyName; begin - FStack.Peek.SetAttribute(anName, Lexer.Token); + FStack.Peek.Attribute[anName]:= Lexer.Token; inherited PropertyName; end; @@ -1900,12 +2432,18 @@ procedure TPasSyntaxTreeBuilder.RaiseStatement; end; procedure TPasSyntaxTreeBuilder.RecordFieldConstant; -var - Node: TSyntaxNode; begin - Node := FStack.PushValuedNode(ntField, Lexer.Token); + //A field in a record constant should have exactly the same layout + //as a field in a class. + //ntField (class) + //+-- ntName (anName = name) + //+-- ntType + //Recordconstant + //ntField (recordconstant) + //+-- ntName + //+-- ntExpression. + FStack.Push(ntField).AddChild(ntName).Attribute[anName]:= Lexer.Token; try - Node.SetAttribute(anType, AttributeValues[atName]); inherited; finally FStack.Pop; @@ -1979,7 +2517,7 @@ procedure TPasSyntaxTreeBuilder.RequiresIdentifier; FStack.Pop; end; - FStack.AddChild(ntPackage).SetAttribute(anName, NodeListToString(NamesNode)); + FStack.AddChild(ntPackage).Attribute[anName]:= NodeListToString(NamesNode); finally NamesNode.Free; end; @@ -1987,10 +2525,20 @@ procedure TPasSyntaxTreeBuilder.RequiresIdentifier; procedure TPasSyntaxTreeBuilder.RequiresIdentifierId; begin - FStack.AddChild(ntUnknown).SetAttribute(anName, Lexer.Token); + FStack.AddChild(ntUnknown).Attribute[anName]:= Lexer.Token; inherited; end; +procedure TPasSyntaxTreeBuilder.Resident; +begin + FStack.Push(ntResident); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.ResourceDeclaration; begin FStack.Push(ntResourceString); @@ -2060,21 +2608,21 @@ class function TPasSyntaxTreeBuilder.Run(const FileName: string; function TPasSyntaxTreeBuilder.Run(SourceStream: TStream): TSyntaxNode; begin - Result := TSyntaxNode.Create(ntUnit); + Result:= nil; try FStack.Clear; - FStack.Push(Result); try self.OnMessage := ParserMessage; inherited Run('', SourceStream); finally + Result:= FStack.Peek; FStack.Pop; end; except on E: EParserException do raise ESyntaxTreeException.Create(E.Line, E.Col, Lexer.FileName, E.Message, Result); - on E: ESyntaxError do - raise ESyntaxTreeException.Create(E.PosXY.X, E.PosXY.Y, Lexer.FileName, E.Message, Result); + on E: ESyntaxError do + raise ESyntaxTreeException.Create(E.PosXY.X, E.PosXY.Y, Lexer.FileName, E.Message, Result); else FreeAndNil(Result); raise; @@ -2090,9 +2638,10 @@ function TPasSyntaxTreeBuilder.NodeListToString(NamesNode: TSyntaxNode): string; Result := ''; for NamePartNode in NamesNode.ChildNodes do begin - if Result <> '' then + //do not add empty parts (in case non-name and name node are mixed. + if (Result <> '') then Result := Result + '.'; - Result := Result + NamePartNode.GetAttribute(anName); + Result:= Result + NamePartNode.Attribute[anName]; end; DoHandleString(Result); end; @@ -2214,7 +2763,7 @@ procedure TPasSyntaxTreeBuilder.SimpleStatement; procedure TPasSyntaxTreeBuilder.SimpleType; begin - FStack.Push(ntType).SetAttribute(anName, Lexer.Token); + FStack.Push(ntType).Attribute[anName]:= Lexer.Token; try inherited; finally @@ -2267,25 +2816,25 @@ procedure TPasSyntaxTreeBuilder.StringConst; DoHandleString(Str); Node := FStack.AddValuedChild(ntLiteral, Str); - Node.SetAttribute(anType, AttributeValues[atString]); + Node.Attribute[anType]:= AttributeValues[atString]; end; procedure TPasSyntaxTreeBuilder.StringConstSimple; begin //TODO support ptAsciiChar - FStack.AddValuedChild(ntLiteral, AnsiDequotedStr(Lexer.Token, '''')); + FStack.AddValuedChild(ntLiteral, {AnsiDequotedStr(}Lexer.Token{, '''')}); inherited; end; procedure TPasSyntaxTreeBuilder.StringStatement; begin - FStack.AddChild(ntType).SetAttribute(anName, Lexer.Token); + FStack.AddChild(ntType).Attribute[anName]:= Lexer.Token; inherited; end; procedure TPasSyntaxTreeBuilder.StructuredType; begin - FStack.Push(ntType).SetAttribute(anType, Lexer.Token); + FStack.Push(ntType).Attribute[anType]:= Lexer.Token; try inherited; finally @@ -2295,7 +2844,39 @@ procedure TPasSyntaxTreeBuilder.StructuredType; procedure TPasSyntaxTreeBuilder.SubrangeType; begin - FStack.Push(ntType).SetAttribute(anName, AttributeValues[atSubRange]); + FStack.Push(ntType).Attribute[anType]:= AttributeValues[atSubRange]; + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.TagField; +var + TagNode: TSyntaxNode; + TypeNode: TSyntaxNode; +begin + TagNode:= FStack.Push(ntCaseSelector); + TagNode.Attribute[anKind]:= Lexer.Token; + try + inherited; + TypeNode:= FStack.Peek.FindNode(ntIdentifier); + if (Assigned(TypeNode)) then begin + //move the name to the correct pos. + TagNode.Attribute[anName]:= TagNode.Attribute[anKind]; + //Fill in the type of te node + TagNode.Attribute[anKind]:= TypeNode.Attribute[anKind]; + TagNode.DeleteChild(TypeNode); + end; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.TagFieldTypeName; +begin + FStack.Push(ntIdentifier).Attribute[anKind]:= Lexer.Token; try inherited; finally @@ -2335,13 +2916,13 @@ procedure TPasSyntaxTreeBuilder.TypeArgs; procedure TPasSyntaxTreeBuilder.TypeDeclaration; begin - FStack.PushCompoundSyntaxNode(ntTypeDecl).SetAttribute(anName, Lexer.Token); + FStack.PushCompoundSyntaxNode(ntTypeDecl).Attribute[anName]:= Lexer.Token; try inherited; SetCurrentCompoundNodesEndPosition; finally FStack.Pop; - end; + end; end; procedure TPasSyntaxTreeBuilder.TypeId; @@ -2352,19 +2933,19 @@ procedure TPasSyntaxTreeBuilder.TypeId; begin TypeNode := FStack.Push(ntType); try - inherited; - + inherited; + InnerTypeName := ''; - InnerTypeNode := TypeNode.FindNode(ntType); + InnerTypeNode := TypeNode.FindNode(ntType); if Assigned(InnerTypeNode) then begin - InnerTypeName := InnerTypeNode.GetAttribute(anName); - for SubNode in InnerTypeNode.ChildNodes do + InnerTypeName := InnerTypeNode.Attribute[anName]; + for SubNode in InnerTypeNode.ChildNodes do TypeNode.AddChild(SubNode.Clone); - + TypeNode.DeleteChild(InnerTypeNode); - end; - + end; + TypeName := ''; for i := Length(TypeNode.ChildNodes) - 1 downto 0 do begin @@ -2373,18 +2954,18 @@ procedure TPasSyntaxTreeBuilder.TypeId; begin if TypeName <> '' then TypeName := '.' + TypeName; - - TypeName := SubNode.GetAttribute(anName) + TypeName; + + TypeName := SubNode.Attribute[anName] + TypeName; TypeNode.DeleteChild(SubNode); - end; + end; end; - + if TypeName <> '' then - TypeName := '.' + TypeName; - TypeName := InnerTypeName + TypeName; - + TypeName := '.' + TypeName; + TypeName := InnerTypeName + TypeName; + DoHandleString(TypeName); - TypeNode.SetAttribute(anName, TypeName); + TypeNode.Attribute[anName]:= TypeName; finally FStack.Pop; end; @@ -2456,7 +3037,7 @@ procedure TPasSyntaxTreeBuilder.TypeSection; procedure TPasSyntaxTreeBuilder.TypeSimple; begin - FStack.Push(ntType).SetAttribute(anName, Lexer.Token); + FStack.Push(ntType).Attribute[anName]:= Lexer.Token; try inherited; finally @@ -2471,17 +3052,17 @@ procedure TPasSyntaxTreeBuilder.UnaryMinus; end; procedure TPasSyntaxTreeBuilder.UnitFile; -var - Temp: TSyntaxNode; begin - Temp := FStack.Peek; - AssignLexerPositionToNode(Lexer, Temp); + //Assert(FStack.Peek.ParentNode = nil); + FStack.Push(TSyntaxNode.Create(ntUnit)); + AssignLexerPositionToNode(Lexer, FStack.Peek); inherited; + //Stack.pop is done in `Run` end; procedure TPasSyntaxTreeBuilder.UnitId; begin - FStack.AddChild(ntUnknown).SetAttribute(anName, Lexer.Token); + FStack.AddChild(ntUnknown).Attribute[anName]:= Lexer.Token; inherited; end; @@ -2498,7 +3079,7 @@ procedure TPasSyntaxTreeBuilder.UnitName; FStack.Pop; end; - FStack.Peek.SetAttribute(anName, NodeListToString(NamesNode)); + FStack.Peek.Attribute[anName]:= NodeListToString(NamesNode); finally NamesNode.Free; end; @@ -2513,7 +3094,7 @@ procedure TPasSyntaxTreeBuilder.UsedUnitName; Position := Lexer.PosXY; FileName := Lexer.FileName; - NamesNode := TSyntaxNode.Create(ntUnit); + NamesNode:= TSyntaxNode.Create(ntUnit); try FStack.Push(NamesNode); try @@ -2523,7 +3104,7 @@ procedure TPasSyntaxTreeBuilder.UsedUnitName; end; UnitNode := FStack.AddChild(ntUnit); - UnitNode.SetAttribute(anName, NodeListToString(NamesNode)); + UnitNode.Attribute[anName]:= NodeListToString(NamesNode); UnitNode.Col := Position.X; UnitNode.Line := Position.Y; UnitNode.FileName := FileName; @@ -2543,6 +3124,24 @@ procedure TPasSyntaxTreeBuilder.UsesClause; end; end; +procedure TPasSyntaxTreeBuilder.VarAbsolute; +var + AbsoluteNode: TSyntaxNode; + ValueNode: TSyntaxNode; +begin + AbsoluteNode:= TSyntaxNode.Create(ntUnknown); + FStack.Push(AbsoluteNode); + try + inherited; + finally + FStack.Pop; + ValueNode:= AbsoluteNode.ExtractChild(AbsoluteNode.ChildNode[0]); + ValueNode.Attribute[anKind]:= AttributeValues[atAbsolute]; + AbsoluteNode.Free; + FStack.Peek.AddChild(ValueNode); + end; +end; + procedure TPasSyntaxTreeBuilder.VarDeclaration; begin FStack.Push(ntVariables); @@ -2553,15 +3152,46 @@ procedure TPasSyntaxTreeBuilder.VarDeclaration; end; end; +procedure TPasSyntaxTreeBuilder.RecordVariantSection; +begin + FStack.Push(ntVariantSection); + try + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.RecordVariantTag; +var + Temp: TSyntaxNode; +begin + Temp:= FStack.Push(ntVariantTag); + try + inherited; + if Temp.ChildCount = 2 then begin + Temp.Attribute[anName]:= Temp.ChildNode[0].Attribute[anName]; + Temp.Attribute[anType]:= Temp.ChildNode[1].Attribute[anName]; + Temp.DeleteChild(Temp.ChildNode[1]); + end else begin + Temp.Attribute[anType]:= Temp.ChildNode[0].Attribute[anName]; + end; + Temp.DeleteChild(Temp.ChildNode[0]); + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.VarName; begin - FStack.AddValuedChild(ntName, Lexer.Token); + //FStack.AddValuedChild(ntName, Lexer.Token); + FStack.AddChild(ntName).Attribute[anName]:= Lexer.Token; //#222 inherited; end; procedure TPasSyntaxTreeBuilder.VarParameter; begin - FStack.Push(ntParameters).SetAttribute(anKind, AttributeValues[atVar]); + FStack.Push(ntParameters).Attribute[anKind]:= AttributeValues[atVar]; try inherited; finally @@ -2622,7 +3252,7 @@ procedure TPasSyntaxTreeBuilder.VisibilityStrictPrivate; begin Temp := FStack.Push(ntStrictPrivate); try - Temp.SetAttribute(anVisibility, AttributeValues[atTrue]); + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; inherited; finally FStack.Pop; @@ -2635,7 +3265,7 @@ procedure TPasSyntaxTreeBuilder.VisibilityPrivate; begin Temp := FStack.Push(ntPrivate); try - Temp.SetAttribute(anVisibility, AttributeValues[atTrue]); + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; inherited; finally FStack.Pop; @@ -2648,7 +3278,7 @@ procedure TPasSyntaxTreeBuilder.VisibilityStrictProtected; begin Temp := FStack.Push(ntStrictProtected); try - Temp.SetAttribute(anVisibility, AttributeValues[atTrue]); + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; inherited; finally FStack.Pop; @@ -2661,7 +3291,7 @@ procedure TPasSyntaxTreeBuilder.VisibilityProtected; begin Temp := FStack.Push(ntProtected); try - Temp.SetAttribute(anVisibility, AttributeValues[atTrue]); + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; inherited; finally FStack.Pop; @@ -2674,7 +3304,7 @@ procedure TPasSyntaxTreeBuilder.VisibilityPublic; begin Temp := FStack.Push(ntPublic); try - Temp.SetAttribute(anVisibility, AttributeValues[atTrue]); + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; inherited; finally FStack.Pop; @@ -2687,7 +3317,20 @@ procedure TPasSyntaxTreeBuilder.VisibilityPublished; begin Temp := FStack.Push(ntPublished); try - Temp.SetAttribute(anVisibility, AttributeValues[atTrue]); + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; + inherited; + finally + FStack.Pop; + end; +end; + +procedure TPasSyntaxTreeBuilder.VisibilityAutomated; +var + Temp: TSyntaxNode; +begin + Temp := FStack.Push(ntAutomated); + try + Temp.Attribute[anVisibility]:= AttributeValues[atTrue]; inherited; finally FStack.Pop; @@ -2741,5 +3384,4 @@ destructor ESyntaxTreeException.Destroy; initialization InitAttributeValues; - end. \ No newline at end of file diff --git a/Source/SimpleParser/SimpleParser.Lexer.Types.pas b/Source/SimpleParser/SimpleParser.Lexer.Types.pas index 97de26a1..81d05823 100644 --- a/Source/SimpleParser/SimpleParser.Lexer.Types.pas +++ b/Source/SimpleParser/SimpleParser.Lexer.Types.pas @@ -56,6 +56,7 @@ interface ptAddressOp, ptAmpersand, ptAnd, + ptAnsiChar, ptAnsiComment, ptAnsiString, ptArray, @@ -96,6 +97,7 @@ interface ptDefault, ptDefineDirect, ptDeprecated, + ptDependency, //for external declarations ptDestructor, ptDispid, ptDispinterface, @@ -248,7 +250,9 @@ interface ptTo, ptTry, ptType, + ptUInt64, ptUndefDirect, + ptUnicodeString, ptUnit, ptUnknown, ptUnsafe, @@ -285,6 +289,14 @@ EIncludeError = class(Exception); function GetIncludeFileContent(const FileName: string): string; end; + const + ReservedWords = [ptAnd, ptEnd, ptInterface, ptrecord, ptvar,ptarray,ptexcept,ptis,ptrepeat,ptwhile,ptas,ptexports, + ptlabel,ptresourcestring, ptwith,ptasm,ptfile,ptlibrary,ptset,ptxor,ptbegin,ptfinalization, + ptmod,ptshl,ptcase,ptfinally,ptnil,ptshr,ptclass,ptfor,ptnot,ptstring,ptconst,ptfunction,ptobject, + ptthen,ptconstructor,ptgoto,ptof,ptthreadvar,ptdestructor,ptif,ptor,ptto,ptdispinterface, + ptimplementation,ptpacked,pttry,ptdiv,ptin,ptprocedure,pttype,ptdo,ptinherited,ptprogram, + ptunit,ptdownto,ptinitialization,ptproperty,ptuntil,ptelse,ptinline,ptraise,ptuses]; + function TokenName(Value: TptTokenKind): string; function ptTokenName(Value: TptTokenKind): string; function IsTokenIDJunk(const aTokenID: TptTokenKind): Boolean; diff --git a/Source/SimpleParser/SimpleParser.Lexer.pas b/Source/SimpleParser/SimpleParser.Lexer.pas index 0ae2b60a..63cb29af 100644 --- a/Source/SimpleParser/SimpleParser.Lexer.pas +++ b/Source/SimpleParser/SimpleParser.Lexer.pas @@ -212,6 +212,7 @@ TmwBasePasLex = class(TObject) function Func141: TptTokenKind; function Func142: TptTokenKind; function Func143: TptTokenKind; + function Func158: TptTokenKind; function Func166: TptTokenKind; function Func167: TptTokenKind; function Func168: TptTokenKind; @@ -279,9 +280,9 @@ TmwBasePasLex = class(TObject) procedure CloneDefinesFrom(ALexer: TmwBasePasLex); procedure DoProcTable(AChar: Char); function IsIdentifiers(AChar: Char): Boolean; inline; - function HashValue(AChar: Char): Integer; + function HashValue(AChar: Char): Integer; inline; function EvaluateComparison(AValue1: Extended; const AOper: String; AValue2: Extended): Boolean; - function EvaluateConditionalExpression(const AParams: String): Boolean; + function EvaluateConditionalExpression(const AParams: String; StartResult: boolean = false): Boolean; procedure IncludeFile; function GetIncludeFileNameFromToken(const IncludeToken: string): string; function GetOrigin: string; @@ -291,6 +292,7 @@ TmwBasePasLex = class(TObject) procedure DisposeBuffer(Buf: PBufferRec); function GetFileName: string; procedure UpdateScopedEnums; + function GetIsJunkAssembly: Boolean; procedure DoOnComment(const CommentText: string); protected procedure SetOrigin(const NewValue: string); virtual; @@ -300,6 +302,7 @@ TmwBasePasLex = class(TObject) function CharAhead: Char; procedure Next; procedure NextNoJunk; + procedure NextNoJunkAssembly; procedure NextNoSpace; procedure Init; procedure InitFrom(ALexer: TmwBasePasLex); @@ -308,6 +311,7 @@ TmwBasePasLex = class(TObject) procedure AddDefine(const ADefine: string); procedure RemoveDefine(const ADefine: string); function IsDefined(const ADefine: string): Boolean; + function IsDeclared(const ADefine: string): Boolean; procedure ClearDefines; procedure InitDefinesDefinedByCompiler; @@ -315,6 +319,7 @@ TmwBasePasLex = class(TObject) property CompilerDirective: string read GetCompilerDirective; property DirectiveParam: string read GetDirectiveParam; property IsJunk: Boolean read GetIsJunk; + property IsJunkAssembly: Boolean read GetIsJunkAssembly; property IsSpace: Boolean read GetIsSpace; property Origin: string read GetOrigin write SetOrigin; property PosXY: TTokenPoint read GetPosXY; @@ -385,7 +390,7 @@ implementation StrUtils; type - TmwPasLexExpressionEvaluation = (leeNone, leeAnd, leeOr); + TmwPasLexExpressionEvaluation = (leeNone, leeAnd, leeOr, leeXor); procedure MakeIdentTable; var @@ -393,14 +398,10 @@ procedure MakeIdentTable; begin for I := #0 to #127 do begin - case I of - '_', '0'..'9', 'a'..'z', 'A'..'Z': Identifiers[I] := True; - else - Identifiers[I] := False; - end; - J := UpperCase(I)[1]; - case I of - 'a'..'z', 'A'..'Z', '_': mHashTable[I] := Ord(J) - 64; + Identifiers[I]:= CharInSet(I,['_', '0'..'9', 'a'..'z', 'A'..'Z']); + J := UpCase(I); + case J of + 'A'..'Z', '_': mHashTable[I] := Ord(J) - 64; else mHashTable[Char(I)] := 0; end; @@ -619,8 +620,8 @@ function TmwBasePasLex.Func15: TptTokenKind; function TmwBasePasLex.Func19: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Do') then Result := ptDo else - if KeyComp('And') then Result := ptAnd; + if KeyComp('Do') then Result := ptDo + else if KeyComp('And') then Result := ptAnd; end; function TmwBasePasLex.Func20: TptTokenKind; @@ -686,9 +687,9 @@ function TmwBasePasLex.Func32: TptTokenKind; function TmwBasePasLex.Func33: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Or') then Result := ptOr else - if KeyComp('Name') then FExID := ptName else - if KeyComp('Asm') then Result := ptAsm; + if KeyComp('Or') then Result := ptOr + else if KeyComp('Name') then FExID := ptName + else if KeyComp('Asm') then Result := ptAsm; end; function TmwBasePasLex.Func35: TptTokenKind; @@ -722,8 +723,8 @@ function TmwBasePasLex.Func38: TptTokenKind; function TmwBasePasLex.Func39: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('For') then Result := ptFor else - if KeyComp('Shl') then Result := ptShl; + if KeyComp('For') then Result := ptFor + else if KeyComp('Shl') then Result := ptShl; end; function TmwBasePasLex.Func40: TptTokenKind; @@ -819,9 +820,9 @@ function TmwBasePasLex.Func56: TptTokenKind; function TmwBasePasLex.Func57: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('While') then Result := ptWhile else - if KeyComp('Xor') then Result := ptXor else - if KeyComp('Goto') then Result := ptGoto; + if KeyComp('While') then Result := ptWhile + else if KeyComp('Xor') then Result := ptXor + else if KeyComp('Goto') then Result := ptGoto; end; function TmwBasePasLex.Func58: TptTokenKind; @@ -923,7 +924,8 @@ function TmwBasePasLex.Func72: TptTokenKind; function TmwBasePasLex.Func73: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Except') then Result := ptExcept; + if KeyComp('Except') then Result := ptExcept else + if KeyComp('AnsiChar') then FExId := ptAnsiChar; end; function TmwBasePasLex.Func75: TptTokenKind; @@ -1020,8 +1022,9 @@ function TmwBasePasLex.Func94: TptTokenKind; function TmwBasePasLex.Func95: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Contains') then FExID := ptContains else - if KeyComp('Absolute') then FExID := ptAbsolute; + if KeyComp('Contains') then FExID := ptContains + else if KeyComp('Absolute') then FExID := ptAbsolute + else if KeyComp('Dependency') then FExID := ptDependency; //#240 end; function TmwBasePasLex.Func96: TptTokenKind; @@ -1061,9 +1064,9 @@ function TmwBasePasLex.Func100: TptTokenKind; function TmwBasePasLex.Func101: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Register') then FExID := ptRegister else - if KeyComp('Platform') then FExID := ptPlatform else - if KeyComp('Continue') then FExID := ptContinue; + if KeyComp('Register') then FExID:= ptRegister + else if KeyComp('Platform') then FExID:= ptPlatform + else if KeyComp('Continue') then FExID:= ptContinue; end; function TmwBasePasLex.Func102: TptTokenKind; @@ -1118,8 +1121,8 @@ function TmwBasePasLex.Func112: TptTokenKind; function TmwBasePasLex.Func117: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Exports') then Result := ptExports else - if KeyComp('OleVariant') then FExID := ptOleVariant; + if KeyComp('Exports') then Result:= ptExports + else if KeyComp('OleVariant') then FExID:= ptOleVariant; end; function TmwBasePasLex.Func123: TptTokenKind; @@ -1155,7 +1158,10 @@ function TmwBasePasLex.Func129: TptTokenKind; function TmwBasePasLex.Func130: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('AnsiString') then FExID := ptAnsiString; + if KeyComp('AnsiString') then begin + Result:= ptString; + FExID := ptAnsiString; + end; end; function TmwBasePasLex.Func132: TptTokenKind; @@ -1194,11 +1200,20 @@ function TmwBasePasLex.Func143: TptTokenKind; if KeyComp('Destructor') then Result := ptDestructor; end; +function TmwBasePasLex.Func158: TptTokenKind; +begin + Result := ptIdentifier; + if KeyComp('Unicodestring') then begin + Result := ptString; + FExID:= ptUnicodeString; + end; +end; + function TmwBasePasLex.Func166: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Constructor') then Result := ptConstructor else - if KeyComp('Implementation') then Result := ptImplementation; + if KeyComp('Constructor') then Result:= ptConstructor + else if KeyComp('Implementation') then Result:= ptImplementation; end; function TmwBasePasLex.Func167: TptTokenKind; @@ -1216,8 +1231,8 @@ function TmwBasePasLex.Func168: TptTokenKind; function TmwBasePasLex.Func191: TptTokenKind; begin Result := ptIdentifier; - if KeyComp('Resourcestring') then Result := ptResourcestring else - if KeyComp('Stringresource') then FExID := ptStringresource; + if KeyComp('Resourcestring') then Result:= ptResourcestring + else if KeyComp('Stringresource') then FExID:= ptStringresource; end; function TmwBasePasLex.AltFunc: TptTokenKind; @@ -1646,111 +1661,289 @@ procedure TmwBasePasLex.BraceOpenProc; function TmwBasePasLex.EvaluateComparison(AValue1: Extended; const AOper: String; AValue2: Extended): Boolean; begin - if AOper = '=' then - Result := AValue1 = AValue2 - else if AOper = '<>' then - Result := AValue1 <> AValue2 - else if AOper = '<' then - Result := AValue1 < AValue2 - else if AOper = '<=' then - Result := AValue1 <= AValue2 - else if AOper = '>' then - Result := AValue1 > AValue2 - else if AOper = '>=' then - Result := AValue1 >= AValue2 - else - Result := False; + case AOper[1] of + '=': Result := (AValue1 = AValue2); + '<': begin + if (AOper = '<') then Result := AValue1 < AValue2 + else if (AOper = '<>') then Result := AValue1 <> AValue2 + else Result:= AValue1 <= AValue2; + end; + '>': begin + if (AOper = '>') then Result := AValue1 > AValue2 + else Result:= AValue1 >= AValue2; + end; + else Result:= false; + end; end; -function TmwBasePasLex.EvaluateConditionalExpression(const AParams: String): Boolean; +function TmwBasePasLex.EvaluateConditionalExpression(const AParams: string; StartResult: boolean = false): Boolean; var - LParams: String; - LDefine: String; - LEvaluation: TmwPasLexExpressionEvaluation; - LIsComVer: Boolean; - LIsRtlVer: Boolean; - LOper: string; - LValue: Integer; - p: Integer; -begin - { TODO : Expand support for <=> evaluations (complicated to do). Expand support for NESTED expressions } - LEvaluation := leeNone; - LParams := TrimLeft(AParams); - LIsComVer := Pos('COMPILERVERSION', LParams) = 1; - LIsRtlVer := Pos('RTLVERSION', LParams) = 1; - if LIsComVer or LIsRtlVer then //simple parser which covers most frequent use cases - begin - Result := False; - if LIsComVer then - Delete(LParams, 1, Length('COMPILERVERSION')); - if LIsRtlVer then - Delete(LParams, 1, Length('RTLVERSION')); - while (LParams <> '') and (LParams[1] = ' ') do - Delete(LParams, 1, 1); - p := Pos(' ', LParams); - if p > 0 then - begin - LOper := Copy(LParams, 1, p-1); - Delete(LParams, 1, p); - while (LParams <> '') and (LParams[1] = ' ') do - Delete(LParams, 1, 1); - p := Pos(' ', LParams); - if p = 0 then - p := Length(LParams) + 1; - if TryStrToInt(Copy(LParams, 1, p-1), LValue) then - begin - Delete(LParams, 1, p); - while (LParams <> '') and (LParams[1] = ' ') do - Delete(LParams, 1, 1); - if LParams = '' then - if LIsComVer then - Result := EvaluateComparison(CompilerVersion, LOper, LValue) - else if LIsRtlVer then - Result := EvaluateComparison(RTLVersion, LOper, LValue); - end; - end; - end else - if (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) then - begin - Result := True; // Optimistic - while (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) do - begin - if Pos('DEFINED(', LParams) = 1 then - begin - LDefine := Copy(LParams, 9, Pos(')', LParams) - 9); - LParams := TrimLeft(Copy(LParams, 10 + Length(LDefine), Length(AParams) - (9 + Length(LDefine)))); - case LEvaluation of - leeNone: Result := IsDefined(LDefine); - leeAnd: Result := Result and IsDefined(LDefine); - leeOr: Result := Result or IsDefined(LDefine); - end; - end - else if Pos('NOT DEFINED(', LParams) = 1 then - begin - LDefine := Copy(LParams, 13, Pos(')', LParams) - 13); - LParams := TrimLeft(Copy(LParams, 14 + Length(LDefine), Length(AParams) - (13 + Length(LDefine)))); - case LEvaluation of - leeNone: Result := (not IsDefined(LDefine)); - leeAnd: Result := Result and (not IsDefined(LDefine)); - leeOr: Result := Result or (not IsDefined(LDefine)); - end; + LParams: string; + i: integer; + NextPart: string; + +function ExtractNextPart(StartPos: integer; BracketCount: integer = 0): string; +var + i: integer; + BracketFound: boolean; + TokenFound: boolean; + InternalBracketCount: integer; +begin + i:= 1; + BracketFound:= false; + TokenFound:= false; + InternalBracketCount:= 0;//BracketCount; + while i < Length(LParams) do begin + case LParams[i] of + '(': begin + Inc(InternalBracketCount); + BracketFound:= true; end; - // Determine next Evaluation - if Pos('AND ', LParams) = 1 then - begin - LEvaluation := leeAnd; - LParams := TrimLeft(Copy(LParams, 4, Length(LParams) - 3)); - end - else if Pos('OR ', LParams) = 1 then - begin - LEvaluation := leeOr; - LParams := TrimLeft(Copy(LParams, 3, Length(LParams) - 2)); + ')': begin + Dec(InternalBracketCount); end; + else TokenFound:= true; end; - end else - Result := False; + if (InternalBracketCount = 0) and BracketFound and TokenFound then begin + break; + end; + Inc(i); + end; + Result:= MidStr(LParams, StartPos, i-((StartPos-1)*2)); end; +//Assumes the first char is part of a number +function ExtractNumber: string; +begin + i:= 1; + while i <= Length(LParams) do begin + if CharInSet(LParams[i], ['0'..'9','-','.']) then Inc(i) + else begin + Dec(i); + Break; + end; + end; {while} + Result:= LeftStr(LParams, i); +end; + +var + LDefine: string; + IsComVer, IsRTLVer: boolean; + LOper: string; + Value: Extended; + MyFormatSettings: TFormatSettings; + +begin + IsComVer:= false; + IsRTLVer:= false; + LParams:= Trim(Uppercase(AParams)); + Result:= StartResult; + while (Length(LParams) > 0) do begin + case LParams[1] of + '(': begin + while Pos('(', LParams) = 1 do begin + NextPart:= ExtractNextPart(2,1); + Result:= EvaluateConditionalExpression(NextPart, Result); + Delete(LParams, 1, Length(NextPart) + 2); + LParams:= TrimLeft(LParams); + end; {while} + end; {'('} + 'O':if Pos('OR',LParams) = 1 then begin + Delete(LParams,1,2); + LParams:= TrimLeft(LParams); + NextPart:= ExtractNextPart(1); + if not(Result) then Result:= Result or EvaluateConditionalExpression(NextPart, Result); + Delete(LParams, 1, Length(NextPart)); + LParams:= TrimLeft(LParams); + end else exit(false); + 'A':if Pos('AND ',LParams) = 1 then begin + Delete(LParams,1,3); + LParams:= TrimLeft(LParams); + NextPart:= ExtractNextPart(1); + if(Result) then Result:= Result and EvaluateConditionalExpression(NextPart, Result); + Delete(LParams, 1, Length(NextPart)); + LParams:= TrimLeft(LParams); + end else exit(false); + 'X':if Pos('XOR',LParams) = 1 then begin + Delete(LParams,1,3); + LParams:= TrimLeft(LParams); + NextPart:= ExtractNextPart(1); + Result:= Result xor EvaluateConditionalExpression(NextPart, Result); + Delete(LParams, 1, Length(NextPart)); + LParams:= TrimLeft(LParams); + end else exit(false); + 'D': if Pos('DEFINED(',LParams) = 1 then begin + LDefine := Copy(LParams, 9, Pos(')', LParams) - 9); + Result:= IsDefined(LDefine); + Delete(LParams, 1, Length(LDefine)+9); + LParams:= TrimLeft(LParams); + end else if Pos('DECLARED(',LParams) = 1 then begin + LDefine := Copy(LParams, 10, Pos(')', LParams) - 10); + Result:= IsDeclared(LDefine); + Delete(LParams, 1, Length(LDefine)+9); + LParams:= TrimLeft(LParams); + end else exit(false); + 'N': if (Pos('NOT',LParams) = 1) then begin + Delete(LParams,1,3); + LParams:= TrimLeft(LParams); + NextPart:= ExtractNextPart(1); + Result:= not EvaluateConditionalExpression(NextPart, Result); + Delete(LParams, 1, Length(NextPart)); + LParams:= TrimLeft(LParams); + end else exit(false); + 'C': if (Pos('COMPILERVERSION',LParams) = 1) then begin + IsComVer := true; + Delete(LParams, 1, Length('COMPILERVERSION')); + LParams:= TrimLeft(LParams); + end else exit(false); + 'R': if (Pos('RTLVERSION',LParams) = 1) then begin + IsRTLVer:= true; + Delete(LParams, 1, Length('RTLVERSION')); + LParams:= TrimLeft(LParams); + end else exit(false); + '<','=','>': begin + if (Pos('>=',LParams) = 1) then LOper:= '>=' + else if (Pos('<=',LParams) = 1) then LOper:= '<=' + else if (Pos('<>',LParams) = 1) then LOper:= '<>' + else LOper:= LParams[1]; + Delete(LParams, 1, Length(LOper)); + LParams:= TrimLeft(LParams); + NextPart:= ExtractNumber; + MyFormatSettings:= FormatSettings; + MyFormatSettings.DecimalSeparator:= '.'; + if TryStrToFloat(NextPart, Value, MyFormatSettings) then begin + if IsComVer then + Result := EvaluateComparison(CompilerVersion, LOper, Value) + else if IsRtlVer then + Result := EvaluateComparison(RTLVersion, LOper, Value); + Delete(LParams, 1, Length(NextPart)); + LParams:= Trim(LParams); + end else Result:= false; + end; + else Exit(false); //Should not happen. + end; {case} + end; {while} +end; + + +//function TmwBasePasLex.EvaluateConditionalExpression(const AParams: string): Boolean; +//var +// LParams: String; +// LDefine: String; +// LEvaluation: TmwPasLexExpressionEvaluation; +// LIsComVer: Boolean; +// LIsRtlVer: Boolean; +// LOper: string; +// LValue: Integer; +// p: Integer; +// BracketCount,i: integer; +// BracketPart: string; +// PartialResult: boolean; +//begin +// { TODO : Expand support for <=> evaluations (complicated to do). Expand support for NESTED expressions } +// LEvaluation := leeNone; +// LParams := TrimLeft(AParams); +// LIsComVer := Pos('COMPILERVERSION', LParams) = 1; +// LIsRtlVer := Pos('RTLVERSION', LParams) = 1; +// if LIsComVer or LIsRtlVer then //simple parser which covers most frequent use cases +// begin +// Result := False; +// if LIsComVer then +// Delete(LParams, 1, Length('COMPILERVERSION')); +// if LIsRtlVer then +// Delete(LParams, 1, Length('RTLVERSION')); +// while (LParams <> '') and (LParams[1] = ' ') do +// Delete(LParams, 1, 1); +// p := Pos(' ', LParams); +// if p > 0 then +// begin +// LOper := Copy(LParams, 1, p-1); +// Delete(LParams, 1, p); +// while (LParams <> '') and (LParams[1] = ' ') do +// Delete(LParams, 1, 1); +// p := Pos(' ', LParams); +// if p = 0 then +// p := Length(LParams) + 1; +// if TryStrToInt(Copy(LParams, 1, p-1), LValue) then +// begin +// Delete(LParams, 1, p); +// while (LParams <> '') and (LParams[1] = ' ') do +// Delete(LParams, 1, 1); +// if LParams = '' then +// if LIsComVer then +// Result := EvaluateComparison(CompilerVersion, LOper, LValue) +// else if LIsRtlVer then +// Result := EvaluateComparison(RTLVersion, LOper, LValue); +// end; +// end; +// end else +// while Pos('(', LParams) = 1 do begin +// //Extract the Part between the brackets and feed this to the evaluator. +// BracketCount:= 1; +// i:= 2; +// while i <= Length(LParams) do begin +// case LParams[i] of +// '(': Inc(BracketCount); +// ')': Dec(BracketCount); +// end; {case} +// if (BracketCount = 0) then break; +// Inc(i); +// end; {while} +// BracketPart:= MidStr(LParams,2,i-2); +// PartialResult:= EvaluateConditionalExpression(BracketPart); +// Result:= Result or PartialResult; +// Delete(LParams, 1, Length(BracketPart)+2); +// LParams:= TrimLeft(LParams); +// end; +// +// if (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) then +// begin +// Result := True; // Optimistic +// while (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) do +// begin +// if Pos('DEFINED(', LParams) = 1 then +// begin +// LDefine := Copy(LParams, 9, Pos(')', LParams) - 9); +// LParams := TrimLeft(Copy(LParams, 10 + Length(LDefine), Length(AParams) - (9 + Length(LDefine)))); +// case LEvaluation of +// leeNone: Result := IsDefined(LDefine); +// leeAnd: Result := Result and IsDefined(LDefine); +// leeOr: Result := Result or IsDefined(LDefine); +// leeXor: Result:= Result xor IsDefined(LDefine); +// end; +// end +// else if Pos('NOT DEFINED(', LParams) = 1 then +// begin +// LDefine := Copy(LParams, 13, Pos(')', LParams) - 13); +// LParams := TrimLeft(Copy(LParams, 14 + Length(LDefine), Length(AParams) - (13 + Length(LDefine)))); +// case LEvaluation of +// leeNone: Result := (not IsDefined(LDefine)); +// leeAnd: Result := Result and (not IsDefined(LDefine)); +// leeOr: Result := Result or (not IsDefined(LDefine)); +// leeXor: Result:= Result xor (not IsDefined(LDefine)); +// end; +// end; +// // Determine next Evaluation +// if Pos('AND ', LParams) = 1 then +// begin +// LEvaluation := leeAnd; +// LParams := TrimLeft(Copy(LParams, 4, Length(LParams) - 3)); +// end +// else if Pos('OR ', LParams) = 1 then +// begin +// LEvaluation := leeOr; +// LParams := TrimLeft(Copy(LParams, 3, Length(LParams) - 2)); +// end +// else if Pos('XOR ', LParams) = 1 then +// begin +// LEvaluation := leeXor; +// LParams := TrimLeft(Copy(LParams, 3, Length(LParams) - 2)); +// end; +// end; +// end else +// Result := False; +//end; + procedure TmwBasePasLex.ColonProc; begin case FBuffer.Buf[FBuffer.Run + 1] of @@ -1870,6 +2063,12 @@ function TmwBasePasLex.IsDefined(const ADefine: string): Boolean; Result := False; end; +function TmwBasePasLex.IsDeclared(const ADefine: string): Boolean; +begin + Result:= true; + {TODO -oJB -cTmwBasePasLex.IsDeclared : Implement} +end; + function TmwBasePasLex.IsIdentifiers(AChar: Char): Boolean; begin {$IFDEF SUPPORTS_INTRINSIC_HELPERS} @@ -2325,6 +2524,13 @@ function TmwBasePasLex.GetIsJunk: Boolean; Result := IsTokenIDJunk(FTokenID) or (FUseDefines and (FDefineStack > 0) and (TokenID <> ptNull)); end; +function TmwBasePasLex.GetIsJunkAssembly: Boolean; +begin + Result := not(FTokenID in [ptCRLF]) and ( + IsTokenIDJunk(FTokenID) or (FUseDefines and (FDefineStack > 0) and (TokenID <> ptNull)) + ); +end; + function TmwBasePasLex.GetIsSpace: Boolean; begin Result := FTokenID in [ptCRLF, ptSpace]; @@ -2347,6 +2553,13 @@ procedure TmwBasePasLex.NextNoJunk; until not IsJunk; end; +procedure TmwBasePasLex.NextNoJunkAssembly; +begin + repeat + Next + until not IsJunkAssembly; +end; + procedure TmwBasePasLex.NextNoSpace; begin repeat @@ -2409,6 +2622,7 @@ function TmwBasePasLex.GetDirectiveKind: TptTokenKind; FDirectiveParamOrigin := FBuffer.Buf + FTokenPos; TempPos := FTokenPos; FTokenPos := FBuffer.Run; + FExId:= ptCompDirect; //Always register the fact that we are in a directive. case KeyHash of 9: if KeyComp('I') and (not CharInSet(FBuffer.Buf[FBuffer.Run], ['+', '-'])) then diff --git a/Source/SimpleParser/SimpleParser.pas b/Source/SimpleParser/SimpleParser.pas index c39f44f2..a57f965e 100644 --- a/Source/SimpleParser/SimpleParser.pas +++ b/Source/SimpleParser/SimpleParser.pas @@ -193,6 +193,7 @@ ESyntaxError = class(Exception) property PosXY: TTokenPoint read FPosXY write FPosXY; end; + TptTokenKinds = set of TptTokenKind; TmwSimplePasPar = class(TObject) private FOnMessage: TMessageEvent; @@ -204,16 +205,17 @@ TmwSimplePasPar = class(TObject) FInRound: Integer; procedure InitAhead; procedure VariableTail; - function GetInRound: Boolean; - function GetUseDefines: Boolean; - function GetScopedEnums: Boolean; - procedure SetUseDefines(const Value: Boolean); - procedure SetIncludeHandler(IncludeHandler: IIncludeHandler); - function GetOnComment: TCommentEvent; - procedure SetOnComment(const Value: TCommentEvent); + function GetInRound: Boolean; inline; + function GetUseDefines: Boolean; inline; + function GetScopedEnums: Boolean; inline; + procedure SetUseDefines(const Value: Boolean); inline; + procedure SetIncludeHandler(IncludeHandler: IIncludeHandler); inline; + function GetOnComment: TCommentEvent; inline; + procedure SetOnComment(const Value: TCommentEvent); inline; protected procedure Expected(Sym: TptTokenKind); virtual; - procedure ExpectedEx(Sym: TptTokenKind); virtual; + procedure ExpectedEx(Sym: TptTokenKind); overload; virtual; + procedure ExpectedEx(const Syms: TptTokenKinds); overload; virtual; procedure ExpectedFatal(Sym: TptTokenKind); virtual; procedure HandlePtCompDirect(Sender: TmwBasePasLex); virtual; procedure HandlePtDefineDirect(Sender: TmwBasePasLex); virtual; @@ -228,6 +230,7 @@ TmwSimplePasPar = class(TObject) procedure HandlePtIfEndDirect(Sender: TmwBasePasLex); virtual; procedure HandlePtElseIfDirect(Sender: TmwBasePasLex); virtual; procedure NextToken; virtual; + procedure NextTokenAssembly; virtual; procedure SkipJunk; virtual; procedure Semicolon; virtual; function GetExID: TptTokenKind; virtual; @@ -242,11 +245,18 @@ TmwSimplePasPar = class(TObject) procedure AncestorId; virtual; procedure AnonymousMethod; virtual; procedure AnonymousMethodType; virtual; + procedure AnonymousMethodTypeFunction; virtual; + procedure AnonymousMethodTypeProcedure; virtual; procedure ArrayConstant; virtual; procedure ArrayBounds; virtual; procedure ArrayDimension; virtual; + procedure ArrayOfConst; virtual; + procedure ArraySubType; virtual; procedure ArrayType; virtual; + procedure AsmFragment; virtual; + procedure AsmLabelAt; virtual; procedure AsmStatement; virtual; + procedure AsmStatements; virtual; procedure AssignOp; virtual; procedure AtExpression; virtual; procedure Block; virtual; @@ -268,13 +278,14 @@ TmwSimplePasPar = class(TObject) procedure ClassMethodResolution; virtual; procedure ClassProcedureHeading; virtual; procedure ClassClass; virtual; - procedure ClassConstraint; virtual; + procedure ClassConstraint; virtual; procedure ClassMethod; virtual; procedure ClassProperty; virtual; procedure ClassReferenceType; virtual; procedure ClassType; virtual; procedure ClassTypeEnd; virtual; procedure ClassVisibility; virtual; + procedure CompilerDirective; virtual; procedure CompoundStatement; virtual; procedure ConstantColon; virtual; procedure ConstantDeclaration; virtual; @@ -285,7 +296,7 @@ TmwSimplePasPar = class(TObject) procedure ConstantValue; virtual; procedure ConstantValueTyped; virtual; procedure ConstParameter; virtual; - procedure ConstructorConstraint; virtual; + procedure ConstructorConstraint; virtual; procedure ConstructorHeading; virtual; procedure ConstructorName; virtual; procedure ConstSection; virtual; @@ -297,17 +308,24 @@ TmwSimplePasPar = class(TObject) procedure DestructorHeading; virtual; procedure DestructorName; virtual; procedure Directive16Bit; virtual; + procedure DirectiveAssembler; virtual; + procedure DirectiveAbstract; virtual; procedure DirectiveBinding; virtual; procedure DirectiveBindingMessage; virtual; procedure DirectiveCalling; virtual; + procedure DirectiveDelayed; virtual; procedure DirectiveDeprecated; virtual; + procedure DirectiveExperimental; virtual; procedure DirectiveInline; virtual; procedure DirectiveLibrary; virtual; procedure DirectiveLocal; virtual; procedure DirectivePlatform; virtual; procedure DirectiveVarargs; virtual; + procedure DirectiveSealed; virtual; + procedure DirectiveStatic; virtual; procedure DispInterfaceForward; virtual; procedure DispIDSpecifier; virtual; + procedure DoubleAddressOp; virtual; procedure DotOp; virtual; procedure ElseStatement; virtual; procedure EmptyStatement; virtual; @@ -329,8 +347,9 @@ TmwSimplePasPar = class(TObject) procedure Expression; virtual; procedure ExpressionList; virtual; procedure ExternalDirective; virtual; - procedure ExternalDirectiveThree; virtual; procedure ExternalDirectiveTwo; virtual; + procedure ExternalDirectiveThree; virtual; + procedure ExternalDependency; virtual; procedure Factor; virtual; procedure FieldDeclaration; virtual; procedure FieldList; virtual; @@ -385,6 +404,7 @@ TmwSimplePasPar = class(TObject) procedure MethodKind; virtual; procedure MultiplicativeOperator; virtual; procedure FormalParameterType; virtual; + procedure NameSpecifier; virtual; procedure NotOp; virtual; procedure NilToken; virtual; procedure Number; virtual; @@ -434,7 +454,7 @@ TmwSimplePasPar = class(TObject) procedure RealIdentifier; virtual; procedure RealType; virtual; procedure RecordConstant; virtual; - procedure RecordConstraint; virtual; + procedure RecordConstraint; virtual; procedure RecordFieldConstant; virtual; procedure RecordType; virtual; procedure RecordVariant; virtual; @@ -443,6 +463,7 @@ TmwSimplePasPar = class(TObject) procedure RequiresClause; virtual; procedure RequiresIdentifier; virtual; procedure RequiresIdentifierId; virtual; + procedure Resident; virtual; procedure ResolutionInterfaceName; virtual; procedure ResourceDeclaration; virtual; procedure ResourceValue; virtual; @@ -515,7 +536,8 @@ TmwSimplePasPar = class(TObject) procedure Variable; virtual; procedure VariableReference; virtual; procedure VariantIdentifier; virtual; - procedure VariantSection; virtual; + procedure RecordVariantSection; virtual; + procedure RecordVariantTag; virtual; procedure VarParameter; virtual; procedure VarName; virtual; procedure VarNameList; virtual; @@ -536,23 +558,23 @@ TmwSimplePasPar = class(TObject) {This is the syntax for custom attributes, based quite strictly on the ECMA syntax specifications for C#, but with a Delphi expression being used at the bottom as opposed to a C# expression} - procedure GlobalAttributes; - procedure GlobalAttributeSections; - procedure GlobalAttributeSection; - procedure GlobalAttributeTargetSpecifier; - procedure GlobalAttributeTarget; - procedure Attributes; + procedure GlobalAttributes; virtual; + procedure GlobalAttributeSections; virtual; + procedure GlobalAttributeSection; virtual; + procedure GlobalAttributeTargetSpecifier; virtual; + procedure GlobalAttributeTarget; virtual; + procedure Attributes; virtual; procedure AttributeSections; virtual; - procedure AttributeSection; - procedure AttributeTargetSpecifier; - procedure AttributeTarget; - procedure AttributeList; + procedure AttributeSection; virtual; + procedure AttributeTargetSpecifier; virtual; + procedure AttributeTarget; virtual; + procedure AttributeList; virtual; procedure Attribute; virtual; procedure AttributeName; virtual; procedure AttributeArguments; virtual; - procedure PositionalArgumentList; + procedure PositionalArgumentList; virtual; procedure PositionalArgument; virtual; - procedure NamedArgumentList; + procedure NamedArgumentList; virtual; procedure NamedArgument; virtual; procedure AttributeArgumentName; virtual; procedure AttributeArgumentExpression; virtual; @@ -567,11 +589,11 @@ TmwSimplePasPar = class(TObject) procedure SynError(Error: TmwParseError); virtual; procedure Run(const UnitName: string; SourceStream: TStream); virtual; - procedure ClearDefines; - procedure InitDefinesDefinedByCompiler; - procedure AddDefine(const ADefine: string); - procedure RemoveDefine(const ADefine: string); - function IsDefined(const ADefine: string): Boolean; + procedure ClearDefines; inline; + procedure InitDefinesDefinedByCompiler; inline; + procedure AddDefine(const ADefine: string); inline; + procedure RemoveDefine(const ADefine: string); inline; + function IsDefined(const ADefine: string): Boolean; inline; property InterfaceOnly: Boolean read FInterfaceOnly write FInterfaceOnly; property Lexer: TmwPasLex read FLexer; @@ -613,8 +635,9 @@ constructor ESyntaxError.CreatePos(const Msg: string; aPosXY: TTokenPoint); procedure TmwSimplePasPar.ForwardDeclaration; begin + //semicolon is optional after forward directive. NextToken; - Semicolon; + if TokenID = ptSemiColon then NextToken; //#166 end; procedure TmwSimplePasPar.ObjectProperty; @@ -768,6 +791,27 @@ procedure TmwSimplePasPar.Expected(Sym: TptTokenKind); NextToken; end; +procedure TmwSimplePasPar.ExpectedEx(const Syms: TptTokenKinds); +var + Sym: TptTokenKind; + Symbols: string; + Optional: string; +begin + if (Lexer.ExID in Syms) then NextToken + else if (Lexer.TokenID = ptNull) or Assigned(FOnMessage) then begin + for Sym in Syms do begin + Symbols:= Symbols + Optional + TokenName(Sym); + Optional:= ' or '; + end; + if (Lexer.TokenID = ptNull) then + raise ESyntaxError.CreatePos(Format(rsExpected, [Symbols, rsEndOfFile]), FLexer.PosXY) + else if Assigned(FOnMessage) then begin + FOnMessage(Self, meError, Format(rsExpected, ['EX:' + Symbols, FLexer.Token]), + FLexer.PosXY.X, FLexer.PosXY.Y); + end; + end; +end; + procedure TmwSimplePasPar.ExpectedEx(Sym: TptTokenKind); begin if Sym <> Lexer.ExID then @@ -804,9 +848,10 @@ procedure TmwSimplePasPar.ExpectedFatal(Sym: TptTokenKind); procedure TmwSimplePasPar.HandlePtCompDirect(Sender: TmwBasePasLex); begin - if Assigned(FOnMessage) then - FOnMessage(Self, meNotSupported, 'Currently not supported ' + FLexer.Token, FLexer.PosXY.X, FLexer.PosXY.Y); - Sender.Next; + if (not Lexer.IsJunk) then CompilerDirective; + //if Assigned(FOnMessage) then + // FOnMessage(Self, meNotSupported, 'Currently not supported ' + FLexer.Token, FLexer.PosXY.X, FLexer.PosXY.Y); + //Sender.Next; end; procedure TmwSimplePasPar.HandlePtDefineDirect(Sender: TmwBasePasLex); @@ -879,9 +924,11 @@ procedure TmwSimplePasPar.HandlePtIfOptDirect(Sender: TmwBasePasLex); procedure TmwSimplePasPar.HandlePtResourceDirect(Sender: TmwBasePasLex); begin - if Assigned(FOnMessage) then - FOnMessage(Self, meNotSupported, 'Currently not supported ' + FLexer.Token, FLexer.PosXY.X, FLexer.PosXY.Y); - Sender.Next; + //{$R *.dfm} + if (not Lexer.IsJunk) then CompilerDirective; +// if Assigned(FOnMessage) then +// FOnMessage(Self, meNotSupported, 'Currently not supported ' + FLexer.Token, FLexer.PosXY.X, FLexer.PosXY.Y); +// Sender.Next; end; procedure TmwSimplePasPar.HandlePtUndefDirect(Sender: TmwBasePasLex); @@ -894,6 +941,11 @@ procedure TmwSimplePasPar.NextToken; FLexer.NextNoJunk; end; +procedure TmwSimplePasPar.NextTokenAssembly; +begin + FLexer.NextNoJunkAssembly; +end; + procedure TmwSimplePasPar.NilToken; begin Expected(ptNil); @@ -975,7 +1027,7 @@ procedure TmwSimplePasPar.ThenStatement; procedure TmwSimplePasPar.Semicolon; begin case Lexer.TokenID of - ptElse, ptEnd, ptExcept, ptfinally, ptFinalization, ptRoundClose, ptUntil: ; + ptElse, ptEnd, ptExcept, ptFinally, ptFinalization, ptRoundClose, ptUntil: ; else Expected(ptSemiColon); end; @@ -1179,34 +1231,10 @@ procedure TmwSimplePasPar.ProgramBlock; Block; end; -procedure TmwSimplePasPar.MainUsesClause; -begin - Expected(ptUses); - MainUsedUnitStatement; - while TokenID = ptComma do - begin - NextToken; - MainUsedUnitStatement; - end; - Semicolon; -end; - procedure TmwSimplePasPar.MethodKind; begin case TokenID of - ptConstructor: - begin - NextToken; - end; - ptDestructor: - begin - NextToken; - end; - ptProcedure: - begin - NextToken; - end; - ptFunction: + ptConstructor, ptDestructor, ptProcedure, ptFunction: begin NextToken; end; @@ -1217,6 +1245,18 @@ procedure TmwSimplePasPar.MethodKind; end; end; +procedure TmwSimplePasPar.MainUsesClause; +begin + Expected(ptUses); + MainUsedUnitStatement; + while TokenID = ptComma do + begin + NextToken; + MainUsedUnitStatement; + end; + Semicolon; +end; + procedure TmwSimplePasPar.MainUsedUnitStatement; begin MainUsedUnitName; @@ -1270,7 +1310,7 @@ procedure TmwSimplePasPar.Block; case TokenID of ptAsm: begin - AsmStatement; + AsmStatements; end; else begin @@ -1410,12 +1450,12 @@ procedure TmwSimplePasPar.AccessSpecifier; procedure TmwSimplePasPar.ReadAccessIdentifier; begin - variable; + Variable; end; procedure TmwSimplePasPar.WriteAccessIdentifier; begin - variable; + Variable; end; procedure TmwSimplePasPar.StorageSpecifier; @@ -1834,41 +1874,26 @@ procedure TmwSimplePasPar.Directive16Bit; end; end; +procedure TmwSimplePasPar.DirectiveAbstract; +begin + ExpectedEx(ptAbstract); //abstract is an ExID. +end; + +procedure TmwSimplePasPar.DirectiveAssembler; +begin + ExpectedEx(ptAssembler); +end; + procedure TmwSimplePasPar.DirectiveBinding; begin case ExID of - ptAbstract: - begin - NextToken; - end; - ptVirtual: - begin - NextToken; - end; - ptDynamic: - begin - NextToken; - end; - ptMessage: - begin - DirectiveBindingMessage; - end; - ptOverride: - begin - NextToken; - end; - ptOverload: - begin - NextToken; - end; - ptReintroduce: - begin - NextToken; - end; - else - begin - SynError(InvalidDirectiveBinding); - end; + ptAbstract, ptVirtual, ptDynamic, ptMessage, ptOverride, ptOverload, + ptReintroduce, ptFinal, ptStatic: begin + NextToken; + end + else begin + SynError(InvalidDirectiveBinding); + end; end; end; @@ -2123,7 +2148,7 @@ procedure TmwSimplePasPar.FunctionProcedureBlock; case TokenID of ptAsm: begin - AsmStatement; + AsmStatements; end; else begin @@ -2148,7 +2173,7 @@ procedure TmwSimplePasPar.ExternalDirective; SimpleExpression; if FLexer.ExID = ptDelayed then - NextToken; + DirectiveDelayed; ExternalDirectiveTwo; end; @@ -2164,15 +2189,15 @@ procedure TmwSimplePasPar.ExternalDirectiveTwo; end; ptName: begin - NextToken; - SimpleExpression; + NameSpecifier; end; ptSemiColon: begin Semicolon; ExternalDirectiveThree; end; - end + end; + if (FLexer.ExID = ptDependency) then ExternalDependency; end; procedure TmwSimplePasPar.ExternalDirectiveThree; @@ -2191,6 +2216,19 @@ procedure TmwSimplePasPar.ExternalDirectiveThree; end; end; + +procedure TmwSimplePasPar.ExternalDependency; +begin + ExpectedEx(ptDependency); + Identifier; + while TokenID = ptComma do begin + NextToken; + Identifier; + end; {while} + SemiColon; +end; + + procedure TmwSimplePasPar.ForStatement; begin Expected(ptFor); @@ -2279,6 +2317,34 @@ procedure TmwSimplePasPar.CaseStatement; Expected(ptEnd); end; +procedure TmwSimplePasPar.RecordVariantTag; +begin + Identifier; + if (TokenId = ptColon) then + Identifier; +end; + + +procedure TmwSimplePasPar.RecordVariantSection; +begin + Expected(ptCase); + RecordVariantTag; + Expected(ptOf); + RecordVariant; + while TokenID = ptSemiColon do + begin + Semicolon; + case TokenID of + ptEnd: + Break; + ptRoundClose: + Break; + else + RecordVariant; + end; + end; +end; + procedure TmwSimplePasPar.CaseSelector; begin CaseLabelList; @@ -2290,6 +2356,18 @@ procedure TmwSimplePasPar.CaseSelector; end; end; +procedure TmwSimplePasPar.RecordVariant; +begin + CaseLabelList; + Expected(ptColon); + Expected(ptRoundOpen); + if TokenID <> ptRoundClose then + begin + FieldList; + end; + Expected(ptRoundClose); +end; + procedure TmwSimplePasPar.CaseElseStatement; begin Expected(ptElse); @@ -2297,6 +2375,16 @@ procedure TmwSimplePasPar.CaseElseStatement; Semicolon; end; +procedure TmwSimplePasPar.CaseLabelList; +begin + CaseLabel; + while TokenID = ptComma do + begin + NextToken; + CaseLabel; + end; +end; + procedure TmwSimplePasPar.CaseLabel; begin ConstantExpression; @@ -2415,36 +2503,59 @@ procedure TmwSimplePasPar.InParameter; end; end; -procedure TmwSimplePasPar.AsmStatement; +procedure TmwSimplePasPar.AsmStatements; begin Lexer.AsmCode := True; Expected(ptAsm); { should be replaced with a Assembler lexer } - while TokenID <> ptEnd do + while TokenID <> ptEnd do begin case FLexer.TokenID of - ptBegin, ptCase, ptEnd, ptIf, ptFunction, ptProcedure, ptRepeat, ptwhile: Break; + ptBegin, ptCase, ptEnd, ptIf, ptFunction, ptProcedure, ptRepeat, ptWhile: Break; ptAddressOp: begin - NextToken; - NextToken; + AsmStatement; end; ptDoubleAddressOp: begin - NextToken; - NextToken; + AsmStatement; end; ptNull: begin Expected(ptEnd); Exit; end; - else - NextToken; - end; + ptCRLF: //empty line + NextTokenAssembly; + else begin + AsmStatement; + Expected(ptCRLF); + end; + end; {case} + end; {while} Lexer.AsmCode := False; Expected(ptEnd); end; +procedure TmwSimplePasPar.AsmStatement; +begin + while not(Lexer.TokenID in [ptCRLF]) do begin + case TokenID of + ptAddressOp, ptDoubleAddressOp: AsmLabelAt; + else AsmFragment; + end; + end; +end; + +procedure TmwSimplePasPar.AsmFragment; +begin + NextTokenAssembly; +end; + +procedure TmwSimplePasPar.AsmLabelAt; +begin + NextTokenAssembly; +end; + procedure TmwSimplePasPar.AsOp; begin Expected(ptAs); @@ -2573,7 +2684,7 @@ procedure TmwSimplePasPar.Statement; case TokenID of ptAsm: begin - AsmStatement; + AsmStatements; end; ptBegin: begin @@ -3109,39 +3220,7 @@ procedure TmwSimplePasPar.DirectiveCalling; end; end; -procedure TmwSimplePasPar.RecordVariant; -begin - ConstantExpression; - while (TokenID = ptComma) do - begin - NextToken; - ConstantExpression; - end; - Expected(ptColon); - Expected(ptRoundOpen); - if TokenID <> ptRoundClose then - begin - FieldList; - end; - Expected(ptRoundClose); -end; -procedure TmwSimplePasPar.VariantSection; -begin - Expected(ptCase); - TagField; - Expected(ptOf); - RecordVariant; - while TokenID = ptSemiColon do - begin - Semicolon; - case TokenID of - ptEnd, ptRoundClose: Break; - else - RecordVariant; - end; - end; -end; procedure TmwSimplePasPar.TagField; begin @@ -3182,7 +3261,7 @@ procedure TmwSimplePasPar.FieldList; end; if TokenID = ptCase then begin - VariantSection; + RecordVariantSection; end; end; @@ -3260,7 +3339,7 @@ procedure TmwSimplePasPar.ArrayType; Expected(ptArray); ArrayBounds; Expected(ptOf); - TypeKind; + ArraySubType; end; procedure TmwSimplePasPar.EnumeratedType; @@ -3349,79 +3428,13 @@ procedure TmwSimplePasPar.RealType; procedure TmwSimplePasPar.OrdinalIdentifier; begin - case ExID of - ptBoolean: - begin - NextToken; - end; - ptByte: - begin - NextToken; - end; - ptBytebool: - begin - NextToken; - end; - ptCardinal: - begin - NextToken; - end; - ptChar: - begin - NextToken; - end; - ptDWord: - begin - NextToken; - end; - ptInt64: - begin - NextToken; - end; - ptInteger: - begin - NextToken; - end; - ptLongBool: - begin - NextToken; - end; - ptLongInt: - begin - NextToken; - end; - ptLongWord: - begin - NextToken; - end; - ptPChar: - begin - NextToken; - end; - ptShortInt: - begin - NextToken; - end; - ptSmallInt: - begin - NextToken; - end; - ptWideChar: - begin - NextToken; - end; - ptWord: - begin - NextToken; - end; - ptWordbool: - begin - NextToken; - end; - else - begin - SynError(InvalidOrdinalIdentifier); - end; + if (ExID in [ptBoolean,ptByte,ptBytebool,ptCardinal,ptChar,ptAnsiChar,ptDWord, + ptInt64,ptUInt64,ptInteger,ptLongBool,ptLongInt,ptLongWord,ptPChar,ptShortInt, + ptSmallInt,ptWideChar,ptWord,ptWordbool]) then + begin + NextToken; + end else begin + SynError(InvalidOrdinalIdentifier); end; end; @@ -3489,7 +3502,7 @@ procedure TmwSimplePasPar.VariableReference; end; ptDoubleAddressOp: begin - NextToken; + DoubleAddressOp; VariableReference; end; ptInherited: @@ -3631,6 +3644,42 @@ procedure TmwSimplePasPar.InterfaceMemberList; end; end; +procedure TmwSimplePasPar.ObjectType; +begin + Expected(ptObject); + case TokenID of + ptEnd: + begin + ObjectTypeEnd; + NextToken; { Direct descendant without new members } + end; + ptRoundOpen: + begin + ObjectHeritage; + case TokenID of + ptEnd: + begin + Expected(ptEnd); + ObjectTypeEnd; + end; + ptSemiColon: ObjectTypeEnd; + else + begin + ObjectMemberList; { Direct descendant } + Expected(ptEnd); + ObjectTypeEnd; + end; + end; + end; + else + begin + ObjectMemberList; { Direct descendant } + Expected(ptEnd); + ObjectTypeEnd; + end; + end; +end; + procedure TmwSimplePasPar.ClassType; begin Expected(ptClass); @@ -3638,13 +3687,13 @@ procedure TmwSimplePasPar.ClassType; ptIdentifier: //NASTY hack because Abstract is generally an ExID, except in this case when it should be a keyword. begin if Lexer.ExID = ptAbstract then - Expected(ptIdentifier); + DirectiveAbstract; if Lexer.ExID = ptHelper then ClassHelper; end; ptSealed: - Expected(ptSealed); + DirectiveSealed; end; case TokenID of ptEnd: @@ -3820,7 +3869,7 @@ procedure TmwSimplePasPar.ClassMemberList; TypeSection; if TokenID = ptCase then begin - VariantSection; + RecordVariantSection; end; end; end; @@ -3911,42 +3960,6 @@ procedure TmwSimplePasPar.ClassField; TypeDirective; end; -procedure TmwSimplePasPar.ObjectType; -begin - Expected(ptObject); - case TokenID of - ptEnd: - begin - ObjectTypeEnd; - NextToken; { Direct descendant without new members } - end; - ptRoundOpen: - begin - ObjectHeritage; - case TokenID of - ptEnd: - begin - Expected(ptEnd); - ObjectTypeEnd; - end; - ptSemiColon: ObjectTypeEnd; - else - begin - ObjectMemberList; { Direct descendant } - Expected(ptEnd); - ObjectTypeEnd; - end; - end; - end; - else - begin - ObjectMemberList; { Direct descendant } - Expected(ptEnd); - ObjectTypeEnd; - end; - end; -end; - procedure TmwSimplePasPar.ObjectHeritage; begin Expected(ptRoundOpen); @@ -4007,7 +4020,9 @@ procedure TmwSimplePasPar.ObjectVisibility; procedure TmwSimplePasPar.ObjectField; begin - IdentifierList; + if TokenID = ptSquareOpen then //#229 + CustomAttribute; + FieldNameList; Expected(ptColon); TypeKind; TypeDirective; @@ -4077,7 +4092,7 @@ procedure TmwSimplePasPar.ProceduralType; end; while TheTokenID in [ptAbstract, ptCdecl, ptDynamic, ptExport, ptExternal, ptFar, ptMessage, ptNear, ptOverload, ptOverride, ptPascal, ptRegister, - ptReintroduce, ptSafeCall, ptStdCall, ptVirtual, ptStatic, ptInline] do + ptReintroduce, ptSafeCall, ptStdCall, ptVirtual, ptStatic, ptInline, ptVarargs] do // DR 2001-11-14 no checking for deprecated etc. since it's captured by the typedecl begin if TokenID = ptSemiColon then Semicolon; @@ -4281,6 +4296,19 @@ procedure TmwSimplePasPar.ArrayDimension; OrdinalType; end; +procedure TmwSimplePasPar.ArrayOfConst; +begin + Expected(ptConst); +end; + +procedure TmwSimplePasPar.ArraySubType; +begin + case TokenID of + ptConst: ArrayOfConst; + else TypeKind; + end; +end; + procedure TmwSimplePasPar.ClassForward; begin Expected(ptClass); @@ -4296,6 +4324,11 @@ procedure TmwSimplePasPar.DotOp; Expected(ptPoint); end; +procedure TmwSimplePasPar.DoubleAddressOp; +begin + Expected(ptDoubleAddressOp); +end; + procedure TmwSimplePasPar.InterfaceForward; begin Expected(ptInterface); @@ -4678,7 +4711,7 @@ procedure TmwSimplePasPar.ProcedureDeclarationSection; else begin SynError(InvalidProcedureDeclarationSection); - end; + end; end; end; @@ -4697,7 +4730,7 @@ procedure TmwSimplePasPar.LabelDeclarationSection; procedure TmwSimplePasPar.ProceduralDirective; begin case GenID of - ptAbstract: + ptAbstract, ptFinal: begin DirectiveBinding; end; @@ -4713,19 +4746,11 @@ procedure TmwSimplePasPar.ProceduralDirective; begin ExternalDirective; end; - ptDynamic, ptMessage, ptOverload, ptOverride, ptReintroduce, ptVirtual: + ptDynamic, ptMessage, ptOverload, ptOverride, ptReintroduce, ptVirtual, ptStatic: begin DirectiveBinding; end; - ptAssembler: - begin - NextToken; - end; - ptStatic: - begin - NextToken; - end; - ptInline: + ptInline, ptAssembler: begin DirectiveInline; end; @@ -4739,8 +4764,10 @@ procedure TmwSimplePasPar.ProceduralDirective; DirectiveLocal; ptVarargs: DirectiveVarargs; - ptFinal, ptExperimental, ptDelayed: - NextToken; + ptExperimental: + DirectiveExperimental; + ptDelayed: + DirectiveDelayed; else begin SynError(InvalidProceduralDirective); @@ -4766,15 +4793,14 @@ procedure TmwSimplePasPar.ExportedHeading; end; if TokenID = ptSemiColon then Semicolon; - //TODO: Add FINAL while ExID in [ptAbstract, ptCdecl, ptDynamic, ptExport, ptExternal, ptFar, ptMessage, ptNear, ptOverload, ptOverride, ptPascal, ptRegister, ptReintroduce, ptSafeCall, ptStdCall, ptVirtual, ptDeprecated, ptLibrary, ptPlatform, ptLocal, ptVarargs, - ptStatic, ptInline, ptAssembler, ptForward, ptDelayed] do + ptStatic, ptInline, ptAssembler, ptForward, ptDelayed, ptFinal] do begin case ExID of - ptAssembler: NextToken; + //ptAssembler: DirectiveAssembler; ptForward: ForwardDeclaration; else ProceduralDirective; @@ -4840,7 +4866,7 @@ procedure TmwSimplePasPar.TypeSection; begin Expected(ptType); - while (TokenID = ptIdentifier) or (Lexer.TokenID = ptSquareOpen) do + while (TokenID in [ptIdentifier, ptSquareOpen]) do begin if TokenID = ptSquareOpen then CustomAttribute @@ -4865,7 +4891,7 @@ procedure TmwSimplePasPar.TypeSection; procedure TmwSimplePasPar.TypeSimple; begin case GenID of - ptBoolean, ptByte, ptChar, ptDWord, ptInt64, ptInteger, ptLongInt, + ptBoolean, ptByte, ptChar, ptAnsiChar, ptDWord, ptInt64, ptUInt64, ptInteger, ptCardinal, ptLongInt, ptLongWord, ptPChar, ptShortInt, ptSmallInt, ptWideChar, ptWord: begin OrdinalIdentifier; @@ -4874,7 +4900,7 @@ procedure TmwSimplePasPar.TypeSimple; begin RealIdentifier; end; - ptAnsiString, ptShortString, ptWideString: + ptAnsiString, ptShortString, ptWideString, ptUnicodeString: begin StringIdentifier; end; @@ -4894,16 +4920,16 @@ procedure TmwSimplePasPar.TypeSimple; begin NextToken; Expected(ptOf); - case TokenID of - ptConst: (*new in ObjectPascal80*) - begin - NextToken; - end; - else - begin - TypeID; - end; - end; +// case TokenID of +// ptConst: (*new in ObjectPascal80*) +// begin +// NextToken; +// end; +// else + // begin + TypeID; +// end; +// end; end; else Expected(ptIdentifier); @@ -5058,20 +5084,28 @@ procedure TmwSimplePasPar.ExportsElement; if FLexer.ExID = ptIndex then begin - NextToken; - Expected(ptIntegerConst); + IndexSpecifier end; if FLexer.ExID = ptName then begin - NextToken; - SimpleExpression; + NameSpecifier end; if FLexer.ExID = ptResident then begin - NextToken; + Resident; end; end; +procedure TmwSimplePasPar.Resident; +begin + ExpectedEx(ptResident); +end; + +procedure TmwSimplePasPar.CompilerDirective; +begin + ExpectedEx(ptCompDirect); +end; + procedure TmwSimplePasPar.CompoundStatement; begin Expected(ptBegin); @@ -5333,11 +5367,20 @@ procedure TmwSimplePasPar.IndexSpecifier; ConstantExpression; end; +procedure TmwSimplePasPar.NameSpecifier; +begin + ExpectedEx(ptName); + SimpleExpression; +end; + procedure TmwSimplePasPar.ClassTypeEnd; begin + //should be while? because all hinting directive can occur. case ExID of - ptExperimental: NextToken; + ptExperimental: DirectiveExperimental; ptDeprecated: DirectiveDeprecated; + ptPlatform: DirectivePlatform; + ptLibrary: DirectiveLibrary; end; end; @@ -5349,12 +5392,12 @@ procedure TmwSimplePasPar.DirectiveDeprecated; begin ExpectedEx(ptDeprecated); if TokenID = ptStringConst then - NextToken; + StringConst; end; procedure TmwSimplePasPar.DirectiveInline; begin - Expected(ptInline); + ExpectedEx([ptInline, ptAssembler]); end; procedure TmwSimplePasPar.DirectiveLibrary; @@ -5367,6 +5410,28 @@ procedure TmwSimplePasPar.DirectivePlatform; ExpectedEx(ptPlatform); end; +procedure TmwSimplePasPar.DirectiveExperimental; +begin + ExpectedEx(ptExperimental); +end; + +procedure TmwSimplePasPar.DirectiveDelayed; +begin + ExpectedEx(ptDelayed); +end; + + + +procedure TmwSimplePasPar.DirectiveSealed; +begin + Expected(ptSealed); +end; + +procedure TmwSimplePasPar.DirectiveStatic; +begin + ExpectedEx(ptStatic); +end; + procedure TmwSimplePasPar.EnumeratedTypeItem; begin QualifiedIdentifier; @@ -5413,16 +5478,18 @@ procedure TmwSimplePasPar.AnonymousMethod; ptFunction: begin NextToken; - if TokenID = ptRoundOpen then + if TokenID = ptRoundOpen then begin FormalParameterList; + end; Expected(ptColon); ReturnType; end; ptProcedure: begin NextToken; - if TokenId = ptRoundOpen then + if TokenID = ptRoundOpen then begin FormalParameterList; + end; end; end; Block; @@ -5435,12 +5502,14 @@ procedure TmwSimplePasPar.AnonymousMethodType; case TokenID of ptProcedure: begin + AnonymousMethodTypeProcedure; NextToken; if TokenID = ptRoundOpen then FormalParameterList; end; ptFunction: begin + AnonymousMethodTypeFunction; NextToken; if TokenID = ptRoundOpen then FormalParameterList; @@ -5450,6 +5519,16 @@ procedure TmwSimplePasPar.AnonymousMethodType; end; end; +procedure TmwSimplePasPar.AnonymousMethodTypeProcedure; +begin + Expected(ptProcedure); +end; + +procedure TmwSimplePasPar.AnonymousMethodTypeFunction; +begin + Expected(ptFunction); +end; + procedure TmwSimplePasPar.AddDefine(const ADefine: string); begin FLexer.AddDefine(ADefine); @@ -5497,15 +5576,6 @@ procedure TmwSimplePasPar.AttributeArgumentName; Expected(ptIdentifier); end; -procedure TmwSimplePasPar.CaseLabelList; -begin - CaseLabel; - while TokenID = ptComma do - begin - NextToken; - CaseLabel; - end; -end; procedure TmwSimplePasPar.ArrayBounds; begin @@ -5543,7 +5613,7 @@ procedure TmwSimplePasPar.TypeDirective; ptDeprecated: DirectiveDeprecated; ptLibrary: DirectiveLibrary; ptPlatform: DirectivePlatform; - ptExperimental: NextToken; + ptExperimental: DirectiveExperimental; end; end;