1st full macro expander

This commit is contained in:
Michael Schimmel
2025-10-03 19:46:30 +02:00
parent bb0ecda6be
commit d9219474e0
16 changed files with 700 additions and 323 deletions
+2 -1
View File
@@ -19,7 +19,8 @@ uses
Myc.Fmx.AstEditor.Workspace in 'Myc.Fmx.AstEditor.Workspace.pas', Myc.Fmx.AstEditor.Workspace in 'Myc.Fmx.AstEditor.Workspace.pas',
Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas', Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas',
Myc.Utils in '..\Src\Myc.Utils.pas', Myc.Utils in '..\Src\Myc.Utils.pas',
Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas'; Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas',
Myc.Ast.MacroExpander in '..\Src\AST\Myc.Ast.MacroExpander.pas';
{$R *.res} {$R *.res}
+2
View File
@@ -105,6 +105,7 @@
<DCC_RemoteDebug>true</DCC_RemoteDebug> <DCC_RemoteDebug>true</DCC_RemoteDebug>
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck> <DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
<DCC_RangeChecking>true</DCC_RangeChecking> <DCC_RangeChecking>true</DCC_RangeChecking>
<DCC_Inlining>off</DCC_Inlining>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''"> <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug> <DCC_RemoteDebug>false</DCC_RemoteDebug>
@@ -151,6 +152,7 @@
<DCCReference Include="Myc.Fmx.AstEditor.Text.pas"/> <DCCReference Include="Myc.Fmx.AstEditor.Text.pas"/>
<DCCReference Include="..\Src\Myc.Utils.pas"/> <DCCReference Include="..\Src\Myc.Utils.pas"/>
<DCCReference Include="..\Src\AST\Myc.Ast.Script.pas"/> <DCCReference Include="..\Src\AST\Myc.Ast.Script.pas"/>
<DCCReference Include="..\Src\AST\Myc.Ast.MacroExpander.pas"/>
<BuildConfiguration Include="Base"> <BuildConfiguration Include="Base">
<Key>Base</Key> <Key>Base</Key>
</BuildConfiguration> </BuildConfiguration>
+18 -1
View File
@@ -33,6 +33,7 @@ uses
Myc.Ast.Binding, Myc.Ast.Binding,
Myc.Ast.RTL, Myc.Ast.RTL,
Myc.Ast.Script, Myc.Ast.Script,
Myc.Ast.MacroExpander,
FMX.Layouts, FMX.Layouts,
FMX.Objects, FMX.Objects,
Myc.Ast.Debugger, Myc.Ast.Debugger,
@@ -214,8 +215,24 @@ var
scriptScope: IExecutionScope; scriptScope: IExecutionScope;
visitor: IEvaluatorVisitor; visitor: IEvaluatorVisitor;
begin begin
var macroExpander :=
TMacroExpander.Create(
function(const ANode: IAstNode): TDataValue
begin
var binder := TAstBinder.Create(AParentScope) as IAstBinder;
var descriptor: IScopeDescriptor;
var boundAst := binder.Execute(ANode, descriptor);
var evalScope := descriptor.CreateScope(AParentScope);
var evaluator := CreateEvaluator(evalScope);
Result := evaluator.Execute(boundAst);
end)
as IMacroExpander;
binder := TAstBinder.Create(AParentScope); binder := TAstBinder.Create(AParentScope);
FCurrAst := binder.Execute(ANode, FCurrDesc); FCurrAst := binder.Execute(macroExpander.Execute(ANode), FCurrDesc);
scriptScope := FCurrDesc.CreateScope(AParentScope); scriptScope := FCurrDesc.CreateScope(AParentScope);
visitor := CreateEvaluator(scriptScope); visitor := CreateEvaluator(scriptScope);
+18
View File
@@ -27,6 +27,9 @@ type
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
@@ -200,6 +203,21 @@ begin
Result := Format('%s.%s', [baseStr, Node.Member.Name]); Result := Format('%s.%s', [baseStr, Node.Member.Name]);
end; end;
function TAstToTextVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
Result := '`' + Node.Expression.Accept(Self).AsText;
end;
function TAstToTextVisitor.VisitUnquote(const Node: IUnquoteNode): TDataValue;
begin
Result := '~' + Node.Expression.Accept(Self).AsText;
end;
function TAstToTextVisitor.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin
Result := '~@' + Node.Expression.Accept(Self).AsText;
end;
function TAstToTextVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; function TAstToTextVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
var var
seriesStr: string; seriesStr: string;
+72
View File
@@ -115,6 +115,9 @@ type
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
@@ -1245,6 +1248,75 @@ begin
Result := TDataValue.Void; Result := TDataValue.Void;
end; end;
function TAstToAuraNodeVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
VisitOperatorNode(
[Node.Expression],
function(const InputResults: TAuraNodeResultList): TAuraNodeResult
var
qqNode: TAuraNode;
inputPin, outPin: TControl;
begin
qqNode := BuildNodeControl('`', '');
qqNode.TitleFont.Size := 20;
inputPin := CreateInput(qqNode, '');
outPin := CreateOutput(qqNode);
if Assigned(InputResults[0].OutputPin) then
FConnections.Add(TPinConnection.Create(InputResults[0].OutputPin, inputPin));
FinalizeNodeLayout(qqNode);
Result.LayoutNode := qqNode;
Result.OutputPin := outPin;
end
);
Result := TDataValue.Void;
end;
function TAstToAuraNodeVisitor.VisitUnquote(const Node: IUnquoteNode): TDataValue;
begin
VisitOperatorNode(
[Node.Expression],
function(const InputResults: TAuraNodeResultList): TAuraNodeResult
var
uqNode: TAuraNode;
inputPin, outPin: TControl;
begin
uqNode := BuildNodeControl('~', '');
uqNode.TitleFont.Size := 20;
inputPin := CreateInput(uqNode, '');
outPin := CreateOutput(uqNode);
if Assigned(InputResults[0].OutputPin) then
FConnections.Add(TPinConnection.Create(InputResults[0].OutputPin, inputPin));
FinalizeNodeLayout(uqNode);
Result.LayoutNode := uqNode;
Result.OutputPin := outPin;
end
);
Result := TDataValue.Void;
end;
function TAstToAuraNodeVisitor.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin
VisitOperatorNode(
[Node.Expression],
function(const InputResults: TAuraNodeResultList): TAuraNodeResult
var
uqsNode: TAuraNode;
inputPin, outPin: TControl;
begin
uqsNode := BuildNodeControl('~@', '');
uqsNode.TitleFont.Size := 20;
inputPin := CreateInput(uqsNode, '');
outPin := CreateOutput(uqsNode);
if Assigned(InputResults[0].OutputPin) then
FConnections.Add(TPinConnection.Create(InputResults[0].OutputPin, inputPin));
FinalizeNodeLayout(uqsNode);
Result.LayoutNode := uqsNode;
Result.OutputPin := outPin;
end
);
Result := TDataValue.Void;
end;
function TAstToAuraNodeVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function TAstToAuraNodeVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
var var
details: string; details: string;
+29 -20
View File
@@ -8,21 +8,23 @@ uses
System.Generics.Collections, System.Generics.Collections,
Myc.Ast.Nodes, Myc.Ast.Nodes,
Myc.Ast.Visitor, Myc.Ast.Visitor,
Myc.Ast.Scope; Myc.Ast.Scope,
Myc.Data.Value;
type type
// This visitor analyzes the AST to find all variables that need to be "lifted" or "boxed" // This visitor analyzes the AST to find all variables that need to be "lifted" or "boxed"
// because they are captured by a nested lambda. // because they are captured by a nested lambda.
TUpvalueAnalyzer = class(TAstTraverser) TUpvalueAnalyzer = class(TAstTransformer)
private private
FBoxedDeclarations: THashSet<IVariableDeclarationNode>; FBoxedDeclarations: THashSet<IVariableDeclarationNode>;
FCurrentScope: IScopeDescriptor; FCurrentScope: IScopeDescriptor;
FDeclarationMap: TDictionary<IScopeDescriptor, TDictionary<string, IVariableDeclarationNode>>; FDeclarationMap: TDictionary<IScopeDescriptor, TDictionary<string, IVariableDeclarationNode>>;
procedure MarkDeclarationForBoxing(const AName: string); procedure MarkDeclarationForBoxing(const AName: string);
protected protected
function TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; override; // Overridden Visit methods to perform analysis during traversal.
function TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
function TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; override; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
public public
constructor Create(const AParent: IScopeDescriptor); constructor Create(const AParent: IScopeDescriptor);
destructor Destroy; override; destructor Destroy; override;
@@ -96,24 +98,26 @@ begin
end; end;
end; end;
function TUpvalueAnalyzer.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; function TUpvalueAnalyzer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
var var
address: TResolvedAddress; address: TResolvedAddress;
begin begin
Result := Node; if Assigned(FCurrentScope) then
if not Assigned(FCurrentScope) then
exit;
address := FCurrentScope.FindSymbol(Node.Name);
if (address.Kind = akLocalOrParent) and (address.ScopeDepth > 0) then
begin begin
// This is an upvalue. Mark its original declaration for boxing. address := FCurrentScope.FindSymbol(Node.Name);
MarkDeclarationForBoxing(Node.Name);
if (address.Kind = akLocalOrParent) and (address.ScopeDepth > 0) then
begin
// This is an upvalue. Mark its original declaration for boxing.
MarkDeclarationForBoxing(Node.Name);
end;
end; end;
// As a traverser, return the original node wrapped in a TDataValue.
Result := TDataValue.FromIntf<IIdentifierNode>(Node);
end; end;
function TUpvalueAnalyzer.TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; function TUpvalueAnalyzer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin begin
// A lambda creates a new lexical scope, inheriting from the current one. // A lambda creates a new lexical scope, inheriting from the current one.
FCurrentScope := TScope.CreateDescriptor(FCurrentScope); FCurrentScope := TScope.CreateDescriptor(FCurrentScope);
@@ -124,19 +128,21 @@ begin
// Traverse the lambda body within the new scope context. // Traverse the lambda body within the new scope context.
Node.Body.Accept(Self); Node.Body.Accept(Self);
Result := Node; // We do not transform, just analyze.
// We do not transform, just analyze. Return the original node wrapped.
Result := TDataValue.FromIntf<ILambdaExpressionNode>(Node);
finally finally
// Restore the parent scope after leaving the lambda. // Restore the parent scope after leaving the lambda.
FCurrentScope := FCurrentScope.Parent; FCurrentScope := FCurrentScope.Parent;
end; end;
end; end;
function TUpvalueAnalyzer.TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; function TUpvalueAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
var var
scopeDeclarations: TDictionary<string, IVariableDeclarationNode>; scopeDeclarations: TDictionary<string, IVariableDeclarationNode>;
begin begin
Result := Node; // Traverse the initializer first. It's evaluated in the current scope
// before the new variable is defined.
if Assigned(Node.Initializer) then if Assigned(Node.Initializer) then
Node.Initializer.Accept(Self); Node.Initializer.Accept(Self);
@@ -150,6 +156,9 @@ begin
FDeclarationMap.Add(FCurrentScope, scopeDeclarations); FDeclarationMap.Add(FCurrentScope, scopeDeclarations);
end; end;
scopeDeclarations.Add(Node.Identifier.Name, Node); scopeDeclarations.Add(Node.Identifier.Name, Node);
// As a traverser, return the original node wrapped in a TDataValue.
Result := TDataValue.FromIntf<IVariableDeclarationNode>(Node);
end; end;
end. end.
+50 -43
View File
@@ -49,25 +49,24 @@ type
// Stack management for tail-call state is centralized here. // Stack management for tail-call state is centralized here.
function Accept(const Node: IAstNode): TDataValue; override; function Accept(const Node: IAstNode): TDataValue; override;
// The binder overrides specific visit methods to enrich the AST.
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
public public
constructor Create(const AInitialScope: IExecutionScope); constructor Create(const AInitialScope: IExecutionScope);
destructor Destroy; override; destructor Destroy; override;
function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode; function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
// The binder overrides specific transform methods to enrich the AST.
function TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; override;
function TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; override;
function TransformAssignment(const Node: IAssignmentNode): IAssignmentNode; override;
function TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; override;
function TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode; override;
function TransformFunctionCall(const Node: IFunctionCallNode): IFunctionCallNode; override;
function TransformRecur(const Node: IRecurNode): IRecurNode; override;
function TransformBlockExpression(const Node: IBlockExpressionNode): IBlockExpressionNode; override;
function TransformIfExpression(const Node: IIfExpressionNode): IIfExpressionNode; override;
function TransformTernaryExpression(const Node: ITernaryExpressionNode): ITernaryExpressionNode; override;
function TransformBinaryExpression(const Node: IBinaryExpressionNode): IBinaryExpressionNode; override;
function TransformUnaryExpression(const Node: IUnaryExpressionNode): IUnaryExpressionNode; override;
end; end;
TBoundIdentifierNode = class(TIdentifierNode) TBoundIdentifierNode = class(TIdentifierNode)
@@ -285,9 +284,10 @@ begin
Result := True; Result := True;
end; end;
function TAstBinder.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; function TAstBinder.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
var var
adr: TResolvedAddress; adr: TResolvedAddress;
boundNode: IIdentifierNode;
begin begin
adr := FCurrentDescriptor.FindSymbol(Node.Name); adr := FCurrentDescriptor.FindSymbol(Node.Name);
if adr.Kind = akLocalOrParent then if adr.Kind = akLocalOrParent then
@@ -306,22 +306,24 @@ begin
upvalue.Map.Add(adr, upvalueIndex); upvalue.Map.Add(adr, upvalueIndex);
end; end;
Result := TBoundIdentifierNode.Create(Node, TResolvedAddress.Create(akUpvalue, 0, upvalueIndex)); boundNode := TBoundIdentifierNode.Create(Node, TResolvedAddress.Create(akUpvalue, 0, upvalueIndex));
end end
else else
Result := TBoundIdentifierNode.Create(Node, adr); boundNode := TBoundIdentifierNode.Create(Node, adr);
Result := TDataValue.FromIntf<IIdentifierNode>(boundNode);
end end
else else
raise Exception.CreateFmt('Undefined identifier: "%s"', [Node.Name]); raise Exception.CreateFmt('Undefined identifier: "%s"', [Node.Name]);
end; end;
function TAstBinder.TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; function TAstBinder.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
var var
initializer: IAstNode; initializer: IAstNode;
slotIndex: Integer; slotIndex: Integer;
address: TResolvedAddress; address: TResolvedAddress;
boundIdentifier: IIdentifierNode; boundIdentifier: IIdentifierNode;
isBoxed: Boolean; isBoxed: Boolean;
boundDecl: IVariableDeclarationNode;
begin begin
if not IsValidIdentifier(Node.Identifier.Name) then if not IsValidIdentifier(Node.Identifier.Name) then
raise Exception.CreateFmt('Invalid identifier name: "%s".', [Node.Identifier.Name]); raise Exception.CreateFmt('Invalid identifier name: "%s".', [Node.Identifier.Name]);
@@ -340,28 +342,29 @@ begin
isBoxed := (FBoxedDeclarations <> nil) and FBoxedDeclarations.Contains(Node); isBoxed := (FBoxedDeclarations <> nil) and FBoxedDeclarations.Contains(Node);
// Always create a bound declaration node, passing the IsBoxed flag. // Always create a bound declaration node, passing the IsBoxed flag.
Result := TBoundVariableDeclarationNode.Create(boundIdentifier, initializer, isBoxed); boundDecl := TBoundVariableDeclarationNode.Create(boundIdentifier, initializer, isBoxed);
Result := TDataValue.FromIntf<IVariableDeclarationNode>(boundDecl);
end; end;
function TAstBinder.TransformAssignment(const Node: IAssignmentNode): IAssignmentNode; function TAstBinder.VisitAssignment(const Node: IAssignmentNode): TDataValue;
begin begin
FNextIsTail := False; FNextIsTail := False;
Result := inherited TransformAssignment(Node); Result := inherited VisitAssignment(Node);
end; end;
function TAstBinder.TransformBinaryExpression(const Node: IBinaryExpressionNode): IBinaryExpressionNode; function TAstBinder.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
begin begin
FNextIsTail := False; FNextIsTail := False;
Result := inherited TransformBinaryExpression(Node); Result := inherited VisitBinaryExpression(Node);
end; end;
function TAstBinder.TransformUnaryExpression(const Node: IUnaryExpressionNode): IUnaryExpressionNode; function TAstBinder.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
begin begin
FNextIsTail := False; FNextIsTail := False;
Result := inherited TransformUnaryExpression(Node); Result := inherited VisitUnaryExpression(Node);
end; end;
function TAstBinder.TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; function TAstBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
var var
i: integer; i: integer;
boundParams: TArray<IIdentifierNode>; boundParams: TArray<IIdentifierNode>;
@@ -370,6 +373,7 @@ var
upvalues: TArray<TResolvedAddress>; upvalues: TArray<TResolvedAddress>;
hasNestedLambdas: Boolean; hasNestedLambdas: Boolean;
lastNestedLambdaCount: Integer; lastNestedLambdaCount: Integer;
boundLambda: ILambdaExpressionNode;
begin begin
FUpvalueStack.Push(TUpvalueMapping.Create); FUpvalueStack.Push(TUpvalueMapping.Create);
try try
@@ -415,14 +419,16 @@ begin
end; end;
inc(FNestedLambdaCount); inc(FNestedLambdaCount);
Result := TBoundLambdaExpressionNode.Create(Node, boundBody, boundParams, lambdaScope, upvalues, hasNestedLambdas); boundLambda := TBoundLambdaExpressionNode.Create(Node, boundBody, boundParams, lambdaScope, upvalues, hasNestedLambdas);
Result := TDataValue.FromIntf<ILambdaExpressionNode>(boundLambda);
end; end;
function TAstBinder.TransformFunctionCall(const Node: IFunctionCallNode): IFunctionCallNode; function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
var var
isTailCall: Boolean; isTailCall: Boolean;
callee: IAstNode; callee: IAstNode;
args: TArray<IAstNode>; args: TArray<IAstNode>;
boundCall: IFunctionCallNode;
begin begin
isTailCall := FIsTailStack.Peek; isTailCall := FIsTailStack.Peek;
@@ -430,19 +436,20 @@ begin
callee := Accept(Node.Callee).AsIntf<IAstNode>; callee := Accept(Node.Callee).AsIntf<IAstNode>;
args := TransformNodes<IAstNode>(Node.Arguments); args := TransformNodes<IAstNode>(Node.Arguments);
Result := TBoundFunctionCallNode.Create(Node, callee, args, isTailCall); boundCall := TBoundFunctionCallNode.Create(Node, callee, args, isTailCall);
Result := TDataValue.FromIntf<IFunctionCallNode>(boundCall);
end; end;
function TAstBinder.TransformRecur(const Node: IRecurNode): IRecurNode; function TAstBinder.VisitRecurNode(const Node: IRecurNode): TDataValue;
begin begin
if not FIsTailStack.Peek then if not FIsTailStack.Peek then
raise Exception.Create('''recur'' can only be used in a tail position.'); raise Exception.Create('''recur'' can only be used in a tail position.');
FNextIsTail := False; FNextIsTail := False;
Result := inherited TransformRecur(Node); Result := inherited VisitRecurNode(Node);
end; end;
function TAstBinder.TransformBlockExpression(const Node: IBlockExpressionNode): IBlockExpressionNode; function TAstBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
var var
exprs: TArray<IAstNode>; exprs: TArray<IAstNode>;
i: Integer; i: Integer;
@@ -450,16 +457,16 @@ var
begin begin
isContextTail := FIsTailStack.Peek; isContextTail := FIsTailStack.Peek;
SetLength(exprs, Node.Expressions.Count); SetLength(exprs, Length(Node.Expressions));
for i := 0 to Node.Expressions.Count - 1 do for i := 0 to High(exprs) do
begin begin
FNextIsTail := isContextTail and (i = Node.Expressions.Count - 1); FNextIsTail := isContextTail and (i = High(exprs));
exprs[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>; exprs[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>;
end; end;
Result := TAst.Block(exprs); Result := TDataValue.FromIntf<IBlockExpressionNode>(TAst.Block(exprs));
end; end;
function TAstBinder.TransformIfExpression(const Node: IIfExpressionNode): IIfExpressionNode; function TAstBinder.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
var var
isContextTail: Boolean; isContextTail: Boolean;
condition, thenBranch, elseBranch: IAstNode; condition, thenBranch, elseBranch: IAstNode;
@@ -474,18 +481,18 @@ begin
elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>; elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
if (condition <> Node.Condition) or (thenBranch <> Node.ThenBranch) or (elseBranch <> Node.ElseBranch) then if (condition <> Node.Condition) or (thenBranch <> Node.ThenBranch) or (elseBranch <> Node.ElseBranch) then
Result := TAst.IfExpr(condition, thenBranch, elseBranch) Result := TDataValue.FromIntf<IIfExpressionNode>(TAst.IfExpr(condition, thenBranch, elseBranch))
else else
Result := Node; Result := TDataValue.FromIntf<IIfExpressionNode>(Node);
end; end;
function TAstBinder.TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode; function TAstBinder.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin begin
// The binder runs after the macro expander. It should never see a macro definition. // The binder runs after the macro expander. It should never see a macro definition.
raise Exception.Create('IMacroDefinitionNode found in AST after macro expansion phase.'); raise Exception.Create('IMacroDefinitionNode found in AST after macro expansion phase.');
end; end;
function TAstBinder.TransformTernaryExpression(const Node: ITernaryExpressionNode): ITernaryExpressionNode; function TAstBinder.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
var var
isContextTail: Boolean; isContextTail: Boolean;
condition, thenBranch, elseBranch: IAstNode; condition, thenBranch, elseBranch: IAstNode;
@@ -500,9 +507,9 @@ begin
elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>; elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
if (condition <> Node.Condition) or (thenBranch <> Node.ThenBranch) or (elseBranch <> Node.ElseBranch) then if (condition <> Node.Condition) or (thenBranch <> Node.ThenBranch) or (elseBranch <> Node.ElseBranch) then
Result := TAst.TernaryExpr(condition, thenBranch, elseBranch) Result := TDataValue.FromIntf<ITernaryExpressionNode>(TAst.TernaryExpr(condition, thenBranch, elseBranch))
else else
Result := Node; Result := TDataValue.FromIntf<ITernaryExpressionNode>(Node);
end; end;
end. end.
+4 -4
View File
@@ -26,7 +26,7 @@ type
protected protected
// Overridden to provide the debug-specific visitor factory. // Overridden to provide the debug-specific visitor factory.
function CreateVisitorFactory: TVisitorFactory; override; function CreateVisitorFactory: TEvaluatorFactory; override;
public public
constructor Create(const AScope: IExecutionScope; ALog: TStrings; AShowScope: Boolean; AInitialIndent: Integer = 0); constructor Create(const AScope: IExecutionScope; ALog: TStrings; AShowScope: Boolean; AInitialIndent: Integer = 0);
@@ -66,13 +66,13 @@ begin
ShowScope; ShowScope;
end; end;
function TDebugEvaluatorVisitor.CreateVisitorFactory: TVisitorFactory; function TDebugEvaluatorVisitor.CreateVisitorFactory: TEvaluatorFactory;
begin begin
// Return a closure that creates a new Debug visitor, using the current context // Return a closure that creates a new Debug visitor, using the current context
var callingVisitor := Self as IAstVisitor; var callingVisitor := Self as IEvaluatorVisitor;
Result := Result :=
function(const AScope: IExecutionScope): IAstVisitor function(const AScope: IExecutionScope): IEvaluatorVisitor
begin begin
var visitor := callingVisitor as TDebugEvaluatorVisitor; var visitor := callingVisitor as TDebugEvaluatorVisitor;
Result := TDebugEvaluatorVisitor.Create(AScope, visitor.FLog, visitor.FShowScope, visitor.FIndentLevel); Result := TDebugEvaluatorVisitor.Create(AScope, visitor.FLog, visitor.FShowScope, visitor.FIndentLevel);
+30
View File
@@ -42,6 +42,9 @@ type
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
@@ -350,6 +353,33 @@ begin
Result := TDataValue.Void; Result := TDataValue.Void;
end; end;
function TAstDumper.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
Log('Quasiquote');
Indent;
Node.Expression.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TAstDumper.VisitUnquote(const Node: IUnquoteNode): TDataValue;
begin
Log('Unquote');
Indent;
Node.Expression.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TAstDumper.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin
Log('UnquoteSplicing');
Indent;
Node.Expression.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TAstDumper.VisitIndexer(const Node: IIndexerNode): TDataValue; function TAstDumper.VisitIndexer(const Node: IIndexerNode): TDataValue;
begin begin
Log('Indexer'); Log('Indexer');
+25 -7
View File
@@ -14,13 +14,13 @@ uses
Myc.Ast.Scope; Myc.Ast.Scope;
type type
// A factory for creating visitors, primarily used by the debugger subsystem.
TVisitorFactory = reference to function(const Scope: IExecutionScope): IAstVisitor;
IEvaluatorVisitor = interface(IAstVisitor) IEvaluatorVisitor = interface(IAstVisitor)
function Execute(const RootNode: IAstNode): TDataValue; function Execute(const RootNode: IAstNode): TDataValue;
end; end;
// A factory for creating visitors, primarily used by the debugger subsystem.
TEvaluatorFactory = reference to function(const Scope: IExecutionScope): IEvaluatorVisitor;
// The standard AST evaluator for production use. // The standard AST evaluator for production use.
TEvaluatorVisitor = class(TAstVisitor, IEvaluatorVisitor) TEvaluatorVisitor = class(TAstVisitor, IEvaluatorVisitor)
private private
@@ -36,6 +36,9 @@ type
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
@@ -50,7 +53,7 @@ type
function IsTruthy(const AValue: TDataValue): Boolean; inline; function IsTruthy(const AValue: TDataValue): Boolean; inline;
// Returns a closure that can create the correct type of visitor for a lambda's body. // Returns a closure that can create the correct type of visitor for a lambda's body.
function CreateVisitorFactory: TVisitorFactory; virtual; function CreateVisitorFactory: TEvaluatorFactory; virtual;
property Scope: IExecutionScope read FScope; property Scope: IExecutionScope read FScope;
public public
@@ -132,10 +135,10 @@ begin
HandleTCO(Result); HandleTCO(Result);
end; end;
function TEvaluatorVisitor.CreateVisitorFactory: TVisitorFactory; function TEvaluatorVisitor.CreateVisitorFactory: TEvaluatorFactory;
begin begin
// The production visitor returns a factory that creates another production visitor. // The production visitor returns a factory that creates another production visitor.
Result := function(const AScope: IExecutionScope): IAstVisitor begin Result := TEvaluatorVisitor.Create(AScope); end; Result := function(const AScope: IExecutionScope): IEvaluatorVisitor begin Result := TEvaluatorVisitor.Create(AScope); end;
end; end;
procedure TEvaluatorVisitor.HandleTCO(var ResultValue: TDataValue); procedure TEvaluatorVisitor.HandleTCO(var ResultValue: TDataValue);
@@ -173,7 +176,7 @@ var
i: Integer; i: Integer;
sourceAddresses: TArray<TResolvedAddress>; sourceAddresses: TArray<TResolvedAddress>;
closureScope: IExecutionScope; closureScope: IExecutionScope;
visitorFactory: TVisitorFactory; visitorFactory: TEvaluatorFactory;
begin begin
// Cast to the bound node to access binder-specific information. // Cast to the bound node to access binder-specific information.
boundNode := Node as TBoundLambdaExpressionNode; boundNode := Node as TBoundLambdaExpressionNode;
@@ -249,6 +252,21 @@ begin
raise Exception.Create('Macro definitions cannot be evaluated at runtime.'); raise Exception.Create('Macro definitions cannot be evaluated at runtime.');
end; end;
function TEvaluatorVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
raise Exception.Create('Quasiquote nodes are a compile-time construct and cannot be evaluated at runtime.');
end;
function TEvaluatorVisitor.VisitUnquote(const Node: IUnquoteNode): TDataValue;
begin
raise Exception.Create('Unquote nodes are a compile-time construct and cannot be evaluated at runtime.');
end;
function TEvaluatorVisitor.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin
raise Exception.Create('Unquote-splicing nodes are a compile-time construct and cannot be evaluated at runtime.');
end;
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
var var
calleeValue: TDataValue; calleeValue: TDataValue;
+70 -1
View File
@@ -35,6 +35,9 @@ type
function JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode; function JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode;
function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode; function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode;
function JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode; function JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode;
function JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
function JsonToUnquoteNode(const AObj: TJSONObject): IUnquoteNode;
function JsonToUnquoteSplicingNode(const AObj: TJSONObject): IUnquoteSplicingNode;
function JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode; function JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
function JsonToRecurNode(const AObj: TJSONObject): IRecurNode; function JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
function JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode; function JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
@@ -55,6 +58,9 @@ type
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
function VisitRecurNode(const Node: IRecurNode): TDataValue; override; function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
@@ -295,6 +301,21 @@ begin
Result := TDataValue.Void; Result := TDataValue.Void;
end; end;
function TJsonAstConverter.JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
begin
Result := TAst.Quasiquote(JsonToNode(AObj.GetValue('Expression')));
end;
function TJsonAstConverter.JsonToUnquoteNode(const AObj: TJSONObject): IUnquoteNode;
begin
Result := TAst.Unquote(JsonToNode(AObj.GetValue('Expression')));
end;
function TJsonAstConverter.JsonToUnquoteSplicingNode(const AObj: TJSONObject): IUnquoteSplicingNode;
begin
Result := TAst.UnquoteSplicing(JsonToNode(AObj.GetValue('Expression')));
end;
function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
var var
obj, calleeObj: TJSONObject; obj, calleeObj: TJSONObject;
@@ -362,7 +383,7 @@ begin
for expr in Node.Expressions do for expr in Node.Expressions do
expr.Accept(Self); expr.Accept(Self);
SetLength(tempExprs, Node.Expressions.Count); SetLength(tempExprs, Length(Node.Expressions));
for i := High(tempExprs) downto 0 do for i := High(tempExprs) downto 0 do
tempExprs[i] := FJsonObjectStack.Pop; tempExprs[i] := FJsonObjectStack.Pop;
@@ -646,6 +667,48 @@ begin
Result := TAst.MacroDef(name, params, body); Result := TAst.MacroDef(name, params, body);
end; end;
function TJsonAstConverter.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
var
obj, exprObj: TJSONObject;
begin
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('Quasiquote'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.VisitUnquote(const Node: IUnquoteNode): TDataValue;
var
obj, exprObj: TJSONObject;
begin
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('Unquote'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
var
obj, exprObj: TJSONObject;
begin
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('UnquoteSplicing'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode; function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
var var
callee: IAstNode; callee: IAstNode;
@@ -774,6 +837,12 @@ begin
Result := JsonToLambdaExprNode(obj) Result := JsonToLambdaExprNode(obj)
else if nodeType = 'MacroDef' then else if nodeType = 'MacroDef' then
Result := JsonToMacroDefNode(obj) Result := JsonToMacroDefNode(obj)
else if nodeType = 'Quasiquote' then
Result := JsonToQuasiquoteNode(obj)
else if nodeType = 'Unquote' then
Result := JsonToUnquoteNode(obj)
else if nodeType = 'UnquoteSplicing' then
Result := JsonToUnquoteSplicingNode(obj)
else if nodeType = 'FunctionCall' then else if nodeType = 'FunctionCall' then
Result := JsonToFunctionCallNode(obj) Result := JsonToFunctionCallNode(obj)
else if nodeType = 'Recur' then else if nodeType = 'Recur' then
+269
View File
@@ -0,0 +1,269 @@
unit Myc.Ast.MacroExpander;
interface
uses
System.SysUtils,
System.Classes,
System.Generics.Collections,
Myc.Data.Value,
Myc.Ast.Nodes,
Myc.Ast.Scope,
Myc.Ast.Visitor;
type
// Defines the strategy for compiling and evaluating an AST node at compile time.
TCompileTimeExecutor = reference to function(const ANode: IAstNode): TDataValue;
IMacroExpander = interface(IAstVisitor)
function Execute(const RootNode: IAstNode): IAstNode;
end;
// The macro expander is now a pure AST transformation engine.
TMacroExpander = class(TAstTransformer, IMacroExpander)
private
FMacros: TDictionary<string, IMacroDefinitionNode>;
FExecutor: TCompileTimeExecutor;
function ExpandNode(const ANode: IAstNode): IAstNode;
protected
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
public
constructor Create(const AExecutor: TCompileTimeExecutor);
destructor Destroy; override;
function Execute(const RootNode: IAstNode): IAstNode;
end;
implementation
uses
Myc.Ast;
type
TExpansionHelper = class(TAstTransformer)
private
FExpansionScope: IExecutionScope;
FExpander: TMacroExpander;
FExecutor: TCompileTimeExecutor;
protected
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
public
constructor Create(AExpansionScope: IExecutionScope; AExpander: TMacroExpander; AExecutor: TCompileTimeExecutor);
class function Expand(
Node: IAstNode;
ExpansionScope: IExecutionScope;
Expander: TMacroExpander;
Executor: TCompileTimeExecutor
): IAstNode; static;
end;
TSubstitutor = class(TAstTransformer)
private
FParamScope: IExecutionScope;
protected
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
public
constructor Create(AParamScope: IExecutionScope);
end;
{ TMacroExpander }
constructor TMacroExpander.Create(const AExecutor: TCompileTimeExecutor);
begin
inherited Create;
Assert(Assigned(AExecutor), 'A TCompileTimeExecutor must be provided.');
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
FExecutor := AExecutor;
end;
destructor TMacroExpander.Destroy;
begin
FMacros.Free;
inherited;
end;
function TMacroExpander.ExpandNode(const ANode: IAstNode): IAstNode;
var
lastNode: IAstNode;
begin
Result := ANode;
if not Assigned(Result) then
exit;
repeat
lastNode := Result;
Result := Self.Accept(lastNode).AsIntf<IAstNode>;
until Result = lastNode;
end;
function TMacroExpander.Execute(const RootNode: IAstNode): IAstNode;
begin
FMacros.Clear;
Result := ExpandNode(RootNode);
end;
function TMacroExpander.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
var
macroDef: IMacroDefinitionNode;
expandedNode: IAstNode;
i: Integer;
begin
if not (Node.Callee is TIdentifierNode) then
begin
Result := inherited VisitFunctionCall(Node);
exit;
end;
var calleeIdentifier := Node.Callee as TIdentifierNode;
if FMacros.TryGetValue(calleeIdentifier.Name, macroDef) then
begin
var expansionScope := TAst.CreateScope(nil); // Temporary scope for parameters, no parent needed.
if Length(Node.Arguments) <> Length(macroDef.Parameters) then
raise Exception.CreateFmt(
'Macro %s expects %d arguments, but got %d',
[macroDef.Name.Name, Length(macroDef.Parameters), Length(Node.Arguments)]);
for i := 0 to High(macroDef.Parameters) do
expansionScope.Define(macroDef.Parameters[i].Name, TDataValue.FromIntf<IAstNode>(Node.Arguments[i]));
if not (macroDef.Body is TQuasiquoteNode) then
raise Exception.CreateFmt('Macro body for "%s" must be a quasiquoted expression.', [macroDef.Name.Name]);
expandedNode := TExpansionHelper.Expand(IQuasiquoteNode(macroDef.Body).Expression, expansionScope, Self, FExecutor);
Result := Self.Accept(expandedNode);
end
else
begin
Result := inherited VisitFunctionCall(Node);
end;
end;
function TMacroExpander.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin
FMacros.AddOrSetValue(Node.Name.Name, Node);
Result := TDataValue.FromIntf<IBlockExpressionNode>(TBlockExpressionNode.Create([]));
end;
{ TExpansionHelper }
constructor TExpansionHelper.Create(AExpansionScope: IExecutionScope; AExpander: TMacroExpander; AExecutor: TCompileTimeExecutor);
begin
inherited Create;
FExpansionScope := AExpansionScope;
FExpander := AExpander;
FExecutor := AExecutor;
end;
class function TExpansionHelper.Expand(
Node: IAstNode;
ExpansionScope: IExecutionScope;
Expander: TMacroExpander;
Executor: TCompileTimeExecutor
): IAstNode;
var
helper: TExpansionHelper;
begin
helper := TExpansionHelper.Create(ExpansionScope, Expander, Executor);
try
Result := helper.Accept(Node).AsIntf<IAstNode>;
finally
helper.Free;
end;
end;
function TExpansionHelper.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
var
newArgs: TList<IAstNode>;
transformedArgValue: TDataValue;
transformedArgNode: IAstNode;
transformedCallee: IAstNode;
begin
newArgs := TList<IAstNode>.Create;
try
for var arg in Node.Arguments do
begin
transformedArgValue := Self.Accept(arg);
if transformedArgValue.IsVoid then
continue;
transformedArgNode := transformedArgValue.AsIntf<IAstNode>;
if (transformedArgNode is TBlockExpressionNode) then
newArgs.AddRange((transformedArgNode as TBlockExpressionNode).Expressions)
else
newArgs.Add(transformedArgNode);
end;
transformedCallee := Self.Accept(Node.Callee).AsIntf<IAstNode>;
Result := TDataValue.FromIntf<IAstNode>(TAst.FunctionCall(transformedCallee, newArgs.ToArray));
finally
newArgs.Free;
end;
end;
function TExpansionHelper.VisitUnquote(const Node: IUnquoteNode): TDataValue;
var
substitutor: TSubstitutor;
substitutedAst, expandedAst: IAstNode;
value: TDataValue;
begin
// Step 1: Substitute macro parameters with their AST node values.
substitutor := TSubstitutor.Create(FExpansionScope);
try
substitutedAst := substitutor.Execute(Node.Expression);
finally
substitutor.Free;
end;
// Step 2: Recursively expand any macros within the substituted expression.
expandedAst := FExpander.ExpandNode(substitutedAst);
// Step 3: Call the injected executor strategy to bind and evaluate the AST.
value := FExecutor(expandedAst);
// Step 4: Wrap the resulting value for insertion into the template.
if value.Kind in [vkScalar, vkText] then
Result := TDataValue.FromIntf<IAstNode>(TAst.Constant(value))
else
Result := value;
end;
function TExpansionHelper.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
var
unquotedValue: TDataValue;
unquotedNode: IAstNode;
begin
unquotedValue := Self.VisitUnquote(TAst.Unquote(Node.Expression));
if unquotedValue.Kind = vkInterface then
unquotedNode := unquotedValue.AsIntf<IAstNode>
else
unquotedNode := nil;
if not (unquotedNode is TBlockExpressionNode) then
raise Exception.Create('Expression inside unquote-splicing (`~@`) must evaluate to a list of nodes (a block).');
Result := unquotedValue;
end;
{ TSubstitutor }
constructor TSubstitutor.Create(AParamScope: IExecutionScope);
begin
inherited Create;
FParamScope := AParamScope;
end;
function TSubstitutor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
var
addr: TResolvedAddress;
nodeValue: TDataValue;
begin
addr := FParamScope.CreateDescriptor.FindSymbol(Node.Name);
if (addr.Kind = akLocalOrParent) and (addr.ScopeDepth = 0) then
begin
nodeValue := FParamScope.Values[addr];
Result := nodeValue;
exit;
end;
Result := inherited VisitIdentifier(Node);
end;
end.
+2 -2
View File
@@ -162,9 +162,9 @@ type
IBlockExpressionNode = interface(IAstNode) IBlockExpressionNode = interface(IAstNode)
{$region 'private'} {$region 'private'}
function GetExpressions: TList<IAstNode>; function GetExpressions: TArray<IAstNode>;
{$endregion} {$endregion}
property Expressions: TList<IAstNode> read GetExpressions; property Expressions: TArray<IAstNode> read GetExpressions;
end; end;
IVariableDeclarationNode = interface(IAstNode) IVariableDeclarationNode = interface(IAstNode)
+3 -3
View File
@@ -386,11 +386,11 @@ begin
// (defmacro name [params] body) // (defmacro name [params] body)
if (Length(tailNodes) <> 3) or (tailTokens[0].Kind <> tkIdentifier) then if (Length(tailNodes) <> 3) or (tailTokens[0].Kind <> tkIdentifier) then
raise Exception.Create('Syntax Error: ''defmacro'' requires a name, a parameter list, and a body.'); raise Exception.Create('Syntax Error: ''defmacro'' requires a name, a parameter list, and a body.');
if elements[1].Node <> nil then if elements[2].Params = nil then
raise Exception.Create('Syntax Error: Expected a parameter list [...] after macro name.'); raise Exception.Create('Syntax Error: Expected a parameter list [...] after macro name.');
var macroName := IIdentifierNode(tailNodes[0]); var macroName := IIdentifierNode(tailNodes[0]);
var macroParams := elements[1].Params; var macroParams := elements[2].Params;
var macroBody := tailNodes[2]; var macroBody := tailNodes[2];
Result := TAst.MacroDef(macroName, macroParams, macroBody); Result := TAst.MacroDef(macroName, macroParams, macroBody);
@@ -405,7 +405,7 @@ begin
begin begin
if Length(tailNodes) <> 2 then if Length(tailNodes) <> 2 then
raise Exception.Create('Syntax Error: ''fn'' requires a parameter list and a body.'); raise Exception.Create('Syntax Error: ''fn'' requires a parameter list and a body.');
if elements[1].Node <> nil then if elements[1].Params = nil then
raise Exception.Create('Syntax Error: Expected a parameter list [...] after ''fn''.'); raise Exception.Create('Syntax Error: Expected a parameter list [...] after ''fn''.');
Result := TAst.LambdaExpr(elements[1].Params, tailNodes[1]); Result := TAst.LambdaExpr(elements[1].Params, tailNodes[1]);
end end
+100 -225
View File
@@ -41,59 +41,34 @@ type
end; end;
// A base visitor that walks the AST and rebuilds it node by node. // A base visitor that walks the AST and rebuilds it node by node.
// This class uses the Template Method pattern: // Derived classes can override the virtual Visit... methods to customize behavior.
// - The Visit... methods are the template and should not be overridden.
// - The virtual Transform... methods are the hooks for derived classes to customize behavior.
TAstTransformer = class abstract(TAstVisitor, IAstTransformer) TAstTransformer = class abstract(TAstVisitor, IAstTransformer)
private private
FDone: Boolean; FDone: Boolean;
protected protected
// Final Visit methods - these should not be overridden. They call the virtual Transform methods. // These virtual methods implement the default identity-transformation (cloning) behavior.
function VisitConstant(const Node: IConstantNode): TDataValue; override; final; function VisitConstant(const Node: IConstantNode): TDataValue; override;
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override; final; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override; final; function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override; final; function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override; final; function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; final; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; final; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; final; function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; final; function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; final; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; final; function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; final; function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override; final; function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override; final; function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override; final; function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; final; function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; final; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; final; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; final; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; final; function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
function VisitRecurNode(const Node: IRecurNode): TDataValue; override; final; function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
// Dispatch methods for each node type. Derived classes override these to change the transformation.
function TransformConstant(const Node: IConstantNode): IConstantNode; virtual;
function TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; virtual;
function TransformBinaryExpression(const Node: IBinaryExpressionNode): IBinaryExpressionNode; virtual;
function TransformUnaryExpression(const Node: IUnaryExpressionNode): IUnaryExpressionNode; virtual;
function TransformIfExpression(const Node: IIfExpressionNode): IIfExpressionNode; virtual;
function TransformTernaryExpression(const Node: ITernaryExpressionNode): ITernaryExpressionNode; virtual;
function TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; virtual;
function TransformFunctionCall(const Node: IFunctionCallNode): IFunctionCallNode; virtual;
function TransformBlockExpression(const Node: IBlockExpressionNode): IBlockExpressionNode; virtual;
function TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; virtual;
function TransformAssignment(const Node: IAssignmentNode): IAssignmentNode; virtual;
function TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode; virtual;
function TransformQuasiquote(const Node: IQuasiquoteNode): IQuasiquoteNode; virtual;
function TransformUnquote(const Node: IUnquoteNode): IUnquoteNode; virtual;
function TransformUnquoteSplicing(const Node: IUnquoteSplicingNode): IUnquoteSplicingNode; virtual;
function TransformIndexer(const Node: IIndexerNode): IIndexerNode; virtual;
function TransformMemberAccess(const Node: IMemberAccessNode): IMemberAccessNode; virtual;
function TransformCreateSeries(const Node: ICreateSeriesNode): ICreateSeriesNode; virtual;
function TransformAddSeriesItem(const Node: IAddSeriesItemNode): IAddSeriesItemNode; virtual;
function TransformSeriesLength(const Node: ISeriesLengthNode): ISeriesLengthNode; virtual;
function TransformRecur(const Node: IRecurNode): IRecurNode; virtual;
// Helper to transform an array of nodes. // Helper to transform an array of nodes.
function TransformNodes<T: IAstNode>(const Nodes: TArray<T>): TArray<T>; function TransformNodes<T: IAstNode>(const Nodes: TArray<T>): TArray<T>;
@@ -106,11 +81,8 @@ type
function Execute(const RootNode: IAstNode): IAstNode; function Execute(const RootNode: IAstNode): IAstNode;
end; end;
// TAstTraverser simply inherits the identity-transform (cloning) behavior from TAstTransformer.
TAstTraverser = class(TAstTransformer);
// Generic traverser for managing state during AST walks. // Generic traverser for managing state during AST walks.
TAstTraverser<T> = class(TAstTraverser) TAstTraverser<T> = class(TAstTransformer)
private private
FData: TStack<T>; FData: TStack<T>;
protected protected
@@ -141,202 +113,210 @@ begin
Result := Accept(RootNode).AsIntf<IAstNode>; Result := Accept(RootNode).AsIntf<IAstNode>;
end; end;
// --- Default implementations for Transform... methods (Identity Transformation / Cloning) --- function TAstTransformer.VisitConstant(const Node: IConstantNode): TDataValue;
function TAstTransformer.TransformConstant(const Node: IConstantNode): IConstantNode;
begin begin
// The node itself is immutable, return it directly. // The node itself is immutable, return it directly.
Result := Node; Result := TDataValue.FromIntf<IConstantNode>(Node);
end; end;
function TAstTransformer.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin begin
Result := Node; Result := TDataValue.FromIntf<IIdentifierNode>(Node);
end; end;
function TAstTransformer.TransformBinaryExpression(const Node: IBinaryExpressionNode): IBinaryExpressionNode; function TAstTransformer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
begin begin
var left := Accept(Node.Left).AsIntf<IAstNode>; var left := Accept(Node.Left).AsIntf<IAstNode>;
var right := Accept(Node.Right).AsIntf<IAstNode>; var right := Accept(Node.Right).AsIntf<IAstNode>;
if (left = Node.Left) and (right = Node.Right) then if (left = Node.Left) and (right = Node.Right) then
Result := Node Result := TDataValue.FromIntf<IBinaryExpressionNode>(Node)
else else
Result := TAst.BinaryExpr(left, Node.Operator, right); Result := TDataValue.FromIntf<IBinaryExpressionNode>(TAst.BinaryExpr(left, Node.Operator, right));
end; end;
function TAstTransformer.TransformUnaryExpression(const Node: IUnaryExpressionNode): IUnaryExpressionNode; function TAstTransformer.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
begin begin
var right := Accept(Node.Right).AsIntf<IAstNode>; var right := Accept(Node.Right).AsIntf<IAstNode>;
if right = Node.Right then if right = Node.Right then
Result := Node Result := TDataValue.FromIntf<IUnaryExpressionNode>(Node)
else else
Result := TAst.UnaryExpr(Node.Operator, right); Result := TDataValue.FromIntf<IUnaryExpressionNode>(TAst.UnaryExpr(Node.Operator, right));
end; end;
function TAstTransformer.TransformIfExpression(const Node: IIfExpressionNode): IIfExpressionNode; function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin begin
var condition := Accept(Node.Condition).AsIntf<IAstNode>; var condition := Accept(Node.Condition).AsIntf<IAstNode>;
var thenBranch := Accept(Node.ThenBranch).AsIntf<IAstNode>; var thenBranch := Accept(Node.ThenBranch).AsIntf<IAstNode>;
var elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>; var elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
if (condition = Node.Condition) and (thenBranch = Node.ThenBranch) and (elseBranch = Node.ElseBranch) then if (condition = Node.Condition) and (thenBranch = Node.ThenBranch) and (elseBranch = Node.ElseBranch) then
Result := Node Result := TDataValue.FromIntf<IIfExpressionNode>(Node)
else else
Result := TAst.IfExpr(condition, thenBranch, elseBranch); Result := TDataValue.FromIntf<IIfExpressionNode>(TAst.IfExpr(condition, thenBranch, elseBranch));
end; end;
function TAstTransformer.TransformTernaryExpression(const Node: ITernaryExpressionNode): ITernaryExpressionNode; function TAstTransformer.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin begin
var condition := Accept(Node.Condition).AsIntf<IAstNode>; var condition := Accept(Node.Condition).AsIntf<IAstNode>;
var thenBranch := Accept(Node.ThenBranch).AsIntf<IAstNode>; var thenBranch := Accept(Node.ThenBranch).AsIntf<IAstNode>;
var elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>; var elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
if (condition = Node.Condition) and (thenBranch = Node.ThenBranch) and (elseBranch = Node.ElseBranch) then if (condition = Node.Condition) and (thenBranch = Node.ThenBranch) and (elseBranch = Node.ElseBranch) then
Result := Node Result := TDataValue.FromIntf<ITernaryExpressionNode>(Node)
else else
Result := TAst.TernaryExpr(condition, thenBranch, elseBranch); Result := TDataValue.FromIntf<ITernaryExpressionNode>(TAst.TernaryExpr(condition, thenBranch, elseBranch));
end; end;
function TAstTransformer.TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin begin
var parameters := TransformNodes<IIdentifierNode>(Node.Parameters); var parameters := TransformNodes<IIdentifierNode>(Node.Parameters);
var body := Accept(Node.Body).AsIntf<IAstNode>; var body := Accept(Node.Body).AsIntf<IAstNode>;
if (parameters = Node.Parameters) and (body = Node.Body) then if (parameters = Node.Parameters) and (body = Node.Body) then
Result := Node Result := TDataValue.FromIntf<ILambdaExpressionNode>(Node)
else else
Result := TAst.LambdaExpr(parameters, body); Result := TDataValue.FromIntf<ILambdaExpressionNode>(TAst.LambdaExpr(parameters, body));
end; end;
function TAstTransformer.TransformFunctionCall(const Node: IFunctionCallNode): IFunctionCallNode; function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
begin begin
var callee := Accept(Node.Callee).AsIntf<IAstNode>; var callee := Accept(Node.Callee).AsIntf<IAstNode>;
var args := TransformNodes<IAstNode>(Node.Arguments); var args := TransformNodes<IAstNode>(Node.Arguments);
if (callee = Node.Callee) and (args = Node.Arguments) then if (callee = Node.Callee) and (args = Node.Arguments) then
Result := Node Result := TDataValue.FromIntf<IFunctionCallNode>(Node)
else else
Result := TAst.FunctionCall(callee, args); Result := TDataValue.FromIntf<IFunctionCallNode>(TAst.FunctionCall(callee, args));
end; end;
function TAstTransformer.TransformBlockExpression(const Node: IBlockExpressionNode): IBlockExpressionNode; function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
var
expressions: TArray<IAstNode>;
i: Integer;
hasChanged: Boolean;
begin begin
// TList is mutable, so we always transform. // Check if any child expression has changed before creating a new node.
var exprs: TArray<IAstNode>; hasChanged := false;
var i: Integer; SetLength(expressions, Length(Node.Expressions));
SetLength(exprs, Node.Expressions.Count); for i := 0 to High(Node.Expressions) do
for i := 0 to Node.Expressions.Count - 1 do begin
exprs[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>; expressions[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>;
Result := TAst.Block(exprs); if expressions[i] <> Node.Expressions[i] then
hasChanged := true;
end;
if hasChanged then
Result := TDataValue.FromIntf<IBlockExpressionNode>(TAst.Block(expressions))
else
Result := TDataValue.FromIntf<IBlockExpressionNode>(Node);
end; end;
function TAstTransformer.TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin begin
var identifier := Accept(Node.Identifier).AsIntf<IIdentifierNode>; var identifier := Accept(Node.Identifier).AsIntf<IIdentifierNode>;
var initializer := Accept(Node.Initializer).AsIntf<IAstNode>; var initializer := Accept(Node.Initializer).AsIntf<IAstNode>;
if (identifier = Node.Identifier) and (initializer = Node.Initializer) then if (identifier = Node.Identifier) and (initializer = Node.Initializer) then
Result := Node Result := TDataValue.FromIntf<IVariableDeclarationNode>(Node)
else else
Result := TAst.VarDecl(identifier, initializer); Result := TDataValue.FromIntf<IVariableDeclarationNode>(TAst.VarDecl(identifier, initializer));
end; end;
function TAstTransformer.TransformAssignment(const Node: IAssignmentNode): IAssignmentNode; function TAstTransformer.VisitAssignment(const Node: IAssignmentNode): TDataValue;
begin begin
var identifier := Accept(Node.Identifier).AsIntf<IIdentifierNode>; var identifier := Accept(Node.Identifier).AsIntf<IIdentifierNode>;
var value := Accept(Node.Value).AsIntf<IAstNode>; var value := Accept(Node.Value).AsIntf<IAstNode>;
if (identifier = Node.Identifier) and (value = Node.Value) then if (identifier = Node.Identifier) and (value = Node.Value) then
Result := Node Result := TDataValue.FromIntf<IAssignmentNode>(Node)
else else
Result := TAst.Assign(identifier, value); Result := TDataValue.FromIntf<IAssignmentNode>(TAst.Assign(identifier, value));
end; end;
function TAstTransformer.TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode; function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin begin
// Added identity transform for macro definitions.
var name := Accept(Node.Name).AsIntf<IIdentifierNode>; var name := Accept(Node.Name).AsIntf<IIdentifierNode>;
var parameters := TransformNodes<IIdentifierNode>(Node.Parameters); var parameters := TransformNodes<IIdentifierNode>(Node.Parameters);
var body := Accept(Node.Body).AsIntf<IAstNode>; var body := Accept(Node.Body).AsIntf<IAstNode>;
if (name = Node.Name) and (parameters = Node.Parameters) and (body = Node.Body) then if (name = Node.Name) and (parameters = Node.Parameters) and (body = Node.Body) then
Result := Node Result := TDataValue.FromIntf<IMacroDefinitionNode>(Node)
else else
Result := TAst.MacroDef(name, parameters, body); Result := TDataValue.FromIntf<IMacroDefinitionNode>(TAst.MacroDef(name, parameters, body));
end; end;
function TAstTransformer.TransformQuasiquote(const Node: IQuasiquoteNode): IQuasiquoteNode; function TAstTransformer.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin begin
var expr := Accept(Node.Expression).AsIntf<IAstNode>; var expr := Accept(Node.Expression).AsIntf<IAstNode>;
if expr = Node.Expression then if expr = Node.Expression then
Result := Node Result := TDataValue.FromIntf<IQuasiquoteNode>(Node)
else else
Result := TAst.Quasiquote(expr); Result := TDataValue.FromIntf<IQuasiquoteNode>(TAst.Quasiquote(expr));
end; end;
function TAstTransformer.TransformUnquote(const Node: IUnquoteNode): IUnquoteNode; function TAstTransformer.VisitUnquote(const Node: IUnquoteNode): TDataValue;
begin begin
var expr := Accept(Node.Expression).AsIntf<IAstNode>; var expr := Accept(Node.Expression).AsIntf<IAstNode>;
if expr = Node.Expression then if expr = Node.Expression then
Result := Node Result := TDataValue.FromIntf<IUnquoteNode>(Node)
else else
Result := TAst.Unquote(expr); Result := TDataValue.FromIntf<IUnquoteNode>(TAst.Unquote(expr));
end; end;
function TAstTransformer.TransformUnquoteSplicing(const Node: IUnquoteSplicingNode): IUnquoteSplicingNode; function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin begin
var expr := Accept(Node.Expression).AsIntf<IAstNode>; var expr := Accept(Node.Expression).AsIntf<IAstNode>;
if expr = Node.Expression then if expr = Node.Expression then
Result := Node Result := TDataValue.FromIntf<IUnquoteSplicingNode>(Node)
else else
Result := TAst.UnquoteSplicing(expr); Result := TDataValue.FromIntf<IUnquoteSplicingNode>(TAst.UnquoteSplicing(expr));
end; end;
function TAstTransformer.TransformIndexer(const Node: IIndexerNode): IIndexerNode; function TAstTransformer.VisitIndexer(const Node: IIndexerNode): TDataValue;
begin begin
var base := Accept(Node.Base).AsIntf<IAstNode>; var base := Accept(Node.Base).AsIntf<IAstNode>;
var index := Accept(Node.Index).AsIntf<IAstNode>; var index := Accept(Node.Index).AsIntf<IAstNode>;
if (base = Node.Base) and (index = Node.Index) then if (base = Node.Base) and (index = Node.Index) then
Result := Node Result := TDataValue.FromIntf<IIndexerNode>(Node)
else else
Result := TAst.Indexer(base, index); Result := TDataValue.FromIntf<IIndexerNode>(TAst.Indexer(base, index));
end; end;
function TAstTransformer.TransformMemberAccess(const Node: IMemberAccessNode): IMemberAccessNode; function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin begin
var base := Accept(Node.Base).AsIntf<IAstNode>; var base := Accept(Node.Base).AsIntf<IAstNode>;
var member := Node.Member; var member := Node.Member;
if (base = Node.Base) and (member = Node.Member) then if (base = Node.Base) and (member = Node.Member) then
Result := Node Result := TDataValue.FromIntf<IMemberAccessNode>(Node)
else else
Result := TAst.MemberAccess(base, member); Result := TDataValue.FromIntf<IMemberAccessNode>(TAst.MemberAccess(base, member));
end; end;
function TAstTransformer.TransformCreateSeries(const Node: ICreateSeriesNode): ICreateSeriesNode; function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin begin
Result := Node; Result := TDataValue.FromIntf<ICreateSeriesNode>(Node);
end; end;
function TAstTransformer.TransformAddSeriesItem(const Node: IAddSeriesItemNode): IAddSeriesItemNode; function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin begin
var series := Accept(Node.Series).AsIntf<IIdentifierNode>; var series := Accept(Node.Series).AsIntf<IIdentifierNode>;
var value := Accept(Node.Value).AsIntf<IAstNode>; var value := Accept(Node.Value).AsIntf<IAstNode>;
var lookback := Accept(Node.Lookback).AsIntf<IAstNode>; var lookback := Accept(Node.Lookback).AsIntf<IAstNode>;
if (series = Node.Series) and (value = Node.Value) and (lookback = Node.Lookback) then if (series = Node.Series) and (value = Node.Value) and (lookback = Node.Lookback) then
Result := Node Result := TDataValue.FromIntf<IAddSeriesItemNode>(Node)
else else
Result := TAst.AddSeriesItem(series, value, lookback); Result := TDataValue.FromIntf<IAddSeriesItemNode>(TAst.AddSeriesItem(series, value, lookback));
end; end;
function TAstTransformer.TransformSeriesLength(const Node: ISeriesLengthNode): ISeriesLengthNode; function TAstTransformer.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin begin
var series := Accept(Node.Series).AsIntf<IIdentifierNode>; var series := Accept(Node.Series).AsIntf<IIdentifierNode>;
if series = Node.Series then if series = Node.Series then
Result := Node Result := TDataValue.FromIntf<ISeriesLengthNode>(Node)
else else
Result := TAst.SeriesLength(series); Result := TDataValue.FromIntf<ISeriesLengthNode>(TAst.SeriesLength(series));
end; end;
function TAstTransformer.TransformRecur(const Node: IRecurNode): IRecurNode; function TAstTransformer.VisitRecurNode(const Node: IRecurNode): TDataValue;
begin begin
var args := TransformNodes<IAstNode>(Node.Arguments); var args := TransformNodes<IAstNode>(Node.Arguments);
if args = Node.Arguments then if args = Node.Arguments then
Result := Node Result := TDataValue.FromIntf<IRecurNode>(Node)
else else
Result := TAst.Recur(args); Result := TDataValue.FromIntf<IRecurNode>(TAst.Recur(args));
end; end;
function TAstTransformer.TransformNodes<T>(const Nodes: TArray<T>): TArray<T>; function TAstTransformer.TransformNodes<T>(const Nodes: TArray<T>): TArray<T>;
@@ -356,111 +336,6 @@ begin
Result := Nodes; Result := Nodes;
end; end;
function TAstTransformer.VisitConstant(const Node: IConstantNode): TDataValue;
begin
Result := TDataValue.FromIntf<IConstantNode>(TransformConstant(Node));
end;
function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin
Result := TDataValue.FromIntf<IIdentifierNode>(TransformIdentifier(Node));
end;
function TAstTransformer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
begin
Result := TDataValue.FromIntf<IBinaryExpressionNode>(TransformBinaryExpression(Node));
end;
function TAstTransformer.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
begin
Result := TDataValue.FromIntf<IUnaryExpressionNode>(TransformUnaryExpression(Node));
end;
function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin
Result := TDataValue.FromIntf<IIfExpressionNode>(TransformIfExpression(Node));
end;
function TAstTransformer.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin
Result := TDataValue.FromIntf<ITernaryExpressionNode>(TransformTernaryExpression(Node));
end;
function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin
Result := TDataValue.FromIntf<ILambdaExpressionNode>(TransformLambdaExpression(Node));
end;
function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
begin
Result := TDataValue.FromIntf<IFunctionCallNode>(TransformFunctionCall(Node));
end;
function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
begin
Result := TDataValue.FromIntf<IBlockExpressionNode>(TransformBlockExpression(Node));
end;
function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin
Result := TDataValue.FromIntf<IVariableDeclarationNode>(TransformVariableDeclaration(Node));
end;
function TAstTransformer.VisitAssignment(const Node: IAssignmentNode): TDataValue;
begin
Result := TDataValue.FromIntf<IAssignmentNode>(TransformAssignment(Node));
end;
function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin
Result := TDataValue.FromIntf<IMacroDefinitionNode>(TransformMacroDefinition(Node));
end;
function TAstTransformer.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
Result := TDataValue.FromIntf<IQuasiquoteNode>(TransformQuasiquote(Node));
end;
function TAstTransformer.VisitUnquote(const Node: IUnquoteNode): TDataValue;
begin
Result := TDataValue.FromIntf<IUnquoteNode>(TransformUnquote(Node));
end;
function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin
Result := TDataValue.FromIntf<IUnquoteSplicingNode>(TransformUnquoteSplicing(Node));
end;
function TAstTransformer.VisitIndexer(const Node: IIndexerNode): TDataValue;
begin
Result := TDataValue.FromIntf<IIndexerNode>(TransformIndexer(Node));
end;
function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin
Result := TDataValue.FromIntf<IMemberAccessNode>(TransformMemberAccess(Node));
end;
function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin
Result := TDataValue.FromIntf<ICreateSeriesNode>(TransformCreateSeries(Node));
end;
function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin
Result := TDataValue.FromIntf<IAddSeriesItemNode>(TransformAddSeriesItem(Node));
end;
function TAstTransformer.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin
Result := TDataValue.FromIntf<ISeriesLengthNode>(TransformSeriesLength(Node));
end;
function TAstTransformer.VisitRecurNode(const Node: IRecurNode): TDataValue;
begin
Result := TDataValue.FromIntf<IRecurNode>(TransformRecur(Node));
end;
{ TAstTraverser<T> } { TAstTraverser<T> }
constructor TAstTraverser<T>.Create; constructor TAstTraverser<T>.Create;
+6 -16
View File
@@ -211,13 +211,12 @@ type
TBlockExpressionNode = class(TAstNode, IBlockExpressionNode) TBlockExpressionNode = class(TAstNode, IBlockExpressionNode)
private private
FExpressions: TList<IAstNode>; FExpressions: TArray<IAstNode>;
function GetExpressions: TList<IAstNode>; function GetExpressions: TArray<IAstNode>;
public public
constructor Create(const AExpressions: array of IAstNode); constructor Create(const AExpressions: array of IAstNode);
destructor Destroy; override;
function Accept(const Visitor: IAstVisitor): TDataValue; override; function Accept(const Visitor: IAstVisitor): TDataValue; override;
property Expressions: TList<IAstNode> read FExpressions; property Expressions: TArray<IAstNode> read FExpressions;
end; end;
TVariableDeclarationNode = class(TAstNode, IVariableDeclarationNode) TVariableDeclarationNode = class(TAstNode, IVariableDeclarationNode)
@@ -605,19 +604,10 @@ end;
{ TBlockExpressionNode } { TBlockExpressionNode }
constructor TBlockExpressionNode.Create(const AExpressions: array of IAstNode); constructor TBlockExpressionNode.Create(const AExpressions: array of IAstNode);
var
expr: IAstNode;
begin begin
inherited Create; inherited Create;
FExpressions := TList<IAstNode>.Create; SetLength(FExpressions, Length(AExpressions));
for expr in AExpressions do TArray.Copy<IAstNode>(AExpressions, FExpressions, 0, 0, Length(AExpressions));
FExpressions.Add(expr);
end;
destructor TBlockExpressionNode.Destroy;
begin
FExpressions.Free;
inherited;
end; end;
function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue; function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue;
@@ -625,7 +615,7 @@ begin
Result := Visitor.VisitBlockExpression(Self); Result := Visitor.VisitBlockExpression(Self);
end; end;
function TBlockExpressionNode.GetExpressions: TList<IAstNode>; function TBlockExpressionNode.GetExpressions: TArray<IAstNode>;
begin begin
Result := FExpressions; Result := FExpressions;
end; end;