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.Text in 'Myc.Fmx.AstEditor.Text.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}
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
<DCC_RemoteDebug>true</DCC_RemoteDebug>
|
||||
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
|
||||
<DCC_RangeChecking>true</DCC_RangeChecking>
|
||||
<DCC_Inlining>off</DCC_Inlining>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
|
||||
<DCC_RemoteDebug>false</DCC_RemoteDebug>
|
||||
@@ -151,6 +152,7 @@
|
||||
<DCCReference Include="Myc.Fmx.AstEditor.Text.pas"/>
|
||||
<DCCReference Include="..\Src\Myc.Utils.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Script.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.MacroExpander.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
|
||||
@@ -33,6 +33,7 @@ uses
|
||||
Myc.Ast.Binding,
|
||||
Myc.Ast.RTL,
|
||||
Myc.Ast.Script,
|
||||
Myc.Ast.MacroExpander,
|
||||
FMX.Layouts,
|
||||
FMX.Objects,
|
||||
Myc.Ast.Debugger,
|
||||
@@ -214,8 +215,24 @@ var
|
||||
scriptScope: IExecutionScope;
|
||||
visitor: IEvaluatorVisitor;
|
||||
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);
|
||||
FCurrAst := binder.Execute(ANode, FCurrDesc);
|
||||
FCurrAst := binder.Execute(macroExpander.Execute(ANode), FCurrDesc);
|
||||
|
||||
scriptScope := FCurrDesc.CreateScope(AParentScope);
|
||||
visitor := CreateEvaluator(scriptScope);
|
||||
|
||||
@@ -27,6 +27,9 @@ type
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||
function VisitIndexer(const Node: IIndexerNode): 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 VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
@@ -200,6 +203,21 @@ begin
|
||||
Result := Format('%s.%s', [baseStr, Node.Member.Name]);
|
||||
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;
|
||||
var
|
||||
seriesStr: string;
|
||||
|
||||
@@ -115,6 +115,9 @@ type
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
function VisitAssignment(const Node: IAssignmentNode): 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 VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
@@ -1245,6 +1248,75 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
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;
|
||||
var
|
||||
details: string;
|
||||
|
||||
@@ -8,21 +8,23 @@ uses
|
||||
System.Generics.Collections,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Ast.Scope;
|
||||
Myc.Ast.Scope,
|
||||
Myc.Data.Value;
|
||||
|
||||
type
|
||||
// This visitor analyzes the AST to find all variables that need to be "lifted" or "boxed"
|
||||
// because they are captured by a nested lambda.
|
||||
TUpvalueAnalyzer = class(TAstTraverser)
|
||||
TUpvalueAnalyzer = class(TAstTransformer)
|
||||
private
|
||||
FBoxedDeclarations: THashSet<IVariableDeclarationNode>;
|
||||
FCurrentScope: IScopeDescriptor;
|
||||
FDeclarationMap: TDictionary<IScopeDescriptor, TDictionary<string, IVariableDeclarationNode>>;
|
||||
procedure MarkDeclarationForBoxing(const AName: string);
|
||||
protected
|
||||
function TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode; override;
|
||||
function TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; override;
|
||||
function TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; override;
|
||||
// Overridden Visit methods to perform analysis during traversal.
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
public
|
||||
constructor Create(const AParent: IScopeDescriptor);
|
||||
destructor Destroy; override;
|
||||
@@ -96,24 +98,26 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode;
|
||||
function TUpvalueAnalyzer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
var
|
||||
address: TResolvedAddress;
|
||||
begin
|
||||
Result := Node;
|
||||
if not Assigned(FCurrentScope) then
|
||||
exit;
|
||||
|
||||
address := FCurrentScope.FindSymbol(Node.Name);
|
||||
|
||||
if (address.Kind = akLocalOrParent) and (address.ScopeDepth > 0) then
|
||||
if Assigned(FCurrentScope) then
|
||||
begin
|
||||
// This is an upvalue. Mark its original declaration for boxing.
|
||||
MarkDeclarationForBoxing(Node.Name);
|
||||
address := FCurrentScope.FindSymbol(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;
|
||||
|
||||
// As a traverser, return the original node wrapped in a TDataValue.
|
||||
Result := TDataValue.FromIntf<IIdentifierNode>(Node);
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode;
|
||||
function TUpvalueAnalyzer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
begin
|
||||
// A lambda creates a new lexical scope, inheriting from the current one.
|
||||
FCurrentScope := TScope.CreateDescriptor(FCurrentScope);
|
||||
@@ -124,19 +128,21 @@ begin
|
||||
|
||||
// Traverse the lambda body within the new scope context.
|
||||
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
|
||||
// Restore the parent scope after leaving the lambda.
|
||||
FCurrentScope := FCurrentScope.Parent;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode;
|
||||
function TUpvalueAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
var
|
||||
scopeDeclarations: TDictionary<string, IVariableDeclarationNode>;
|
||||
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
|
||||
Node.Initializer.Accept(Self);
|
||||
|
||||
@@ -150,6 +156,9 @@ begin
|
||||
FDeclarationMap.Add(FCurrentScope, scopeDeclarations);
|
||||
end;
|
||||
scopeDeclarations.Add(Node.Identifier.Name, Node);
|
||||
|
||||
// As a traverser, return the original node wrapped in a TDataValue.
|
||||
Result := TDataValue.FromIntf<IVariableDeclarationNode>(Node);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
+50
-43
@@ -49,25 +49,24 @@ type
|
||||
// Stack management for tail-call state is centralized here.
|
||||
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
|
||||
constructor Create(const AInitialScope: IExecutionScope);
|
||||
destructor Destroy; override;
|
||||
|
||||
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;
|
||||
|
||||
TBoundIdentifierNode = class(TIdentifierNode)
|
||||
@@ -285,9 +284,10 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode;
|
||||
function TAstBinder.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
var
|
||||
adr: TResolvedAddress;
|
||||
boundNode: IIdentifierNode;
|
||||
begin
|
||||
adr := FCurrentDescriptor.FindSymbol(Node.Name);
|
||||
if adr.Kind = akLocalOrParent then
|
||||
@@ -306,22 +306,24 @@ begin
|
||||
upvalue.Map.Add(adr, upvalueIndex);
|
||||
end;
|
||||
|
||||
Result := TBoundIdentifierNode.Create(Node, TResolvedAddress.Create(akUpvalue, 0, upvalueIndex));
|
||||
boundNode := TBoundIdentifierNode.Create(Node, TResolvedAddress.Create(akUpvalue, 0, upvalueIndex));
|
||||
end
|
||||
else
|
||||
Result := TBoundIdentifierNode.Create(Node, adr);
|
||||
boundNode := TBoundIdentifierNode.Create(Node, adr);
|
||||
Result := TDataValue.FromIntf<IIdentifierNode>(boundNode);
|
||||
end
|
||||
else
|
||||
raise Exception.CreateFmt('Undefined identifier: "%s"', [Node.Name]);
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode;
|
||||
function TAstBinder.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
var
|
||||
initializer: IAstNode;
|
||||
slotIndex: Integer;
|
||||
address: TResolvedAddress;
|
||||
boundIdentifier: IIdentifierNode;
|
||||
isBoxed: Boolean;
|
||||
boundDecl: IVariableDeclarationNode;
|
||||
begin
|
||||
if not IsValidIdentifier(Node.Identifier.Name) then
|
||||
raise Exception.CreateFmt('Invalid identifier name: "%s".', [Node.Identifier.Name]);
|
||||
@@ -340,28 +342,29 @@ begin
|
||||
isBoxed := (FBoxedDeclarations <> nil) and FBoxedDeclarations.Contains(Node);
|
||||
|
||||
// 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;
|
||||
|
||||
function TAstBinder.TransformAssignment(const Node: IAssignmentNode): IAssignmentNode;
|
||||
function TAstBinder.VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
||||
begin
|
||||
FNextIsTail := False;
|
||||
Result := inherited TransformAssignment(Node);
|
||||
Result := inherited VisitAssignment(Node);
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformBinaryExpression(const Node: IBinaryExpressionNode): IBinaryExpressionNode;
|
||||
function TAstBinder.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||
begin
|
||||
FNextIsTail := False;
|
||||
Result := inherited TransformBinaryExpression(Node);
|
||||
Result := inherited VisitBinaryExpression(Node);
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformUnaryExpression(const Node: IUnaryExpressionNode): IUnaryExpressionNode;
|
||||
function TAstBinder.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
||||
begin
|
||||
FNextIsTail := False;
|
||||
Result := inherited TransformUnaryExpression(Node);
|
||||
Result := inherited VisitUnaryExpression(Node);
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode;
|
||||
function TAstBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
var
|
||||
i: integer;
|
||||
boundParams: TArray<IIdentifierNode>;
|
||||
@@ -370,6 +373,7 @@ var
|
||||
upvalues: TArray<TResolvedAddress>;
|
||||
hasNestedLambdas: Boolean;
|
||||
lastNestedLambdaCount: Integer;
|
||||
boundLambda: ILambdaExpressionNode;
|
||||
begin
|
||||
FUpvalueStack.Push(TUpvalueMapping.Create);
|
||||
try
|
||||
@@ -415,14 +419,16 @@ begin
|
||||
end;
|
||||
|
||||
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;
|
||||
|
||||
function TAstBinder.TransformFunctionCall(const Node: IFunctionCallNode): IFunctionCallNode;
|
||||
function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
var
|
||||
isTailCall: Boolean;
|
||||
callee: IAstNode;
|
||||
args: TArray<IAstNode>;
|
||||
boundCall: IFunctionCallNode;
|
||||
begin
|
||||
isTailCall := FIsTailStack.Peek;
|
||||
|
||||
@@ -430,19 +436,20 @@ begin
|
||||
callee := Accept(Node.Callee).AsIntf<IAstNode>;
|
||||
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;
|
||||
|
||||
function TAstBinder.TransformRecur(const Node: IRecurNode): IRecurNode;
|
||||
function TAstBinder.VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
begin
|
||||
if not FIsTailStack.Peek then
|
||||
raise Exception.Create('''recur'' can only be used in a tail position.');
|
||||
|
||||
FNextIsTail := False;
|
||||
Result := inherited TransformRecur(Node);
|
||||
Result := inherited VisitRecurNode(Node);
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformBlockExpression(const Node: IBlockExpressionNode): IBlockExpressionNode;
|
||||
function TAstBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
var
|
||||
exprs: TArray<IAstNode>;
|
||||
i: Integer;
|
||||
@@ -450,16 +457,16 @@ var
|
||||
begin
|
||||
isContextTail := FIsTailStack.Peek;
|
||||
|
||||
SetLength(exprs, Node.Expressions.Count);
|
||||
for i := 0 to Node.Expressions.Count - 1 do
|
||||
SetLength(exprs, Length(Node.Expressions));
|
||||
for i := 0 to High(exprs) do
|
||||
begin
|
||||
FNextIsTail := isContextTail and (i = Node.Expressions.Count - 1);
|
||||
FNextIsTail := isContextTail and (i = High(exprs));
|
||||
exprs[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>;
|
||||
end;
|
||||
Result := TAst.Block(exprs);
|
||||
Result := TDataValue.FromIntf<IBlockExpressionNode>(TAst.Block(exprs));
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformIfExpression(const Node: IIfExpressionNode): IIfExpressionNode;
|
||||
function TAstBinder.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||
var
|
||||
isContextTail: Boolean;
|
||||
condition, thenBranch, elseBranch: IAstNode;
|
||||
@@ -474,18 +481,18 @@ begin
|
||||
elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
|
||||
|
||||
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
|
||||
Result := Node;
|
||||
Result := TDataValue.FromIntf<IIfExpressionNode>(Node);
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode;
|
||||
function TAstBinder.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
begin
|
||||
// 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.');
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformTernaryExpression(const Node: ITernaryExpressionNode): ITernaryExpressionNode;
|
||||
function TAstBinder.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
||||
var
|
||||
isContextTail: Boolean;
|
||||
condition, thenBranch, elseBranch: IAstNode;
|
||||
@@ -500,9 +507,9 @@ begin
|
||||
elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
|
||||
|
||||
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
|
||||
Result := Node;
|
||||
Result := TDataValue.FromIntf<ITernaryExpressionNode>(Node);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -26,7 +26,7 @@ type
|
||||
|
||||
protected
|
||||
// Overridden to provide the debug-specific visitor factory.
|
||||
function CreateVisitorFactory: TVisitorFactory; override;
|
||||
function CreateVisitorFactory: TEvaluatorFactory; override;
|
||||
|
||||
public
|
||||
constructor Create(const AScope: IExecutionScope; ALog: TStrings; AShowScope: Boolean; AInitialIndent: Integer = 0);
|
||||
@@ -66,13 +66,13 @@ begin
|
||||
ShowScope;
|
||||
end;
|
||||
|
||||
function TDebugEvaluatorVisitor.CreateVisitorFactory: TVisitorFactory;
|
||||
function TDebugEvaluatorVisitor.CreateVisitorFactory: TEvaluatorFactory;
|
||||
begin
|
||||
// Return a closure that creates a new Debug visitor, using the current context
|
||||
|
||||
var callingVisitor := Self as IAstVisitor;
|
||||
var callingVisitor := Self as IEvaluatorVisitor;
|
||||
Result :=
|
||||
function(const AScope: IExecutionScope): IAstVisitor
|
||||
function(const AScope: IExecutionScope): IEvaluatorVisitor
|
||||
begin
|
||||
var visitor := callingVisitor as TDebugEvaluatorVisitor;
|
||||
Result := TDebugEvaluatorVisitor.Create(AScope, visitor.FLog, visitor.FShowScope, visitor.FIndentLevel);
|
||||
|
||||
@@ -42,6 +42,9 @@ type
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
function VisitAssignment(const Node: IAssignmentNode): 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 VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
@@ -350,6 +353,33 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
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;
|
||||
begin
|
||||
Log('Indexer');
|
||||
|
||||
@@ -14,13 +14,13 @@ uses
|
||||
Myc.Ast.Scope;
|
||||
|
||||
type
|
||||
// A factory for creating visitors, primarily used by the debugger subsystem.
|
||||
TVisitorFactory = reference to function(const Scope: IExecutionScope): IAstVisitor;
|
||||
|
||||
IEvaluatorVisitor = interface(IAstVisitor)
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
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.
|
||||
TEvaluatorVisitor = class(TAstVisitor, IEvaluatorVisitor)
|
||||
private
|
||||
@@ -36,6 +36,9 @@ type
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): 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 VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
@@ -50,7 +53,7 @@ type
|
||||
function IsTruthy(const AValue: TDataValue): Boolean; inline;
|
||||
|
||||
// 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;
|
||||
public
|
||||
@@ -132,10 +135,10 @@ begin
|
||||
HandleTCO(Result);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.CreateVisitorFactory: TVisitorFactory;
|
||||
function TEvaluatorVisitor.CreateVisitorFactory: TEvaluatorFactory;
|
||||
begin
|
||||
// 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;
|
||||
|
||||
procedure TEvaluatorVisitor.HandleTCO(var ResultValue: TDataValue);
|
||||
@@ -173,7 +176,7 @@ var
|
||||
i: Integer;
|
||||
sourceAddresses: TArray<TResolvedAddress>;
|
||||
closureScope: IExecutionScope;
|
||||
visitorFactory: TVisitorFactory;
|
||||
visitorFactory: TEvaluatorFactory;
|
||||
begin
|
||||
// Cast to the bound node to access binder-specific information.
|
||||
boundNode := Node as TBoundLambdaExpressionNode;
|
||||
@@ -249,6 +252,21 @@ begin
|
||||
raise Exception.Create('Macro definitions cannot be evaluated at runtime.');
|
||||
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;
|
||||
var
|
||||
calleeValue: TDataValue;
|
||||
|
||||
@@ -35,6 +35,9 @@ type
|
||||
function JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode;
|
||||
function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode;
|
||||
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 JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
|
||||
function JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
|
||||
@@ -55,6 +58,9 @@ type
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): 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 VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
@@ -295,6 +301,21 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
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;
|
||||
var
|
||||
obj, calleeObj: TJSONObject;
|
||||
@@ -362,7 +383,7 @@ begin
|
||||
for expr in Node.Expressions do
|
||||
expr.Accept(Self);
|
||||
|
||||
SetLength(tempExprs, Node.Expressions.Count);
|
||||
SetLength(tempExprs, Length(Node.Expressions));
|
||||
for i := High(tempExprs) downto 0 do
|
||||
tempExprs[i] := FJsonObjectStack.Pop;
|
||||
|
||||
@@ -646,6 +667,48 @@ begin
|
||||
Result := TAst.MacroDef(name, params, body);
|
||||
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;
|
||||
var
|
||||
callee: IAstNode;
|
||||
@@ -774,6 +837,12 @@ begin
|
||||
Result := JsonToLambdaExprNode(obj)
|
||||
else if nodeType = 'MacroDef' then
|
||||
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
|
||||
Result := JsonToFunctionCallNode(obj)
|
||||
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)
|
||||
{$region 'private'}
|
||||
function GetExpressions: TList<IAstNode>;
|
||||
function GetExpressions: TArray<IAstNode>;
|
||||
{$endregion}
|
||||
property Expressions: TList<IAstNode> read GetExpressions;
|
||||
property Expressions: TArray<IAstNode> read GetExpressions;
|
||||
end;
|
||||
|
||||
IVariableDeclarationNode = interface(IAstNode)
|
||||
|
||||
@@ -386,11 +386,11 @@ begin
|
||||
// (defmacro name [params] body)
|
||||
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.');
|
||||
if elements[1].Node <> nil then
|
||||
if elements[2].Params = nil then
|
||||
raise Exception.Create('Syntax Error: Expected a parameter list [...] after macro name.');
|
||||
|
||||
var macroName := IIdentifierNode(tailNodes[0]);
|
||||
var macroParams := elements[1].Params;
|
||||
var macroParams := elements[2].Params;
|
||||
var macroBody := tailNodes[2];
|
||||
|
||||
Result := TAst.MacroDef(macroName, macroParams, macroBody);
|
||||
@@ -405,7 +405,7 @@ begin
|
||||
begin
|
||||
if Length(tailNodes) <> 2 then
|
||||
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''.');
|
||||
Result := TAst.LambdaExpr(elements[1].Params, tailNodes[1]);
|
||||
end
|
||||
|
||||
+100
-225
@@ -41,59 +41,34 @@ type
|
||||
end;
|
||||
|
||||
// A base visitor that walks the AST and rebuilds it node by node.
|
||||
// This class uses the Template Method pattern:
|
||||
// - The Visit... methods are the template and should not be overridden.
|
||||
// - The virtual Transform... methods are the hooks for derived classes to customize behavior.
|
||||
// Derived classes can override the virtual Visit... methods to customize behavior.
|
||||
TAstTransformer = class abstract(TAstVisitor, IAstTransformer)
|
||||
private
|
||||
FDone: Boolean;
|
||||
|
||||
protected
|
||||
// Final Visit methods - these should not be overridden. They call the virtual Transform methods.
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override; final;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override; final;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override; final;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override; final;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override; final;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; final;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; final;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; final;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; final;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; final;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; final;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; final;
|
||||
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override; final;
|
||||
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override; final;
|
||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override; final;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; final;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; final;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; final;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; final;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; final;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override; final;
|
||||
|
||||
// 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;
|
||||
// These virtual methods implement the default identity-transformation (cloning) behavior.
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||
function 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 VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||
|
||||
// Helper to transform an array of nodes.
|
||||
function TransformNodes<T: IAstNode>(const Nodes: TArray<T>): TArray<T>;
|
||||
@@ -106,11 +81,8 @@ type
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
end;
|
||||
|
||||
// TAstTraverser simply inherits the identity-transform (cloning) behavior from TAstTransformer.
|
||||
TAstTraverser = class(TAstTransformer);
|
||||
|
||||
// Generic traverser for managing state during AST walks.
|
||||
TAstTraverser<T> = class(TAstTraverser)
|
||||
TAstTraverser<T> = class(TAstTransformer)
|
||||
private
|
||||
FData: TStack<T>;
|
||||
protected
|
||||
@@ -141,202 +113,210 @@ begin
|
||||
Result := Accept(RootNode).AsIntf<IAstNode>;
|
||||
end;
|
||||
|
||||
// --- Default implementations for Transform... methods (Identity Transformation / Cloning) ---
|
||||
|
||||
function TAstTransformer.TransformConstant(const Node: IConstantNode): IConstantNode;
|
||||
function TAstTransformer.VisitConstant(const Node: IConstantNode): TDataValue;
|
||||
begin
|
||||
// The node itself is immutable, return it directly.
|
||||
Result := Node;
|
||||
Result := TDataValue.FromIntf<IConstantNode>(Node);
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode;
|
||||
function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
begin
|
||||
Result := Node;
|
||||
Result := TDataValue.FromIntf<IIdentifierNode>(Node);
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformBinaryExpression(const Node: IBinaryExpressionNode): IBinaryExpressionNode;
|
||||
function TAstTransformer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||
begin
|
||||
var left := Accept(Node.Left).AsIntf<IAstNode>;
|
||||
var right := Accept(Node.Right).AsIntf<IAstNode>;
|
||||
if (left = Node.Left) and (right = Node.Right) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IBinaryExpressionNode>(Node)
|
||||
else
|
||||
Result := TAst.BinaryExpr(left, Node.Operator, right);
|
||||
Result := TDataValue.FromIntf<IBinaryExpressionNode>(TAst.BinaryExpr(left, Node.Operator, right));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformUnaryExpression(const Node: IUnaryExpressionNode): IUnaryExpressionNode;
|
||||
function TAstTransformer.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
||||
begin
|
||||
var right := Accept(Node.Right).AsIntf<IAstNode>;
|
||||
if right = Node.Right then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IUnaryExpressionNode>(Node)
|
||||
else
|
||||
Result := TAst.UnaryExpr(Node.Operator, right);
|
||||
Result := TDataValue.FromIntf<IUnaryExpressionNode>(TAst.UnaryExpr(Node.Operator, right));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformIfExpression(const Node: IIfExpressionNode): IIfExpressionNode;
|
||||
function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||
begin
|
||||
var condition := Accept(Node.Condition).AsIntf<IAstNode>;
|
||||
var thenBranch := Accept(Node.ThenBranch).AsIntf<IAstNode>;
|
||||
var elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
|
||||
if (condition = Node.Condition) and (thenBranch = Node.ThenBranch) and (elseBranch = Node.ElseBranch) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IIfExpressionNode>(Node)
|
||||
else
|
||||
Result := TAst.IfExpr(condition, thenBranch, elseBranch);
|
||||
Result := TDataValue.FromIntf<IIfExpressionNode>(TAst.IfExpr(condition, thenBranch, elseBranch));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformTernaryExpression(const Node: ITernaryExpressionNode): ITernaryExpressionNode;
|
||||
function TAstTransformer.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
||||
begin
|
||||
var condition := Accept(Node.Condition).AsIntf<IAstNode>;
|
||||
var thenBranch := Accept(Node.ThenBranch).AsIntf<IAstNode>;
|
||||
var elseBranch := Accept(Node.ElseBranch).AsIntf<IAstNode>;
|
||||
if (condition = Node.Condition) and (thenBranch = Node.ThenBranch) and (elseBranch = Node.ElseBranch) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<ITernaryExpressionNode>(Node)
|
||||
else
|
||||
Result := TAst.TernaryExpr(condition, thenBranch, elseBranch);
|
||||
Result := TDataValue.FromIntf<ITernaryExpressionNode>(TAst.TernaryExpr(condition, thenBranch, elseBranch));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformLambdaExpression(const Node: ILambdaExpressionNode): ILambdaExpressionNode;
|
||||
function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
begin
|
||||
var parameters := TransformNodes<IIdentifierNode>(Node.Parameters);
|
||||
var body := Accept(Node.Body).AsIntf<IAstNode>;
|
||||
if (parameters = Node.Parameters) and (body = Node.Body) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<ILambdaExpressionNode>(Node)
|
||||
else
|
||||
Result := TAst.LambdaExpr(parameters, body);
|
||||
Result := TDataValue.FromIntf<ILambdaExpressionNode>(TAst.LambdaExpr(parameters, body));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformFunctionCall(const Node: IFunctionCallNode): IFunctionCallNode;
|
||||
function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
begin
|
||||
var callee := Accept(Node.Callee).AsIntf<IAstNode>;
|
||||
var args := TransformNodes<IAstNode>(Node.Arguments);
|
||||
if (callee = Node.Callee) and (args = Node.Arguments) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IFunctionCallNode>(Node)
|
||||
else
|
||||
Result := TAst.FunctionCall(callee, args);
|
||||
Result := TDataValue.FromIntf<IFunctionCallNode>(TAst.FunctionCall(callee, args));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformBlockExpression(const Node: IBlockExpressionNode): IBlockExpressionNode;
|
||||
function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
var
|
||||
expressions: TArray<IAstNode>;
|
||||
i: Integer;
|
||||
hasChanged: Boolean;
|
||||
begin
|
||||
// TList is mutable, so we always transform.
|
||||
var exprs: TArray<IAstNode>;
|
||||
var i: Integer;
|
||||
SetLength(exprs, Node.Expressions.Count);
|
||||
for i := 0 to Node.Expressions.Count - 1 do
|
||||
exprs[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>;
|
||||
Result := TAst.Block(exprs);
|
||||
// Check if any child expression has changed before creating a new node.
|
||||
hasChanged := false;
|
||||
SetLength(expressions, Length(Node.Expressions));
|
||||
for i := 0 to High(Node.Expressions) do
|
||||
begin
|
||||
expressions[i] := Accept(Node.Expressions[i]).AsIntf<IAstNode>;
|
||||
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;
|
||||
|
||||
function TAstTransformer.TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode;
|
||||
function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
begin
|
||||
var identifier := Accept(Node.Identifier).AsIntf<IIdentifierNode>;
|
||||
var initializer := Accept(Node.Initializer).AsIntf<IAstNode>;
|
||||
if (identifier = Node.Identifier) and (initializer = Node.Initializer) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IVariableDeclarationNode>(Node)
|
||||
else
|
||||
Result := TAst.VarDecl(identifier, initializer);
|
||||
Result := TDataValue.FromIntf<IVariableDeclarationNode>(TAst.VarDecl(identifier, initializer));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformAssignment(const Node: IAssignmentNode): IAssignmentNode;
|
||||
function TAstTransformer.VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
||||
begin
|
||||
var identifier := Accept(Node.Identifier).AsIntf<IIdentifierNode>;
|
||||
var value := Accept(Node.Value).AsIntf<IAstNode>;
|
||||
if (identifier = Node.Identifier) and (value = Node.Value) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IAssignmentNode>(Node)
|
||||
else
|
||||
Result := TAst.Assign(identifier, value);
|
||||
Result := TDataValue.FromIntf<IAssignmentNode>(TAst.Assign(identifier, value));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode;
|
||||
function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
begin
|
||||
// Added identity transform for macro definitions.
|
||||
var name := Accept(Node.Name).AsIntf<IIdentifierNode>;
|
||||
var parameters := TransformNodes<IIdentifierNode>(Node.Parameters);
|
||||
var body := Accept(Node.Body).AsIntf<IAstNode>;
|
||||
if (name = Node.Name) and (parameters = Node.Parameters) and (body = Node.Body) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IMacroDefinitionNode>(Node)
|
||||
else
|
||||
Result := TAst.MacroDef(name, parameters, body);
|
||||
Result := TDataValue.FromIntf<IMacroDefinitionNode>(TAst.MacroDef(name, parameters, body));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformQuasiquote(const Node: IQuasiquoteNode): IQuasiquoteNode;
|
||||
function TAstTransformer.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
|
||||
begin
|
||||
var expr := Accept(Node.Expression).AsIntf<IAstNode>;
|
||||
if expr = Node.Expression then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IQuasiquoteNode>(Node)
|
||||
else
|
||||
Result := TAst.Quasiquote(expr);
|
||||
Result := TDataValue.FromIntf<IQuasiquoteNode>(TAst.Quasiquote(expr));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformUnquote(const Node: IUnquoteNode): IUnquoteNode;
|
||||
function TAstTransformer.VisitUnquote(const Node: IUnquoteNode): TDataValue;
|
||||
begin
|
||||
var expr := Accept(Node.Expression).AsIntf<IAstNode>;
|
||||
if expr = Node.Expression then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IUnquoteNode>(Node)
|
||||
else
|
||||
Result := TAst.Unquote(expr);
|
||||
Result := TDataValue.FromIntf<IUnquoteNode>(TAst.Unquote(expr));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformUnquoteSplicing(const Node: IUnquoteSplicingNode): IUnquoteSplicingNode;
|
||||
function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
|
||||
begin
|
||||
var expr := Accept(Node.Expression).AsIntf<IAstNode>;
|
||||
if expr = Node.Expression then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IUnquoteSplicingNode>(Node)
|
||||
else
|
||||
Result := TAst.UnquoteSplicing(expr);
|
||||
Result := TDataValue.FromIntf<IUnquoteSplicingNode>(TAst.UnquoteSplicing(expr));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformIndexer(const Node: IIndexerNode): IIndexerNode;
|
||||
function TAstTransformer.VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||
begin
|
||||
var base := Accept(Node.Base).AsIntf<IAstNode>;
|
||||
var index := Accept(Node.Index).AsIntf<IAstNode>;
|
||||
if (base = Node.Base) and (index = Node.Index) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IIndexerNode>(Node)
|
||||
else
|
||||
Result := TAst.Indexer(base, index);
|
||||
Result := TDataValue.FromIntf<IIndexerNode>(TAst.Indexer(base, index));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformMemberAccess(const Node: IMemberAccessNode): IMemberAccessNode;
|
||||
function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||
begin
|
||||
var base := Accept(Node.Base).AsIntf<IAstNode>;
|
||||
var member := Node.Member;
|
||||
if (base = Node.Base) and (member = Node.Member) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IMemberAccessNode>(Node)
|
||||
else
|
||||
Result := TAst.MemberAccess(base, member);
|
||||
Result := TDataValue.FromIntf<IMemberAccessNode>(TAst.MemberAccess(base, member));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformCreateSeries(const Node: ICreateSeriesNode): ICreateSeriesNode;
|
||||
function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
begin
|
||||
Result := Node;
|
||||
Result := TDataValue.FromIntf<ICreateSeriesNode>(Node);
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformAddSeriesItem(const Node: IAddSeriesItemNode): IAddSeriesItemNode;
|
||||
function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
||||
begin
|
||||
var series := Accept(Node.Series).AsIntf<IIdentifierNode>;
|
||||
var value := Accept(Node.Value).AsIntf<IAstNode>;
|
||||
var lookback := Accept(Node.Lookback).AsIntf<IAstNode>;
|
||||
if (series = Node.Series) and (value = Node.Value) and (lookback = Node.Lookback) then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IAddSeriesItemNode>(Node)
|
||||
else
|
||||
Result := TAst.AddSeriesItem(series, value, lookback);
|
||||
Result := TDataValue.FromIntf<IAddSeriesItemNode>(TAst.AddSeriesItem(series, value, lookback));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformSeriesLength(const Node: ISeriesLengthNode): ISeriesLengthNode;
|
||||
function TAstTransformer.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
||||
begin
|
||||
var series := Accept(Node.Series).AsIntf<IIdentifierNode>;
|
||||
if series = Node.Series then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<ISeriesLengthNode>(Node)
|
||||
else
|
||||
Result := TAst.SeriesLength(series);
|
||||
Result := TDataValue.FromIntf<ISeriesLengthNode>(TAst.SeriesLength(series));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformRecur(const Node: IRecurNode): IRecurNode;
|
||||
function TAstTransformer.VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
begin
|
||||
var args := TransformNodes<IAstNode>(Node.Arguments);
|
||||
if args = Node.Arguments then
|
||||
Result := Node
|
||||
Result := TDataValue.FromIntf<IRecurNode>(Node)
|
||||
else
|
||||
Result := TAst.Recur(args);
|
||||
Result := TDataValue.FromIntf<IRecurNode>(TAst.Recur(args));
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformNodes<T>(const Nodes: TArray<T>): TArray<T>;
|
||||
@@ -356,111 +336,6 @@ begin
|
||||
Result := Nodes;
|
||||
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> }
|
||||
|
||||
constructor TAstTraverser<T>.Create;
|
||||
|
||||
+6
-16
@@ -211,13 +211,12 @@ type
|
||||
|
||||
TBlockExpressionNode = class(TAstNode, IBlockExpressionNode)
|
||||
private
|
||||
FExpressions: TList<IAstNode>;
|
||||
function GetExpressions: TList<IAstNode>;
|
||||
FExpressions: TArray<IAstNode>;
|
||||
function GetExpressions: TArray<IAstNode>;
|
||||
public
|
||||
constructor Create(const AExpressions: array of IAstNode);
|
||||
destructor Destroy; override;
|
||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||
property Expressions: TList<IAstNode> read FExpressions;
|
||||
property Expressions: TArray<IAstNode> read FExpressions;
|
||||
end;
|
||||
|
||||
TVariableDeclarationNode = class(TAstNode, IVariableDeclarationNode)
|
||||
@@ -605,19 +604,10 @@ end;
|
||||
{ TBlockExpressionNode }
|
||||
|
||||
constructor TBlockExpressionNode.Create(const AExpressions: array of IAstNode);
|
||||
var
|
||||
expr: IAstNode;
|
||||
begin
|
||||
inherited Create;
|
||||
FExpressions := TList<IAstNode>.Create;
|
||||
for expr in AExpressions do
|
||||
FExpressions.Add(expr);
|
||||
end;
|
||||
|
||||
destructor TBlockExpressionNode.Destroy;
|
||||
begin
|
||||
FExpressions.Free;
|
||||
inherited;
|
||||
SetLength(FExpressions, Length(AExpressions));
|
||||
TArray.Copy<IAstNode>(AExpressions, FExpressions, 0, 0, Length(AExpressions));
|
||||
end;
|
||||
|
||||
function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
||||
@@ -625,7 +615,7 @@ begin
|
||||
Result := Visitor.VisitBlockExpression(Self);
|
||||
end;
|
||||
|
||||
function TBlockExpressionNode.GetExpressions: TList<IAstNode>;
|
||||
function TBlockExpressionNode.GetExpressions: TArray<IAstNode>;
|
||||
begin
|
||||
Result := FExpressions;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user