unit Myc.Fmx.AstEditor.Text; interface uses System.SysUtils, Myc.Data.Value, Myc.Data.Scalar, Myc.Ast.Visitor, Myc.Ast.Nodes; type // This visitor converts an AST expression subtree into a single string. TAstToTextVisitor = class(TAstVisitor) public function VisitConstant(const Node: IConstantNode): TDataValue; override; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override; function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override; function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override; function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; function VisitIndexer(const Node: IIndexerNode): TDataValue; override; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; function VisitRecurNode(const Node: IRecurNode): TDataValue; override; end; implementation { 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.VisitRecurNode(const Node: IRecurNode): TDataValue; var i: Integer; sb: TStringBuilder; begin sb := TStringBuilder.Create; try sb.Append('recur('); 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.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; var i: Integer; sb: TStringBuilder; begin // Added text representation for macro definitions. sb := TStringBuilder.Create; try sb.Append('defmacro '); sb.Append(Node.Name.Name); sb.Append('('); 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.