unit Myc.Fmx.AstEditor.Text; interface uses System.SysUtils, Myc.Data.Value, Myc.Data.Scalar, Myc.Ast.Nodes; type // This visitor converts an AST expression subtree into a single string. TAstToTextVisitor = class(TInterfacedObject, IAstVisitor) public { IAstVisitor } function Execute(const RootNode: IAstNode): TDataValue; function VisitConstant(const Node: IConstantNode): TDataValue; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function VisitAssignment(const Node: IAssignmentNode): TDataValue; function VisitIndexer(const Node: IIndexerNode): TDataValue; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; end; implementation function TAstToTextVisitor.Execute(const RootNode: IAstNode): TDataValue; begin Result := RootNode.Accept(Self); end; { TAstToTextVisitor } function TAstToTextVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; var seriesStr, valueStr, lookbackStr: string; begin seriesStr := Node.Series.Accept(Self).AsText; valueStr := Node.Value.Accept(Self).AsText; lookbackStr := ''; if Assigned(Node.Lookback) then lookbackStr := ', ' + Node.Lookback.Accept(Self).AsText; Result := Format('%s.add(%s%s)', [seriesStr, valueStr, lookbackStr]); end; function TAstToTextVisitor.VisitAssignment(const Node: IAssignmentNode): TDataValue; begin Result := Node.Identifier.Name + ' := ' + Node.Value.Accept(Self).AsText; end; function TAstToTextVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; begin var leftStr := Node.Left.Accept(Self).AsText; var rightStr := Node.Right.Accept(Self).AsText; Result := '(' + leftStr + ' ' + Node.Operator.ToString + ' ' + rightStr + ')'; end; function TAstToTextVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; begin Result := '{...}'; end; function TAstToTextVisitor.VisitConstant(const Node: IConstantNode): TDataValue; begin Result := Node.Value.ToString; end; function TAstToTextVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; begin Result := 'new series(' + Node.Definition + ')'; end; function TAstToTextVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; var i: Integer; sb: TStringBuilder; calleeStr: string; begin calleeStr := Node.Callee.Accept(Self).AsText; sb := TStringBuilder.Create; try sb.Append(calleeStr); sb.Append('('); for i := 0 to High(Node.Arguments) do begin sb.Append(Node.Arguments[i].Accept(Self).AsText); if i < High(Node.Arguments) then sb.Append(', '); end; sb.Append(')'); Result := sb.ToString; finally sb.Free; end; end; function TAstToTextVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue; begin Result := Node.Name; end; function TAstToTextVisitor.VisitIfExpression(const Node: IIfExpressionNode): TDataValue; begin Result := Node.Condition.Accept(Self).AsText; end; function TAstToTextVisitor.VisitIndexer(const Node: IIndexerNode): TDataValue; var baseStr, indexStr: string; begin baseStr := Node.Base.Accept(Self).AsText; indexStr := Node.Index.Accept(Self).AsText; Result := Format('%s[%s]', [baseStr, indexStr]); end; function TAstToTextVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; var i: Integer; sb: TStringBuilder; begin sb := TStringBuilder.Create; try sb.Append(#$03BB + '('); if Length(Node.Parameters) > 0 then begin for i := 0 to High(Node.Parameters) do begin sb.Append(Node.Parameters[i].Name); if i < High(Node.Parameters) then sb.Append(', '); end; end; sb.Append(') => {...}'); Result := sb.ToString; finally sb.Free; end; end; function TAstToTextVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; var baseStr: string; begin baseStr := Node.Base.Accept(Self).AsText; Result := Format('%s.%s', [baseStr, Node.Member.Name]); end; function TAstToTextVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; var seriesStr: string; begin seriesStr := Node.Series.Accept(Self).AsText; Result := Format('length(%s)', [seriesStr]); end; function TAstToTextVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; begin var condStr := Node.Condition.Accept(Self).AsText; var thenStr := Node.ThenBranch.Accept(Self).AsText; var elseStr := Node.ElseBranch.Accept(Self).AsText; Result := Format('(%s ? %s : %s)', [condStr, thenStr, elseStr]); end; function TAstToTextVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; begin Result := Node.Operator.ToString + ' ' + Node.Right.Accept(Self).AsText; end; function TAstToTextVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; var initStr: string; begin if Assigned(Node.Initializer) then initStr := ' := ' + Node.Initializer.Accept(Self).AsText else initStr := ''; Result := 'var ' + Node.Identifier.Name + initStr; end; end.