Global data value refactoring + 1st scripting version

This commit is contained in:
Michael Schimmel
2025-09-20 18:30:32 +02:00
parent 09bd25b318
commit 00f5861148
17 changed files with 1430 additions and 2742 deletions
+100 -101
View File
@@ -11,15 +11,17 @@ uses
Myc.Ast;
type
// A visitor that converts an AST into a LISP-like (Clojure-style) string representation.
TPrettyPrintVisitor = class(TInterfacedObject, IAstVisitor)
private
FBuilder: TStringBuilder;
FIndentLevel: Integer;
procedure Indent;
procedure Unindent;
procedure AppendLine(const S: string);
procedure Append(const S: string);
procedure NewLine;
public
constructor Create(AIndentLevel: Integer = 0);
constructor Create;
destructor Destroy; override;
function GetResult: string;
// IAstVisitor
@@ -46,17 +48,15 @@ type
implementation
uses
Myc.Data.Scalar,
Myc.Data.Decimal;
Myc.Data.Scalar;
{ TPrettyPrintVisitor }
constructor TPrettyPrintVisitor.Create(AIndentLevel: Integer);
constructor TPrettyPrintVisitor.Create;
begin
inherited Create;
FBuilder := TStringBuilder.Create;
FIndentLevel := 0;
FIndentLevel := AIndentLevel;
end;
destructor TPrettyPrintVisitor.Destroy;
@@ -72,119 +72,126 @@ end;
procedure TPrettyPrintVisitor.Indent;
begin
inc(FIndentLevel, 4);
inc(FIndentLevel, 2);
end;
procedure TPrettyPrintVisitor.Unindent;
begin
dec(FIndentLevel, 4);
dec(FIndentLevel, 2);
end;
procedure TPrettyPrintVisitor.AppendLine(const S: string);
procedure TPrettyPrintVisitor.Append(const S: string);
begin
FBuilder.Append(S);
end;
procedure TPrettyPrintVisitor.NewLine;
begin
FBuilder.AppendLine;
FBuilder.Append(''.PadLeft(FIndentLevel));
FBuilder.AppendLine(S);
end;
function TPrettyPrintVisitor.Execute(const RootNode: IAstNode): TDataValue;
begin
Result := RootNode.Accept(Self);
if Assigned(RootNode) then
RootNode.Accept(Self);
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
var
val: TDataValue;
begin
AppendLine(Format('Constant (%s)', [Node.Value.ToString]));
val := Node.Value;
if val.Kind = vkText then
Append('"' + val.AsText + '"')
else
Append(val.ToString);
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin
AppendLine(Format('Identifier (%s)', [Node.Name]));
Append(Node.Name);
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
begin
AppendLine(Format('BinaryExpr "%s"', [Node.Operator.ToString]));
Indent;
Append('(' + Node.Operator.ToString);
Append(' ');
Node.Left.Accept(Self);
Append(' ');
Node.Right.Accept(Self);
Unindent;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
begin
AppendLine(Format('UnaryExpr "%s"', [Node.Operator.ToString]));
Indent;
Append('(' + Node.Operator.ToString);
Append(' ');
Node.Right.Accept(Self);
Unindent;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin
AppendLine('IfExpr');
Indent;
AppendLine('Condition:');
Indent;
Append('(if ');
Node.Condition.Accept(Self);
Unindent;
AppendLine('Then:');
Indent;
NewLine;
Node.ThenBranch.Accept(Self);
Unindent;
if Node.ElseBranch <> nil then
if Assigned(Node.ElseBranch) then
begin
AppendLine('Else:');
Indent;
NewLine;
Node.ElseBranch.Accept(Self);
Unindent;
end;
Unindent;
NewLine;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin
AppendLine('TernaryExpr');
Indent;
AppendLine('Condition:');
Indent;
Append('(if ');
Node.Condition.Accept(Self);
Unindent;
AppendLine('Then:');
Indent;
NewLine;
Node.ThenBranch.Accept(Self);
Unindent;
AppendLine('Else:');
Indent;
NewLine;
Node.ElseBranch.Accept(Self);
Unindent;
Unindent;
NewLine;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
var
param: IIdentifierNode;
paramNames: TStringList;
sb: TStringBuilder;
begin
paramNames := TStringList.Create;
sb := TStringBuilder.Create;
try
for param in Node.Parameters do
paramNames.Add(param.Name);
AppendLine(Format('Lambda (params: %s)', [paramNames.CommaText]));
sb.Append(param.Name + ' ');
if sb.Length > 0 then
sb.Remove(sb.Length - 1, 1);
Append('(fn [' + sb.ToString + ']');
finally
paramNames.Free;
sb.Free;
end;
Indent;
AppendLine('Body:');
Indent;
NewLine;
Node.Body.Accept(Self);
Unindent;
Unindent;
NewLine;
Append(')');
Result := TDataValue.Void;
end;
@@ -192,18 +199,21 @@ function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): T
var
arg: IAstNode;
begin
AppendLine('FunctionCall');
Indent;
AppendLine('Callee:');
Indent;
Append('(');
Node.Callee.Accept(Self);
Unindent;
AppendLine('Arguments:');
Indent;
for arg in Node.Arguments do
begin
NewLine;
arg.Accept(Self);
end;
Unindent;
Unindent;
if Length(Node.Arguments) > 0 then
NewLine;
Append(')');
Result := TDataValue.Void;
end;
@@ -211,14 +221,17 @@ function TPrettyPrintVisitor.VisitRecurNode(const Node: IRecurNode): TDataValue;
var
arg: IAstNode;
begin
AppendLine('Recur');
Indent;
AppendLine('Arguments:');
Append('(recur');
Indent;
for arg in Node.Arguments do
begin
NewLine;
arg.Accept(Self);
end;
Unindent;
Unindent;
if Length(Node.Arguments) > 0 then
NewLine;
Append(')');
Result := TDataValue.Void;
end;
@@ -226,102 +239,88 @@ function TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNo
var
expr: IAstNode;
begin
AppendLine('Block');
Append('(do');
Indent;
for expr in Node.Expressions do
begin
NewLine;
expr.Accept(Self);
end;
Unindent;
NewLine;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin
AppendLine(Format('VarDecl (%s)', [Node.Identifier.Name]));
Append('(def ');
Node.Identifier.Accept(Self);
if Assigned(Node.Initializer) then
begin
Indent;
Append(' ');
Node.Initializer.Accept(Self);
Unindent;
end;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitAssignment(const Node: IAssignmentNode): TDataValue;
begin
// Print the assignment node.
AppendLine(Format('Assignment (%s)', [Node.Identifier.Name]));
Indent;
Append('(assign ');
Node.Identifier.Accept(Self);
Append(' ');
Node.Value.Accept(Self);
Unindent;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitIndexer(const Node: IIndexerNode): TDataValue;
begin
AppendLine('Indexer');
Indent;
AppendLine('Base:');
Indent;
Append('(get ');
Node.Base.Accept(Self);
Unindent;
AppendLine('Index:');
Indent;
Append(' ');
Node.Index.Accept(Self);
Unindent;
Unindent;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin
AppendLine(Format('MemberAccess (Member: %s)', [Node.Member.Name]));
Indent;
AppendLine('Base:');
Indent;
Append('(.');
Node.Member.Accept(Self);
Append(' ');
Node.Base.Accept(Self);
Unindent;
Unindent;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin
AppendLine('CreateSeries');
Indent;
AppendLine('Definition: ' + Node.Definition);
Unindent;
Append(Format('(new-series "%s")', [Node.Definition]));
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin
AppendLine('AddSeriesItem');
Indent;
AppendLine('Series:');
Indent;
Append('(add-item ');
Node.Series.Accept(Self);
Unindent;
AppendLine('Value:');
Indent;
Append(' ');
Node.Value.Accept(Self);
Unindent;
if Assigned(Node.Lookback) then
begin
AppendLine('Lookback:');
Indent;
Append(' ');
Node.Lookback.Accept(Self);
Unindent;
end;
Unindent;
Append(')');
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin
AppendLine('SeriesLength');
Indent;
Append('(count ');
Node.Series.Accept(Self);
Unindent;
Append(')');
Result := TDataValue.Void;
end;