unit DelphiAST;
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
interface
uses
SysUtils, Classes, Generics.Collections, SimpleParser, SimpleParser.Lexer,
SimpleParser.Lexer.Types, DelphiAST.Classes, DelphiAST.Consts, DelphiAST.SimpleParserEx;
type
ESyntaxTreeException = class(EParserException)
strict private
FSyntaxTree: TSyntaxNode;
public
constructor Create(Line, Col: Integer; const FileName, Msg: string; SyntaxTree: TSyntaxNode); reintroduce;
destructor Destroy; override;
property SyntaxTree: TSyntaxNode read FSyntaxTree write FSyntaxTree;
end;
TNodeStack = class
strict private
FLexer: TPasLexer;
FStack: TStack;
function GetCount: Integer;
public
constructor Create(Lexer: TPasLexer);
destructor Destroy; override;
function AddChild(Typ: TSyntaxNodeType): TSyntaxNode; overload;
function AddChild(Node: TSyntaxNode): TSyntaxNode; overload;
function AddValuedChild(Typ: TSyntaxNodeType; const Value: string): TSyntaxNode;
procedure Clear;
function Peek: TSyntaxNode;
function Pop: TSyntaxNode;
function Push(Typ: TSyntaxNodeType): TSyntaxNode; overload;
function Push(Node: TSyntaxNode): TSyntaxNode; overload;
function PushCompoundSyntaxNode(Typ: TSyntaxNodeType): TSyntaxNode;
function PushValuedNode(Typ: TSyntaxNodeType; const Value: string): TSyntaxNode;
property Count: Integer read GetCount;
end;
TPasSyntaxTreeBuilder = class(TmwSimplePasParEx)
private type
TTreeBuilderMethod = procedure of object;
private
procedure BuildExpressionTree(ExpressionMethod: TTreeBuilderMethod);
procedure BuildParametersList(ParametersListMethod: TTreeBuilderMethod);
procedure RearrangeVarSection(const VarSect: TSyntaxNode);
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 DoOnComment(Sender: TObject; const Text: string);
protected
FStack: TNodeStack;
FComments: TObjectList;
procedure AccessSpecifier; override;
procedure AdditiveOperator; override;
procedure AddressOp; override;
procedure AlignmentParameter; override;
procedure AnonymousMethod; override;
procedure ArrayBounds; override;
procedure ArrayConstant; override;
procedure ArrayDimension; override;
procedure AsmStatement; override;
procedure AsOp; override;
procedure AssignOp; override;
procedure AtExpression; override;
procedure CaseElseStatement; override;
procedure CaseLabel; override;
procedure CaseLabelList; override;
procedure CaseSelector; override;
procedure CaseStatement; override;
procedure ClassClass; override;
procedure ClassConstraint; override;
procedure ClassField; override;
procedure ClassForward; override;
procedure ClassFunctionHeading; override;
procedure ClassHelper; override;
procedure ClassMethod; override;
procedure ClassMethodResolution; override;
procedure ClassMethodHeading; override;
procedure ClassProcedureHeading; override;
procedure ClassProperty; override;
procedure ClassReferenceType; override;
procedure ClassType; override;
procedure CompoundStatement; override;
procedure ConstParameter; override;
procedure ConstantDeclaration; override;
procedure ConstantExpression; override;
procedure ConstantName; override;
procedure ConstraintList; override;
procedure ConstSection; override;
procedure ConstantValue; override;
procedure ConstantValueTyped; override;
procedure ConstructorConstraint; override;
procedure ConstructorName; override;
procedure ContainsClause; override;
procedure DestructorName; override;
procedure DirectiveBinding; override;
procedure DirectiveBindingMessage; override;
procedure DirectiveCalling; override;
procedure DirectiveInline; override;
procedure DispInterfaceForward; override;
procedure DotOp; override;
procedure ElseStatement; override;
procedure EmptyStatement; override;
procedure EnumeratedType; override;
procedure ExceptBlock; override;
procedure ExceptionBlockElseBranch; override;
procedure ExceptionHandler; override;
procedure ExceptionVariable; override;
procedure ExportedHeading; override;
procedure ExportsClause; override;
procedure ExportsElement; override;
procedure ExportsName; override;
procedure ExportsNameId; override;
procedure Expression; override;
procedure ExpressionList; override;
procedure ExternalDirective; override;
procedure FieldName; override;
procedure FinalizationSection; override;
procedure FinallyBlock; override;
procedure FormalParameterList; override;
procedure ForStatement; override;
procedure ForStatementDownTo; override;
procedure ForStatementFrom; override;
procedure ForStatementIn; override;
procedure ForStatementTo; override;
procedure FunctionHeading; override;
procedure FunctionMethodName; override;
procedure FunctionProcedureName; override;
procedure GotoStatement; override;
procedure IfStatement; override;
procedure Identifier; override;
procedure ImplementationSection; override;
procedure ImplementsSpecifier; override;
procedure IndexSpecifier; override;
procedure IndexOp; override;
procedure InheritedStatement; override;
procedure InheritedVariableReference; override;
procedure InitializationSection; override;
procedure InlineVarDeclaration; override;
procedure InlineVarSection; override;
procedure InterfaceForward; override;
procedure InterfaceGUID; override;
procedure InterfaceSection; override;
procedure InterfaceType; override;
procedure LabelId; override;
procedure MainUsesClause; override;
procedure MainUsedUnitStatement; override;
procedure MethodKind; override;
procedure MultiplicativeOperator; override;
procedure NotOp; override;
procedure NilToken; override;
procedure Number; override;
procedure ObjectNameOfMethod; override;
procedure OutParameter; override;
procedure ParameterFormal; override;
procedure ParameterName; override;
procedure PointerSymbol; override;
procedure PointerType; override;
procedure ProceduralType; override;
procedure ProcedureHeading; override;
procedure ProcedureDeclarationSection; override;
procedure ProcedureProcedureName; override;
procedure PropertyName; override;
procedure PropertyParameterList; override;
procedure RaiseStatement; override;
procedure RecordConstraint; override;
procedure RecordFieldConstant; override;
procedure RecordType; override;
procedure RelativeOperator; override;
procedure RepeatStatement; override;
procedure ResourceDeclaration; override;
procedure ResourceValue; override;
procedure RequiresClause; override;
procedure RequiresIdentifier; override;
procedure RequiresIdentifierId; override;
procedure ReturnType; override;
procedure RoundClose; override;
procedure RoundOpen; override;
procedure SetConstructor; override;
procedure SetElement; override;
procedure SimpleStatement; override;
procedure SimpleType; override;
procedure StatementList; override;
procedure StorageDefault; override;
procedure StringConst; override;
procedure StringConstSimple; override;
procedure StringStatement; override;
procedure StructuredType; override;
procedure SubrangeType; override;
procedure ThenStatement; override;
procedure TryStatement; override;
procedure TypeArgs; override;
procedure TypeDeclaration; override;
procedure TypeId; override;
procedure TypeParamDecl; override;
procedure TypeParams; override;
procedure TypeSection; override;
procedure TypeSimple; override;
procedure UnaryMinus; override;
procedure UnitFile; override;
procedure UnitName; override;
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 VisibilityPrivate; override;
procedure VisibilityProtected; override;
procedure VisibilityPublic; override;
procedure VisibilityPublished; override;
procedure VisibilityStrictPrivate; override;
procedure VisibilityStrictProtected; override;
procedure WhileStatement; override;
procedure WithExpressionList; override;
procedure WithStatement; override;
procedure AttributeSections; override;
procedure Attribute; override;
procedure AttributeName; override;
procedure AttributeArguments; override;
procedure PositionalArgument; override;
procedure NamedArgument; override;
procedure AttributeArgumentName; override;
procedure AttributeArgumentExpression; override;
public
constructor Create; override;
destructor Destroy; override;
function Run(SourceStream: TStream): TSyntaxNode; reintroduce; overload; virtual;
class function Run(const FileName: string; InterfaceOnly: Boolean = False;
IncludeHandler: IIncludeHandler = nil;
OnHandleString: TStringEvent = nil): TSyntaxNode; reintroduce; overload; static;
property Comments: TObjectList read FComments;
end;
implementation
uses
TypInfo;
{$IFDEF FPC}
type
TStringStreamHelper = class helper for TStringStream
class function Create: TStringStream; overload;
procedure LoadFromFile(const FileName: string);
end;
{ TStringStreamHelper }
class function TStringStreamHelper.Create: TStringStream;
begin
Result := TStringStream.Create('');
end;
procedure TStringStreamHelper.LoadFromFile(const FileName: string);
var
Strings: TStringList;
begin
Strings := TStringList.Create;
try
Strings.LoadFromFile(FileName);
Strings.SaveToStream(Self);
finally
FreeAndNil(Strings);
end;
end;
{$ENDIF}
// do not use const strings here to prevent allocating new strings every time
type
TAttributeValue = (atAsm, atTrue, atFunction, atProcedure, atClassOf, atClass,
atConst, atConstructor, atDestructor, atEnum, atInterface, atNil, atNumeric,
atOut, atPointer, atName, atString, atSubRange, atVar, atDispInterface);
var
AttributeValues: array[TAttributeValue] of string;
procedure InitAttributeValues;
var
value: TAttributeValue;
begin
for value := Low(TAttributeValue) to High(TAttributeValue) do
AttributeValues[value] := Copy(LowerCase(GetEnumName(TypeInfo(TAttributeValue), Ord(value))), 3);
end;
procedure AssignLexerPositionToNode(const Lexer: TPasLexer; const Node: TSyntaxNode);
begin
Node.Col := Lexer.PosXY.X;
Node.Line := Lexer.PosXY.Y;
Node.FileName := Lexer.FileName;
end;
{ TNodeStack }
function TNodeStack.AddChild(Typ: TSyntaxNodeType): TSyntaxNode;
begin
Result := FStack.Peek.AddChild(TSyntaxNode.Create(Typ));
AssignLexerPositionToNode(FLexer, Result);
end;
function TNodeStack.AddChild(Node: TSyntaxNode): TSyntaxNode;
begin
Result := FStack.Peek.AddChild(Node);
end;
function TNodeStack.AddValuedChild(Typ: TSyntaxNodeType;
const Value: string): TSyntaxNode;
begin
Result := FStack.Peek.AddChild(TValuedSyntaxNode.Create(Typ));
AssignLexerPositionToNode(FLexer, Result);
TValuedSyntaxNode(Result).Value := Value;
end;
procedure TNodeStack.Clear;
begin
FStack.Clear;
end;
constructor TNodeStack.Create(Lexer: TPasLexer);
begin
FLexer := Lexer;
FStack := TStack.Create;
end;
destructor TNodeStack.Destroy;
begin
FStack.Free;
inherited;
end;
function TNodeStack.GetCount: Integer;
begin
Result := FStack.Count;
end;
function TNodeStack.Peek: TSyntaxNode;
begin
Result := FStack.Peek;
end;
function TNodeStack.Pop: TSyntaxNode;
begin
Result := FStack.Pop;
end;
function TNodeStack.Push(Node: TSyntaxNode): TSyntaxNode;
begin
FStack.Push(Node);
Result := Node;
AssignLexerPositionToNode(FLexer, Result);
end;
function TNodeStack.PushCompoundSyntaxNode(Typ: TSyntaxNodeType): TSyntaxNode;
begin
Result := Push(Peek.AddChild(TCompoundSyntaxNode.Create(Typ)));
end;
function TNodeStack.PushValuedNode(Typ: TSyntaxNodeType;
const Value: string): TSyntaxNode;
begin
Result := Push(Peek.AddChild(TValuedSyntaxNode.Create(Typ)));
TValuedSyntaxNode(Result).Value := Value;
end;
function TNodeStack.Push(Typ: TSyntaxNodeType): TSyntaxNode;
begin
Result := FStack.Peek.AddChild(TSyntaxNode.Create(Typ));
Push(Result);
end;
{ TPasSyntaxTreeBuilder }
procedure TPasSyntaxTreeBuilder.AccessSpecifier;
begin
case ExID of
ptRead:
FStack.Push(ntRead);
ptWrite:
FStack.Push(ntWrite);
else
FStack.Push(ntUnknown);
end;
try
inherited AccessSpecifier;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AdditiveOperator;
begin
case TokenID of
ptMinus: FStack.AddChild(ntSub);
ptOr: FStack.AddChild(ntOr);
ptPlus: FStack.AddChild(ntAdd);
ptXor: FStack.AddChild(ntXor);
end;
inherited;
end;
procedure TPasSyntaxTreeBuilder.AddressOp;
begin
FStack.Push(ntAddr);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AlignmentParameter;
begin
FStack.Push(ntAlignmentParam);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AnonymousMethod;
begin
FStack.Push(ntAnonymousMethod);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ArrayBounds;
begin
FStack.Push(ntBounds);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ArrayConstant;
begin
FStack.Push(ntExpressions);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ArrayDimension;
begin
FStack.Push(ntDimension);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AsmStatement;
begin
FStack.PushCompoundSyntaxNode(ntStatements).SetAttribute(anType, AttributeValues[atAsm]);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AsOp;
begin
FStack.AddChild(ntAs);
inherited;
end;
procedure TPasSyntaxTreeBuilder.AssignOp;
begin
FStack.AddChild(ntAssign);
inherited;
end;
procedure TPasSyntaxTreeBuilder.AtExpression;
begin
FStack.Push(ntAt);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.Attribute;
begin
FStack.Push(ntAttribute);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AttributeArgumentExpression;
begin
FStack.Push(ntValue);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AttributeArgumentName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.AttributeArguments;
begin
FStack.Push(ntArguments);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.AttributeName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.AttributeSections;
begin
FStack.Push(ntAttributes);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.BuildExpressionTree(
ExpressionMethod: TTreeBuilderMethod);
var
RawExprNode: TSyntaxNode;
ExprNode: TSyntaxNode;
NodeList: TList;
Node: TSyntaxNode;
Col, Line: Integer;
FileName: string;
begin
Line := Lexer.PosXY.Y;
Col := Lexer.PosXY.X;
FileName := Lexer.FileName;
RawExprNode := TSyntaxNode.Create(ntExpression);
try
FStack.Push(RawExprNode);
try
ExpressionMethod;
finally
FStack.Pop;
end;
if RawExprNode.HasChildren then
begin
ExprNode := FStack.Push(ntExpression);
try
ExprNode.Line := Line;
ExprNode.Col := Col;
ExprNode.FileName := FileName;
NodeList := TList.Create;
try
for Node in RawExprNode.ChildNodes do
NodeList.Add(Node);
TExpressionTools.RawNodeListToTree(RawExprNode, NodeList, ExprNode);
finally
NodeList.Free;
end;
finally
FStack.Pop;
end;
end;
finally
RawExprNode.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.BuildParametersList(
ParametersListMethod: TTreeBuilderMethod);
var
Params, Temp: 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.FindNode(ntType);
ParamKind := ParamList.GetAttribute(anKind);
ParamExpr := ParamList.FindNode(ntExpression);
for Param in ParamList.ChildNodes do
begin
if Param.Typ ntName then
Continue;
Temp := FStack.Push(ntParameter);
if ParamKind '' then
Temp.SetAttribute(anKind, ParamKind);
Temp.Col := Param.Col;
Temp.Line := Param.Line;
FStack.AddChild(Param.Clone);
if Assigned(TypeInfo) then
FStack.AddChild(TypeInfo.Clone);
if Assigned(ParamExpr) then
FStack.AddChild(ParamExpr.Clone);
FStack.Pop;
end;
end;
FStack.Pop;
finally
Params.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.CaseElseStatement;
begin
FStack.Push(ntCaseElse);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.CaseLabel;
begin
FStack.Push(ntCaseLabel);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.CaseLabelList;
begin
FStack.Push(ntCaseLabels);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.CaseSelector;
begin
FStack.Push(ntCaseSelector);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.CaseStatement;
begin
FStack.Push(ntCase);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassClass;
begin
FStack.Peek.SetAttribute(anClass, AttributeValues[atTrue]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ClassField;
var
Fields, Temp: TSyntaxNode;
Field, TypeInfo, TypeArgs: TSyntaxNode;
begin
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);
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.ClassForward;
begin
FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]);
inherited ClassForward;
end;
procedure TPasSyntaxTreeBuilder.ClassFunctionHeading;
begin
FStack.Peek.SetAttribute(anKind, AttributeValues[atFunction]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ClassHelper;
begin
FStack.Push(ntHelper);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassMethod;
begin
FStack.Peek.SetAttribute(anClass, AttributeValues[atTrue]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ClassMethodResolution;
begin
FStack.Push(ntResolutionClause);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassMethodHeading;
begin
FStack.PushCompoundSyntaxNode(ntMethod);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassProcedureHeading;
begin
FStack.Peek.SetAttribute(anKind, AttributeValues[atProcedure]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ClassProperty;
begin
FStack.Push(ntProperty);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassReferenceType;
begin
FStack.Push(ntType).SetAttribute(anType, AttributeValues[atClassof]);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassType;
begin
FStack.Push(ntType).SetAttribute(anType, AttributeValues[atClass]);
try
inherited;
finally
MoveMembersToVisibilityNodes(FStack.Pop);
end;
end;
procedure TPasSyntaxTreeBuilder.MoveMembersToVisibilityNodes(TypeNode: TSyntaxNode);
var
child, vis: TSyntaxNode;
i: Integer;
extracted: Boolean;
begin
vis := nil;
i := 0;
while i < Length(TypeNode.ChildNodes) do
begin
child := TypeNode.ChildNodes[i];
extracted := false;
if child.HasAttribute(anVisibility) then
vis := child
else if Assigned(vis) then
begin
TypeNode.ExtractChild(child);
vis.AddChild(child);
extracted := true;
end;
if not extracted then
inc(i);
end;
end;
procedure TPasSyntaxTreeBuilder.ConstParameter;
begin
FStack.Push(ntParameters).SetAttribute(anKind, AttributeValues[atConst]);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstructorName;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Peek;
Temp.SetAttribute(anKind, AttributeValues[atConstructor]);
Temp.SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.CompoundStatement;
begin
FStack.PushCompoundSyntaxNode(ntStatements);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstantDeclaration;
begin
FStack.Push(ntConstant);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstantExpression;
var
ExpressionMethod: TTreeBuilderMethod;
begin
ExpressionMethod := CallInheritedConstantExpression;
BuildExpressionTree(ExpressionMethod);
end;
procedure TPasSyntaxTreeBuilder.CallInheritedFormalParameterList;
begin
inherited FormalParameterList;
end;
procedure TPasSyntaxTreeBuilder.CallInheritedConstantExpression;
begin
inherited ConstantExpression;
end;
procedure TPasSyntaxTreeBuilder.ConstantName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ConstantValue;
begin
FStack.Push(ntValue);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstantValueTyped;
begin
FStack.Push(ntValue);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstraintList;
begin
FStack.Push(ntConstraints);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ClassConstraint;
begin
FStack.Push(ntClassConstraint);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstructorConstraint;
begin
FStack.Push(ntConstructorConstraint);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.RecordConstraint;
begin
FStack.Push(ntRecordConstraint);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ConstSection;
var
ConstSect, Temp: TSyntaxNode;
ConstList, Constant, TypeInfo, Value: TSyntaxNode;
begin
ConstSect := TSyntaxNode.Create(ntConstants);
try
FStack.Push(ntConstants);
FStack.Push(ConstSect);
try
inherited ConstSection;
finally
FStack.Pop;
end;
for ConstList in ConstSect.ChildNodes do
begin
TypeInfo := ConstList.FindNode(ntType);
Value := ConstList.FindNode(ntValue);
for Constant in ConstList.ChildNodes do
begin
if Constant.Typ ntName then
Continue;
Temp := FStack.Push(ConstList.Typ);
try
Temp.AssignPositionFrom(Constant);
FStack.AddChild(Constant.Clone);
if Assigned(TypeInfo) then
FStack.AddChild(TypeInfo.Clone);
FStack.AddChild(Value.Clone);
finally
FStack.Pop;
end;
end;
end;
FStack.Pop;
finally
ConstSect.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.ContainsClause;
begin
FStack.Push(ntContains);
try
inherited;
finally
FStack.Pop;
end;
end;
constructor TPasSyntaxTreeBuilder.Create;
begin
inherited;
FStack := TNodeStack.Create(Lexer);
FComments := TObjectList.Create(True);
OnComment := DoOnComment;
end;
destructor TPasSyntaxTreeBuilder.Destroy;
begin
FStack.Free;
FComments.Free;
inherited;
end;
procedure TPasSyntaxTreeBuilder.DestructorName;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Peek;
Temp.SetAttribute(anKind, AttributeValues[atDestructor]);
Temp.SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.DirectiveBinding;
var
token: string;
begin
token := Lexer.Token;
// Method bindings:
if SameText(token, 'override') or SameText(token, 'virtual')
or SameText(token, 'dynamic')
then
FStack.Peek.SetAttribute(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]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.DirectiveBindingMessage;
begin
FStack.Push(ntMessage);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.DirectiveCalling;
begin
FStack.Peek.SetAttribute(anCallingConvention, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.DirectiveInline;
begin
FStack.Peek.SetAttribute(anInline, AttributeValues[atTrue]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.DispInterfaceForward;
begin
FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.DotOp;
begin
FStack.AddChild(ntDot);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ElseStatement;
begin
FStack.Push(ntElse);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.EmptyStatement;
begin
FStack.Push(ntEmptyStatement);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.EnumeratedType;
var
TypeNode: TSyntaxNode;
begin
TypeNode := FStack.Push(ntType);
try
TypeNode.SetAttribute(anName, AttributeValues[atEnum]);
if ScopedEnums then
TypeNode.SetAttribute(anVisibility, 'scoped');
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExceptBlock;
begin
FStack.Push(ntExcept);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExceptionBlockElseBranch;
begin
FStack.Push(ntElse);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExceptionHandler;
begin
FStack.Push(ntExceptionHandler);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExceptionVariable;
begin
FStack.Push(ntVariable);
FStack.AddValuedChild(ntName, Lexer.Token);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExportedHeading;
begin
FStack.PushCompoundSyntaxNode(ntMethod);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExportsClause;
begin
FStack.Push(ntExports);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExportsElement;
begin
FStack.Push(ntElement);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExportsName;
var
NamesNode: TSyntaxNode;
begin
NamesNode := TSyntaxNode.Create(ntUnknown);
try
FStack.Push(NamesNode);
try
inherited;
finally
FStack.Pop;
end;
FStack.Peek.SetAttribute(anName, NodeListToString(NamesNode));
finally
NamesNode.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.ExportsNameId;
begin
FStack.AddChild(ntUnknown).SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.Expression;
var
ExpressionMethod: TTreeBuilderMethod;
begin
ExpressionMethod := CallInheritedExpression;
BuildExpressionTree(ExpressionMethod);
end;
procedure TPasSyntaxTreeBuilder.SetCurrentCompoundNodesEndPosition;
var
Temp: TCompoundSyntaxNode;
begin
Temp := TCompoundSyntaxNode(FStack.Peek);
Temp.EndCol := Lexer.PosXY.X;
Temp.EndLine := Lexer.PosXY.Y;
Temp.FileName := Lexer.FileName;
end;
procedure TPasSyntaxTreeBuilder.CallInheritedExpression;
begin
inherited Expression;
end;
procedure TPasSyntaxTreeBuilder.CallInheritedPropertyParameterList;
begin
inherited PropertyParameterList;
end;
procedure TPasSyntaxTreeBuilder.ExpressionList;
begin
FStack.Push(ntExpressions);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ExternalDirective;
begin
FStack.Push(ntExternal);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.FieldName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.FinalizationSection;
begin
FStack.PushCompoundSyntaxNode(ntFinalization);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.FinallyBlock;
begin
FStack.Push(ntFinally);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.FormalParameterList;
var
TreeBuilderMethod: TTreeBuilderMethod;
begin
TreeBuilderMethod := CallInheritedFormalParameterList;
BuildParametersList(TreeBuilderMethod);
end;
procedure TPasSyntaxTreeBuilder.ForStatement;
begin
FStack.Push(ntFor);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ForStatementDownTo;
begin
FStack.Push(ntDownTo);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ForStatementFrom;
begin
FStack.Push(ntFrom);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ForStatementIn;
begin
FStack.Push(ntIn);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ForStatementTo;
begin
FStack.Push(ntTo);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.FunctionHeading;
begin
FStack.Peek.SetAttribute(anKind, AttributeValues[atFunction]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.FunctionMethodName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.FunctionProcedureName;
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 + '';
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;
end;
procedure TPasSyntaxTreeBuilder.GotoStatement;
begin
FStack.Push(ntGoto);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.Identifier;
begin
FStack.AddChild(ntIdentifier).SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.IfStatement;
begin
FStack.Push(ntIf);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ImplementationSection;
begin
FStack.PushCompoundSyntaxNode(ntImplementation);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ImplementsSpecifier;
begin
FStack.Push(ntImplements);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.IndexOp;
begin
FStack.Push(ntIndexed);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.IndexSpecifier;
begin
FStack.Push(ntIndex);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InheritedStatement;
begin
FStack.Push(ntInherited);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InheritedVariableReference;
begin
FStack.Push(ntInherited);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InitializationSection;
begin
FStack.PushCompoundSyntaxNode(ntInitialization);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InlineVarDeclaration;
begin
FStack.Push(ntVariables);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InlineVarSection;
var
VarSect, Variables, Expression: TSyntaxNode;
begin
VarSect := TSyntaxNode.Create(ntUnknown);
try
Variables := FStack.Push(ntVariables);
FStack.Push(VarSect);
try
inherited InlineVarSection;
finally
FStack.Pop;
end;
RearrangeVarSection(VarSect);
Expression := VarSect.FindNode(ntExpression);
if Assigned(Expression) then
Variables.AddChild(ntAssign).AddChild(Expression.Clone);
FStack.Pop;
finally
VarSect.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.InterfaceForward;
begin
FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]);
inherited InterfaceForward;
end;
procedure TPasSyntaxTreeBuilder.InterfaceGUID;
begin
FStack.Push(ntGuid);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InterfaceSection;
begin
FStack.PushCompoundSyntaxNode(ntInterface);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.InterfaceType;
begin
case TokenID of
ptInterface:
FStack.Push(ntType).SetAttribute(anType, AttributeValues[atInterface]);
ptDispInterface:
FStack.Push(ntType).SetAttribute(anType, AttributeValues[atDispInterface]);
end;
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.LabelId;
begin
FStack.AddValuedChild(ntLabel, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.MainUsedUnitStatement;
var
NameNode, PathNode, PathLiteralNode, Temp: TSyntaxNode;
begin
FStack.Push(ntUnit);
try
inherited;
NameNode := FStack.Peek.FindNode(ntUnit);
if Assigned(NameNode) then
begin
Temp := FStack.Peek;
Temp.SetAttribute(anName, NameNode.GetAttribute(anName));
Temp.DeleteChild(NameNode);
end;
PathNode := FStack.Peek.FindNode(ntExpression);
if Assigned(PathNode) then
begin
FStack.Peek.ExtractChild(PathNode);
try
PathLiteralNode := PathNode.FindNode(ntLiteral);
if PathLiteralNode is TValuedSyntaxNode then
FStack.Peek.SetAttribute(anPath, TValuedSyntaxNode(PathLiteralNode).Value);
finally
PathNode.Free;
end;
end;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.MainUsesClause;
begin
FStack.PushCompoundSyntaxNode(ntUses);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.MethodKind;
var
value: string;
begin
value := LowerCase(Lexer.Token);
DoHandleString(value);
FStack.Peek.SetAttribute(anKind, value);
inherited;
end;
procedure TPasSyntaxTreeBuilder.MultiplicativeOperator;
begin
case TokenID of
ptAnd:
FStack.AddChild(ntAnd);
ptDiv:
FStack.AddChild(ntDiv);
ptMod:
FStack.AddChild(ntMod);
ptShl:
FStack.AddChild(ntShl);
ptShr:
FStack.AddChild(ntShr);
ptSlash:
FStack.AddChild(ntFDiv);
ptStar:
FStack.AddChild(ntMul);
else
FStack.AddChild(ntUnknown);
end;
inherited;
end;
procedure TPasSyntaxTreeBuilder.NamedArgument;
begin
FStack.Push(ntNamedArgument);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.NilToken;
begin
FStack.AddChild(ntLiteral).SetAttribute(anType, AttributeValues[atNil]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.NotOp;
begin
FStack.AddChild(ntNot);
inherited;
end;
procedure TPasSyntaxTreeBuilder.Number;
var
Node: TSyntaxNode;
begin
Node := FStack.AddValuedChild(ntLiteral, Lexer.Token);
Node.SetAttribute(anType, AttributeValues[atNumeric]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ObjectNameOfMethod;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.DoOnComment(Sender: TObject; const Text: string);
var
Node: TCommentNode;
begin
case TokenID of
ptAnsiComment: Node := TCommentNode.Create(ntAnsiComment);
ptBorComment: Node := TCommentNode.Create(ntAnsiComment);
ptSlashesComment: Node := TCommentNode.Create(ntSlashesComment);
else
raise EParserException.Create(Lexer.PosXY.Y, Lexer.PosXY.X, Lexer.FileName, 'Invalid comment type');
end;
AssignLexerPositionToNode(Lexer, Node);
Node.Text := Text;
FComments.Add(Node);
end;
procedure TPasSyntaxTreeBuilder.ParserMessage(Sender: TObject;
const Typ: TMessageEventType; const Msg: string; X, Y: Integer);
begin
if Typ = TMessageEventType.meError then
raise EParserException.Create(Y, X, Lexer.FileName, Msg);
end;
procedure TPasSyntaxTreeBuilder.OutParameter;
begin
FStack.Push(ntParameters).SetAttribute(anKind, AttributeValues[atOut]);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ParameterFormal;
begin
FStack.Push(ntParameters);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ParameterName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.PointerSymbol;
begin
FStack.AddChild(ntDeref);
inherited;
end;
procedure TPasSyntaxTreeBuilder.PointerType;
begin
FStack.Push(ntType).SetAttribute(anType, AttributeValues[atPointer]);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.PositionalArgument;
begin
FStack.Push(ntPositionalArgument);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ProceduralType;
begin
FStack.Push(ntType).SetAttribute(anName, Lexer.Token);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ProcedureDeclarationSection;
begin
FStack.PushCompoundSyntaxNode(ntMethod);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ProcedureHeading;
begin
FStack.Peek.SetAttribute(anKind, AttributeValues[atProcedure]);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ProcedureProcedureName;
begin
FStack.Peek.SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.PropertyName;
begin
FStack.Peek.SetAttribute(anName, Lexer.Token);
inherited PropertyName;
end;
procedure TPasSyntaxTreeBuilder.PropertyParameterList;
var
TreeBuilderMethod: TTreeBuilderMethod;
begin
TreeBuilderMethod := CallInheritedPropertyParameterList;
BuildParametersList(TreeBuilderMethod);
end;
procedure TPasSyntaxTreeBuilder.RaiseStatement;
begin
FStack.Push(ntRaise);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.RecordFieldConstant;
var
Node: TSyntaxNode;
begin
Node := FStack.PushValuedNode(ntField, Lexer.Token);
try
Node.SetAttribute(anType, AttributeValues[atName]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.RecordType;
begin
inherited RecordType;
MoveMembersToVisibilityNodes(FStack.Peek);
end;
procedure TPasSyntaxTreeBuilder.RelativeOperator;
begin
case TokenID of
ptAs:
FStack.AddChild(ntAs);
ptEqual:
FStack.AddChild(ntEqual);
ptGreater:
FStack.AddChild(ntGreater);
ptGreaterEqual:
FStack.AddChild(ntGreaterEqual);
ptIn:
FStack.AddChild(ntIn);
ptIs:
FStack.AddChild(ntIs);
ptLower:
FStack.AddChild(ntLower);
ptLowerEqual:
FStack.AddChild(ntLowerEqual);
ptNotEqual:
FStack.AddChild(ntNotEqual);
else
FStack.AddChild(ntUnknown);
end;
inherited;
end;
procedure TPasSyntaxTreeBuilder.RepeatStatement;
begin
FStack.Push(ntRepeat);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.RequiresClause;
begin
FStack.Push(ntRequires);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.RequiresIdentifier;
var
NamesNode: TSyntaxNode;
begin
NamesNode := TSyntaxNode.Create(ntUnknown);
try
FStack.Push(NamesNode);
try
inherited;
finally
FStack.Pop;
end;
FStack.AddChild(ntPackage).SetAttribute(anName, NodeListToString(NamesNode));
finally
NamesNode.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.RequiresIdentifierId;
begin
FStack.AddChild(ntUnknown).SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.ResourceDeclaration;
begin
FStack.Push(ntResourceString);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ResourceValue;
begin
FStack.Push(ntValue);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ReturnType;
begin
FStack.Push(ntReturnType);
try
inherited;
finally
FStack.Pop
end;
end;
procedure TPasSyntaxTreeBuilder.RoundClose;
begin
FStack.AddChild(ntRoundClose);
inherited;
end;
procedure TPasSyntaxTreeBuilder.RoundOpen;
begin
FStack.AddChild(ntRoundOpen);
inherited;
end;
class function TPasSyntaxTreeBuilder.Run(const FileName: string;
InterfaceOnly: Boolean; IncludeHandler: IIncludeHandler;
OnHandleString: TStringEvent): TSyntaxNode;
var
Stream: TStringStream;
Builder: TPasSyntaxTreeBuilder;
begin
Stream := TStringStream.Create;
try
Stream.LoadFromFile(FileName);
Builder := TPasSyntaxTreeBuilder.Create;
Builder.InterfaceOnly := InterfaceOnly;
Builder.OnHandleString := OnHandleString;
try
Builder.InitDefinesDefinedByCompiler;
Builder.IncludeHandler := IncludeHandler;
Result := Builder.Run(Stream);
finally
Builder.Free;
end;
finally
Stream.Free;
end;
end;
function TPasSyntaxTreeBuilder.Run(SourceStream: TStream): TSyntaxNode;
begin
Result := TSyntaxNode.Create(ntUnit);
try
FStack.Clear;
FStack.Push(Result);
try
self.OnMessage := ParserMessage;
inherited Run('', SourceStream);
finally
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);
else
FreeAndNil(Result);
raise;
end;
Assert(FStack.Count = 0);
end;
function TPasSyntaxTreeBuilder.NodeListToString(NamesNode: TSyntaxNode): string;
var
NamePartNode: TSyntaxNode;
begin
Result := '';
for NamePartNode in NamesNode.ChildNodes do
begin
if Result '' then
Result := Result + '.';
Result := Result + NamePartNode.GetAttribute(anName);
end;
DoHandleString(Result);
end;
procedure TPasSyntaxTreeBuilder.SetConstructor;
begin
FStack.Push(ntSet);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.SetElement;
begin
FStack.Push(ntElement);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.SimpleStatement;
var
RawStatement, Temp: TSyntaxNode;
Node, LHS, RHS: TSyntaxNode;
NodeList: TList;
I, AssignIdx: Integer;
Position: TTokenPoint;
FileName: string;
begin
Position := Lexer.PosXY;
FileName := Lexer.FileName;
RawStatement := TSyntaxNode.Create(ntStatement);
try
FStack.Push(RawStatement);
try
inherited;
finally
FStack.Pop;
end;
if not RawStatement.HasChildren then
Exit;
if RawStatement.FindNode(ntAssign) nil then
begin
Temp := FStack.Push(ntAssign);
try
Temp.Col := Position.X;
Temp.Line := Position.Y;
Temp.FileName := FileName;
NodeList := TList.Create;
try
AssignIdx := -1;
for I := 0 to Length(RawStatement.ChildNodes) - 1 do
begin
if RawStatement.ChildNodes[I].Typ = ntAssign then
begin
AssignIdx := I;
Break;
end;
NodeList.Add(RawStatement.ChildNodes[I]);
end;
if NodeList.Count = 0 then
raise EParserException.Create(Position.Y, Position.X, Lexer.FileName, 'Illegal expression');
LHS := FStack.AddChild(ntLHS);
LHS.AssignPositionFrom(NodeList[0]);
TExpressionTools.RawNodeListToTree(RawStatement, NodeList, LHS);
NodeList.Clear;
for I := AssignIdx + 1 to Length(RawStatement.ChildNodes) - 1 do
NodeList.Add(RawStatement.ChildNodes[I]);
if NodeList.Count = 0 then
raise EParserException.Create(Position.Y, Position.X, Lexer.FileName, 'Illegal expression');
RHS := FStack.AddChild(ntRHS);
RHS.AssignPositionFrom(NodeList[0]);
TExpressionTools.RawNodeListToTree(RawStatement, NodeList, RHS);
finally
NodeList.Free;
end;
finally
FStack.Pop;
end;
end else
begin
Temp := FStack.Push(ntCall);
try
Temp.Col := Position.X;
Temp.Line := Position.Y;
NodeList := TList.Create;
try
for Node in RawStatement.ChildNodes do
NodeList.Add(Node);
TExpressionTools.RawNodeListToTree(RawStatement, NodeList, FStack.Peek);
finally
NodeList.Free;
end;
finally
FStack.Pop;
end;
end;
finally
RawStatement.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.SimpleType;
begin
FStack.Push(ntType).SetAttribute(anName, Lexer.Token);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.StatementList;
begin
FStack.PushCompoundSyntaxNode(ntStatements);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.StorageDefault;
begin
FStack.Push(ntDefault);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.StringConst;
var
StrConst: TSyntaxNode;
Literal, Node: TSyntaxNode;
Str: string;
begin
StrConst := TSyntaxNode.Create(ntUnknown);
try
FStack.Push(StrConst);
try
inherited;
finally
FStack.Pop;
end;
Str := '';
for Literal in StrConst.ChildNodes do
Str := Str + TValuedSyntaxNode(Literal).Value;
finally
StrConst.Free;
end;
DoHandleString(Str);
Node := FStack.AddValuedChild(ntLiteral, Str);
Node.SetAttribute(anType, AttributeValues[atString]);
end;
procedure TPasSyntaxTreeBuilder.StringConstSimple;
begin
//TODO support ptAsciiChar
FStack.AddValuedChild(ntLiteral, AnsiDequotedStr(Lexer.Token, ''''));
inherited;
end;
procedure TPasSyntaxTreeBuilder.StringStatement;
begin
FStack.AddChild(ntType).SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.StructuredType;
begin
FStack.Push(ntType).SetAttribute(anType, Lexer.Token);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.SubrangeType;
begin
FStack.Push(ntType).SetAttribute(anName, AttributeValues[atSubRange]);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.ThenStatement;
begin
FStack.Push(ntThen);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TryStatement;
begin
FStack.Push(ntTry);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeArgs;
begin
FStack.Push(ntTypeArgs);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeDeclaration;
begin
FStack.PushCompoundSyntaxNode(ntTypeDecl).SetAttribute(anName, Lexer.Token);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeId;
var
TypeNode, InnerTypeNode, SubNode: TSyntaxNode;
TypeName, InnerTypeName: string;
i: integer;
begin
TypeNode := FStack.Push(ntType);
try
inherited;
InnerTypeName := '';
InnerTypeNode := TypeNode.FindNode(ntType);
if Assigned(InnerTypeNode) then
begin
InnerTypeName := InnerTypeNode.GetAttribute(anName);
for SubNode in InnerTypeNode.ChildNodes do
TypeNode.AddChild(SubNode.Clone);
TypeNode.DeleteChild(InnerTypeNode);
end;
TypeName := '';
for i := Length(TypeNode.ChildNodes) - 1 downto 0 do
begin
SubNode := TypeNode.ChildNodes[i];
if SubNode.Typ = ntType then
begin
if TypeName '' then
TypeName := '.' + TypeName;
TypeName := SubNode.GetAttribute(anName) + TypeName;
TypeNode.DeleteChild(SubNode);
end;
end;
if TypeName '' then
TypeName := '.' + TypeName;
TypeName := InnerTypeName + TypeName;
DoHandleString(TypeName);
TypeNode.SetAttribute(anName, TypeName);
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeParamDecl;
var
OriginTypeParamNode, NewTypeParamNode, Constraints, TypeNode: TSyntaxNode;
TypeNodeCount: integer;
TypeNodesToDelete: TList;
begin
OriginTypeParamNode := FStack.Push(ntTypeParam);
try
inherited;
finally
FStack.Pop;
end;
Constraints := OriginTypeParamNode.FindNode(ntConstraints);
TypeNodeCount := 0;
TypeNodesToDelete := TList.Create;
try
for TypeNode in OriginTypeParamNode.ChildNodes do
begin
if TypeNode.Typ = ntType then
begin
inc(TypeNodeCount);
if TypeNodeCount > 1 then
begin
NewTypeParamNode := FStack.Push(ntTypeParam);
try
NewTypeParamNode.AddChild(TypeNode.Clone);
if Assigned(Constraints) then
NewTypeParamNode.AddChild(Constraints.Clone);
TypeNodesToDelete.Add(TypeNode);
finally
FStack.Pop;
end;
end;
end;
end;
for TypeNode in TypeNodesToDelete do
OriginTypeParamNode.DeleteChild(TypeNode);
finally
TypeNodesToDelete.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeParams;
begin
FStack.Push(ntTypeParams);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeSection;
begin
FStack.Push(ntTypeSection);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.TypeSimple;
begin
FStack.Push(ntType).SetAttribute(anName, Lexer.Token);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.UnaryMinus;
begin
FStack.AddChild(ntUnaryMinus);
inherited;
end;
procedure TPasSyntaxTreeBuilder.UnitFile;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Peek;
AssignLexerPositionToNode(Lexer, Temp);
inherited;
end;
procedure TPasSyntaxTreeBuilder.UnitId;
begin
FStack.AddChild(ntUnknown).SetAttribute(anName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.UnitName;
var
NamesNode: TSyntaxNode;
begin
NamesNode := TSyntaxNode.Create(ntUnknown);
try
FStack.Push(NamesNode);
try
inherited;
finally
FStack.Pop;
end;
FStack.Peek.SetAttribute(anName, NodeListToString(NamesNode));
finally
NamesNode.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.UsedUnitName;
var
NamesNode, UnitNode: TSyntaxNode;
Position: TTokenPoint;
FileName: string;
begin
Position := Lexer.PosXY;
FileName := Lexer.FileName;
NamesNode := TSyntaxNode.Create(ntUnit);
try
FStack.Push(NamesNode);
try
inherited;
finally
FStack.Pop;
end;
UnitNode := FStack.AddChild(ntUnit);
UnitNode.SetAttribute(anName, NodeListToString(NamesNode));
UnitNode.Col := Position.X;
UnitNode.Line := Position.Y;
UnitNode.FileName := FileName;
finally
NamesNode.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.UsesClause;
begin
FStack.PushCompoundSyntaxNode(ntUses);
try
inherited;
SetCurrentCompoundNodesEndPosition;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VarAbsolute;
begin
FStack.Push(ntAbsolute);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VarDeclaration;
begin
FStack.Push(ntVariables);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VarName;
begin
FStack.AddValuedChild(ntName, Lexer.Token);
inherited;
end;
procedure TPasSyntaxTreeBuilder.VarParameter;
begin
FStack.Push(ntParameters).SetAttribute(anKind, AttributeValues[atVar]);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VarSection;
var
VarSect: TSyntaxNode;
begin
VarSect := TSyntaxNode.Create(ntUnknown);
try
FStack.Push(ntVariables);
FStack.Push(VarSect);
try
inherited VarSection;
finally
FStack.Pop;
end;
RearrangeVarSection(VarSect);
FStack.Pop;
finally
VarSect.Free;
end;
end;
procedure TPasSyntaxTreeBuilder.RearrangeVarSection(const VarSect: TSyntaxNode);
var
Temp: TSyntaxNode;
VarList, Variable, TypeInfo, ValueInfo: TSyntaxNode;
begin
for VarList in VarSect.ChildNodes do
begin
TypeInfo := VarList.FindNode(ntType);
ValueInfo := VarList.FindNode(ntValue);
for Variable in VarList.ChildNodes do
begin
if Variable.Typ ntName then
Continue;
Temp := FStack.Push(ntVariable);
try
Temp.AssignPositionFrom(Variable);
FStack.AddChild(Variable.Clone);
if Assigned(TypeInfo) then
FStack.AddChild(TypeInfo.Clone);
if Assigned(ValueInfo) then
FStack.AddChild(ValueInfo.Clone)
else
begin
Temp := VarList.FindNode([ntAbsolute, ntValue, ntExpression, ntIdentifier]);
if Assigned(Temp) then
FStack.AddChild(ntAbsolute).AddChild(Temp.Clone);
end;
finally
FStack.Pop;
end;
end;
end;
end;
procedure TPasSyntaxTreeBuilder.VisibilityStrictPrivate;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Push(ntStrictPrivate);
try
Temp.SetAttribute(anVisibility, AttributeValues[atTrue]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VisibilityPrivate;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Push(ntPrivate);
try
Temp.SetAttribute(anVisibility, AttributeValues[atTrue]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VisibilityStrictProtected;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Push(ntStrictProtected);
try
Temp.SetAttribute(anVisibility, AttributeValues[atTrue]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VisibilityProtected;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Push(ntProtected);
try
Temp.SetAttribute(anVisibility, AttributeValues[atTrue]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VisibilityPublic;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Push(ntPublic);
try
Temp.SetAttribute(anVisibility, AttributeValues[atTrue]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.VisibilityPublished;
var
Temp: TSyntaxNode;
begin
Temp := FStack.Push(ntPublished);
try
Temp.SetAttribute(anVisibility, AttributeValues[atTrue]);
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.WhileStatement;
begin
FStack.Push(ntWhile);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.WithExpressionList;
begin
FStack.Push(ntExpressions);
try
inherited;
finally
FStack.Pop;
end;
end;
procedure TPasSyntaxTreeBuilder.WithStatement;
begin
FStack.Push(ntWith);
try
inherited;
finally
FStack.Pop;
end;
end;
{ ESyntaxTreeException }
constructor ESyntaxTreeException.Create(Line, Col: Integer; const FileName, Msg: string;
SyntaxTree: TSyntaxNode);
begin
inherited Create(Line, Col, FileName, Msg);
FSyntaxTree := SyntaxTree;
end;
destructor ESyntaxTreeException.Destroy;
begin
FSyntaxTree.Free;
inherited;
end;
initialization
InitAttributeValues;
end.