added macrodef
This commit is contained in:
@@ -20,6 +20,7 @@ type
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
@@ -164,6 +165,33 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstToTextVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
var
|
||||
i: Integer;
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
// Added text representation for macro definitions.
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('defmacro ');
|
||||
sb.Append(Node.Name.Name);
|
||||
sb.Append('(');
|
||||
if Length(Node.Parameters) > 0 then
|
||||
begin
|
||||
for i := 0 to High(Node.Parameters) do
|
||||
begin
|
||||
sb.Append(Node.Parameters[i].Name);
|
||||
if i < High(Node.Parameters) then
|
||||
sb.Append(', ');
|
||||
end;
|
||||
end;
|
||||
sb.Append(') => {...}');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstToTextVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||
var
|
||||
baseStr: string;
|
||||
|
||||
@@ -114,6 +114,7 @@ type
|
||||
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 VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
@@ -1147,6 +1148,103 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TAstToAuraNodeVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
var
|
||||
paramStr: String;
|
||||
macroNode: TAuraNode;
|
||||
i: Integer;
|
||||
childVisitor: TAstToAuraNodeVisitor;
|
||||
childStartPos: TPointF;
|
||||
maxRight, maxBottom: Single;
|
||||
control: TControl;
|
||||
childLastResult: TAuraNodeResult;
|
||||
entryNode, exitNode: TAuraNode;
|
||||
paramDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
// Create a string representation of the parameters for the node title.
|
||||
paramStr := '(';
|
||||
if Length(Node.Parameters) > 0 then
|
||||
begin
|
||||
paramStr := paramStr + Node.Parameters[0].Name;
|
||||
for i := 1 to High(Node.Parameters) do
|
||||
paramStr := paramStr + ', ' + Node.Parameters[i].Name;
|
||||
end;
|
||||
paramStr := paramStr + ')';
|
||||
|
||||
// 1. Create the main container node for the macro definition.
|
||||
macroNode := BuildNodeControl('defmacro: ' + Node.Name.Name, paramStr);
|
||||
macroNode.Position.Point := FCurrentPos;
|
||||
|
||||
// A macro definition is a statement, so it has execution pins.
|
||||
CreateEntry(macroNode);
|
||||
|
||||
// 2. Create a temporary scope descriptor for the macro's parameters.
|
||||
// This allows the child visitor to correctly visualize parameter nodes.
|
||||
paramDescriptor := TScope.CreateDescriptor(nil);
|
||||
for i := 0 to High(Node.Parameters) do
|
||||
paramDescriptor.Define(Node.Parameters[i].Name);
|
||||
|
||||
// 3. Create a child visitor for the new scope within the macro's body.
|
||||
const pinNodeHeight = cPinSize + cVerticalPadding;
|
||||
childStartPos := TPointF.Create(FSpacing.X, FSpacing.Y + pinNodeHeight);
|
||||
childVisitor := TAstToAuraNodeVisitor.Create(FWorkspace, macroNode, childStartPos, FConnections, [], FMode, Self, nil, paramDescriptor);
|
||||
|
||||
// 4. Create the visual nodes for the parameters inside the macro's scope.
|
||||
for i := 0 to High(Node.Parameters) do
|
||||
begin
|
||||
var param := Node.Parameters[i];
|
||||
var paramNode := childVisitor.CreateNodeControl('Parameter', param.Name);
|
||||
var paramResult: TAuraNodeResult;
|
||||
paramResult.LayoutNode := paramNode;
|
||||
paramResult.OutputPin := childVisitor.CreateOutput(paramNode);
|
||||
childVisitor.FinalizeNodeLayout(paramNode);
|
||||
// Cache the parameter node by its slot index for lookups within the body.
|
||||
if i < Length(childVisitor.FSlotCache) then
|
||||
childVisitor.FSlotCache[i] := paramResult;
|
||||
end;
|
||||
|
||||
// 5. Let the child visitor render the macro's body.
|
||||
Node.Body.Accept(childVisitor);
|
||||
childLastResult := childVisitor.FLastResult;
|
||||
|
||||
// 6. Resize the container to fit all internally generated nodes.
|
||||
maxRight := 0;
|
||||
maxBottom := 0;
|
||||
for control in macroNode.Controls do
|
||||
begin
|
||||
if control is TAuraNode then
|
||||
begin
|
||||
maxRight := Max(maxRight, control.Position.X + control.Width);
|
||||
maxBottom := Max(maxBottom, control.Position.Y + control.Height);
|
||||
end;
|
||||
end;
|
||||
macroNode.Width := Max(macroNode.Width, maxRight + FSpacing.X);
|
||||
macroNode.Height := Max(macroNode.Height, maxBottom + FSpacing.Y);
|
||||
|
||||
// 7. Create an internal 'expansion' exit point, showing what the macro produces.
|
||||
exitNode := BuildNodeControl('Expansion', '');
|
||||
exitNode.Parent := macroNode;
|
||||
exitNode.Height := pinNodeHeight;
|
||||
// Connect the data flow (the result of the last expression in the body) to the expansion node.
|
||||
if Assigned(childLastResult.OutputPin) then
|
||||
begin
|
||||
var dataResultPin := childVisitor.CreateInput(exitNode, 'AST');
|
||||
FConnections.Add(TPinConnection.Create(childLastResult.OutputPin, dataResultPin));
|
||||
end;
|
||||
childVisitor.FinalizeNodeLayout(exitNode);
|
||||
macroNode.Height := Max(macroNode.Height, maxBottom + FSpacing.Y + exitNode.Height);
|
||||
exitNode.Position.Point := TPointF.Create(FSpacing.X, macroNode.Height - exitNode.Height - FSpacing.Y);
|
||||
|
||||
// 8. Finalize the main visitor state.
|
||||
FCurrentPos.Y := macroNode.Position.Y + macroNode.Height + FSpacing.Y;
|
||||
FLastResult.LayoutNode := macroNode;
|
||||
FLastResult.OutputPin := nil; // A macro definition itself does not return a value.
|
||||
CreateExit(macroNode, ''); // Execution flow continues after the definition.
|
||||
FinalizeNodeLayout(macroNode);
|
||||
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TAstToAuraNodeVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
var
|
||||
details: string;
|
||||
|
||||
@@ -60,6 +60,7 @@ type
|
||||
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;
|
||||
@@ -478,6 +479,12 @@ begin
|
||||
Result := Node;
|
||||
end;
|
||||
|
||||
function TAstBinder.TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode;
|
||||
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;
|
||||
var
|
||||
isContextTail: Boolean;
|
||||
|
||||
@@ -41,6 +41,7 @@ type
|
||||
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 VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
@@ -322,6 +323,33 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TAstDumper.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
var
|
||||
param: IIdentifierNode;
|
||||
begin
|
||||
Log('MacroDefinition');
|
||||
Indent;
|
||||
|
||||
Log('Name:');
|
||||
Indent;
|
||||
Node.Name.Accept(Self);
|
||||
Unindent;
|
||||
|
||||
Log('Parameters:');
|
||||
Indent;
|
||||
for param in Node.Parameters do
|
||||
param.Accept(Self);
|
||||
Unindent;
|
||||
|
||||
Log('Body:');
|
||||
Indent;
|
||||
Node.Body.Accept(Self);
|
||||
Unindent;
|
||||
|
||||
Unindent;
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TAstDumper.VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||
begin
|
||||
Log('Indexer');
|
||||
|
||||
@@ -35,6 +35,7 @@ type
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
@@ -240,6 +241,14 @@ begin
|
||||
Result := closure;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
begin
|
||||
// Macro definitions are compile-time constructs and should have been
|
||||
// processed and removed from the AST by the TMacroExpander.
|
||||
// If we encounter one here, it's a compiler pipeline error.
|
||||
raise Exception.Create('Macro definitions cannot be evaluated at runtime.');
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
var
|
||||
calleeValue: TDataValue;
|
||||
|
||||
@@ -34,6 +34,7 @@ type
|
||||
function JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode;
|
||||
function JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode;
|
||||
function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode;
|
||||
function JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode;
|
||||
function JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
|
||||
function JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
|
||||
function JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
|
||||
@@ -53,6 +54,7 @@ type
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
@@ -258,6 +260,41 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
var
|
||||
obj, nameObj, bodyObj: TJSONObject;
|
||||
paramsArray: TJSONArray;
|
||||
tempParams: TArray<TJSONObject>;
|
||||
param: IIdentifierNode;
|
||||
i: Integer;
|
||||
begin
|
||||
// Added serialization for macro definitions.
|
||||
Node.Name.Accept(Self);
|
||||
for param in Node.Parameters do
|
||||
param.Accept(Self);
|
||||
Node.Body.Accept(Self);
|
||||
|
||||
bodyObj := FJsonObjectStack.Pop;
|
||||
|
||||
SetLength(tempParams, Length(Node.Parameters));
|
||||
for i := High(tempParams) downto 0 do
|
||||
tempParams[i] := FJsonObjectStack.Pop;
|
||||
|
||||
nameObj := FJsonObjectStack.Pop;
|
||||
|
||||
paramsArray := TJSONArray.Create;
|
||||
for i := 0 to High(tempParams) do
|
||||
paramsArray.Add(tempParams[i]);
|
||||
|
||||
obj := TJSONObject.Create;
|
||||
obj.AddPair('NodeType', TJSONString.Create('MacroDef'));
|
||||
obj.AddPair('Name', nameObj);
|
||||
obj.AddPair('Parameters', paramsArray);
|
||||
obj.AddPair('Body', bodyObj);
|
||||
FJsonObjectStack.Push(obj);
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
var
|
||||
obj, calleeObj: TJSONObject;
|
||||
@@ -589,6 +626,26 @@ begin
|
||||
Result := TAst.LambdaExpr(params, body);
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode;
|
||||
var
|
||||
name: IIdentifierNode;
|
||||
params: TArray<IIdentifierNode>;
|
||||
body: IAstNode;
|
||||
paramArray: TJSONArray;
|
||||
i: Integer;
|
||||
begin
|
||||
// Added deserialization for macro definitions.
|
||||
name := JsonToIdentifierNode(AObj.GetValue('Name') as TJSONObject);
|
||||
|
||||
paramArray := AObj.GetValue<TJSONArray>('Parameters');
|
||||
SetLength(params, paramArray.Count);
|
||||
for i := 0 to paramArray.Count - 1 do
|
||||
params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject);
|
||||
|
||||
body := JsonToNode(AObj.GetValue('Body'));
|
||||
Result := TAst.MacroDef(name, params, body);
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
|
||||
var
|
||||
callee: IAstNode;
|
||||
@@ -715,6 +772,8 @@ begin
|
||||
Result := JsonToTernaryExprNode(obj)
|
||||
else if nodeType = 'LambdaExpr' then
|
||||
Result := JsonToLambdaExprNode(obj)
|
||||
else if nodeType = 'MacroDef' then
|
||||
Result := JsonToMacroDefNode(obj)
|
||||
else if nodeType = 'FunctionCall' then
|
||||
Result := JsonToFunctionCallNode(obj)
|
||||
else if nodeType = 'Recur' then
|
||||
|
||||
@@ -23,6 +23,7 @@ type
|
||||
IBlockExpressionNode = interface;
|
||||
IVariableDeclarationNode = interface;
|
||||
IAssignmentNode = interface;
|
||||
IMacroDefinitionNode = interface;
|
||||
IIndexerNode = interface;
|
||||
IMemberAccessNode = interface;
|
||||
ICreateSeriesNode = interface;
|
||||
@@ -57,6 +58,7 @@ type
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
@@ -177,6 +179,17 @@ type
|
||||
property Value: IAstNode read GetValue;
|
||||
end;
|
||||
|
||||
IMacroDefinitionNode = interface(IAstNode)
|
||||
{$region 'private'}
|
||||
function GetName: IIdentifierNode;
|
||||
function GetParameters: TArray<IIdentifierNode>;
|
||||
function GetBody: IAstNode;
|
||||
{$endregion}
|
||||
property Name: IIdentifierNode read GetName;
|
||||
property Parameters: TArray<IIdentifierNode> read GetParameters;
|
||||
property Body: IAstNode read GetBody;
|
||||
end;
|
||||
|
||||
IIndexerNode = interface(IAstNode)
|
||||
{$region 'private'}
|
||||
function GetBase: IAstNode;
|
||||
|
||||
@@ -108,6 +108,7 @@ type
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
@@ -359,6 +360,20 @@ begin
|
||||
raise Exception.Create('Syntax Error: Expected an identifier for def statement.');
|
||||
Result := TAst.VarDecl(IIdentifierNode(tailNodes[0]), IfThen(Length(tailNodes) > 1, tailNodes[1], nil));
|
||||
end
|
||||
else if SameText(head.Token.Text, 'defmacro') then
|
||||
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
|
||||
raise Exception.Create('Syntax Error: Expected a parameter list [...] after macro name.');
|
||||
|
||||
var macroName := IIdentifierNode(tailNodes[0]);
|
||||
var macroParams := elements[1].Params;
|
||||
var macroBody := tailNodes[2];
|
||||
|
||||
Result := TAst.MacroDef(macroName, macroParams, macroBody);
|
||||
end
|
||||
else if SameText(head.Token.Text, 'assign') then
|
||||
begin
|
||||
if tailTokens[0].Kind <> tkIdentifier then
|
||||
@@ -424,6 +439,19 @@ var
|
||||
i64: Int64;
|
||||
dbl: Double;
|
||||
begin
|
||||
// TODO: Implement reader macros for quasiquoting here.
|
||||
// The current lexer will tokenize `, ~, and ~@ as identifiers.
|
||||
// Check for them here and wrap the subsequent expression accordingly.
|
||||
// Example:
|
||||
// if FCurrentToken.Text = '`' then
|
||||
// begin
|
||||
// NextToken;
|
||||
// var exprToQuote := ParseExpression;
|
||||
// Result.Node := TAst.Quasiquote(exprToQuote.Node);
|
||||
// exit;
|
||||
// end;
|
||||
// (This requires IQuasiquoteNode and TAst.Quasiquote to be defined first).
|
||||
|
||||
Result.Token := FCurrentToken;
|
||||
case FCurrentToken.Kind of
|
||||
tkNumber:
|
||||
@@ -606,6 +634,33 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
var
|
||||
param: IIdentifierNode;
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
// Added visitor for pretty printing macro definitions.
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
for param in Node.Parameters do
|
||||
sb.Append(param.Name + ' ');
|
||||
if sb.Length > 0 then
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
|
||||
Append('(defmacro ' + Node.Name.Name + ' [' + sb.ToString + ']');
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
|
||||
Indent;
|
||||
NewLine;
|
||||
Node.Body.Accept(Self);
|
||||
Unindent;
|
||||
NewLine;
|
||||
Append(')');
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
var
|
||||
arg: IAstNode;
|
||||
|
||||
@@ -24,6 +24,7 @@ type
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; virtual; abstract;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; virtual; abstract;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; virtual; abstract;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; virtual; abstract;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; virtual; abstract;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; virtual; abstract;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; virtual; abstract;
|
||||
@@ -57,6 +58,7 @@ type
|
||||
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 VisitIndexer(const Node: IIndexerNode): TDataValue; override; final;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; final;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; final;
|
||||
@@ -76,6 +78,7 @@ type
|
||||
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 TransformIndexer(const Node: IIndexerNode): IIndexerNode; virtual;
|
||||
function TransformMemberAccess(const Node: IMemberAccessNode): IMemberAccessNode; virtual;
|
||||
function TransformCreateSeries(const Node: ICreateSeriesNode): ICreateSeriesNode; virtual;
|
||||
@@ -234,6 +237,18 @@ begin
|
||||
Result := TAst.Assign(identifier, value);
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformMacroDefinition(const Node: IMacroDefinitionNode): IMacroDefinitionNode;
|
||||
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
|
||||
else
|
||||
Result := TAst.MacroDef(name, parameters, body);
|
||||
end;
|
||||
|
||||
function TAstTransformer.TransformIndexer(const Node: IIndexerNode): IIndexerNode;
|
||||
begin
|
||||
var base := Accept(Node.Base).AsIntf<IAstNode>;
|
||||
@@ -360,6 +375,12 @@ begin
|
||||
Result := TDataValue.FromIntf<IAssignmentNode>(TransformAssignment(Node));
|
||||
end;
|
||||
|
||||
function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
begin
|
||||
// Added visit method for macro definitions.
|
||||
Result := TDataValue.FromIntf<IMacroDefinitionNode>(TransformMacroDefinition(Node));
|
||||
end;
|
||||
|
||||
function TAstTransformer.VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromIntf<IIndexerNode>(TransformIndexer(Node));
|
||||
|
||||
+64
-5
@@ -36,6 +36,11 @@ type
|
||||
class function IfExpr(const ACondition: IAstNode; const AThenBranch, AElseBranch: IAstNode): IIfExpressionNode; static;
|
||||
class function TernaryExpr(const ACondition: IAstNode; const AThenBranch, AElseBranch: IAstNode): ITernaryExpressionNode; static;
|
||||
class function LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode; static;
|
||||
class function MacroDef(
|
||||
const AName: IIdentifierNode;
|
||||
const AParameters: TArray<IIdentifierNode>;
|
||||
const ABody: IAstNode
|
||||
): IMacroDefinitionNode; static;
|
||||
class function FunctionCall(const ACallee: IAstNode; const AArguments: TArray<IAstNode>): IFunctionCallNode; static;
|
||||
class function Recur(const AArguments: array of IAstNode): IRecurNode; static;
|
||||
class function Block(const AExpressions: array of IAstNode): IBlockExpressionNode; static;
|
||||
@@ -141,6 +146,19 @@ type
|
||||
property Parameters: TArray<IIdentifierNode> read FParameters;
|
||||
end;
|
||||
|
||||
TMacroDefinitionNode = class(TAstNode, IMacroDefinitionNode)
|
||||
private
|
||||
FName: IIdentifierNode;
|
||||
FParameters: TArray<IIdentifierNode>;
|
||||
FBody: IAstNode;
|
||||
function GetName: IIdentifierNode;
|
||||
function GetParameters: TArray<IIdentifierNode>;
|
||||
function GetBody: IAstNode;
|
||||
public
|
||||
constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode);
|
||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||
end;
|
||||
|
||||
TFunctionCallNode = class(TAstNode, IFunctionCallNode)
|
||||
private
|
||||
FCallee: IAstNode;
|
||||
@@ -428,6 +446,37 @@ begin
|
||||
Result := FParameters;
|
||||
end;
|
||||
|
||||
{ TMacroDefinitionNode }
|
||||
|
||||
constructor TMacroDefinitionNode.Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode);
|
||||
begin
|
||||
// Added concrete class for macro definitions.
|
||||
inherited Create;
|
||||
FName := AName;
|
||||
FParameters := AParameters;
|
||||
FBody := ABody;
|
||||
end;
|
||||
|
||||
function TMacroDefinitionNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
||||
begin
|
||||
Result := Visitor.VisitMacroDefinition(Self);
|
||||
end;
|
||||
|
||||
function TMacroDefinitionNode.GetBody: IAstNode;
|
||||
begin
|
||||
Result := FBody;
|
||||
end;
|
||||
|
||||
function TMacroDefinitionNode.GetName: IIdentifierNode;
|
||||
begin
|
||||
Result := FName;
|
||||
end;
|
||||
|
||||
function TMacroDefinitionNode.GetParameters: TArray<IIdentifierNode>;
|
||||
begin
|
||||
Result := FParameters;
|
||||
end;
|
||||
|
||||
{ TFunctionCallNode }
|
||||
|
||||
constructor TFunctionCallNode.Create(const ACallee: IAstNode; const AArguments: TArray<IAstNode>);
|
||||
@@ -751,6 +800,21 @@ begin
|
||||
Result := TIndexerNode.Create(ABase, AIndex);
|
||||
end;
|
||||
|
||||
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode;
|
||||
begin
|
||||
Result := TLambdaExpressionNode.Create(AParameters, ABody);
|
||||
end;
|
||||
|
||||
class function TAst.MacroDef(
|
||||
const AName: IIdentifierNode;
|
||||
const AParameters: TArray<IIdentifierNode>;
|
||||
const ABody: IAstNode
|
||||
): IMacroDefinitionNode;
|
||||
begin
|
||||
// Added factory for macro definitions.
|
||||
Result := TMacroDefinitionNode.Create(AName, AParameters, ABody);
|
||||
end;
|
||||
|
||||
class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IIdentifierNode): IMemberAccessNode;
|
||||
begin
|
||||
Result := TMemberAccessNode.Create(ABase, AMember);
|
||||
@@ -777,11 +841,6 @@ begin
|
||||
Result := TTernaryExpressionNode.Create(ACondition, AThenBranch, AElseBranch);
|
||||
end;
|
||||
|
||||
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode;
|
||||
begin
|
||||
Result := TLambdaExpressionNode.Create(AParameters, ABody);
|
||||
end;
|
||||
|
||||
class function TAst.UnaryExpr(const AOperator: TScalar.TUnaryOp; const ARight: IAstNode): IUnaryExpressionNode;
|
||||
begin
|
||||
Result := TUnaryExpressionNode.Create(AOperator, ARight);
|
||||
|
||||
Reference in New Issue
Block a user