unit Myc.Fmx.AstEditor.Visualizer; interface uses System.SysUtils, System.Classes, FMX.Controls, Myc.Data.Value, Myc.Ast.Nodes, Myc.Ast.Visitor, Myc.Fmx.AstEditor.Render, // Virtual Engine Myc.Fmx.AstEditor.Node, // View Nodes Myc.Fmx.AstEditor.Workspace; // Host type // Implementation of the Factory/Visitor for the Virtual Tree // Uses TAstVisitor which uses closures for dispatch. TAstVisualizer = class(TAstVisitor, IAstVisualizer) private FExprDepth: Integer; FParentNode: TVisualNode; FWorkspace: TWorkspace; function CallAccept(const Node: IAstNode): TAstViewNode; // IAstVisualizer Implementation function GetExprDepth: Integer; function GetParentNode: TVisualNode; function GetWorkspace: TWorkspace; protected // Setup registry using closures procedure SetupHandlers; override; // --- Visitor Implementations (Strict IAstNode signature) --- function VisitConstant(const Node: IAstNode): TAstViewNode; function VisitIdentifier(const Node: IAstNode): TAstViewNode; function VisitKeyword(const Node: IAstNode): TAstViewNode; // Unified List Handler function VisitTuple(const Node: IAstNode): TAstViewNode; // Elements function VisitRecordField(const Node: IAstNode): TAstViewNode; // Control Flow function VisitIfExpression(const Node: IAstNode): TAstViewNode; function VisitCondExpression(const Node: IAstNode): TAstViewNode; function VisitBlockExpression(const Node: IAstNode): TAstViewNode; function VisitRecurNode(const Node: IAstNode): TAstViewNode; function VisitNop(const Node: IAstNode): TAstViewNode; // Functions function VisitLambdaExpression(const Node: IAstNode): TAstViewNode; function VisitFunctionCall(const Node: IAstNode): TAstViewNode; function VisitMacroExpansionNode(const Node: IAstNode): TAstViewNode; // Declarations function VisitVariableDeclaration(const Node: IAstNode): TAstViewNode; function VisitAssignment(const Node: IAstNode): TAstViewNode; function VisitMacroDefinition(const Node: IAstNode): TAstViewNode; // Metaprogramming function VisitQuasiquote(const Node: IAstNode): TAstViewNode; function VisitUnquote(const Node: IAstNode): TAstViewNode; function VisitUnquoteSplicing(const Node: IAstNode): TAstViewNode; // Data Access function VisitIndexer(const Node: IAstNode): TAstViewNode; function VisitMemberAccess(const Node: IAstNode): TAstViewNode; function VisitRecordLiteral(const Node: IAstNode): TAstViewNode; // Series function VisitCreateSeries(const Node: IAstNode): TAstViewNode; function VisitAddSeriesItem(const Node: IAstNode): TAstViewNode; function VisitSeriesLength(const Node: IAstNode): TAstViewNode; // Pipes function VisitPipe(const Node: IAstNode): TAstViewNode; public constructor Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer); destructor Destroy; override; function Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer; property ExprDepth: Integer read GetExprDepth; property ParentNode: TVisualNode read GetParentNode; property Workspace: TWorkspace read GetWorkspace; end; implementation uses System.StrUtils, Myc.Fmx.AstEditor.Handlers.Data, Myc.Fmx.AstEditor.Handlers.Control, Myc.Fmx.AstEditor.Handlers.Primitives, Myc.Fmx.AstEditor.Handlers.Lists, Myc.Fmx.AstEditor.Handlers.Pipes; function IsStandardOperator(const Name: string): Boolean; begin Result := MatchStr(Name, ['+', '-', '*', '/', 'div', 'mod', '=', '<>', '<', '>', '<=', '>=', 'and', 'or', 'xor', 'not', 'shl', 'shr']); end; { TAstVisualizer } constructor TAstVisualizer.Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer); begin inherited Create; // Calls SetupHandlers FWorkspace := AWorkspace; FParentNode := AParentNode; FExprDepth := AExprDepth; end; destructor TAstVisualizer.Destroy; begin inherited; end; procedure TAstVisualizer.SetupHandlers; begin // Core Primitives Register(akConstant, VisitConstant); Register(akIdentifier, VisitIdentifier); Register(akKeyword, VisitKeyword); Register(akNop, VisitNop); // Lists (Unified) Register(akTuple, VisitTuple); Register(akRecordField, VisitRecordField); // Control Flow Register(akIfExpression, VisitIfExpression); Register(akCondExpression, VisitCondExpression); Register(akBlockExpression, VisitBlockExpression); Register(akRecur, VisitRecurNode); // Functions Register(akLambdaExpression, VisitLambdaExpression); Register(akFunctionCall, VisitFunctionCall); Register(akMacroExpansion, VisitMacroExpansionNode); // Declarations Register(akVariableDeclaration, VisitVariableDeclaration); Register(akAssignment, VisitAssignment); Register(akMacroDefinition, VisitMacroDefinition); // Metaprogramming Register(akQuasiquote, VisitQuasiquote); Register(akUnquote, VisitUnquote); Register(akUnquoteSplicing, VisitUnquoteSplicing); // Data Access Register(akIndexer, VisitIndexer); Register(akMemberAccess, VisitMemberAccess); Register(akRecordLiteral, VisitRecordLiteral); // Series Register(akCreateSeries, VisitCreateSeries); Register(akAddSeriesItem, VisitAddSeriesItem); Register(akSeriesLength, VisitSeriesLength); // Pipes (Simplified) Register(akPipe, VisitPipe); end; function TAstVisualizer.CallAccept(const Node: IAstNode): TAstViewNode; var dataValue: TDataValue; begin if not Assigned(Node) then exit(nil); dataValue := Node.Accept(Self); if dataValue.Kind = vkGeneric then Result := dataValue.AsGeneric else Result := nil; end; function TAstVisualizer.Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer; begin Result := TAstVisualizer.Create(FWorkspace, ParentNode, ExprDepth); end; function TAstVisualizer.GetExprDepth: Integer; begin Result := FExprDepth; end; function TAstVisualizer.GetParentNode: TVisualNode; begin Result := FParentNode; end; function TAstVisualizer.GetWorkspace: TWorkspace; begin Result := FWorkspace; end; // --- Visitor Implementations --- function TAstVisualizer.VisitConstant(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TConstantNodeHandler.Create(Node.AsConstant)); end; function TAstVisualizer.VisitIdentifier(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TIdentifierNodeHandler.Create(Node.AsIdentifier)); end; function TAstVisualizer.VisitKeyword(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TKeywordNodeHandler.Create(Node.AsKeyword)); end; function TAstVisualizer.VisitNop(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node.AsNop)); end; function TAstVisualizer.VisitTuple(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TTupleHandler.Create(Node.AsTuple)); end; function TAstVisualizer.VisitRecordField(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TRecordFieldHandler.Create(Node.AsRecordField)); end; function TAstVisualizer.VisitBlockExpression(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TBlockExpressionNodeHandler.Create(Node.AsBlockExpression)); end; function TAstVisualizer.VisitIfExpression(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TIfExpressionNodeHandler.Create(Node.AsIfExpression)); end; function TAstVisualizer.VisitCondExpression(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TCondExpressionNodeHandler.Create(Node.AsCondExpression)); end; function TAstVisualizer.VisitRecurNode(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TRecurNodeHandler.Create(Node.AsRecur)); end; function TAstVisualizer.VisitLambdaExpression(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TLambdaExpressionNodeHandler.Create(Node.AsLambdaExpression)); end; function TAstVisualizer.VisitFunctionCall(const Node: IAstNode): TAstViewNode; var C: IFunctionCallNode; calleeName: string; isOp: Boolean; begin C := Node.AsFunctionCall; isOp := False; if C.Callee.Kind = akIdentifier then begin calleeName := C.Callee.AsIdentifier.Name; isOp := IsStandardOperator(calleeName); end else if C.Callee.Kind = akKeyword then begin calleeName := C.Callee.AsKeyword.Value.Name; isOp := IsStandardOperator(calleeName); end; if isOp then Result := TAstViewNode.Create(Self, TOperatorCallHandler.Create(C)) else Result := TAstViewNode.Create(Self, TFunctionCallNodeHandler.Create(C)); end; function TAstVisualizer.VisitMacroExpansionNode(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TMacroExpansionNodeHandler.Create(Node.AsMacroExpansion)); end; function TAstVisualizer.VisitVariableDeclaration(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TVariableDeclarationNodeHandler.Create(Node.AsVariableDeclaration)); end; function TAstVisualizer.VisitAssignment(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TAssignmentNodeHandler.Create(Node.AsAssignment)); end; function TAstVisualizer.VisitMacroDefinition(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TMacroDefinitionNodeHandler.Create(Node.AsMacroDefinition)); end; function TAstVisualizer.VisitQuasiquote(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TQuasiquoteNodeHandler.Create(Node.AsQuasiquote)); end; function TAstVisualizer.VisitUnquote(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TUnquoteNodeHandler.Create(Node.AsUnquote)); end; function TAstVisualizer.VisitUnquoteSplicing(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TUnquoteSplicingNodeHandler.Create(Node.AsUnquoteSplicing)); end; function TAstVisualizer.VisitIndexer(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TIndexerNodeHandler.Create(Node.AsIndexer)); end; function TAstVisualizer.VisitMemberAccess(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TMemberAccessNodeHandler.Create(Node.AsMemberAccess)); end; function TAstVisualizer.VisitRecordLiteral(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TRecordLiteralNodeHandler.Create(Node.AsRecordLiteral)); end; function TAstVisualizer.VisitCreateSeries(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TCreateSeriesNodeHandler.Create(Node.AsCreateSeries)); end; function TAstVisualizer.VisitAddSeriesItem(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TAddSeriesItemNodeHandler.Create(Node.AsAddSeriesItem)); end; function TAstVisualizer.VisitSeriesLength(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TSeriesLengthNodeHandler.Create(Node.AsSeriesLength)); end; function TAstVisualizer.VisitPipe(const Node: IAstNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TPipeNodeHandler.Create(Node.AsPipe)); end; end.