221 lines
6.4 KiB
ObjectPascal
221 lines
6.4 KiB
ObjectPascal
unit Myc.Ast.Traverser;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.Classes,
|
|
System.Generics.Collections,
|
|
Myc.Data.Value,
|
|
Myc.Ast.Nodes;
|
|
|
|
type
|
|
// TAstTraverser provides a default AST traversal implementation.
|
|
TAstTraverser = class abstract(TInterfacedObject, IAstVisitor)
|
|
private
|
|
FDone: Boolean;
|
|
protected
|
|
function Accept(const Node: IAstNode): TDataValue; virtual;
|
|
property Done: Boolean read FDone write FDone;
|
|
public
|
|
function Execute(const RootNode: IAstNode): TDataValue;
|
|
|
|
function VisitConstant(const Node: IConstantNode): TDataValue; virtual;
|
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual;
|
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; virtual;
|
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; virtual;
|
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual;
|
|
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; virtual;
|
|
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; virtual;
|
|
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; virtual;
|
|
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; virtual;
|
|
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; virtual;
|
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; virtual;
|
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; virtual;
|
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; virtual;
|
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; virtual;
|
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; virtual;
|
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; virtual;
|
|
end;
|
|
|
|
// Generic traverser for managing state during AST walks.
|
|
TAstTraverser<T> = class abstract(TAstTraverser)
|
|
private
|
|
FData: TStack<T>;
|
|
protected
|
|
function Accept(const Node: IAstNode): TDataValue; override;
|
|
// Called before a node is visited. The returned value is pushed onto the state stack.
|
|
function EnterNode(const Node: IAstNode): T; virtual; abstract;
|
|
// Called after a node has been visited.
|
|
procedure ExitNode(const Node: IAstNode; const Data: T); virtual;
|
|
property Data: TStack<T> read FData;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TAstTraverser }
|
|
|
|
function TAstTraverser.Accept(const Node: IAstNode): TDataValue;
|
|
begin
|
|
if not Assigned(Node) or FDone then
|
|
exit;
|
|
Result := Node.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.Execute(const RootNode: IAstNode): TDataValue;
|
|
begin
|
|
Result := RootNode.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
|
begin
|
|
Accept(Node.Series);
|
|
Accept(Node.Value);
|
|
if Assigned(Node.Lookback) then
|
|
Accept(Node.Lookback);
|
|
end;
|
|
|
|
function TAstTraverser.VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
|
begin
|
|
Accept(Node.Value);
|
|
Accept(Node.Identifier);
|
|
end;
|
|
|
|
function TAstTraverser.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
|
begin
|
|
Accept(Node.Left);
|
|
Accept(Node.Right);
|
|
end;
|
|
|
|
function TAstTraverser.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
|
var
|
|
expr: IAstNode;
|
|
begin
|
|
for expr in Node.Expressions do
|
|
begin
|
|
if FDone then
|
|
break;
|
|
Accept(expr);
|
|
end;
|
|
end;
|
|
|
|
function TAstTraverser.VisitConstant(const Node: IConstantNode): TDataValue;
|
|
begin
|
|
end;
|
|
|
|
function TAstTraverser.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
|
begin
|
|
end;
|
|
|
|
function TAstTraverser.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
|
var
|
|
arg: IAstNode;
|
|
begin
|
|
Accept(Node.Callee);
|
|
|
|
for arg in Node.Arguments do
|
|
begin
|
|
if FDone then
|
|
break;
|
|
Accept(arg);
|
|
end;
|
|
end;
|
|
|
|
function TAstTraverser.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
|
begin
|
|
end;
|
|
|
|
function TAstTraverser.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
|
begin
|
|
Accept(Node.Condition);
|
|
Accept(Node.ThenBranch);
|
|
if Assigned(Node.ElseBranch) then
|
|
Accept(Node.ElseBranch);
|
|
end;
|
|
|
|
function TAstTraverser.VisitIndexer(const Node: IIndexerNode): TDataValue;
|
|
begin
|
|
Accept(Node.Base);
|
|
Accept(Node.Index);
|
|
end;
|
|
|
|
function TAstTraverser.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
|
var
|
|
param: IIdentifierNode;
|
|
begin
|
|
for param in Node.Parameters do
|
|
begin
|
|
if FDone then
|
|
break;
|
|
Accept(param);
|
|
end;
|
|
Accept(Node.Body);
|
|
end;
|
|
|
|
function TAstTraverser.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
|
begin
|
|
// Do not visit the member identifier, as it's not a variable in the current scope.
|
|
Accept(Node.Base);
|
|
end;
|
|
|
|
function TAstTraverser.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
|
begin
|
|
Accept(Node.Series);
|
|
end;
|
|
|
|
function TAstTraverser.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
|
begin
|
|
Accept(Node.Condition);
|
|
Accept(Node.ThenBranch);
|
|
Accept(Node.ElseBranch);
|
|
end;
|
|
|
|
function TAstTraverser.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
|
begin
|
|
Accept(Node.Right);
|
|
end;
|
|
|
|
function TAstTraverser.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
|
begin
|
|
if Assigned(Node.Initializer) then
|
|
Accept(Node.Initializer);
|
|
Accept(Node.Identifier);
|
|
end;
|
|
|
|
{ TAstTraverser<T> }
|
|
|
|
constructor TAstTraverser<T>.Create;
|
|
begin
|
|
inherited Create;
|
|
FData := TStack<T>.Create;
|
|
end;
|
|
|
|
destructor TAstTraverser<T>.Destroy;
|
|
begin
|
|
FData.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TAstTraverser<T>.Accept(const Node: IAstNode): TDataValue;
|
|
begin
|
|
if not Assigned(Node) or Done then
|
|
exit;
|
|
|
|
FData.Push(EnterNode(Node));
|
|
try
|
|
Result := inherited Accept(Node);
|
|
finally
|
|
var data := FData.Pop;
|
|
ExitNode(Node, data);
|
|
end;
|
|
end;
|
|
|
|
procedure TAstTraverser<T>.ExitNode(const Node: IAstNode; const Data: T);
|
|
begin
|
|
|
|
end;
|
|
|
|
end.
|