1st full macro expander
This commit is contained in:
@@ -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}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user