Ast list nodes

This commit is contained in:
Michael Schimmel
2025-11-29 18:59:16 +01:00
parent 250f950a68
commit 851f56c63f
24 changed files with 1819 additions and 863 deletions
File diff suppressed because one or more lines are too long
+62 -1
View File
@@ -148,7 +148,8 @@
}, },
"ElseBranch": { "ElseBranch": {
"NodeType": "Block", "NodeType": "Block",
"Expressions": [] "Expressions": [
]
} }
} }
} }
@@ -1095,5 +1096,65 @@
} }
] ]
} }
},
"test2": {
"NodeType": "MacroDef",
"Name": {
"NodeType": "Identifier",
"Name": "test2"
},
"Parameters": [
{
"NodeType": "Identifier",
"Name": "body"
}
],
"Body": {
"NodeType": "Quasiquote",
"Expression": {
"NodeType": "LambdaExpr",
"Parameters": [
],
"Body": {
"NodeType": "Unquote",
"Expression": {
"NodeType": "Identifier",
"Name": "body"
}
}
}
}
},
"debug-mode": {
"NodeType": "Keyword",
"Name": "true"
},
"test": {
"NodeType": "MacroDef",
"Name": {
"NodeType": "Identifier",
"Name": "test"
},
"Parameters": [
{
"NodeType": "Identifier",
"Name": "body"
}
],
"Body": {
"NodeType": "Quasiquote",
"Expression": {
"NodeType": "LambdaExpr",
"Parameters": [
],
"Body": {
"NodeType": "Unquote",
"Expression": {
"NodeType": "Identifier",
"Name": "body"
}
}
}
}
} }
} }
+52 -17
View File
@@ -29,6 +29,13 @@ type
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean; override;
function VisitSeriesLength(const Node: ISeriesLengthNode): Boolean; override; function VisitSeriesLength(const Node: ISeriesLengthNode): Boolean; override;
// --- List Visitors (New) ---
function VisitParameterList(const Node: IParameterList): Boolean; override;
function VisitArgumentList(const Node: IArgumentList): Boolean; override;
function VisitExpressionList(const Node: IExpressionList): Boolean; override;
function VisitRecordFieldList(const Node: IRecordFieldList): Boolean; override;
function VisitRecordField(const Node: IRecordFieldNode): Boolean; override;
// --- Critical Checks --- // --- Critical Checks ---
function VisitIdentifier(const Node: IIdentifierNode): Boolean; override; function VisitIdentifier(const Node: IIdentifierNode): Boolean; override;
function VisitFunctionCall(const Node: IFunctionCallNode): Boolean; override; function VisitFunctionCall(const Node: IFunctionCallNode): Boolean; override;
@@ -81,6 +88,44 @@ begin
Result := Node.Accept(Self).AsGeneric<Boolean>; Result := Node.Accept(Self).AsGeneric<Boolean>;
end; end;
// --- List Visitors ---
function TPurityAnalyzer.VisitParameterList(const Node: IParameterList): Boolean;
begin
// Declarations are pure
Result := True;
end;
function TPurityAnalyzer.VisitArgumentList(const Node: IArgumentList): Boolean;
begin
for var item in Node do
if not Accept(item) then
exit(False);
Result := True;
end;
function TPurityAnalyzer.VisitExpressionList(const Node: IExpressionList): Boolean;
begin
for var item in Node do
if not Accept(item) then
exit(False);
Result := True;
end;
function TPurityAnalyzer.VisitRecordFieldList(const Node: IRecordFieldList): Boolean;
begin
for var item in Node do
if not Accept(item) then
exit(False);
Result := True;
end;
function TPurityAnalyzer.VisitRecordField(const Node: IRecordFieldNode): Boolean;
begin
// Key is usually pure (Keyword), check Value
Result := Accept(Node.Key) and Accept(Node.Value);
end;
// --- Safe Leaves --- // --- Safe Leaves ---
function TPurityAnalyzer.VisitConstant(const Node: IConstantNode): Boolean; function TPurityAnalyzer.VisitConstant(const Node: IConstantNode): Boolean;
@@ -120,11 +165,8 @@ begin
exit(False); exit(False);
// 2. All arguments must be pure expressions. // 2. All arguments must be pure expressions.
for var arg in Node.Arguments do // Delegate to ArgumentList visitor
if not Accept(arg) then Result := Accept(Node.Arguments);
exit(False);
Result := True;
end; end;
// --- Recursion --- // --- Recursion ---
@@ -132,10 +174,7 @@ end;
function TPurityAnalyzer.VisitRecurNode(const Node: IRecurNode): Boolean; function TPurityAnalyzer.VisitRecurNode(const Node: IRecurNode): Boolean;
begin begin
// 'recur' is just control flow. It is pure if its arguments are pure. // 'recur' is just control flow. It is pure if its arguments are pure.
for var arg in Node.Arguments do Result := Accept(Node.Arguments);
if not Accept(arg) then
exit(False);
Result := True;
end; end;
// --- Structures: Recursive Checks --- // --- Structures: Recursive Checks ---
@@ -152,10 +191,8 @@ end;
function TPurityAnalyzer.VisitBlockExpression(const Node: IBlockExpressionNode): Boolean; function TPurityAnalyzer.VisitBlockExpression(const Node: IBlockExpressionNode): Boolean;
begin begin
for var expr in Node.Expressions do // Delegate to ExpressionList
if not Accept(expr) then Result := Accept(Node.Expressions);
exit(False);
Result := True;
end; end;
function TPurityAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean; function TPurityAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean;
@@ -167,10 +204,8 @@ end;
function TPurityAnalyzer.VisitRecordLiteral(const Node: IRecordLiteralNode): Boolean; function TPurityAnalyzer.VisitRecordLiteral(const Node: IRecordLiteralNode): Boolean;
begin begin
for var field in Node.Fields do // Delegate to RecordFieldList
if not Accept(field.Value) then Result := Accept(Node.Fields);
exit(False);
Result := True;
end; end;
function TPurityAnalyzer.VisitIndexer(const Node: IIndexerNode): Boolean; function TPurityAnalyzer.VisitIndexer(const Node: IIndexerNode): Boolean;
+1 -1
View File
@@ -186,7 +186,7 @@ begin
// 2. Register parameters (they mask outer variables) // 2. Register parameters (they mask outer variables)
// We pass 'nil' as the node because we currently don't box parameters, // We pass 'nil' as the node because we currently don't box parameters,
// but we must ensure Resolve() finds them so we don't accidentally box a shadowed variable. // but we must ensure Resolve() finds them so we don't accidentally box a shadowed variable.
for i := 0 to High(Node.Parameters) do for i := 0 to Node.Parameters.Count - 1 do
begin begin
FCurrentScope.Define(Node.Parameters[i].Name, nil); FCurrentScope.Define(Node.Parameters[i].Name, nil);
end; end;
+25 -8
View File
@@ -342,6 +342,7 @@ var
startCount: Integer; startCount: Integer;
hasNested: Boolean; hasNested: Boolean;
paramIdentity: INamedIdentity; paramIdentity: INamedIdentity;
paramList: IParameterList;
begin begin
startCount := FLambdaCounter; startCount := FLambdaCounter;
Inc(FLambdaCounter); Inc(FLambdaCounter);
@@ -355,8 +356,10 @@ begin
try try
FCurrentBuilder.Define('<self>'); FCurrentBuilder.Define('<self>');
SetLength(newParams, Length(Node.Parameters)); // Create Array to hold transformed parameters
for i := 0 to High(Node.Parameters) do SetLength(newParams, Node.Parameters.Count);
for i := 0 to Node.Parameters.Count - 1 do
begin begin
var paramNode := Node.Parameters[i]; var paramNode := Node.Parameters[i];
var paramName := paramNode.Name; var paramName := paramNode.Name;
@@ -414,11 +417,15 @@ begin
hasNested := FLambdaCounter > (startCount + 1); hasNested := FLambdaCounter > (startCount + 1);
// Wrap the array in a List wrapper to satisfy the factory interface
// We reuse the identity of the old parameter list
paramList := TParameterList.Create(newParams, Node.Parameters.Identity);
// Rebuild Lambda using original identity // Rebuild Lambda using original identity
Result := Result :=
TAst.LambdaExpr( TAst.LambdaExpr(
Node.Identity, Node.Identity,
newParams, paramList,
newBody, newBody,
finalLayout, finalLayout,
nil, // Descriptor is created in TypeChecker nil, // Descriptor is created in TypeChecker
@@ -433,11 +440,21 @@ begin
if Node.Callee.Kind = akKeyword then if Node.Callee.Kind = akKeyword then
begin begin
// Transform keyword call (:key obj) into member access (.key obj) // Transform keyword call (:key obj) into member access (.key obj)
// Note: The new MemberAccess node gets the identity of the original FunctionCall // Check argument count
// The member keyword retains its own identity. if Node.Arguments.Count <> 1 then
var memberAccess := TAst.MemberAccess(Node.Identity, Accept(Node.Arguments[0]), Node.Callee.AsKeyword); begin
Result := memberAccess; if Assigned(FLog) then
exit; FLog.AddError(Format('Keyword access :%s requires exactly one argument.', [Node.Callee.AsKeyword.Value.Name]), Node);
// Fallthrough to standard visit/recreation to avoid crash
end
else
begin
// Note: The new MemberAccess node gets the identity of the original FunctionCall
// The member keyword retains its own identity.
var memberAccess := TAst.MemberAccess(Node.Identity, Accept(Node.Arguments[0]), Node.Callee.AsKeyword);
Result := memberAccess;
exit;
end;
end; end;
Result := inherited VisitFunctionCall(Node); Result := inherited VisitFunctionCall(Node);
end; end;
+63 -17
View File
@@ -34,15 +34,20 @@ type
class var class var
FGensymCounter: Int64; FGensymCounter: Int64;
function TransformAndSpliceNodes(const ANodes: TArray<IAstNode>): TArray<IAstNode>; // Helper to handle unquote-splicing (~@) within lists.
// Takes a source list (e.g., Arguments) and returns a flattened array for the new node.
function TransformAndSpliceNodes(const ANodes: INodeList<IAstNode>): TArray<IAstNode>;
function Gensym(const ABaseName: string): string; function Gensym(const ABaseName: string): string;
protected protected
function VisitUnquote(const Node: IUnquoteNode): IAstNode; override; function VisitUnquote(const Node: IUnquoteNode): IAstNode; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; override; function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; override;
// We override these container visits to handle Splicing manually,
// bypassing the standard 1:1 list visitor.
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override; function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override; function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override; function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override;
@@ -169,15 +174,16 @@ begin
end; end;
end; end;
function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: TArray<IAstNode>): TArray<IAstNode>; function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: INodeList<IAstNode>): TArray<IAstNode>;
var var
newList: TList<IAstNode>; newList: TList<IAstNode>;
nodeToSplice: IAstNode; nodeToSplice: IAstNode;
transformedNode: IAstNode; transformedNode: IAstNode;
node: IAstNode;
begin begin
newList := TList<IAstNode>.Create; newList := TList<IAstNode>.Create;
try try
for var node in ANodes do for node in ANodes do
begin begin
if node.Kind = akUnquoteSplicing then if node.Kind = akUnquoteSplicing then
begin begin
@@ -196,10 +202,30 @@ begin
if (not evaluatedSpliceValue.IsVoid) and (evaluatedSpliceValue.Kind = vkInterface) then if (not evaluatedSpliceValue.IsVoid) and (evaluatedSpliceValue.Kind = vkInterface) then
begin begin
nodeToSplice := evaluatedSpliceValue.AsIntf<IAstNode>; nodeToSplice := evaluatedSpliceValue.AsIntf<IAstNode>;
if nodeToSplice.Kind = akBlockExpression then
newList.AddRange(nodeToSplice.AsBlockExpression.Expressions) // Splicing implies the value must be a list-like AST structure (Block or just a List Node)
// If the evaluated value is an IArgumentList, IExpressionList etc., we flatten it.
if nodeToSplice.Kind = akExpressionList then
begin
for var subItem in nodeToSplice.AsExpressionList do
newList.Add(subItem);
end
else if nodeToSplice.Kind = akArgumentList then
begin
for var subItem in nodeToSplice.AsArgumentList do
newList.Add(subItem);
end
else if nodeToSplice.Kind = akBlockExpression then
begin
// Splice content of block
for var subItem in nodeToSplice.AsBlockExpression.Expressions do
newList.Add(subItem);
end
else else
begin
// Treat as single item
newList.Add(nodeToSplice); newList.Add(nodeToSplice);
end;
end end
else if (not evaluatedSpliceValue.IsVoid) then else if (not evaluatedSpliceValue.IsVoid) then
begin begin
@@ -261,19 +287,24 @@ var
newBody: IAstNode; newBody: IAstNode;
newName: string; newName: string;
i: Integer; i: Integer;
paramList: IParameterList;
begin begin
SetLength(newParams, Length(Node.Parameters)); SetLength(newParams, Node.Parameters.Count);
for i := 0 to High(Node.Parameters) do for i := 0 to Node.Parameters.Count - 1 do
begin begin
newName := Gensym(Node.Parameters[i].Name); var param := Node.Parameters[i];
newName := Gensym(param.Name);
// Use location from original param // Use location from original param
newParams[i] := TAst.Identifier(newName, Node.Parameters[i].Identity.Location); newParams[i] := TAst.Identifier(newName, param.Identity.Location);
end; end;
newBody := Accept(Node.Body); newBody := Accept(Node.Body);
// Rebuild structural lambda // Rebuild: Wrap array in TParameterList with original Identity
Result := TAst.LambdaExpr(Node.Identity, newParams, newBody); paramList := TParameterList.Create(newParams, Node.Parameters.Identity);
// Use transformation overload
Result := TAst.LambdaExpr(Node.Identity, paramList, newBody);
end; end;
function TExpansionVisitor.VisitUnquote(const Node: IUnquoteNode): IAstNode; function TExpansionVisitor.VisitUnquote(const Node: IUnquoteNode): IAstNode;
@@ -284,6 +315,7 @@ var
begin begin
expr := Node.Expression; expr := Node.Expression;
// Optimization: If unquote refers to a local macro variable directly, try to get it.
if expr.Kind = akIdentifier then if expr.Kind = akIdentifier then
begin begin
addr := FMacroScope.Resolve(expr.AsIdentifier.Name); addr := FMacroScope.Resolve(expr.AsIdentifier.Name);
@@ -329,22 +361,36 @@ function TExpansionVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IAs
var var
newArgs: TArray<IAstNode>; newArgs: TArray<IAstNode>;
transformedCallee: IAstNode; transformedCallee: IAstNode;
argList: IArgumentList;
begin begin
transformedCallee := Self.Accept(Node.Callee); transformedCallee := Self.Accept(Node.Callee);
// Use splicing aware transformation for arguments (returns TArray)
newArgs := TransformAndSpliceNodes(Node.Arguments); newArgs := TransformAndSpliceNodes(Node.Arguments);
Result := TAst.FunctionCall(Node.Identity, transformedCallee, newArgs);
// Wrap in List container to use Transformation overload
argList := TArgumentList.Create(newArgs, Node.Arguments.Identity);
Result := TAst.FunctionCall(Node.Identity, transformedCallee, argList);
end; end;
function TExpansionVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; function TExpansionVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
var var
newExprs: TArray<IAstNode>; newExprs: TArray<IAstNode>;
exprList: IExpressionList;
begin begin
// Use splicing aware transformation for block expressions
newExprs := TransformAndSpliceNodes(Node.Expressions); newExprs := TransformAndSpliceNodes(Node.Expressions);
Result := TAst.Block(Node.Identity, newExprs);
// Wrap in List
exprList := TExpressionList.Create(newExprs, Node.Expressions.Identity);
Result := TAst.Block(Node.Identity, exprList);
end; end;
function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
begin begin
// For now, standard transformation for records (no splicing key-values yet)
Result := inherited VisitRecordLiteral(Node); Result := inherited VisitRecordLiteral(Node);
end; end;
@@ -438,10 +484,10 @@ begin
var expansionScope := TScope.CreateScope(FInitialScope, nil, nil); var expansionScope := TScope.CreateScope(FInitialScope, nil, nil);
var params := macroDef.Parameters; var params := macroDef.Parameters;
if Length(Node.Arguments) <> Length(params) then if Node.Arguments.Count <> params.Count then
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, Length(params)]); raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, params.Count]);
for i := 0 to High(params) do for i := 0 to params.Count - 1 do
expansionScope.Define(params[i].Name, TDataValue.FromIntf<IAstNode>(Node.Arguments[i])); expansionScope.Define(params[i].Name, TDataValue.FromIntf<IAstNode>(Node.Arguments[i]));
var expandedBody := TExpansionVisitor.Expand(expansionScope, macroDef.Body.AsQuasiquote.Expression, FMacroEvaluator); var expandedBody := TExpansionVisitor.Expand(expansionScope, macroDef.Body.AsQuasiquote.Expression, FMacroEvaluator);
+16 -15
View File
@@ -122,7 +122,7 @@ end;
function TStaticSpecializer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; function TStaticSpecializer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var var
newCallee: IAstNode; newCallee: IAstNode;
newArgs: TArray<IAstNode>; newArgsList: IArgumentList;
i: Integer; i: Integer;
calleeIdent: IIdentifierNode; calleeIdent: IIdentifierNode;
argTypes: TArray<IStaticType>; argTypes: TArray<IStaticType>;
@@ -134,15 +134,16 @@ var
begin begin
// 1. Specialize children first (bottom-up) // 1. Specialize children first (bottom-up)
newCallee := Accept(Node.Callee); newCallee := Accept(Node.Callee);
newArgs := AcceptNodes(Node.Arguments); // Arguments are now visited as a List, returning an IArgumentList
newArgsList := Accept(Node.Arguments).AsArgumentList;
// 2. Check if this call is a candidate for specialization // 2. Check if this call is a candidate for specialization
if newCallee.Kind <> akIdentifier then if newCallee.Kind <> akIdentifier then
begin begin
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) then
Result := Node Result := Node
else else
Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil);
exit; exit;
end; end;
@@ -151,10 +152,10 @@ begin
// 3. Check if all argument types are statically known // 3. Check if all argument types are statically known
allTypesKnown := True; allTypesKnown := True;
SetLength(argTypes, Length(newArgs)); SetLength(argTypes, newArgsList.Count);
for i := 0 to High(newArgs) do for i := 0 to newArgsList.Count - 1 do
begin begin
argTypes[i] := newArgs[i].AsTypedNode.StaticType; argTypes[i] := newArgsList[i].AsTypedNode.StaticType;
if argTypes[i].Kind = stUnknown then if argTypes[i].Kind = stUnknown then
begin begin
allTypesKnown := False; allTypesKnown := False;
@@ -164,10 +165,10 @@ begin
if not allTypesKnown then if not allTypesKnown then
begin begin
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) then
Result := Node Result := Node
else else
Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil);
exit; exit;
end; end;
@@ -183,7 +184,7 @@ begin
TAst.FunctionCall( TAst.FunctionCall(
Node.Identity, Node.Identity,
newCallee, newCallee,
newArgs, newArgsList,
specializedMethod.ReturnType, specializedMethod.ReturnType,
Node.IsTailCall, Node.IsTailCall,
specializedMethod.Target, specializedMethod.Target,
@@ -203,7 +204,7 @@ begin
TAst.FunctionCall( TAst.FunctionCall(
Node.Identity, Node.Identity,
newCallee, newCallee,
newArgs, newArgsList,
specializedMethod.ReturnType, specializedMethod.ReturnType,
Node.IsTailCall, Node.IsTailCall,
specializedMethod.Target, specializedMethod.Target,
@@ -223,7 +224,7 @@ begin
var lambdaDef := funcDef.AsLambdaExpression; var lambdaDef := funcDef.AsLambdaExpression;
if (Length(lambdaDef.Upvalues) > 0) or (lambdaDef.HasNestedLambdas) then if (Length(lambdaDef.Upvalues) > 0) or (lambdaDef.HasNestedLambdas) then
begin begin
Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil);
exit; exit;
end; end;
end; end;
@@ -244,15 +245,15 @@ begin
FMonomorphCache.Add(key, specializedMethod); FMonomorphCache.Add(key, specializedMethod);
// 6c. Return the new node // 6c. Return the new node
Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, returnType, Node.IsTailCall, compiled.Func, compiled.IsPure); Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, returnType, Node.IsTailCall, compiled.Func, compiled.IsPure);
exit; exit;
end; end;
// 7. Fallback: Not RTL, Not User-Code -> Dynamic // 7. Fallback: Not RTL, Not User-Code -> Dynamic
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) then
Result := Node Result := Node
else else
Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil);
end; end;
{ TMonoCacheKey } { TMonoCacheKey }
+47 -27
View File
@@ -99,26 +99,42 @@ function TAstTCO.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNod
var var
isContextTail: Boolean; isContextTail: Boolean;
newExprs: TArray<IAstNode>; newExprs: TArray<IAstNode>;
exprsList: IExpressionList;
i: Integer;
item, newItem: IAstNode;
hasChanged: Boolean;
begin begin
isContextTail := FIsTailStack.Peek; isContextTail := FIsTailStack.Peek;
exprsList := Node.Expressions;
var nTail := High(Node.Expressions); SetLength(newExprs, exprsList.Count);
newExprs := hasChanged := False;
AcceptNodes(
Node.Expressions,
function(idx: Integer; Node: IAstNode): IAstNode
begin
// Only the last expression in the block inherits the tail position status
FNextIsTail := isContextTail and (idx = nTail);
Result := Accept(Node);
end
);
if newExprs = Node.Expressions then var nTail := exprsList.Count - 1;
for i := 0 to nTail do
begin
item := exprsList[i];
// Only the last expression in the block inherits the tail position status
FNextIsTail := isContextTail and (i = nTail);
newItem := Accept(item);
newExprs[i] := newItem;
if item <> newItem then
hasChanged := True;
end;
if not hasChanged then
Result := Node Result := Node
else else
begin
// Wrap array in List container
var newList := TExpressionList.Create(newExprs, Node.Expressions.Identity);
// CoW: Reuse Identity // CoW: Reuse Identity
Result := TAst.Block(Node.Identity, newExprs, Node.StaticType); Result := TAst.Block(Node.Identity, newList, Node.StaticType);
end;
end; end;
function TAstTCO.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; function TAstTCO.VisitIfExpression(const Node: IIfExpressionNode): IAstNode;
@@ -169,12 +185,13 @@ end;
function TAstTCO.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; function TAstTCO.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
var var
newParams: TArray<IIdentifierNode>; newParams: IParameterList;
newBody: IAstNode; newBody: IAstNode;
begin begin
// Parameters are not in tail position // Parameters are not in tail position
FNextIsTail := False; FNextIsTail := False;
newParams := AcceptParameters(Node.Parameters); // Visit list node to handle potential transformations in children
newParams := Accept(Node.Parameters).AsParameterList;
// The body of a lambda is *always* a tail position (relative to the lambda execution) // The body of a lambda is *always* a tail position (relative to the lambda execution)
FNextIsTail := True; FNextIsTail := True;
@@ -185,8 +202,7 @@ begin
else else
begin begin
// Rebuild using factory. // Rebuild using factory.
// IMPORTANT: Pass Layout AND Descriptor (TCO runs after TypeChecker). // CoW: Reuse Identity. Factory expects IParameterList now.
// CoW: Reuse Identity
Result := Result :=
TAst.LambdaExpr( TAst.LambdaExpr(
Node.Identity, Node.Identity,
@@ -204,20 +220,21 @@ end;
function TAstTCO.VisitRecurNode(const Node: IRecurNode): IAstNode; function TAstTCO.VisitRecurNode(const Node: IRecurNode): IAstNode;
var var
newArgs: TArray<IAstNode>; newArgsList: IArgumentList;
begin begin
if not FIsTailStack.Peek then if not FIsTailStack.Peek then
raise EOptimizerException.Create('''recur'' can only be used in a tail position.'); raise EOptimizerException.Create('''recur'' can only be used in a tail position.');
// Arguments are not in tail position // Arguments are not in tail position
FNextIsTail := False; FNextIsTail := False;
newArgs := AcceptNodes(Node.Arguments); // Visit the list node. Accept() ensures children are visited via TAstTransformer.VisitArgumentList
newArgsList := Accept(Node.Arguments).AsArgumentList;
if newArgs = Node.Arguments then if newArgsList = Node.Arguments then
Result := Node Result := Node
else else
// CoW: Reuse Identity // CoW: Reuse Identity. Factory expects IArgumentList.
Result := TAst.Recur(Node.Identity, newArgs, Node.StaticType); Result := TAst.Recur(Node.Identity, newArgsList, Node.StaticType);
end; end;
function TAstTCO.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; function TAstTCO.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode;
@@ -239,29 +256,32 @@ function TAstTCO.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var var
isTailCall: Boolean; isTailCall: Boolean;
newCallee: IAstNode; newCallee: IAstNode;
newArgs: TArray<IAstNode>; newArgsList: IArgumentList;
begin begin
isTailCall := FIsTailStack.Peek; isTailCall := FIsTailStack.Peek;
// Callee/Arguments are not in tail position // Callee/Arguments are not in tail position
FNextIsTail := False; FNextIsTail := False;
newCallee := Accept(Node.Callee); newCallee := Accept(Node.Callee);
newArgs := AcceptNodes(Node.Arguments);
// Visit the arguments list
newArgsList := Accept(Node.Arguments).AsArgumentList;
// CoW check: Create a new node only if children changed OR IsTailCall needs update // CoW check: Create a new node only if children changed OR IsTailCall needs update
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) and (isTailCall = Node.IsTailCall) then if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) and (isTailCall = Node.IsTailCall) then
begin begin
Result := Node; Result := Node;
exit; exit;
end; end;
// Use factory to create new node, passing the *new* TCO status // Use factory to create new node, passing the *new* TCO status
// CoW: Reuse Identity // CoW: Reuse Identity. Factory expects IArgumentList.
Result := Result :=
TAst.FunctionCall( TAst.FunctionCall(
Node.Identity, Node.Identity,
newCallee, newCallee,
newArgs, newArgsList,
Node.StaticType, Node.StaticType,
isTailCall, isTailCall,
Node.StaticTarget, // Preserve the static target from Specializer Node.StaticTarget, // Preserve the static target from Specializer
+45 -55
View File
@@ -12,7 +12,7 @@ uses
Myc.Ast.Visitor, Myc.Ast.Visitor,
Myc.Ast.Scope, Myc.Ast.Scope,
Myc.Ast.Types, Myc.Ast.Types,
Myc.Ast.Identities, // Wichtig für Casts (AsNamed etc.) Myc.Ast.Identities,
Myc.Ast; Myc.Ast;
type type
@@ -200,17 +200,15 @@ var
identity: INamedIdentity; identity: INamedIdentity;
begin begin
adr := Node.Address; adr := Node.Address;
identity := Node.Identity.AsNamed; // Extract specific identity identity := Node.Identity.AsNamed;
if adr.Kind = akUnresolved then if adr.Kind = akUnresolved then
begin begin
// Propagate identity, set type to Unknown
Result := TAst.Identifier(identity, adr, TTypes.Unknown); Result := TAst.Identifier(identity, adr, TTypes.Unknown);
Exit; Exit;
end; end;
typ := FCurrentContext.LookupType(adr); typ := FCurrentContext.LookupType(adr);
// CoW: Reuse Identity
Result := TAst.Identifier(identity, adr, typ); Result := TAst.Identifier(identity, adr, typ);
end; end;
@@ -219,12 +217,13 @@ var
newArgs: TArray<IAstNode>; newArgs: TArray<IAstNode>;
i: Integer; i: Integer;
begin begin
SetLength(newArgs, Length(Node.Arguments)); SetLength(newArgs, Node.Arguments.Count);
for i := 0 to High(Node.Arguments) do for i := 0 to Node.Arguments.Count - 1 do
newArgs[i] := Accept(Node.Arguments[i]); newArgs[i] := Accept(Node.Arguments[i]);
// CoW: Reuse Identity // FIX: Wrap in List
Result := TAst.Recur(Node.Identity, newArgs, TTypes.Void); var argList := TArgumentList.Create(newArgs, Node.Arguments.Identity);
Result := TAst.Recur(Node.Identity, argList, TTypes.Void);
end; end;
function TTypeChecker.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; function TTypeChecker.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode;
@@ -256,7 +255,7 @@ begin
begin begin
lambdaNode := Node.Initializer.AsLambdaExpression; lambdaNode := Node.Initializer.AsLambdaExpression;
var paramTypes: TArray<IStaticType>; var paramTypes: TArray<IStaticType>;
SetLength(paramTypes, Length(lambdaNode.Parameters)); SetLength(paramTypes, lambdaNode.Parameters.Count);
for i := 0 to High(paramTypes) do for i := 0 to High(paramTypes) do
paramTypes[i] := TTypes.Unknown; paramTypes[i] := TTypes.Unknown;
@@ -278,10 +277,8 @@ begin
if initType.Kind <> stUnknown then if initType.Kind <> stUnknown then
FCurrentContext.SetType(adr.SlotIndex, initType); FCurrentContext.SetType(adr.SlotIndex, initType);
// Reuse Identity for Identifier
newIdent := TAst.Identifier(identIdentity, adr, initType); newIdent := TAst.Identifier(identIdentity, adr, initType);
// Reuse Identity for VarDecl
Result := TAst.VarDecl(Node.Identity, newIdent, newInitializer, initType, Node.IsBoxed); Result := TAst.VarDecl(Node.Identity, newIdent, newInitializer, initType, Node.IsBoxed);
end; end;
@@ -296,11 +293,10 @@ var
identNode: IIdentifierNode; identNode: IIdentifierNode;
identIdentity: INamedIdentity; identIdentity: INamedIdentity;
begin begin
// Rebuild Identifier with potential type info updates
identNode := Node.Target.AsIdentifier; identNode := Node.Target.AsIdentifier;
identIdentity := identNode.Identity.AsNamed; identIdentity := identNode.Identity.AsNamed;
newIdent := Accept(Node.Target); // This visits identifier and might update type from context newIdent := Accept(Node.Target);
targetType := newIdent.AsTypedNode.StaticType; targetType := newIdent.AsTypedNode.StaticType;
adr := identNode.Address; adr := identNode.Address;
@@ -318,7 +314,7 @@ begin
if (targetType.Kind <> stMethod) then if (targetType.Kind <> stMethod) then
begin begin
var paramTypes: TArray<IStaticType>; var paramTypes: TArray<IStaticType>;
SetLength(paramTypes, Length(lambdaNode.Parameters)); SetLength(paramTypes, lambdaNode.Parameters.Count);
for i := 0 to High(paramTypes) do for i := 0 to High(paramTypes) do
paramTypes[i] := TTypes.Unknown; paramTypes[i] := TTypes.Unknown;
@@ -343,12 +339,10 @@ begin
if ((targetType.Kind = stUnknown) or Assigned(placeholderType)) and (sourceType.Kind <> stUnknown) then if ((targetType.Kind = stUnknown) or Assigned(placeholderType)) and (sourceType.Kind <> stUnknown) then
begin begin
FCurrentContext.SetType(adr.SlotIndex, sourceType); FCurrentContext.SetType(adr.SlotIndex, sourceType);
// Recreate Identifier with new type and original identity
newIdent := TAst.Identifier(identIdentity, adr, sourceType); newIdent := TAst.Identifier(identIdentity, adr, sourceType);
targetType := sourceType; targetType := sourceType;
end; end;
// CoW: Reuse Assignment Identity
Result := TAst.Assign(Node.Identity, newIdent, newValue, targetType); Result := TAst.Assign(Node.Identity, newIdent, newValue, targetType);
end; end;
@@ -372,10 +366,10 @@ begin
FCurrentContext := TTypeContext.Create(FCurrentContext, Node.Layout, upvalueTypes); FCurrentContext := TTypeContext.Create(FCurrentContext, Node.Layout, upvalueTypes);
try try
SetLength(newParams, Length(Node.Parameters)); SetLength(newParams, Node.Parameters.Count);
SetLength(paramTypes, Length(Node.Parameters)); SetLength(paramTypes, Node.Parameters.Count);
for i := 0 to High(Node.Parameters) do for i := 0 to Node.Parameters.Count - 1 do
begin begin
paramIdent := Node.Parameters[i]; paramIdent := Node.Parameters[i];
paramIdentity := paramIdent.Identity.AsNamed; paramIdentity := paramIdent.Identity.AsNamed;
@@ -386,7 +380,6 @@ begin
if paramAdr.Kind <> akUnresolved then if paramAdr.Kind <> akUnresolved then
FCurrentContext.SetType(paramAdr.SlotIndex, paramTypes[i]); FCurrentContext.SetType(paramAdr.SlotIndex, paramTypes[i]);
// CoW: Reuse Parameter Identity
newParams[i] := TAst.Identifier(paramIdentity, paramAdr, paramTypes[i]); newParams[i] := TAst.Identifier(paramIdentity, paramAdr, paramTypes[i]);
end; end;
@@ -402,11 +395,13 @@ begin
temp.Free; temp.Free;
end; end;
// CoW: Reuse Lambda Identity // FIX: Wrap in List
var paramList := TParameterList.Create(newParams, Node.Parameters.Identity);
Result := Result :=
TAst.LambdaExpr( TAst.LambdaExpr(
Node.Identity, Node.Identity,
newParams, paramList,
newBody, newBody,
Node.Layout, Node.Layout,
finalDescriptor, finalDescriptor,
@@ -431,11 +426,11 @@ var
argsStr: string; argsStr: string;
begin begin
newCallee := Accept(Node.Callee); newCallee := Accept(Node.Callee);
SetLength(newArgs, Length(Node.Arguments)); SetLength(newArgs, Node.Arguments.Count);
SetLength(argTypes, Length(Node.Arguments)); SetLength(argTypes, Node.Arguments.Count);
hasUnknownArgs := False; hasUnknownArgs := False;
for i := 0 to High(Node.Arguments) do for i := 0 to Node.Arguments.Count - 1 do
begin begin
newArgs[i] := Accept(Node.Arguments[i]); newArgs[i] := Accept(Node.Arguments[i]);
argTypes[i] := newArgs[i].AsTypedNode.StaticType; argTypes[i] := newArgs[i].AsTypedNode.StaticType;
@@ -498,17 +493,10 @@ begin
retType := TTypes.Unknown; retType := TTypes.Unknown;
end; end;
// CoW: Reuse Call Identity // FIX: Wrap in List
Result := var argList := TArgumentList.Create(newArgs, Node.Arguments.Identity);
TAst.FunctionCall(
Node.Identity, Result := TAst.FunctionCall(Node.Identity, newCallee, argList, retType, Node.IsTailCall, nil, False);
newCallee,
newArgs,
retType,
Node.IsTailCall,
nil, // StaticTarget set by Specializer
False // IsTargetPure set by Specializer
);
end; end;
function TTypeChecker.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; function TTypeChecker.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
@@ -517,8 +505,8 @@ var
newExprs: TArray<IAstNode>; newExprs: TArray<IAstNode>;
i: Integer; i: Integer;
begin begin
SetLength(newExprs, Length(Node.Expressions)); SetLength(newExprs, Node.Expressions.Count);
for i := 0 to High(Node.Expressions) do for i := 0 to Node.Expressions.Count - 1 do
newExprs[i] := Accept(Node.Expressions[i]); newExprs[i] := Accept(Node.Expressions[i]);
if Length(newExprs) > 0 then if Length(newExprs) > 0 then
@@ -526,8 +514,9 @@ begin
else else
blockType := TTypes.Void; blockType := TTypes.Void;
// CoW: Reuse Block Identity // FIX: Wrap in List
Result := TAst.Block(Node.Identity, newExprs, blockType); var exprList := TExpressionList.Create(newExprs, Node.Expressions.Identity);
Result := TAst.Block(Node.Identity, exprList, blockType);
end; end;
function TTypeChecker.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; function TTypeChecker.VisitIfExpression(const Node: IIfExpressionNode): IAstNode;
@@ -561,7 +550,6 @@ begin
resultType := TTypes.Unknown; resultType := TTypes.Unknown;
end; end;
// CoW: Reuse If Identity
Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, resultType); Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, resultType);
end; end;
@@ -594,7 +582,6 @@ begin
resultType := TTypes.Unknown; resultType := TTypes.Unknown;
end; end;
// CoW: Reuse Ternary Identity
Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, resultType); Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, resultType);
end; end;
@@ -648,7 +635,6 @@ begin
end; end;
end; end;
// CoW: Reuse MemberAccess Identity
Result := TAst.MemberAccess(Node.Identity, newBase, newMember.AsKeyword, elemType); Result := TAst.MemberAccess(Node.Identity, newBase, newMember.AsKeyword, elemType);
end; end;
@@ -686,7 +672,6 @@ begin
FLog.AddError(Format('Indexer `[]` requires an Ordinal index, but got %s', [indexType.ToString]), Node); FLog.AddError(Format('Indexer `[]` requires an Ordinal index, but got %s', [indexType.ToString]), Node);
end; end;
// CoW: Reuse Indexer Identity
Result := TAst.Indexer(Node.Identity, newBase, newIndex, elemType); Result := TAst.Indexer(Node.Identity, newBase, newIndex, elemType);
end; end;
@@ -699,13 +684,19 @@ var
valType: IStaticType; valType: IStaticType;
scalarKind: TScalar.TKind; scalarKind: TScalar.TKind;
allScalar: Boolean; allScalar: Boolean;
newFields: TArray<TRecordFieldLiteral>; newFields: TArray<IRecordFieldNode>;
begin begin
SetLength(newFields, Length(Node.Fields)); SetLength(newFields, Node.Fields.Count);
for i := 0 to High(Node.Fields) do for i := 0 to Node.Fields.Count - 1 do
begin begin
newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword; var field := Node.Fields[i];
newFields[i].Value := Accept(Node.Fields[i].Value); var newKey := Accept(field.Key).AsKeyword;
var newValue := Accept(field.Value);
if (newKey = field.Key) and (newValue = field.Value) then
newFields[i] := field
else
newFields[i] := TAst.RecordField(field.Identity, newKey, newValue);
end; end;
SetLength(scalarDefFields, Length(newFields)); SetLength(scalarDefFields, Length(newFields));
@@ -735,11 +726,14 @@ begin
scalarDefFields[i] := TScalarRecordField.Create(newFields[i].Key.Value, scalarKind); scalarDefFields[i] := TScalarRecordField.Create(newFields[i].Key.Value, scalarKind);
end; end;
// FIX: Wrap in List
var fieldList := TRecordFieldList.Create(newFields, Node.Fields.Identity);
if allScalar then if allScalar then
begin begin
def := TScalarRecordRegistry.Intern(scalarDefFields); def := TScalarRecordRegistry.Intern(scalarDefFields);
staticType := TTypes.CreateRecord(def); staticType := TTypes.CreateRecord(def);
Result := TAst.RecordLiteral(Node.Identity, newFields, def, nil, staticType); Result := TAst.RecordLiteral(Node.Identity, fieldList, def, nil, staticType);
end end
else else
begin begin
@@ -750,7 +744,7 @@ begin
var genDef := TGenericRecordRegistry.Intern(genDefFields); var genDef := TGenericRecordRegistry.Intern(genDefFields);
staticType := TTypes.CreateGenericRecord(genDef); staticType := TTypes.CreateGenericRecord(genDef);
Result := TAst.RecordLiteral(Node.Identity, newFields, nil, genDef, staticType); Result := TAst.RecordLiteral(Node.Identity, fieldList, nil, genDef, staticType);
end; end;
end; end;
@@ -760,7 +754,6 @@ var
defIdentity: IDefinitionIdentity; defIdentity: IDefinitionIdentity;
begin begin
try try
// Use definition from Identity to ensure SSOT
defIdentity := Node.Identity.AsDefinition; defIdentity := Node.Identity.AsDefinition;
elemType := TTypes.FromScalarKind(TScalar.StringToKind(defIdentity.Definition)); elemType := TTypes.FromScalarKind(TScalar.StringToKind(defIdentity.Definition));
except except
@@ -772,7 +765,6 @@ begin
end; end;
end; end;
// CoW: Reuse Definition Identity
Result := TAst.CreateSeries(defIdentity, TTypes.CreateSeries(elemType)); Result := TAst.CreateSeries(defIdentity, TTypes.CreateSeries(elemType));
end; end;
@@ -818,7 +810,6 @@ begin
end; end;
end; end;
// CoW: Reuse Add Identity
Result := TAst.AddSeriesItem(Node.Identity, newSeries.AsIdentifier, newValue, newLookback, TTypes.Void); Result := TAst.AddSeriesItem(Node.Identity, newSeries.AsIdentifier, newValue, newLookback, TTypes.Void);
end; end;
@@ -843,7 +834,6 @@ begin
FLog.AddError(Format('"length" requires a series, but got %s', [seriesType.ToString]), Node); FLog.AddError(Format('"length" requires a series, but got %s', [seriesType.ToString]), Node);
end; end;
// CoW: Reuse SeriesLength Identity
Result := TAst.SeriesLength(Node.Identity, newSeries.AsIdentifier, TTypes.Ordinal); Result := TAst.SeriesLength(Node.Identity, newSeries.AsIdentifier, TTypes.Ordinal);
end; end;
+1
View File
@@ -267,6 +267,7 @@ begin
AppendLine('Block {'); AppendLine('Block {');
Indent; Indent;
try try
// Delegates to VisitExpressionList via inherited
Result := inherited VisitBlockExpression(Node); Result := inherited VisitBlockExpression(Node);
// Scope might have changed after block execution if vars were defined // Scope might have changed after block execution if vars were defined
ShowScope; ShowScope;
+57 -10
View File
@@ -30,7 +30,7 @@ type
function FormatAddress(const Addr: TResolvedAddress): string; function FormatAddress(const Addr: TResolvedAddress): string;
protected protected
// Override abstract PROCEDURES from TAstVisitor (not functions!) // Override abstract PROCEDURES from TAstVisitor
procedure VisitConstant(const Node: IConstantNode); override; procedure VisitConstant(const Node: IConstantNode); override;
procedure VisitIdentifier(const Node: IIdentifierNode); override; procedure VisitIdentifier(const Node: IIdentifierNode); override;
procedure VisitKeyword(const Node: IKeywordNode); override; procedure VisitKeyword(const Node: IKeywordNode); override;
@@ -55,6 +55,14 @@ type
procedure VisitSeriesLength(const Node: ISeriesLengthNode); override; procedure VisitSeriesLength(const Node: ISeriesLengthNode); override;
procedure VisitNop(const Node: INopNode); override; procedure VisitNop(const Node: INopNode); override;
// List Visitors are handled implicitly by parent node iteration in Dumper,
// but we implement them empty/default to satisfy the abstract base class if called directly.
procedure VisitParameterList(const Node: IParameterList); override;
procedure VisitArgumentList(const Node: IArgumentList); override;
procedure VisitExpressionList(const Node: IExpressionList); override;
procedure VisitRecordFieldList(const Node: IRecordFieldList); override;
procedure VisitRecordField(const Node: IRecordFieldNode); override;
public public
constructor Create(const AOutput: TStrings); constructor Create(const AOutput: TStrings);
class procedure Dump(const RootNode: IAstNode; const Output: TStrings); class procedure Dump(const RootNode: IAstNode; const Output: TStrings);
@@ -201,7 +209,6 @@ var
slot: Integer; slot: Integer;
typ: IStaticType; typ: IStaticType;
begin begin
// (* UPDATED: Added IsPure output *)
LogFmt( LogFmt(
'LambdaExpression (HasNested: %s, IsPure: %s)', 'LambdaExpression (HasNested: %s, IsPure: %s)',
[Node.HasNestedLambdas.ToString(TUseBoolStrs.True), BoolToStr(Node.IsPure, True)], [Node.HasNestedLambdas.ToString(TUseBoolStrs.True), BoolToStr(Node.IsPure, True)],
@@ -236,6 +243,7 @@ begin
// 3. Parameters // 3. Parameters
Log('Parameters:'); Log('Parameters:');
Indent; Indent;
// Iterate over IParameterList
for var param in Node.Parameters do for var param in Node.Parameters do
param.Accept(Self); param.Accept(Self);
Unindent; Unindent;
@@ -266,11 +274,12 @@ var
i: Integer; i: Integer;
begin begin
sigStr := ''; sigStr := '';
// Note: Node.Arguments is IArgumentList now.
if Assigned(Node.StaticTarget) then if Assigned(Node.StaticTarget) then
begin begin
staticStatus := 'Assigned'; staticStatus := 'Assigned';
SetLength(argTypes, Length(Node.Arguments)); SetLength(argTypes, Node.Arguments.Count);
for i := 0 to High(Node.Arguments) do for i := 0 to Node.Arguments.Count - 1 do
begin begin
if Node.Arguments[i].IsTyped then if Node.Arguments[i].IsTyped then
argTypes[i] := Node.Arguments[i].AsTypedNode.StaticType.ToString argTypes[i] := Node.Arguments[i].AsTypedNode.StaticType.ToString
@@ -282,7 +291,6 @@ begin
else else
staticStatus := 'nil'; staticStatus := 'nil';
// (* UPDATED: Added IsTargetPure output *)
LogFmt( LogFmt(
'FunctionCall (IsTailCall: %s, StaticTarget: %s%s, IsTargetPure: %s)', 'FunctionCall (IsTailCall: %s, StaticTarget: %s%s, IsTargetPure: %s)',
[Node.IsTailCall.ToString(TUseBoolStrs.True), staticStatus, sigStr, BoolToStr(Node.IsTargetPure, True)], [Node.IsTailCall.ToString(TUseBoolStrs.True), staticStatus, sigStr, BoolToStr(Node.IsTargetPure, True)],
@@ -292,8 +300,9 @@ begin
Indent; Indent;
Log('Callee:'); Log('Callee:');
Node.Callee.Accept(Self); Node.Callee.Accept(Self);
LogFmt('Arguments (%d):', [Length(Node.Arguments)]); LogFmt('Arguments (%d):', [Node.Arguments.Count]);
Indent; Indent;
// Iterate over IArgumentList
for arg in Node.Arguments do for arg in Node.Arguments do
arg.Accept(Self); arg.Accept(Self);
Unindent; Unindent;
@@ -311,7 +320,7 @@ begin
Indent; Indent;
Log('Callee:'); Log('Callee:');
Node.CallNode.Callee.Accept(Self); Node.CallNode.Callee.Accept(Self);
LogFmt('Arguments (%d):', [Length(Node.CallNode.Arguments)]); LogFmt('Arguments (%d):', [Node.CallNode.Arguments.Count]);
Indent; Indent;
for arg in Node.CallNode.Arguments do for arg in Node.CallNode.Arguments do
arg.Accept(Self); arg.Accept(Self);
@@ -332,7 +341,7 @@ var
begin begin
Log('Recur', Node); Log('Recur', Node);
Indent; Indent;
LogFmt('Arguments (%d):', [Length(Node.Arguments)]); LogFmt('Arguments (%d):', [Node.Arguments.Count]);
Indent; Indent;
for arg in Node.Arguments do for arg in Node.Arguments do
arg.Accept(Self); arg.Accept(Self);
@@ -446,10 +455,11 @@ end;
procedure TAstDumper.VisitRecordLiteral(const Node: IRecordLiteralNode); procedure TAstDumper.VisitRecordLiteral(const Node: IRecordLiteralNode);
var var
field: TRecordFieldLiteral; field: IRecordFieldNode;
begin begin
LogFmt('RecordLiteral (%d fields)', [Length(Node.Fields)], Node); LogFmt('RecordLiteral (%d fields)', [Node.Fields.Count], Node);
Indent; Indent;
// Iterate over IRecordFieldList
for field in Node.Fields do for field in Node.Fields do
begin begin
LogFmt('Field :%s', [field.Key.Value.Name]); LogFmt('Field :%s', [field.Key.Value.Name]);
@@ -495,4 +505,41 @@ begin
Log('Nop', Node); Log('Nop', Node);
end; end;
// --- List Visitors Implementation ---
procedure TAstDumper.VisitParameterList(const Node: IParameterList);
begin
// Usually handled by Parent Node iteration (Lambda),
// but if visited directly:
for var item in Node do
item.Accept(Self);
end;
procedure TAstDumper.VisitArgumentList(const Node: IArgumentList);
begin
for var item in Node do
item.Accept(Self);
end;
procedure TAstDumper.VisitExpressionList(const Node: IExpressionList);
begin
for var item in Node do
item.Accept(Self);
end;
procedure TAstDumper.VisitRecordFieldList(const Node: IRecordFieldList);
begin
for var item in Node do
item.Accept(Self);
end;
procedure TAstDumper.VisitRecordField(const Node: IRecordFieldNode);
begin
// If visited directly (e.g. inside a list)
LogFmt('Field :%s', [Node.Key.Value.Name]);
Indent;
Node.Value.Accept(Self);
Unindent;
end;
end. end.
+65 -23
View File
@@ -25,6 +25,14 @@ type
function VisitConstant(const Node: IConstantNode): TDataValue; virtual; function VisitConstant(const Node: IConstantNode): TDataValue; virtual;
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual;
function VisitKeyword(const Node: IKeywordNode): TDataValue; virtual; function VisitKeyword(const Node: IKeywordNode): TDataValue; virtual;
// List Visitors
function VisitParameterList(const Node: IParameterList): TDataValue; virtual;
function VisitArgumentList(const Node: IArgumentList): TDataValue; virtual;
function VisitExpressionList(const Node: IExpressionList): TDataValue; virtual;
function VisitRecordFieldList(const Node: IRecordFieldList): TDataValue; virtual;
function VisitRecordField(const Node: IRecordFieldNode): TDataValue; virtual;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual; function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; virtual; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; virtual;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; virtual; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; virtual;
@@ -230,8 +238,8 @@ begin
i: Integer; i: Integer;
adr: TResolvedAddress; adr: TResolvedAddress;
begin begin
if (Length(ArgValues) <> Length(params)) then if (Length(ArgValues) <> params.Count) then
raise EEvaluatorException.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(params), Length(ArgValues)]); raise EEvaluatorException.CreateFmt('Argument count mismatch: expected %d, got %d', [params.Count, Length(ArgValues)]);
// Create the new execution scope for this function call. // Create the new execution scope for this function call.
lambdaScope := TScope.CreateScope(closureScope, descriptor, capturedCells); lambdaScope := TScope.CreateScope(closureScope, descriptor, capturedCells);
@@ -243,7 +251,7 @@ begin
lambdaScope[adr] := TDataValue(closure); lambdaScope[adr] := TDataValue(closure);
// Populate the scope with the actual parameters passed to the function. // Populate the scope with the actual parameters passed to the function.
for i := 0 to High(ArgValues) do for i := 0 to params.Count - 1 do
begin begin
adr := params[i].Address; adr := params[i].Address;
Assert(adr.ScopeDepth = 0); Assert(adr.ScopeDepth = 0);
@@ -283,15 +291,15 @@ var
calleeValue: TDataValue; calleeValue: TDataValue;
argValues: TArray<TDataValue>; argValues: TArray<TDataValue>;
i: Integer; i: Integer;
argNodes: TArray<IAstNode>; argList: IArgumentList;
begin begin
if Assigned(Node.StaticTarget) then if Assigned(Node.StaticTarget) then
begin begin
// --- Static Path (Optimized) --- // --- Static Path (Optimized) ---
argNodes := Node.Arguments; argList := Node.Arguments;
SetLength(argValues, Length(argNodes)); SetLength(argValues, argList.Count);
for i := 0 to High(argNodes) do for i := 0 to argList.Count - 1 do
argValues[i] := argNodes[i].Accept(Self); argValues[i] := argList[i].Accept(Self);
// Call static target. Exceptions here are caught by Execute/HandleTCO. // Call static target. Exceptions here are caught by Execute/HandleTCO.
Result := Node.StaticTarget(argValues); Result := Node.StaticTarget(argValues);
@@ -304,10 +312,10 @@ begin
if calleeValue.Kind <> vkMethod then if calleeValue.Kind <> vkMethod then
raise EEvaluatorException.Create('Expression is not invokable in this context.'); raise EEvaluatorException.Create('Expression is not invokable in this context.');
argNodes := Node.Arguments; argList := Node.Arguments;
SetLength(argValues, Length(argNodes)); SetLength(argValues, argList.Count);
for i := 0 to High(argNodes) do for i := 0 to argList.Count - 1 do
argValues[i] := argNodes[i].Accept(Self); argValues[i] := argList[i].Accept(Self);
if Node.IsTailCall then if Node.IsTailCall then
begin begin
@@ -333,8 +341,8 @@ var
calleeValue: TDataValue; calleeValue: TDataValue;
i: Integer; i: Integer;
begin begin
SetLength(argValues, Length(Node.Arguments)); SetLength(argValues, Node.Arguments.Count);
for i := 0 to High(Node.Arguments) do for i := 0 to Node.Arguments.Count - 1 do
argValues[i] := Node.Arguments[i].Accept(Self); argValues[i] := Node.Arguments[i].Accept(Self);
calleeAddress.Kind := akLocalOrParent; calleeAddress.Kind := akLocalOrParent;
@@ -517,11 +525,12 @@ begin
if Assigned(Node.GenericDefinition) then if Assigned(Node.GenericDefinition) then
begin begin
var genFields: TArray<TPair<IKeyword, TDataValue>>; var genFields: TArray<TPair<IKeyword, TDataValue>>;
SetLength(genFields, Length(Node.Fields)); SetLength(genFields, Node.Fields.Count);
for i := 0 to High(Node.Fields) do for i := 0 to Node.Fields.Count - 1 do
begin begin
genFields[i] := TPair<IKeyword, TDataValue>.Create(Node.Fields[i].Key.Value, Node.Fields[i].Value.Accept(Self)); var field := Node.Fields[i];
genFields[i] := TPair<IKeyword, TDataValue>.Create(field.Key.Value, field.Value.Accept(Self));
end; end;
var dynRec := TDynamicRecord.Create(genFields); var dynRec := TDynamicRecord.Create(genFields);
@@ -530,11 +539,12 @@ begin
else if Assigned(Node.ScalarDefinition) then else if Assigned(Node.ScalarDefinition) then
begin begin
var values: TArray<TScalar.TValue>; var values: TArray<TScalar.TValue>;
SetLength(values, Length(Node.Fields)); SetLength(values, Node.Fields.Count);
for i := 0 to High(Node.Fields) do for i := 0 to Node.Fields.Count - 1 do
begin begin
var valData := Node.Fields[i].Value.Accept(Self); var field := Node.Fields[i];
var valData := field.Value.Accept(Self);
values[i] := valData.AsScalar.Value; values[i] := valData.AsScalar.Value;
end; end;
@@ -589,12 +599,18 @@ begin
end; end;
function TEvaluatorVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function TEvaluatorVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
begin
// Delegate to ExpressionList visitor
Result := Node.Expressions.Accept(Self);
end;
function TEvaluatorVisitor.VisitExpressionList(const Node: IExpressionList): TDataValue;
var var
expression: IAstNode; i: Integer;
begin begin
Result := TDataValue.Void; Result := TDataValue.Void;
for expression in Node.Expressions do for i := 0 to Node.Count - 1 do
Result := expression.Accept(Self); Result := Node[i].Accept(Self);
end; end;
function TEvaluatorVisitor.VisitNop(const Node: INopNode): TDataValue; function TEvaluatorVisitor.VisitNop(const Node: INopNode): TDataValue;
@@ -620,4 +636,30 @@ begin
Result := TDataValue(TScalar.FromInt64(len)); Result := TDataValue(TScalar.FromInt64(len));
end; end;
// --- List Visitor Stubs (Mostly Unused directly, but required by Interface) ---
function TEvaluatorVisitor.VisitParameterList(const Node: IParameterList): TDataValue;
begin
Result := TDataValue.Void;
end;
function TEvaluatorVisitor.VisitArgumentList(const Node: IArgumentList): TDataValue;
begin
// Could evaluate arguments here and return an array-wrapped TDataValue,
// but VisitFunctionCall handles iteration manually for efficiency.
Result := TDataValue.Void;
end;
function TEvaluatorVisitor.VisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
begin
// Handled by VisitRecordLiteral
Result := TDataValue.Void;
end;
function TEvaluatorVisitor.VisitRecordField(const Node: IRecordFieldNode): TDataValue;
begin
// Handled by manual iteration in VisitRecordLiteral
Result := TDataValue.Void;
end;
end. end.
+83 -1
View File
@@ -13,6 +13,7 @@ type
IConstantIdentity = interface; IConstantIdentity = interface;
IKeywordIdentity = interface; IKeywordIdentity = interface;
IDefinitionIdentity = interface; IDefinitionIdentity = interface;
IListIdentity = interface;
// Represents a position in the source code. // Represents a position in the source code.
ISourceLocation = interface ISourceLocation = interface
@@ -29,7 +30,8 @@ type
ikNamed, // Identifier, MacroDef (Name + Location) ikNamed, // Identifier, MacroDef (Name + Location)
ikConstant, // Literals (Value + Location) ikConstant, // Literals (Value + Location)
ikKeyword, // Keywords (Keyword + Location) ikKeyword, // Keywords (Keyword + Location)
ikDefinition // Complex definitions (DefString + Location) ikDefinition, // Complex definitions (DefString + Location)
ikList // Lists (Open/Close Tokens + Separator + Location)
); );
// Base interface for the "Green Tree" nodes. // Base interface for the "Green Tree" nodes.
@@ -47,6 +49,7 @@ type
function AsConstant: IConstantIdentity; function AsConstant: IConstantIdentity;
function AsKeyword: IKeywordIdentity; function AsKeyword: IKeywordIdentity;
function AsDefinition: IDefinitionIdentity; function AsDefinition: IDefinitionIdentity;
function AsList: IListIdentity;
property Kind: TAstIdentityKind read GetKind; property Kind: TAstIdentityKind read GetKind;
@@ -82,6 +85,18 @@ type
property Definition: string read GetDefinition; property Definition: string read GetDefinition;
end; end;
// Spezifische Identität für Listen
IListIdentity = interface(IAstIdentity)
{$region 'private'}
function GetOpenToken: string;
function GetCloseToken: string;
function GetSeparator: string;
{$endregion}
property OpenToken: string read GetOpenToken;
property CloseToken: string read GetCloseToken;
property Separator: string read GetSeparator;
end;
// Factory and static access. // Factory and static access.
TIdentities = record TIdentities = record
public public
@@ -92,6 +107,8 @@ type
class function Constant(const AValue: TDataValue; const ALoc: ISourceLocation = nil): IConstantIdentity; static; class function Constant(const AValue: TDataValue; const ALoc: ISourceLocation = nil): IConstantIdentity; static;
class function Keyword(const AValue: IKeyword; const ALoc: ISourceLocation = nil): IKeywordIdentity; static; class function Keyword(const AValue: IKeyword; const ALoc: ISourceLocation = nil): IKeywordIdentity; static;
class function Definition(const ADef: string; const ALoc: ISourceLocation = nil): IDefinitionIdentity; static; class function Definition(const ADef: string; const ALoc: ISourceLocation = nil): IDefinitionIdentity; static;
class function List(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation = nil): IListIdentity; static;
end; end;
implementation implementation
@@ -121,6 +138,7 @@ type
function AsConstant: IConstantIdentity; virtual; function AsConstant: IConstantIdentity; virtual;
function AsKeyword: IKeywordIdentity; virtual; function AsKeyword: IKeywordIdentity; virtual;
function AsDefinition: IDefinitionIdentity; virtual; function AsDefinition: IDefinitionIdentity; virtual;
function AsList: IListIdentity; virtual;
end; end;
TStructuralIdentity = class(TAbstractIdentity) TStructuralIdentity = class(TAbstractIdentity)
@@ -176,6 +194,20 @@ type
function AsDefinition: IDefinitionIdentity; override; function AsDefinition: IDefinitionIdentity; override;
end; end;
TListIdentity = class(TAbstractIdentity, IListIdentity)
private
FOpen, FClose, FSeparator: string;
function GetOpenToken: string;
function GetCloseToken: string;
function GetSeparator: string;
protected
function GetKind: TAstIdentityKind; override;
public
constructor Create(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation);
function ToString: string; override;
function AsList: IListIdentity; override;
end;
{ TSourceLocation } { TSourceLocation }
constructor TSourceLocation.Create(ALine, ACol: Integer); constructor TSourceLocation.Create(ALine, ACol: Integer);
@@ -241,6 +273,11 @@ begin
raise EInvalidCast.Create('Identity is not a Definition Identity'); raise EInvalidCast.Create('Identity is not a Definition Identity');
end; end;
function TAbstractIdentity.AsList: IListIdentity;
begin
raise EInvalidCast.Create('Identity is not a List Identity');
end;
{ TStructuralIdentity } { TStructuralIdentity }
function TStructuralIdentity.GetKind: TAstIdentityKind; function TStructuralIdentity.GetKind: TAstIdentityKind;
@@ -360,6 +397,46 @@ begin
Result := Format('Def: "%s" (%s)', [FDefinition, inherited ToString]); Result := Format('Def: "%s" (%s)', [FDefinition, inherited ToString]);
end; end;
{ TListIdentity }
constructor TListIdentity.Create(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation);
begin
inherited Create(ALoc);
FOpen := AOpen;
FClose := AClose;
FSeparator := ASeparator;
end;
function TListIdentity.GetKind: TAstIdentityKind;
begin
Result := ikList;
end;
function TListIdentity.GetOpenToken: string;
begin
Result := FOpen;
end;
function TListIdentity.GetCloseToken: string;
begin
Result := FClose;
end;
function TListIdentity.GetSeparator: string;
begin
Result := FSeparator;
end;
function TListIdentity.AsList: IListIdentity;
begin
Result := Self;
end;
function TListIdentity.ToString: string;
begin
Result := Format('List: "%s...%s" (Sep: "%s") (%s)', [FOpen, FClose, FSeparator, inherited ToString]);
end;
{ TIdentities } { TIdentities }
class function TIdentities.Location(ALine, ACol: Integer): ISourceLocation; class function TIdentities.Location(ALine, ACol: Integer): ISourceLocation;
@@ -392,4 +469,9 @@ begin
Result := TDefinitionIdentity.Create(ADef, ALoc); Result := TDefinitionIdentity.Create(ADef, ALoc);
end; end;
class function TIdentities.List(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation): IListIdentity;
begin
Result := TListIdentity.Create(AOpen, AClose, ASeparator, ALoc);
end;
end. end.
+78 -34
View File
@@ -44,7 +44,7 @@ type
function JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode; function JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode;
function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode; function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode;
function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode; function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode;
function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode; function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode; // <--- KORRIGIERT
function JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode; function JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode; function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode; function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
@@ -56,6 +56,14 @@ type
function VisitConstant(const Node: IConstantNode): TJSONObject; override; function VisitConstant(const Node: IConstantNode): TJSONObject; override;
function VisitIdentifier(const Node: IIdentifierNode): TJSONObject; override; function VisitIdentifier(const Node: IIdentifierNode): TJSONObject; override;
function VisitKeyword(const Node: IKeywordNode): TJSONObject; override; function VisitKeyword(const Node: IKeywordNode): TJSONObject; override;
// List Visitors (stubbed mostly, as parents handle array generation for JSON structure)
function VisitParameterList(const Node: IParameterList): TJSONObject; override;
function VisitArgumentList(const Node: IArgumentList): TJSONObject; override;
function VisitExpressionList(const Node: IExpressionList): TJSONObject; override;
function VisitRecordFieldList(const Node: IRecordFieldList): TJSONObject; override;
function VisitRecordField(const Node: IRecordFieldNode): TJSONObject; override;
function VisitIfExpression(const Node: IIfExpressionNode): TJSONObject; override; function VisitIfExpression(const Node: IIfExpressionNode): TJSONObject; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TJSONObject; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TJSONObject; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TJSONObject; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TJSONObject; override;
@@ -197,12 +205,13 @@ function TJsonAstConverter.VisitLambdaExpression(const Node: ILambdaExpressionNo
var var
bodyObj: TJSONObject; bodyObj: TJSONObject;
paramsArray: TJSONArray; paramsArray: TJSONArray;
i: Integer;
begin begin
bodyObj := Accept(Node.Body); bodyObj := Accept(Node.Body);
paramsArray := TJSONArray.Create; paramsArray := TJSONArray.Create;
for var param in Node.Parameters do for i := 0 to Node.Parameters.Count - 1 do
paramsArray.Add(Accept(param)); paramsArray.Add(Accept(Node.Parameters[i]));
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('LambdaExpr')); Result.AddPair('NodeType', TJSONString.Create('LambdaExpr'));
@@ -214,13 +223,14 @@ function TJsonAstConverter.VisitMacroDefinition(const Node: IMacroDefinitionNode
var var
nameObj, bodyObj: TJSONObject; nameObj, bodyObj: TJSONObject;
paramsArray: TJSONArray; paramsArray: TJSONArray;
i: Integer;
begin begin
nameObj := Accept(Node.Name); nameObj := Accept(Node.Name);
bodyObj := Accept(Node.Body); bodyObj := Accept(Node.Body);
paramsArray := TJSONArray.Create; paramsArray := TJSONArray.Create;
for var param in Node.Parameters do for i := 0 to Node.Parameters.Count - 1 do
paramsArray.Add(Accept(param)); paramsArray.Add(Accept(Node.Parameters[i]));
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('MacroDef')); Result.AddPair('NodeType', TJSONString.Create('MacroDef'));
@@ -254,13 +264,13 @@ function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TJS
var var
calleeObj: TJSONObject; calleeObj: TJSONObject;
argsArray: TJSONArray; argsArray: TJSONArray;
arg: IAstNode; i: Integer;
begin begin
calleeObj := Accept(Node.Callee); calleeObj := Accept(Node.Callee);
argsArray := TJSONArray.Create; argsArray := TJSONArray.Create;
for arg in Node.Arguments do for i := 0 to Node.Arguments.Count - 1 do
argsArray.Add(Accept(arg)); argsArray.Add(Accept(Node.Arguments[i]));
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('FunctionCall')); Result.AddPair('NodeType', TJSONString.Create('FunctionCall'));
@@ -272,14 +282,14 @@ function TJsonAstConverter.VisitMacroExpansionNode(const Node: IMacroExpansionNo
var var
calleeObj, bodyObj: TJSONObject; calleeObj, bodyObj: TJSONObject;
argsArray: TJSONArray; argsArray: TJSONArray;
arg: IAstNode; i: Integer;
begin begin
calleeObj := Accept(Node.CallNode.Callee); calleeObj := Accept(Node.CallNode.Callee);
bodyObj := Accept(Node.ExpandedBody); bodyObj := Accept(Node.ExpandedBody);
argsArray := TJSONArray.Create; argsArray := TJSONArray.Create;
for arg in Node.CallNode.Arguments do for i := 0 to Node.CallNode.Arguments.Count - 1 do
argsArray.Add(Accept(arg)); argsArray.Add(Accept(Node.CallNode.Arguments[i]));
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('MacroExpansion')); Result.AddPair('NodeType', TJSONString.Create('MacroExpansion'));
@@ -291,11 +301,11 @@ end;
function TJsonAstConverter.VisitRecurNode(const Node: IRecurNode): TJSONObject; function TJsonAstConverter.VisitRecurNode(const Node: IRecurNode): TJSONObject;
var var
argsArray: TJSONArray; argsArray: TJSONArray;
arg: IAstNode; i: Integer;
begin begin
argsArray := TJSONArray.Create; argsArray := TJSONArray.Create;
for arg in Node.Arguments do for i := 0 to Node.Arguments.Count - 1 do
argsArray.Add(Accept(arg)); argsArray.Add(Accept(Node.Arguments[i]));
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('Recur')); Result.AddPair('NodeType', TJSONString.Create('Recur'));
@@ -305,11 +315,11 @@ end;
function TJsonAstConverter.VisitBlockExpression(const Node: IBlockExpressionNode): TJSONObject; function TJsonAstConverter.VisitBlockExpression(const Node: IBlockExpressionNode): TJSONObject;
var var
exprsArray: TJSONArray; exprsArray: TJSONArray;
expr: IAstNode; i: Integer;
begin begin
exprsArray := TJSONArray.Create; exprsArray := TJSONArray.Create;
for expr in Node.Expressions do for i := 0 to Node.Expressions.Count - 1 do
exprsArray.Add(Accept(expr)); exprsArray.Add(Accept(Node.Expressions[i]));
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('Block')); Result.AddPair('NodeType', TJSONString.Create('Block'));
@@ -375,24 +385,28 @@ end;
function TJsonAstConverter.VisitRecordLiteral(const Node: IRecordLiteralNode): TJSONObject; function TJsonAstConverter.VisitRecordLiteral(const Node: IRecordLiteralNode): TJSONObject;
var var
fieldsArray: TJSONArray; fieldsArray: TJSONArray;
field: TRecordFieldLiteral; i: Integer;
fieldObj: TJSONObject;
begin begin
Result := TJSONObject.Create; Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('RecordLiteral')); Result.AddPair('NodeType', TJSONString.Create('RecordLiteral'));
fieldsArray := TJSONArray.Create; fieldsArray := TJSONArray.Create;
for field in Node.Fields do for i := 0 to Node.Fields.Count - 1 do
begin begin
fieldObj := TJSONObject.Create; // We visit the RecordFieldNode, which returns a JSON Object
fieldObj.AddPair('Name', TJSONString.Create(field.Key.Value.Name)); fieldsArray.Add(Accept(Node.Fields[i]));
fieldObj.AddPair('Value', Accept(field.Value)); // Get TJSONObject
fieldsArray.Add(fieldObj);
end; end;
Result.AddPair('Fields', fieldsArray); Result.AddPair('Fields', fieldsArray);
end; end;
function TJsonAstConverter.VisitRecordField(const Node: IRecordFieldNode): TJSONObject;
begin
Result := TJSONObject.Create;
Result.AddPair('Name', TJSONString.Create(Node.Key.Value.Name));
Result.AddPair('Value', Accept(Node.Value));
end;
function TJsonAstConverter.VisitCreateSeries(const Node: ICreateSeriesNode): TJSONObject; function TJsonAstConverter.VisitCreateSeries(const Node: ICreateSeriesNode): TJSONObject;
begin begin
Result := TJSONObject.Create; Result := TJSONObject.Create;
@@ -436,7 +450,35 @@ begin
Result.AddPair('NodeType', TJSONString.Create('Nop')); Result.AddPair('NodeType', TJSONString.Create('Nop'));
end; end;
{ TJsonAstConverter - Deserialization } // --- List Visitors (Placeholder return) ---
// Since we iterate manually in parent nodes to form JSON Arrays, these are technically not used
// by the current logic, but required by the interface.
// Note: If we wanted strict visitor compliance, VisitFunctionCall would call Accept(List),
// which would return TJSONObject wrapping the array. We skip that level of nesting here.
function TJsonAstConverter.VisitParameterList(const Node: IParameterList): TJSONObject;
begin
Result := nil;
end;
function TJsonAstConverter.VisitArgumentList(const Node: IArgumentList): TJSONObject;
begin
Result := nil;
end;
function TJsonAstConverter.VisitExpressionList(const Node: IExpressionList): TJSONObject;
begin
Result := nil;
end;
function TJsonAstConverter.VisitRecordFieldList(const Node: IRecordFieldList): TJSONObject;
begin
Result := nil;
end;
// ------------------------------------------------------------------------------------------------
// Deserialization
// ------------------------------------------------------------------------------------------------
function TJsonAstConverter.JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue; function TJsonAstConverter.JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue;
var var
@@ -532,11 +574,10 @@ function TJsonAstConverter.JsonToMacroDefNode(const AObj: TJSONObject): IMacroDe
var var
name: IIdentifierNode; name: IIdentifierNode;
params: TArray<IIdentifierNode>; params: TArray<IIdentifierNode>;
body: IQuasiquoteNode; body: IAstNode;
paramArray: TJSONArray; paramArray: TJSONArray;
i: Integer; i: Integer;
begin begin
name := JsonToIdentifierNode(AObj.GetValue('Name') as TJSONObject); name := JsonToIdentifierNode(AObj.GetValue('Name') as TJSONObject);
paramArray := AObj.GetValue<TJSONArray>('Parameters'); paramArray := AObj.GetValue<TJSONArray>('Parameters');
@@ -544,7 +585,7 @@ begin
for i := 0 to paramArray.Count - 1 do for i := 0 to paramArray.Count - 1 do
params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject); params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject);
body := IQuasiquoteNode(JsonToNode(AObj.GetValue('Body'), 'Quasiquote')); body := JsonToNode(AObj.GetValue('Body'), 'Quasiquote');
Result := TAst.MacroDef(name, params, body); Result := TAst.MacroDef(name, params, body);
end; end;
@@ -556,7 +597,6 @@ var
i: Integer; i: Integer;
tempCallNode: IFunctionCallNode; tempCallNode: IFunctionCallNode;
begin begin
// Recursively deserialize all parts of the macro expansion node
callee := JsonToNode(AObj.GetValue('Callee')); callee := JsonToNode(AObj.GetValue('Callee'));
expandedBody := JsonToNode(AObj.GetValue('ExpandedBody')); expandedBody := JsonToNode(AObj.GetValue('ExpandedBody'));
argsArray := AObj.GetValue<TJSONArray>('Arguments'); argsArray := AObj.GetValue<TJSONArray>('Arguments');
@@ -564,10 +604,7 @@ begin
for i := 0 to argsArray.Count - 1 do for i := 0 to argsArray.Count - 1 do
args[i] := JsonToNode(argsArray.Items[i]); args[i] := JsonToNode(argsArray.Items[i]);
// Create a temporary IFunctionCallNode to pass to the factory
tempCallNode := TAst.FunctionCall(callee, args); tempCallNode := TAst.FunctionCall(callee, args);
// Use the new global factory function from the TAst record
Result := TAst.MacroExpansionNode(tempCallNode, expandedBody); Result := TAst.MacroExpansionNode(tempCallNode, expandedBody);
end; end;
@@ -666,18 +703,25 @@ end;
function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode; function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
var var
fields: TArray<TRecordFieldLiteral>; fields: TArray<IRecordFieldNode>;
fieldsArray: TJSONArray; fieldsArray: TJSONArray;
fieldObj: TJSONObject; fieldObj: TJSONObject;
i: Integer; i: Integer;
keyNode: IKeywordNode;
valueNode: IAstNode;
begin begin
fieldsArray := AObj.GetValue<TJSONArray>('Fields'); fieldsArray := AObj.GetValue<TJSONArray>('Fields');
SetLength(fields, fieldsArray.Count); SetLength(fields, fieldsArray.Count);
for i := 0 to fieldsArray.Count - 1 do for i := 0 to fieldsArray.Count - 1 do
begin begin
fieldObj := fieldsArray.Items[i] as TJSONObject; fieldObj := fieldsArray.Items[i] as TJSONObject;
fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(fieldObj.GetValue<string>('Name')), JsonToNode(fieldObj.GetValue('Value'))); keyNode := TAst.Keyword(fieldObj.GetValue<string>('Name'));
valueNode := JsonToNode(fieldObj.GetValue('Value'));
fields[i] := TAst.RecordField(keyNode, valueNode);
end; end;
Result := TAst.RecordLiteral(fields); Result := TAst.RecordLiteral(fields);
end; end;
+369 -65
View File
@@ -76,9 +76,20 @@ type
IAstVisitor = interface; IAstVisitor = interface;
IAstTypedNode = interface; IAstTypedNode = interface;
// Core Nodes
IConstantNode = interface; IConstantNode = interface;
IIdentifierNode = interface; IIdentifierNode = interface;
IKeywordNode = interface; IKeywordNode = interface;
// Lists & Containers
IParameterList = interface;
IArgumentList = interface;
IExpressionList = interface;
IRecordFieldList = interface;
IRecordFieldNode = interface;
// Control Flow & Structure
IIfExpressionNode = interface; IIfExpressionNode = interface;
ITernaryExpressionNode = interface; ITernaryExpressionNode = interface;
ILambdaExpressionNode = interface; ILambdaExpressionNode = interface;
@@ -105,6 +116,12 @@ type
akConstant, akConstant,
akIdentifier, akIdentifier,
akKeyword, akKeyword,
// Lists
akParameterList,
akArgumentList,
akExpressionList,
akRecordFieldList,
akRecordField,
akIfExpression, akIfExpression,
akTernaryExpression, akTernaryExpression,
akLambdaExpression, akLambdaExpression,
@@ -148,6 +165,13 @@ type
function AsConstant: IConstantNode; function AsConstant: IConstantNode;
function AsIdentifier: IIdentifierNode; function AsIdentifier: IIdentifierNode;
function AsKeyword: IKeywordNode; function AsKeyword: IKeywordNode;
function AsParameterList: IParameterList;
function AsArgumentList: IArgumentList;
function AsExpressionList: IExpressionList;
function AsRecordFieldList: IRecordFieldList;
function AsRecordField: IRecordFieldNode;
function AsIfExpression: IIfExpressionNode; function AsIfExpression: IIfExpressionNode;
function AsTernaryExpression: ITernaryExpressionNode; function AsTernaryExpression: ITernaryExpressionNode;
function AsLambdaExpression: ILambdaExpressionNode; function AsLambdaExpression: ILambdaExpressionNode;
@@ -174,6 +198,17 @@ type
property Identity: IAstIdentity read GetIdentity; property Identity: IAstIdentity read GetIdentity;
end; end;
INodeList<T: IAstNode> = interface(IAstNode)
{$region 'private'}
function GetCount: Integer;
function GetItem(Index: Integer): T;
{$endregion}
function GetEnumerator: TEnumerator<T>;
function ToArray: TArray<T>;
property Count: Integer read GetCount;
property Items[Index: Integer]: T read GetItem; default;
end;
IAstTypedNode = interface(IAstNode) IAstTypedNode = interface(IAstNode)
{$region 'private'} {$region 'private'}
function GetStaticType: IStaticType; function GetStaticType: IStaticType;
@@ -181,17 +216,29 @@ type
property StaticType: IStaticType read GetStaticType; property StaticType: IStaticType read GetStaticType;
end; end;
IRecordFieldNode = interface(IAstNode)
{$region 'private'}
function GetKey: IKeywordNode;
function GetValue: IAstNode;
{$endregion}
property Key: IKeywordNode read GetKey;
property Value: IAstNode read GetValue;
end;
IRecordFieldList = interface(INodeList<IRecordFieldNode>)
end;
// --- Node Interfaces (Definitions) --- // --- Node Interfaces (Definitions) ---
// Function Definition (Lambda) // Function Definition (Lambda)
IFunctionDefinition = interface(IAstTypedNode) IFunctionDefinition = interface(IAstTypedNode)
{$region 'private'} {$region 'private'}
function GetBody: IAstNode; function GetBody: IAstNode;
function GetParameters: TArray<IIdentifierNode>; function GetParameters: IParameterList;
function GetIsPure: Boolean; function GetIsPure: Boolean;
{$endregion} {$endregion}
property Body: IAstNode read GetBody; property Body: IAstNode read GetBody;
property Parameters: TArray<IIdentifierNode> read GetParameters; property Parameters: IParameterList read GetParameters;
property IsPure: Boolean read GetIsPure; property IsPure: Boolean read GetIsPure;
end; end;
@@ -259,13 +306,13 @@ type
IFunctionCallNode = interface(IAstTypedNode) IFunctionCallNode = interface(IAstTypedNode)
{$region 'private'} {$region 'private'}
function GetCallee: IAstNode; function GetCallee: IAstNode;
function GetArguments: TArray<IAstNode>; function GetArguments: IArgumentList;
function GetIsTailCall: Boolean; function GetIsTailCall: Boolean;
function GetStaticTarget: TDataValue.TFunc; function GetStaticTarget: TDataValue.TFunc;
function GetIsTargetPure: Boolean; function GetIsTargetPure: Boolean;
{$endregion} {$endregion}
property Callee: IAstNode read GetCallee; property Callee: IAstNode read GetCallee;
property Arguments: TArray<IAstNode> read GetArguments; property Arguments: IArgumentList read GetArguments;
property IsTailCall: Boolean read GetIsTailCall; property IsTailCall: Boolean read GetIsTailCall;
property StaticTarget: TDataValue.TFunc read GetStaticTarget; property StaticTarget: TDataValue.TFunc read GetStaticTarget;
property IsTargetPure: Boolean read GetIsTargetPure; property IsTargetPure: Boolean read GetIsTargetPure;
@@ -282,16 +329,16 @@ type
IRecurNode = interface(IAstTypedNode) IRecurNode = interface(IAstTypedNode)
{$region 'private'} {$region 'private'}
function GetArguments: TArray<IAstNode>; function GetArguments: IArgumentList;
{$endregion} {$endregion}
property Arguments: TArray<IAstNode> read GetArguments; property Arguments: IArgumentList read GetArguments;
end; end;
IBlockExpressionNode = interface(IAstTypedNode) IBlockExpressionNode = interface(IAstTypedNode)
{$region 'private'} {$region 'private'}
function GetExpressions: TArray<IAstNode>; function GetExpressions: IExpressionList;
{$endregion} {$endregion}
property Expressions: TArray<IAstNode> read GetExpressions; property Expressions: IExpressionList read GetExpressions;
end; end;
IVariableDeclarationNode = interface(IAstTypedNode) IVariableDeclarationNode = interface(IAstTypedNode)
@@ -317,11 +364,11 @@ type
IMacroDefinitionNode = interface(IAstTypedNode) IMacroDefinitionNode = interface(IAstTypedNode)
{$region 'private'} {$region 'private'}
function GetName: IIdentifierNode; function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>; function GetParameters: IParameterList;
function GetBody: IAstNode; function GetBody: IAstNode;
{$endregion} {$endregion}
property Name: IIdentifierNode read GetName; property Name: IIdentifierNode read GetName;
property Parameters: TArray<IIdentifierNode> read GetParameters; property Parameters: IParameterList read GetParameters;
property Body: IAstNode read GetBody; property Body: IAstNode read GetBody;
end; end;
@@ -364,19 +411,13 @@ type
property Member: IKeywordNode read GetMember; property Member: IKeywordNode read GetMember;
end; end;
TRecordFieldLiteral = record
Key: IKeywordNode;
Value: IAstNode;
constructor Create(const AKey: IKeywordNode; const AValue: IAstNode);
end;
IRecordLiteralNode = interface(IAstTypedNode) IRecordLiteralNode = interface(IAstTypedNode)
{$region 'private'} {$region 'private'}
function GetFields: TArray<TRecordFieldLiteral>; function GetFields: IRecordFieldList;
function GetGenericDefinition: IGenericRecordDefinition; function GetGenericDefinition: IGenericRecordDefinition;
function GetScalarDefinition: IScalarRecordDefinition; function GetScalarDefinition: IScalarRecordDefinition;
{$endregion} {$endregion}
property Fields: TArray<TRecordFieldLiteral> read GetFields; property Fields: IRecordFieldList read GetFields;
property GenericDefinition: IGenericRecordDefinition read GetGenericDefinition; property GenericDefinition: IGenericRecordDefinition read GetGenericDefinition;
property ScalarDefinition: IScalarRecordDefinition read GetScalarDefinition; property ScalarDefinition: IScalarRecordDefinition read GetScalarDefinition;
end; end;
@@ -406,10 +447,25 @@ type
property Series: IIdentifierNode read GetSeries; property Series: IIdentifierNode read GetSeries;
end; end;
IParameterList = interface(INodeList<IIdentifierNode>)
end;
IArgumentList = interface(INodeList<IAstNode>)
end;
IExpressionList = interface(INodeList<IAstNode>)
end;
IAstVisitor = interface IAstVisitor = interface
function VisitConstant(const Node: IConstantNode): TDataValue; function VisitConstant(const Node: IConstantNode): TDataValue;
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
function VisitKeyword(const Node: IKeywordNode): TDataValue; function VisitKeyword(const Node: IKeywordNode): TDataValue;
// List Visits
function VisitParameterList(const Node: IParameterList): TDataValue;
function VisitArgumentList(const Node: IArgumentList): TDataValue;
function VisitExpressionList(const Node: IExpressionList): TDataValue;
function VisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
function VisitRecordField(const Node: IRecordFieldNode): TDataValue;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
@@ -451,6 +507,13 @@ type
function AsConstant: IConstantNode; virtual; function AsConstant: IConstantNode; virtual;
function AsIdentifier: IIdentifierNode; virtual; function AsIdentifier: IIdentifierNode; virtual;
function AsKeyword: IKeywordNode; virtual; function AsKeyword: IKeywordNode; virtual;
function AsParameterList: IParameterList; virtual;
function AsArgumentList: IArgumentList; virtual;
function AsExpressionList: IExpressionList; virtual;
function AsRecordFieldList: IRecordFieldList; virtual;
function AsRecordField: IRecordFieldNode; virtual;
function AsIfExpression: IIfExpressionNode; virtual; function AsIfExpression: IIfExpressionNode; virtual;
function AsTernaryExpression: ITernaryExpressionNode; virtual; function AsTernaryExpression: ITernaryExpressionNode; virtual;
function AsLambdaExpression: ILambdaExpressionNode; virtual; function AsLambdaExpression: ILambdaExpressionNode; virtual;
@@ -490,6 +553,82 @@ type
property StaticType: IStaticType read GetStaticType; property StaticType: IStaticType read GetStaticType;
end; end;
// --- List Implementation Bases ---
TAstNodeList<T: IAstNode> = class(TAstNode, INodeList<T>)
type
TEnumerator = class(TEnumerator<T>)
private
FArray: TArray<T>;
FIndex: NativeInt;
function GetCurrent: T; inline;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AArray: TArray<T>);
function MoveNext: Boolean; inline;
property Current: T read GetCurrent;
end;
private
FItems: TArray<T>;
function GetCount: Integer;
function GetItem(Index: Integer): T;
public
constructor Create(const AItems: TArray<T>; const AIdentity: IAstIdentity);
function GetEnumerator: TEnumerator<T>;
function ToArray: TArray<T>;
property Count: Integer read GetCount;
property Items[Index: Integer]: T read GetItem; default;
end;
TParameterList = class(TAstNodeList<IIdentifierNode>, IParameterList)
protected
function GetKind: TAstNodeKind; override;
public
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsParameterList: IParameterList; override;
end;
TArgumentList = class(TAstNodeList<IAstNode>, IArgumentList)
protected
function GetKind: TAstNodeKind; override;
public
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsArgumentList: IArgumentList; override;
end;
TExpressionList = class(TAstNodeList<IAstNode>, IExpressionList)
protected
function GetKind: TAstNodeKind; override;
public
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsExpressionList: IExpressionList; override;
end;
TRecordFieldNode = class(TAstNode, IRecordFieldNode)
private
FKey: IKeywordNode;
FValue: IAstNode;
function GetKey: IKeywordNode;
function GetValue: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AKey: IKeywordNode; const AValue: IAstNode; const AIdentity: IAstIdentity);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsRecordField: IRecordFieldNode; override;
end;
TRecordFieldList = class(TAstNodeList<IRecordFieldNode>, IRecordFieldList)
protected
function GetKind: TAstNodeKind; override;
public
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsRecordFieldList: IRecordFieldList; override;
end;
// --- Core Nodes Implementations ---
TConstantNode = class(TAstTypedNode, IConstantNode) TConstantNode = class(TAstTypedNode, IConstantNode)
private private
FConstIdentity: IConstantIdentity; // Typed reference for fast access FConstIdentity: IConstantIdentity; // Typed reference for fast access
@@ -574,13 +713,13 @@ type
TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode, IFunctionDefinition) TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode, IFunctionDefinition)
private private
FParameters: TArray<IIdentifierNode>; FParameters: IParameterList;
FBody: IAstNode; FBody: IAstNode;
FLayout: IScopeLayout; FLayout: IScopeLayout;
FDescriptor: IScopeDescriptor; FDescriptor: IScopeDescriptor;
FUpvalues: TArray<TResolvedAddress>; FUpvalues: TArray<TResolvedAddress>;
FHasNestedLambdas, FIsPure: Boolean; FHasNestedLambdas, FIsPure: Boolean;
function GetParameters: TArray<IIdentifierNode>; function GetParameters: IParameterList;
function GetBody: IAstNode; function GetBody: IAstNode;
function GetLayout: IScopeLayout; function GetLayout: IScopeLayout;
function GetDescriptor: IScopeDescriptor; function GetDescriptor: IScopeDescriptor;
@@ -590,7 +729,7 @@ type
function GetKind: TAstNodeKind; override; function GetKind: TAstNodeKind; override;
public public
constructor Create( constructor Create(
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode; const ABody: IAstNode;
const AStaticType: IStaticType; const AStaticType: IStaticType;
const ALayout: IScopeLayout; const ALayout: IScopeLayout;
@@ -606,12 +745,12 @@ type
TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode) TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode)
private private
FCallee: IAstNode; FCallee: IAstNode;
FArguments: TArray<IAstNode>; FArguments: IArgumentList;
FIsTailCall: Boolean; FIsTailCall: Boolean;
FStaticTarget: TDataValue.TFunc; FStaticTarget: TDataValue.TFunc;
FIsTargetPure: Boolean; FIsTargetPure: Boolean;
function GetCallee: IAstNode; function GetCallee: IAstNode;
function GetArguments: TArray<IAstNode>; function GetArguments: IArgumentList;
function GetIsTailCall: Boolean; function GetIsTailCall: Boolean;
function GetStaticTarget: TDataValue.TFunc; function GetStaticTarget: TDataValue.TFunc;
function GetIsTargetPure: Boolean; function GetIsTargetPure: Boolean;
@@ -619,7 +758,7 @@ type
public public
constructor Create( constructor Create(
const ACallee: IAstNode; const ACallee: IAstNode;
const AArguments: TArray<IAstNode>; const AArguments: IArgumentList;
const AStaticType: IStaticType; const AStaticType: IStaticType;
const AIsTailCall: Boolean; const AIsTailCall: Boolean;
const AStaticTarget: TDataValue.TFunc; const AStaticTarget: TDataValue.TFunc;
@@ -633,16 +772,16 @@ type
TMacroDefinitionNode = class(TAstTypedNode, IMacroDefinitionNode) TMacroDefinitionNode = class(TAstTypedNode, IMacroDefinitionNode)
private private
FName: IIdentifierNode; FName: IIdentifierNode;
FParameters: TArray<IIdentifierNode>; FParameters: IParameterList;
FBody: IAstNode; FBody: IAstNode;
function GetName: IIdentifierNode; function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>; function GetParameters: IParameterList;
function GetBody: IAstNode; function GetBody: IAstNode;
function GetKind: TAstNodeKind; override; function GetKind: TAstNodeKind; override;
public public
constructor Create( constructor Create(
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode; const ABody: IAstNode;
const AIdentity: IAstIdentity const AIdentity: IAstIdentity
); );
@@ -698,22 +837,22 @@ type
TRecurNode = class(TAstTypedNode, IRecurNode) TRecurNode = class(TAstTypedNode, IRecurNode)
private private
FArguments: TArray<IAstNode>; FArguments: IArgumentList;
function GetArguments: TArray<IAstNode>; function GetArguments: IArgumentList;
function GetKind: TAstNodeKind; override; function GetKind: TAstNodeKind; override;
public public
constructor Create(const AArguments: TArray<IAstNode>; const AStaticType: IStaticType; const AIdentity: IAstIdentity); constructor Create(const AArguments: IArgumentList; const AStaticType: IStaticType; const AIdentity: IAstIdentity);
function Accept(const Visitor: IAstVisitor): TDataValue; override; function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsRecur: IRecurNode; override; function AsRecur: IRecurNode; override;
end; end;
TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode) TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode)
private private
FExpressions: TArray<IAstNode>; FExpressions: IExpressionList;
function GetExpressions: TArray<IAstNode>; function GetExpressions: IExpressionList;
function GetKind: TAstNodeKind; override; function GetKind: TAstNodeKind; override;
public public
constructor Create(const AExpressions: array of IAstNode; const AStaticType: IStaticType; const AIdentity: IAstIdentity); constructor Create(const AExpressions: IExpressionList; const AStaticType: IStaticType; const AIdentity: IAstIdentity);
function Accept(const Visitor: IAstVisitor): TDataValue; override; function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsBlockExpression: IBlockExpressionNode; override; function AsBlockExpression: IBlockExpressionNode; override;
end; end;
@@ -782,16 +921,16 @@ type
TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode) TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode)
private private
FFields: TArray<TRecordFieldLiteral>; FFields: IRecordFieldList;
FScalarDef: IScalarRecordDefinition; FScalarDef: IScalarRecordDefinition;
FGenericDef: IGenericRecordDefinition; FGenericDef: IGenericRecordDefinition;
function GetFields: TArray<TRecordFieldLiteral>; function GetFields: IRecordFieldList;
function GetGenericDefinition: IGenericRecordDefinition; function GetGenericDefinition: IGenericRecordDefinition;
function GetScalarDefinition: IScalarRecordDefinition; function GetScalarDefinition: IScalarRecordDefinition;
function GetKind: TAstNodeKind; override; function GetKind: TAstNodeKind; override;
public public
constructor Create( constructor Create(
const AFields: TArray<TRecordFieldLiteral>; const AFields: IRecordFieldList;
const AScalarDef: IScalarRecordDefinition; const AScalarDef: IScalarRecordDefinition;
const AGenericDef: IGenericRecordDefinition; const AGenericDef: IGenericRecordDefinition;
const AStaticType: IStaticType; const AStaticType: IStaticType;
@@ -865,14 +1004,6 @@ begin
Result := Result.Substring(2); Result := Result.Substring(2);
end; end;
{ TRecordFieldLiteral }
constructor TRecordFieldLiteral.Create(const AKey: IKeywordNode; const AValue: IAstNode);
begin
Key := AKey;
Value := AValue;
end;
{ TCompilerError } { TCompilerError }
constructor TCompilerError.Create(ALevel: TCompilerErrorLevel; const AMessage: string; const ANode: IAstNode); constructor TCompilerError.Create(ALevel: TCompilerErrorLevel; const AMessage: string; const ANode: IAstNode);
@@ -1017,6 +1148,28 @@ function TAstNode.AsKeyword: IKeywordNode;
begin begin
Result := nil; Result := nil;
end; end;
function TAstNode.AsParameterList: IParameterList;
begin
Result := nil;
end;
function TAstNode.AsArgumentList: IArgumentList;
begin
Result := nil;
end;
function TAstNode.AsExpressionList: IExpressionList;
begin
Result := nil;
end;
function TAstNode.AsRecordFieldList: IRecordFieldList;
begin
Result := nil;
end;
function TAstNode.AsRecordField: IRecordFieldNode;
begin
Result := nil;
end;
function TAstNode.AsIfExpression: IIfExpressionNode; function TAstNode.AsIfExpression: IIfExpressionNode;
begin begin
Result := nil; Result := nil;
@@ -1125,6 +1278,136 @@ begin
Result := Self; Result := Self;
end; end;
{ TAstNodeList<T> }
constructor TAstNodeList<T>.Create(const AItems: TArray<T>; const AIdentity: IAstIdentity);
begin
inherited Create(AIdentity);
FItems := AItems;
end;
function TAstNodeList<T>.GetCount: Integer;
begin
Result := Length(FItems);
end;
function TAstNodeList<T>.GetEnumerator: TEnumerator<T>;
begin
Result := TEnumerator.Create(FItems);
end;
function TAstNodeList<T>.GetItem(Index: Integer): T;
begin
Result := FItems[Index];
end;
function TAstNodeList<T>.ToArray: TArray<T>;
begin
Result := FItems;
end;
{ TParameterList }
function TParameterList.Accept(const Visitor: IAstVisitor): TDataValue;
begin
Result := Visitor.VisitParameterList(Self);
end;
function TParameterList.AsParameterList: IParameterList;
begin
Result := Self;
end;
function TParameterList.GetKind: TAstNodeKind;
begin
Result := akParameterList;
end;
{ TArgumentList }
function TArgumentList.Accept(const Visitor: IAstVisitor): TDataValue;
begin
Result := Visitor.VisitArgumentList(Self);
end;
function TArgumentList.AsArgumentList: IArgumentList;
begin
Result := Self;
end;
function TArgumentList.GetKind: TAstNodeKind;
begin
Result := akArgumentList;
end;
{ TExpressionList }
function TExpressionList.Accept(const Visitor: IAstVisitor): TDataValue;
begin
Result := Visitor.VisitExpressionList(Self);
end;
function TExpressionList.AsExpressionList: IExpressionList;
begin
Result := Self;
end;
function TExpressionList.GetKind: TAstNodeKind;
begin
Result := akExpressionList;
end;
{ TRecordFieldNode }
constructor TRecordFieldNode.Create(const AKey: IKeywordNode; const AValue: IAstNode; const AIdentity: IAstIdentity);
begin
inherited Create(AIdentity);
FKey := AKey;
FValue := AValue;
end;
function TRecordFieldNode.Accept(const Visitor: IAstVisitor): TDataValue;
begin
Result := Visitor.VisitRecordField(Self);
end;
function TRecordFieldNode.AsRecordField: IRecordFieldNode;
begin
Result := Self;
end;
function TRecordFieldNode.GetKey: IKeywordNode;
begin
Result := FKey;
end;
function TRecordFieldNode.GetKind: TAstNodeKind;
begin
Result := akRecordField;
end;
function TRecordFieldNode.GetValue: IAstNode;
begin
Result := FValue;
end;
{ TRecordFieldList }
function TRecordFieldList.Accept(const Visitor: IAstVisitor): TDataValue;
begin
Result := Visitor.VisitRecordFieldList(Self);
end;
function TRecordFieldList.AsRecordFieldList: IRecordFieldList;
begin
Result := Self;
end;
function TRecordFieldList.GetKind: TAstNodeKind;
begin
Result := akRecordFieldList;
end;
{ TConstantNode } { TConstantNode }
constructor TConstantNode.Create(const AIdentity: IConstantIdentity; const AStaticType: IStaticType); constructor TConstantNode.Create(const AIdentity: IConstantIdentity; const AStaticType: IStaticType);
@@ -1328,7 +1611,7 @@ end;
{ TLambdaExpressionNode } { TLambdaExpressionNode }
constructor TLambdaExpressionNode.Create( constructor TLambdaExpressionNode.Create(
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode; const ABody: IAstNode;
const AStaticType: IStaticType; const AStaticType: IStaticType;
const ALayout: IScopeLayout; const ALayout: IScopeLayout;
@@ -1362,7 +1645,7 @@ function TLambdaExpressionNode.GetBody: IAstNode;
begin begin
Result := FBody; Result := FBody;
end; end;
function TLambdaExpressionNode.GetParameters: TArray<IIdentifierNode>; function TLambdaExpressionNode.GetParameters: IParameterList;
begin begin
Result := FParameters; Result := FParameters;
end; end;
@@ -1395,7 +1678,7 @@ end;
constructor TFunctionCallNode.Create( constructor TFunctionCallNode.Create(
const ACallee: IAstNode; const ACallee: IAstNode;
const AArguments: TArray<IAstNode>; const AArguments: IArgumentList;
const AStaticType: IStaticType; const AStaticType: IStaticType;
const AIsTailCall: Boolean; const AIsTailCall: Boolean;
const AStaticTarget: TDataValue.TFunc; const AStaticTarget: TDataValue.TFunc;
@@ -1425,7 +1708,7 @@ function TFunctionCallNode.GetCallee: IAstNode;
begin begin
Result := FCallee; Result := FCallee;
end; end;
function TFunctionCallNode.GetArguments: TArray<IAstNode>; function TFunctionCallNode.GetArguments: IArgumentList;
begin begin
Result := FArguments; Result := FArguments;
end; end;
@@ -1450,7 +1733,7 @@ end;
constructor TMacroDefinitionNode.Create( constructor TMacroDefinitionNode.Create(
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode; const ABody: IAstNode;
const AIdentity: IAstIdentity const AIdentity: IAstIdentity
); );
@@ -1475,7 +1758,7 @@ function TMacroDefinitionNode.GetName: IIdentifierNode;
begin begin
Result := FName; Result := FName;
end; end;
function TMacroDefinitionNode.GetParameters: TArray<IIdentifierNode>; function TMacroDefinitionNode.GetParameters: IParameterList;
begin begin
Result := FParameters; Result := FParameters;
end; end;
@@ -1606,7 +1889,7 @@ end;
{ TRecurNode } { TRecurNode }
constructor TRecurNode.Create(const AArguments: TArray<IAstNode>; const AStaticType: IStaticType; const AIdentity: IAstIdentity); constructor TRecurNode.Create(const AArguments: IArgumentList; const AStaticType: IStaticType; const AIdentity: IAstIdentity);
begin begin
inherited Create(AStaticType, AIdentity); inherited Create(AStaticType, AIdentity);
FArguments := AArguments; FArguments := AArguments;
@@ -1622,7 +1905,7 @@ begin
Result := Self; Result := Self;
end; end;
function TRecurNode.GetArguments: TArray<IAstNode>; function TRecurNode.GetArguments: IArgumentList;
begin begin
Result := FArguments; Result := FArguments;
end; end;
@@ -1633,18 +1916,10 @@ end;
{ TBlockExpressionNode } { TBlockExpressionNode }
constructor TBlockExpressionNode.Create( constructor TBlockExpressionNode.Create(const AExpressions: IExpressionList; const AStaticType: IStaticType; const AIdentity: IAstIdentity);
const AExpressions: array of IAstNode;
const AStaticType: IStaticType;
const AIdentity: IAstIdentity
);
var
i: Integer;
begin begin
inherited Create(AStaticType, AIdentity); inherited Create(AStaticType, AIdentity);
SetLength(FExpressions, Length(AExpressions)); FExpressions := AExpressions;
for i := 0 to High(AExpressions) do
FExpressions[i] := AExpressions[i];
end; end;
function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue; function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue;
@@ -1657,7 +1932,7 @@ begin
Result := Self; Result := Self;
end; end;
function TBlockExpressionNode.GetExpressions: TArray<IAstNode>; function TBlockExpressionNode.GetExpressions: IExpressionList;
begin begin
Result := FExpressions; Result := FExpressions;
end; end;
@@ -1813,7 +2088,7 @@ end;
{ TRecordLiteralNode } { TRecordLiteralNode }
constructor TRecordLiteralNode.Create( constructor TRecordLiteralNode.Create(
const AFields: TArray<TRecordFieldLiteral>; const AFields: IRecordFieldList;
const AScalarDef: IScalarRecordDefinition; const AScalarDef: IScalarRecordDefinition;
const AGenericDef: IGenericRecordDefinition; const AGenericDef: IGenericRecordDefinition;
const AStaticType: IStaticType; const AStaticType: IStaticType;
@@ -1836,7 +2111,7 @@ begin
Result := Self; Result := Self;
end; end;
function TRecordLiteralNode.GetFields: TArray<TRecordFieldLiteral>; function TRecordLiteralNode.GetFields: IRecordFieldList;
begin begin
Result := FFields; Result := FFields;
end; end;
@@ -1944,4 +2219,33 @@ begin
Result := akNop; Result := akNop;
end; end;
constructor TAstNodeList<T>.TEnumerator.Create(const AArray: TArray<T>);
begin
inherited Create;
FArray := AArray;
FIndex := -1;
end;
function TAstNodeList<T>.TEnumerator.DoGetCurrent: T;
begin
Result := Current;
end;
function TAstNodeList<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TAstNodeList<T>.TEnumerator.GetCurrent: T;
begin
Result := FArray[FIndex];
end;
function TAstNodeList<T>.TEnumerator.MoveNext: Boolean;
begin
Result := FIndex < High(FArray);
if Result then
Inc(FIndex);
end;
end. end.
+88 -83
View File
@@ -4,6 +4,7 @@ interface
uses uses
System.SysUtils, System.SysUtils,
Myc.Data.Value,
Myc.Ast.Nodes, Myc.Ast.Nodes,
Myc.Ast.Visitor; Myc.Ast.Visitor;
@@ -35,7 +36,7 @@ var
atom ::= number | string | identifier | keyword atom ::= number | string | identifier | keyword
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
(* ---- Reader-Macros (Syntactic Sugar) ---- *) (* ---- Reader-Macros (Syntactic Sugar) ---- *)
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
reader_macro ::= "'" expression (* (quote ...) *) reader_macro ::= "'" expression (* (quote ...) *)
| "`" expression (* (quasiquote ...) *) | "`" expression (* (quasiquote ...) *)
@@ -43,7 +44,7 @@ var
| "~@" expression (* (unquote-splicing ...) *) | "~@" expression (* (unquote-splicing ...) *)
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
(* ---- Lists (S-Expressions) ---- *) (* ---- Lists (S-Expressions) ---- *)
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
list ::= "(" list_content ")" list ::= "(" list_content ")"
list_content ::= special_form | function_call list_content ::= special_form | function_call
@@ -62,13 +63,13 @@ var
function_call ::= expression expression* function_call ::= expression expression*
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
(* ---- Parameter Lists and Records ---- *) (* ---- Parameter Lists and Records ---- *)
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
parameter_list ::= "[" identifier* "]" parameter_list ::= "[" identifier* "]"
record_literal ::= "{" (keyword expression)* "}" record_literal ::= "{" (keyword expression)* "}"
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
(* ---- Terminals (Lexer Tokens) ---- *) (* ---- Terminals (Lexer Tokens) ---- *)
(* ---------------------------------------------------------------------- *) (* ---------------------------------------------------------------------- *)
number ::= ["-"] digit+ ["." digit+] number ::= ["-"] digit+ ["." digit+]
string ::= '"' ( ? any char except \ or " ? | '\' ( '"' | '\' | 'n' | 'r' | 't' ) )* '"' string ::= '"' ( ? any char except \ or " ? | '\' ( '"' | '\' | 'n' | 'r' | 't' ) )* '"'
@@ -94,7 +95,6 @@ uses
System.Character, System.Character,
System.Math, System.Math,
Myc.Data.Scalar, Myc.Data.Scalar,
Myc.Data.Value,
Myc.Data.Keyword, Myc.Data.Keyword,
Myc.Ast, Myc.Ast,
Myc.Ast.Identities; Myc.Ast.Identities;
@@ -197,6 +197,14 @@ type
procedure VisitConstant(const Node: IConstantNode); override; procedure VisitConstant(const Node: IConstantNode); override;
procedure VisitIdentifier(const Node: IIdentifierNode); override; procedure VisitIdentifier(const Node: IIdentifierNode); override;
procedure VisitKeyword(const Node: IKeywordNode); override; procedure VisitKeyword(const Node: IKeywordNode); override;
// List Visitors
procedure VisitParameterList(const Node: IParameterList); override;
procedure VisitArgumentList(const Node: IArgumentList); override;
procedure VisitExpressionList(const Node: IExpressionList); override;
procedure VisitRecordFieldList(const Node: IRecordFieldList); override;
procedure VisitRecordField(const Node: IRecordFieldNode); override;
procedure VisitIfExpression(const Node: IIfExpressionNode); override; procedure VisitIfExpression(const Node: IIfExpressionNode); override;
procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); override; procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); override;
procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); override; procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); override;
@@ -315,7 +323,6 @@ var
startPos: Integer; startPos: Integer;
begin begin
startPos := FCurrentPos; startPos := FCurrentPos;
// Reader macro characters and comments are now also delimiters for identifiers.
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '{', '}', '''', '`', '~', ';']))) do while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '{', '}', '''', '`', '~', ';']))) do
Advance; Advance;
Result := Copy(FSource, startPos, FCurrentPos - startPos); Result := Copy(FSource, startPos, FCurrentPos - startPos);
@@ -544,7 +551,6 @@ begin
if FCurrentToken.Kind <> tkIdentifier then if FCurrentToken.Kind <> tkIdentifier then
Error('Syntax Error: Expected identifier in parameter list.'); Error('Syntax Error: Expected identifier in parameter list.');
// Pass Location to Factory
params.Add(TAst.Identifier(FCurrentToken.Text, FCurrentToken.GetLocation)); params.Add(TAst.Identifier(FCurrentToken.Text, FCurrentToken.GetLocation));
NextToken; NextToken;
end; end;
@@ -557,14 +563,15 @@ end;
function TParser.ParseRecordLiteral: IAstNode; function TParser.ParseRecordLiteral: IAstNode;
var var
fields: TList<TRecordFieldLiteral>; fields: TList<IRecordFieldNode>;
fieldName: string; fieldName: string;
fieldValue: IAstNode; fieldValue: IAstNode;
keyToken: TToken; keyToken: TToken;
keyNode: IKeywordNode;
begin begin
var startLoc := FCurrentToken.GetLocation; var startLoc := FCurrentToken.GetLocation;
Consume(tkLeftBrace); Consume(tkLeftBrace);
fields := TList<TRecordFieldLiteral>.Create; fields := TList<IRecordFieldNode>.Create;
try try
while FCurrentToken.Kind <> tkRightBrace do while FCurrentToken.Kind <> tkRightBrace do
begin begin
@@ -576,13 +583,15 @@ begin
keyToken := FCurrentToken; keyToken := FCurrentToken;
fieldName := FCurrentToken.Text; fieldName := FCurrentToken.Text;
keyNode := TAst.Keyword(fieldName, keyToken.GetLocation);
NextToken; NextToken;
if FCurrentToken.Kind = tkRightBrace then if FCurrentToken.Kind = tkRightBrace then
Error('Syntax Error: Missing value for key ' + fieldName + ' in record literal.'); Error('Syntax Error: Missing value for key ' + fieldName + ' in record literal.');
fieldValue := ParseExpression.Node; fieldValue := ParseExpression.Node;
fields.Add(TRecordFieldLiteral.Create(TAst.Keyword(fieldName, keyToken.GetLocation), fieldValue)); fields.Add(TAst.RecordField(keyNode, fieldValue, keyToken.GetLocation));
end; end;
Result := TAst.RecordLiteral(fields.ToArray, startLoc); Result := TAst.RecordLiteral(fields.ToArray, startLoc);
@@ -863,6 +872,63 @@ begin
Append(':' + Node.Value.Name); Append(':' + Node.Value.Name);
end; end;
// --- List Visitors Implementation ---
procedure TPrettyPrintVisitor.VisitParameterList(const Node: IParameterList);
begin
Append('[');
for var i := 0 to Node.Count - 1 do
begin
if i > 0 then
Append(' ');
Node[i].Accept(Self);
end;
Append(']');
end;
procedure TPrettyPrintVisitor.VisitArgumentList(const Node: IArgumentList);
begin
// Argument list does not have brackets of its own in Lisp call syntax
for var i := 0 to Node.Count - 1 do
begin
Append(' '); // Space before each argument
Node[i].Accept(Self);
end;
end;
procedure TPrettyPrintVisitor.VisitExpressionList(const Node: IExpressionList);
begin
Indent;
for var item in Node do
begin
NewLine;
item.Accept(Self);
end;
Unindent;
NewLine;
end;
procedure TPrettyPrintVisitor.VisitRecordFieldList(const Node: IRecordFieldList);
begin
Indent;
for var item in Node do
begin
NewLine;
item.Accept(Self);
end;
Unindent;
NewLine;
end;
procedure TPrettyPrintVisitor.VisitRecordField(const Node: IRecordFieldNode);
begin
Node.Key.Accept(Self);
Append(' ');
Node.Value.Accept(Self);
end;
// --- Node Visitors ---
procedure TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode); procedure TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode);
begin begin
Append('(if '); Append('(if ');
@@ -895,21 +961,9 @@ begin
end; end;
procedure TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode); procedure TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode);
var
sb: TStringBuilder;
begin begin
sb := TStringBuilder.Create; Append('(fn ');
try Node.Parameters.Accept(Self);
for var param in Node.Parameters do
sb.Append(param.Name + ' ');
if sb.Length > 0 then
sb.Remove(sb.Length - 1, 1);
Append('(fn [' + sb.ToString + ']');
finally
sb.Free;
end;
Indent; Indent;
NewLine; NewLine;
Node.Body.Accept(Self); Node.Body.Accept(Self);
@@ -919,21 +973,11 @@ begin
end; end;
procedure TPrettyPrintVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode); procedure TPrettyPrintVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode);
var
sb: TStringBuilder;
begin begin
sb := TStringBuilder.Create; Append('(defmacro ');
try Node.Name.Accept(Self);
for var param in Node.Parameters do Append(' ');
sb.Append(param.Name + ' '); Node.Parameters.Accept(Self);
if sb.Length > 0 then
sb.Remove(sb.Length - 1, 1);
Append('(defmacro ' + Node.Name.Name + ' [' + sb.ToString + ']');
finally
sb.Free;
end;
Indent; Indent;
NewLine; NewLine;
Node.Body.Accept(Self); Node.Body.Accept(Self);
@@ -961,10 +1005,8 @@ begin
end; end;
procedure TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode); procedure TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode);
var
arg: IAstNode;
begin begin
if (Node.Callee.Kind = akIdentifier) and (Node.Callee.AsIdentifier.Name = 'quote') and (Length(Node.Arguments) = 1) then if (Node.Callee.Kind = akIdentifier) and (Node.Callee.AsIdentifier.Name = 'quote') and (Node.Arguments.Count = 1) then
begin begin
Append(''''); Append('''');
Node.Arguments[0].Accept(Self); Node.Arguments[0].Accept(Self);
@@ -973,15 +1015,7 @@ begin
Append('('); Append('(');
Node.Callee.Accept(Self); Node.Callee.Accept(Self);
Node.Arguments.Accept(Self); // Prints separated by space
Indent;
for arg in Node.Arguments do
begin
Append(' ');
arg.Accept(Self);
end;
Unindent;
Append(')'); Append(')');
end; end;
@@ -991,34 +1025,16 @@ begin
end; end;
procedure TPrettyPrintVisitor.VisitRecurNode(const Node: IRecurNode); procedure TPrettyPrintVisitor.VisitRecurNode(const Node: IRecurNode);
var
arg: IAstNode;
begin begin
Append('(recur'); Append('(recur');
Indent; Node.Arguments.Accept(Self);
for arg in Node.Arguments do
begin
Append(' ');
arg.Accept(Self);
end;
Unindent;
Append(')'); Append(')');
end; end;
procedure TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode); procedure TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode);
var
expr: IAstNode;
begin begin
Append('(do'); Append('(do');
Indent; Node.Expressions.Accept(Self);
for expr in Node.Expressions do
begin
NewLine;
expr.Accept(Self);
end;
Unindent;
NewLine;
Append(')'); Append(')');
end; end;
@@ -1062,26 +1078,15 @@ begin
end; end;
procedure TPrettyPrintVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode); procedure TPrettyPrintVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode);
var
field: TRecordFieldLiteral;
begin begin
if Length(Node.Fields) = 0 then if Node.Fields.Count = 0 then
begin begin
Append('{}'); Append('{}');
exit; exit;
end; end;
Append('{'); Append('{');
Indent; Node.Fields.Accept(Self);
for field in Node.Fields do
begin
NewLine;
Append(':' + field.Key.Value.Name);
Append(' ');
field.Value.Accept(Self);
end;
Unindent;
NewLine;
Append('}'); Append('}');
end; end;
+310 -184
View File
@@ -9,7 +9,7 @@ uses
Myc.Ast, Myc.Ast,
Myc.Ast.Types, Myc.Ast.Types,
Myc.Ast.Nodes, Myc.Ast.Nodes,
Myc.Ast.Identities; // Needed for identity casting Myc.Ast.Identities;
type type
TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor) TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor)
@@ -18,6 +18,13 @@ type
function IAstVisitor.VisitConstant = DoVisitConstant; function IAstVisitor.VisitConstant = DoVisitConstant;
function IAstVisitor.VisitIdentifier = DoVisitIdentifier; function IAstVisitor.VisitIdentifier = DoVisitIdentifier;
function IAstVisitor.VisitKeyword = DoVisitKeyword; function IAstVisitor.VisitKeyword = DoVisitKeyword;
function IAstVisitor.VisitParameterList = DoVisitParameterList;
function IAstVisitor.VisitArgumentList = DoVisitArgumentList;
function IAstVisitor.VisitExpressionList = DoVisitExpressionList;
function IAstVisitor.VisitRecordFieldList = DoVisitRecordFieldList;
function IAstVisitor.VisitRecordField = DoVisitRecordField;
function IAstVisitor.VisitIfExpression = DoVisitIfExpression; function IAstVisitor.VisitIfExpression = DoVisitIfExpression;
function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression; function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression;
function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression; function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression;
@@ -43,6 +50,13 @@ type
function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitConstant(const Node: IConstantNode): TDataValue;
function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue;
function DoVisitKeyword(const Node: IKeywordNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue;
function DoVisitParameterList(const Node: IParameterList): TDataValue;
function DoVisitArgumentList(const Node: IArgumentList): TDataValue;
function DoVisitExpressionList(const Node: IExpressionList): TDataValue;
function DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
function DoVisitRecordField(const Node: IRecordFieldNode): TDataValue;
function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
@@ -71,6 +85,13 @@ type
function VisitConstant(const Node: IConstantNode): T; virtual; abstract; function VisitConstant(const Node: IConstantNode): T; virtual; abstract;
function VisitIdentifier(const Node: IIdentifierNode): T; virtual; abstract; function VisitIdentifier(const Node: IIdentifierNode): T; virtual; abstract;
function VisitKeyword(const Node: IKeywordNode): T; virtual; abstract; function VisitKeyword(const Node: IKeywordNode): T; virtual; abstract;
function VisitParameterList(const Node: IParameterList): T; virtual; abstract;
function VisitArgumentList(const Node: IArgumentList): T; virtual; abstract;
function VisitExpressionList(const Node: IExpressionList): T; virtual; abstract;
function VisitRecordFieldList(const Node: IRecordFieldList): T; virtual; abstract;
function VisitRecordField(const Node: IRecordFieldNode): T; virtual; abstract;
function VisitIfExpression(const Node: IIfExpressionNode): T; virtual; abstract; function VisitIfExpression(const Node: IIfExpressionNode): T; virtual; abstract;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): T; virtual; abstract; function VisitTernaryExpression(const Node: ITernaryExpressionNode): T; virtual; abstract;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): T; virtual; abstract; function VisitLambdaExpression(const Node: ILambdaExpressionNode): T; virtual; abstract;
@@ -95,12 +116,16 @@ type
TAstTransformer = class abstract(TAstVisitor<IAstNode>) TAstTransformer = class abstract(TAstVisitor<IAstNode>)
protected protected
function AcceptParameters(const Nodes: TArray<IIdentifierNode>): TArray<IIdentifierNode>;
function AcceptNodes(const Nodes: TArray<IAstNode>; const AcceptProc: TFunc<Integer, IAstNode, IAstNode> = nil): TArray<IAstNode>;
function VisitConstant(const Node: IConstantNode): IAstNode; override; function VisitConstant(const Node: IConstantNode): IAstNode; override;
function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override; function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override;
function VisitKeyword(const Node: IKeywordNode): IAstNode; override; function VisitKeyword(const Node: IKeywordNode): IAstNode; override;
function VisitParameterList(const Node: IParameterList): IAstNode; override;
function VisitArgumentList(const Node: IArgumentList): IAstNode; override;
function VisitExpressionList(const Node: IExpressionList): IAstNode; override;
function VisitRecordFieldList(const Node: IRecordFieldList): IAstNode; override;
function VisitRecordField(const Node: IRecordFieldNode): IAstNode; override;
function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override; function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
@@ -129,6 +154,11 @@ type
function IAstVisitor.VisitConstant = DoVisitConstant; function IAstVisitor.VisitConstant = DoVisitConstant;
function IAstVisitor.VisitIdentifier = DoVisitIdentifier; function IAstVisitor.VisitIdentifier = DoVisitIdentifier;
function IAstVisitor.VisitKeyword = DoVisitKeyword; function IAstVisitor.VisitKeyword = DoVisitKeyword;
function IAstVisitor.VisitParameterList = DoVisitParameterList;
function IAstVisitor.VisitArgumentList = DoVisitArgumentList;
function IAstVisitor.VisitExpressionList = DoVisitExpressionList;
function IAstVisitor.VisitRecordFieldList = DoVisitRecordFieldList;
function IAstVisitor.VisitRecordField = DoVisitRecordField;
function IAstVisitor.VisitIfExpression = DoVisitIfExpression; function IAstVisitor.VisitIfExpression = DoVisitIfExpression;
function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression; function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression;
function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression; function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression;
@@ -154,6 +184,11 @@ type
function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitConstant(const Node: IConstantNode): TDataValue;
function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue;
function DoVisitKeyword(const Node: IKeywordNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue;
function DoVisitParameterList(const Node: IParameterList): TDataValue;
function DoVisitArgumentList(const Node: IArgumentList): TDataValue;
function DoVisitExpressionList(const Node: IExpressionList): TDataValue;
function DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
function DoVisitRecordField(const Node: IRecordFieldNode): TDataValue;
function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
@@ -183,6 +218,13 @@ type
procedure VisitConstant(const Node: IConstantNode); virtual; procedure VisitConstant(const Node: IConstantNode); virtual;
procedure VisitIdentifier(const Node: IIdentifierNode); virtual; procedure VisitIdentifier(const Node: IIdentifierNode); virtual;
procedure VisitKeyword(const Node: IKeywordNode); virtual; procedure VisitKeyword(const Node: IKeywordNode); virtual;
procedure VisitParameterList(const Node: IParameterList); virtual;
procedure VisitArgumentList(const Node: IArgumentList); virtual;
procedure VisitExpressionList(const Node: IExpressionList); virtual;
procedure VisitRecordFieldList(const Node: IRecordFieldList); virtual;
procedure VisitRecordField(const Node: IRecordFieldNode); virtual;
procedure VisitIfExpression(const Node: IIfExpressionNode); virtual; procedure VisitIfExpression(const Node: IIfExpressionNode); virtual;
procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); virtual; procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); virtual;
procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); virtual; procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); virtual;
@@ -207,7 +249,7 @@ type
implementation implementation
{ TAstVisitor } { TAstVisitor<T> }
function TAstVisitor<T>.Accept(const Node: IAstNode): T; function TAstVisitor<T>.Accept(const Node: IAstNode): T;
begin begin
@@ -217,205 +259,122 @@ begin
Result := Default(T); Result := Default(T);
end; end;
{ TAstVisitor<T> }
function TAstVisitor<T>.DoVisitConstant(const Node: IConstantNode): TDataValue; function TAstVisitor<T>.DoVisitConstant(const Node: IConstantNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitConstant(Node)); Result := TDataValue.FromGeneric<T>(VisitConstant(Node));
end; end;
function TAstVisitor<T>.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function TAstVisitor<T>.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitIdentifier(Node)); Result := TDataValue.FromGeneric<T>(VisitIdentifier(Node));
end; end;
function TAstVisitor<T>.DoVisitKeyword(const Node: IKeywordNode): TDataValue; function TAstVisitor<T>.DoVisitKeyword(const Node: IKeywordNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitKeyword(Node)); Result := TDataValue.FromGeneric<T>(VisitKeyword(Node));
end; end;
function TAstVisitor<T>.DoVisitParameterList(const Node: IParameterList): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitParameterList(Node));
end;
function TAstVisitor<T>.DoVisitArgumentList(const Node: IArgumentList): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitArgumentList(Node));
end;
function TAstVisitor<T>.DoVisitExpressionList(const Node: IExpressionList): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitExpressionList(Node));
end;
function TAstVisitor<T>.DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitRecordFieldList(Node));
end;
function TAstVisitor<T>.DoVisitRecordField(const Node: IRecordFieldNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitRecordField(Node));
end;
function TAstVisitor<T>.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function TAstVisitor<T>.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitIfExpression(Node)); Result := TDataValue.FromGeneric<T>(VisitIfExpression(Node));
end; end;
function TAstVisitor<T>.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function TAstVisitor<T>.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitTernaryExpression(Node)); Result := TDataValue.FromGeneric<T>(VisitTernaryExpression(Node));
end; end;
function TAstVisitor<T>.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function TAstVisitor<T>.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitLambdaExpression(Node)); Result := TDataValue.FromGeneric<T>(VisitLambdaExpression(Node));
end; end;
function TAstVisitor<T>.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function TAstVisitor<T>.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitFunctionCall(Node)); Result := TDataValue.FromGeneric<T>(VisitFunctionCall(Node));
end; end;
function TAstVisitor<T>.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; function TAstVisitor<T>.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitMacroExpansionNode(Node)); Result := TDataValue.FromGeneric<T>(VisitMacroExpansionNode(Node));
end; end;
function TAstVisitor<T>.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function TAstVisitor<T>.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitBlockExpression(Node)); Result := TDataValue.FromGeneric<T>(VisitBlockExpression(Node));
end; end;
function TAstVisitor<T>.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function TAstVisitor<T>.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitVariableDeclaration(Node)); Result := TDataValue.FromGeneric<T>(VisitVariableDeclaration(Node));
end; end;
function TAstVisitor<T>.DoVisitAssignment(const Node: IAssignmentNode): TDataValue; function TAstVisitor<T>.DoVisitAssignment(const Node: IAssignmentNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitAssignment(Node)); Result := TDataValue.FromGeneric<T>(VisitAssignment(Node));
end; end;
function TAstVisitor<T>.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; function TAstVisitor<T>.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitMacroDefinition(Node)); Result := TDataValue.FromGeneric<T>(VisitMacroDefinition(Node));
end; end;
function TAstVisitor<T>.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; function TAstVisitor<T>.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitQuasiquote(Node)); Result := TDataValue.FromGeneric<T>(VisitQuasiquote(Node));
end; end;
function TAstVisitor<T>.DoVisitUnquote(const Node: IUnquoteNode): TDataValue; function TAstVisitor<T>.DoVisitUnquote(const Node: IUnquoteNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitUnquote(Node)); Result := TDataValue.FromGeneric<T>(VisitUnquote(Node));
end; end;
function TAstVisitor<T>.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; function TAstVisitor<T>.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitUnquoteSplicing(Node)); Result := TDataValue.FromGeneric<T>(VisitUnquoteSplicing(Node));
end; end;
function TAstVisitor<T>.DoVisitIndexer(const Node: IIndexerNode): TDataValue; function TAstVisitor<T>.DoVisitIndexer(const Node: IIndexerNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitIndexer(Node)); Result := TDataValue.FromGeneric<T>(VisitIndexer(Node));
end; end;
function TAstVisitor<T>.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; function TAstVisitor<T>.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitMemberAccess(Node)); Result := TDataValue.FromGeneric<T>(VisitMemberAccess(Node));
end; end;
function TAstVisitor<T>.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; function TAstVisitor<T>.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitRecordLiteral(Node)); Result := TDataValue.FromGeneric<T>(VisitRecordLiteral(Node));
end; end;
function TAstVisitor<T>.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; function TAstVisitor<T>.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitCreateSeries(Node)); Result := TDataValue.FromGeneric<T>(VisitCreateSeries(Node));
end; end;
function TAstVisitor<T>.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; function TAstVisitor<T>.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitAddSeriesItem(Node)); Result := TDataValue.FromGeneric<T>(VisitAddSeriesItem(Node));
end; end;
function TAstVisitor<T>.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; function TAstVisitor<T>.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitSeriesLength(Node)); Result := TDataValue.FromGeneric<T>(VisitSeriesLength(Node));
end; end;
function TAstVisitor<T>.DoVisitRecurNode(const Node: IRecurNode): TDataValue; function TAstVisitor<T>.DoVisitRecurNode(const Node: IRecurNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitRecurNode(Node)); Result := TDataValue.FromGeneric<T>(VisitRecurNode(Node));
end; end;
function TAstVisitor<T>.DoVisitNop(const Node: INopNode): TDataValue; function TAstVisitor<T>.DoVisitNop(const Node: INopNode): TDataValue;
begin begin
Result := TDataValue.FromGeneric<T>(VisitNop(Node)); Result := TDataValue.FromGeneric<T>(VisitNop(Node));
end; end;
function TAstTransformer.AcceptParameters(const Nodes: TArray<IIdentifierNode>): TArray<IIdentifierNode>; { TAstTransformer }
var
i: Integer;
hasChanged: Boolean;
newNode: IIdentifierNode;
begin
hasChanged := False;
SetLength(Result, Length(Nodes));
for i := 0 to High(Nodes) do
begin
newNode := Accept(Nodes[i]).AsIdentifier;
Result[i] := newNode;
if newNode <> Nodes[i] then
hasChanged := True;
end;
if not hasChanged then
Result := Nodes;
end;
function TAstTransformer.AcceptNodes(
const Nodes: TArray<IAstNode>;
const AcceptProc: TFunc<Integer, IAstNode, IAstNode> = nil
): TArray<IAstNode>;
var
i: Integer;
newNode: IAstNode;
newList: TList<IAstNode>;
hasChanged: Boolean;
begin
hasChanged := False;
newList := nil;
for i := 0 to High(Nodes) do
begin
if Assigned(AcceptProc) then
newNode := AcceptProc(i, Nodes[i])
else
newNode := Accept(Nodes[i]);
if not Assigned(newNode) then
begin
hasChanged := True;
if newList = nil then
begin
newList := TList<IAstNode>.Create;
for var j := 0 to i - 1 do
newList.Add(Nodes[j]);
end;
end
else
begin
if newNode <> Nodes[i] then
begin
hasChanged := True;
if newList = nil then
begin
newList := TList<IAstNode>.Create;
for var j := 0 to i - 1 do
newList.Add(Nodes[j]);
end;
newList.Add(newNode);
end
else
begin
if newList <> nil then
newList.Add(Nodes[i]);
end;
end;
end;
if not hasChanged then
Result := Nodes
else if newList <> nil then
begin
Result := newList.ToArray;
newList.Free;
end
else
Result := [];
end;
// --- Base Virtual Implementations --- // --- Base Virtual Implementations ---
@@ -423,21 +382,138 @@ function TAstTransformer.VisitConstant(const Node: IConstantNode): IAstNode;
begin begin
Result := Node; Result := Node;
end; end;
function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): IAstNode; function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): IAstNode;
begin begin
Result := Node; Result := Node;
end; end;
function TAstTransformer.VisitKeyword(const Node: IKeywordNode): IAstNode; function TAstTransformer.VisitKeyword(const Node: IKeywordNode): IAstNode;
begin begin
Result := Node; Result := Node;
end; end;
function TAstTransformer.VisitNop(const Node: INopNode): IAstNode; function TAstTransformer.VisitNop(const Node: INopNode): IAstNode;
begin begin
Result := Node; Result := Node;
end; end;
function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode;
begin
Result := Node;
end;
// --- List Transformations ---
function TAstTransformer.VisitParameterList(const Node: IParameterList): IAstNode;
var
hasChanged: Boolean;
newItems: TArray<IIdentifierNode>;
item, newItem: IIdentifierNode;
i: Integer;
begin
hasChanged := False;
SetLength(newItems, Node.Count);
for i := 0 to Node.Count - 1 do
begin
item := Node[i];
newItem := Accept(item).AsIdentifier;
newItems[i] := newItem;
if item <> newItem then
hasChanged := True;
end;
if not hasChanged then
Result := Node
else
// Manually reconstruct using concrete class to verify transformation
Result := TParameterList.Create(newItems, Node.Identity);
end;
function TAstTransformer.VisitArgumentList(const Node: IArgumentList): IAstNode;
var
hasChanged: Boolean;
newItems: TArray<IAstNode>;
item, newItem: IAstNode;
i: Integer;
begin
hasChanged := False;
SetLength(newItems, Node.Count);
for i := 0 to Node.Count - 1 do
begin
item := Node[i];
newItem := Accept(item);
newItems[i] := newItem;
if item <> newItem then
hasChanged := True;
end;
if not hasChanged then
Result := Node
else
Result := TArgumentList.Create(newItems, Node.Identity);
end;
function TAstTransformer.VisitExpressionList(const Node: IExpressionList): IAstNode;
var
hasChanged: Boolean;
newItems: TArray<IAstNode>;
item, newItem: IAstNode;
i: Integer;
begin
hasChanged := False;
SetLength(newItems, Node.Count);
for i := 0 to Node.Count - 1 do
begin
item := Node[i];
newItem := Accept(item);
newItems[i] := newItem;
if item <> newItem then
hasChanged := True;
end;
if not hasChanged then
Result := Node
else
Result := TExpressionList.Create(newItems, Node.Identity);
end;
function TAstTransformer.VisitRecordFieldList(const Node: IRecordFieldList): IAstNode;
var
hasChanged: Boolean;
newItems: TArray<IRecordFieldNode>;
item, newItem: IRecordFieldNode;
i: Integer;
begin
hasChanged := False;
SetLength(newItems, Node.Count);
for i := 0 to Node.Count - 1 do
begin
item := Node[i];
// Ensure we transform the field node itself via Accept to trigger VisitRecordField
newItem := Accept(item).AsRecordField;
newItems[i] := newItem;
if item <> newItem then
hasChanged := True;
end;
if not hasChanged then
Result := Node
else
Result := TRecordFieldList.Create(newItems, Node.Identity);
end;
function TAstTransformer.VisitRecordField(const Node: IRecordFieldNode): IAstNode;
var
newKey: IKeywordNode;
newValue: IAstNode;
begin
newKey := Accept(Node.Key).AsKeyword;
newValue := Accept(Node.Value);
if (newKey = Node.Key) and (newValue = Node.Value) then
Result := Node
else
Result := TAst.RecordField(newKey, newValue, Node.Identity.Location);
end;
// --- Node Transformations ---
function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): IAstNode;
var var
@@ -469,27 +545,29 @@ end;
function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
var var
newParams: TArray<IIdentifierNode>; newParams: IParameterList;
newBody: IAstNode; newBody: IAstNode;
begin begin
newParams := AcceptParameters(Node.Parameters); newParams := Accept(Node.Parameters).AsParameterList;
newBody := Accept(Node.Body); newBody := Accept(Node.Body);
if (newParams = Node.Parameters) and (newBody = Node.Body) then if (newParams = Node.Parameters) and (newBody = Node.Body) then
Result := Node Result := Node
else else
begin begin
// Rebuild Lambda via concrete constructor to keep Layout/Descriptor info
// TAst factory would reset layout info.
Result := Result :=
TAst.LambdaExpr( TLambdaExpressionNode.Create(
Node.Identity,
newParams, newParams,
newBody, newBody,
Node.StaticType,
Node.Layout, Node.Layout,
Node.Descriptor, Node.Descriptor,
Node.Upvalues, Node.Upvalues,
Node.HasNestedLambdas, Node.HasNestedLambdas,
Node.IsPure, Node.IsPure,
Node.StaticType Node.Identity
); );
end; end;
end; end;
@@ -497,17 +575,18 @@ end;
function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var var
newCallee: IAstNode; newCallee: IAstNode;
newArgs: TArray<IAstNode>; newArgs: IArgumentList;
begin begin
newCallee := Accept(Node.Callee); newCallee := Accept(Node.Callee);
newArgs := AcceptNodes(Node.Arguments); newArgs := Accept(Node.Arguments).AsArgumentList;
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then
Result := Node Result := Node
else else
begin begin
Result := Result :=
TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, Node.StaticTarget, Node.IsTargetPure); TFunctionCallNode
.Create(newCallee, newArgs, Node.StaticType, Node.IsTailCall, Node.StaticTarget, Node.IsTargetPure, Node.Identity);
end; end;
end; end;
@@ -519,20 +598,22 @@ begin
if newBody = Node.ExpandedBody then if newBody = Node.ExpandedBody then
exit(Node); exit(Node);
// Macro Expansion Nodes are structural, reuse identity // Macro Expansion Nodes are structural, reuse identity.
// Note: We don't visit the CallNode as it is the "source" which doesn't change during this transformation typically
Result := TAst.MacroExpansionNode(Node.Identity, Node.CallNode, newBody); Result := TAst.MacroExpansionNode(Node.Identity, Node.CallNode, newBody);
end; end;
function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
var var
newExprs: TArray<IAstNode>; newExprs: IExpressionList;
begin begin
newExprs := AcceptNodes(Node.Expressions); newExprs := Accept(Node.Expressions).AsExpressionList;
if newExprs = Node.Expressions then if newExprs = Node.Expressions then
Result := Node Result := Node
else else
Result := TAst.Block(Node.Identity, newExprs, Node.StaticType); // Rebuild manually to preserve type
Result := TBlockExpressionNode.Create(newExprs, Node.StaticType, Node.Identity);
end; end;
function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode;
@@ -598,15 +679,11 @@ function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode):
var var
newExpr: IAstNode; newExpr: IAstNode;
begin begin
// Note: Accept expects IAstNode, IQuasiquoteNode inherits from it.
newExpr := Accept(Node.Expression); newExpr := Accept(Node.Expression);
if (newExpr = Node.Expression) then if (newExpr = Node.Expression) then
Result := Node Result := Node
else else
// We need to ensure the transformed expression is still a Quasiquote,
// or we have to assume the transformer knows what it's doing.
// For safety, we cast back. If transformation changed type, this will fail fast.
Result := TAst.UnquoteSplicing(Node.Identity, newExpr.AsQuasiquote); Result := TAst.UnquoteSplicing(Node.Identity, newExpr.AsQuasiquote);
end; end;
@@ -639,35 +716,18 @@ end;
function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
var var
i: Integer; newFields: IRecordFieldList;
newFields: TArray<TRecordFieldLiteral>;
hasChanged: Boolean;
begin begin
SetLength(newFields, Length(Node.Fields)); newFields := Accept(Node.Fields).AsRecordFieldList;
hasChanged := False;
for i := 0 to High(Node.Fields) do if newFields = Node.Fields then
begin
// Keys are typically static, but we visit them anyway
newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword;
newFields[i].Value := Accept(Node.Fields[i].Value);
if (newFields[i].Key <> Node.Fields[i].Key) or (newFields[i].Value <> Node.Fields[i].Value) then
hasChanged := True;
end;
if not hasChanged then
Result := Node Result := Node
else else
begin begin
Result := TAst.RecordLiteral(Node.Identity, newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType); Result := TRecordLiteralNode.Create(newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType, Node.Identity);
end; end;
end; end;
function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode;
begin
Result := Node;
end;
function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode; function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode;
var var
newSeries: IIdentifierNode; newSeries: IIdentifierNode;
@@ -697,14 +757,14 @@ end;
function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode; function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode;
var var
newArgs: TArray<IAstNode>; newArgs: IArgumentList;
begin begin
newArgs := AcceptNodes(Node.Arguments); newArgs := Accept(Node.Arguments).AsArgumentList;
if newArgs = Node.Arguments then if newArgs = Node.Arguments then
Result := Node Result := Node
else else
Result := TAst.Recur(Node.Identity, newArgs, Node.StaticType); Result := TRecurNode.Create(newArgs, Node.StaticType, Node.Identity);
end; end;
{ TAstVisitor } { TAstVisitor }
@@ -717,17 +777,49 @@ end;
procedure TAstVisitor.VisitConstant(const Node: IConstantNode); procedure TAstVisitor.VisitConstant(const Node: IConstantNode);
begin begin
// Leaf node
end; end;
procedure TAstVisitor.VisitIdentifier(const Node: IIdentifierNode); procedure TAstVisitor.VisitIdentifier(const Node: IIdentifierNode);
begin begin
// Leaf node
end; end;
procedure TAstVisitor.VisitKeyword(const Node: IKeywordNode); procedure TAstVisitor.VisitKeyword(const Node: IKeywordNode);
begin begin
// Leaf node end;
procedure TAstVisitor.VisitNop(const Node: INopNode);
begin
end;
procedure TAstVisitor.VisitCreateSeries(const Node: ICreateSeriesNode);
begin
end;
// List visitors iterate children by default
procedure TAstVisitor.VisitParameterList(const Node: IParameterList);
begin
for var item in Node do
Accept(item);
end;
procedure TAstVisitor.VisitArgumentList(const Node: IArgumentList);
begin
for var item in Node do
Accept(item);
end;
procedure TAstVisitor.VisitExpressionList(const Node: IExpressionList);
begin
for var item in Node do
Accept(item);
end;
procedure TAstVisitor.VisitRecordFieldList(const Node: IRecordFieldList);
begin
for var item in Node do
Accept(item);
end;
procedure TAstVisitor.VisitRecordField(const Node: IRecordFieldNode);
begin
Accept(Node.Key);
Accept(Node.Value);
end; end;
procedure TAstVisitor.VisitIfExpression(const Node: IIfExpressionNode); procedure TAstVisitor.VisitIfExpression(const Node: IIfExpressionNode);
@@ -746,16 +838,14 @@ end;
procedure TAstVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode); procedure TAstVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode);
begin begin
for var param in Node.Parameters do Accept(Node.Parameters);
Accept(param);
Accept(Node.Body); Accept(Node.Body);
end; end;
procedure TAstVisitor.VisitFunctionCall(const Node: IFunctionCallNode); procedure TAstVisitor.VisitFunctionCall(const Node: IFunctionCallNode);
begin begin
Accept(Node.Callee); Accept(Node.Callee);
for var arg in Node.Arguments do Accept(Node.Arguments);
Accept(arg);
end; end;
procedure TAstVisitor.VisitMacroExpansionNode(const Node: IMacroExpansionNode); procedure TAstVisitor.VisitMacroExpansionNode(const Node: IMacroExpansionNode);
@@ -766,8 +856,7 @@ end;
procedure TAstVisitor.VisitBlockExpression(const Node: IBlockExpressionNode); procedure TAstVisitor.VisitBlockExpression(const Node: IBlockExpressionNode);
begin begin
for var expr in Node.Expressions do Accept(Node.Expressions);
Accept(expr);
end; end;
procedure TAstVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode); procedure TAstVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode);
@@ -785,8 +874,7 @@ end;
procedure TAstVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode); procedure TAstVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode);
begin begin
Accept(Node.Name); Accept(Node.Name);
for var param in Node.Parameters do Accept(Node.Parameters);
Accept(param);
Accept(Node.Body); Accept(Node.Body);
end; end;
@@ -819,16 +907,7 @@ end;
procedure TAstVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode); procedure TAstVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode);
begin begin
for var field in Node.Fields do Accept(Node.Fields);
begin
Accept(field.Key);
Accept(field.Value);
end;
end;
procedure TAstVisitor.VisitCreateSeries(const Node: ICreateSeriesNode);
begin
// Leaf node
end; end;
procedure TAstVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode); procedure TAstVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode);
@@ -845,130 +924,177 @@ end;
procedure TAstVisitor.VisitRecurNode(const Node: IRecurNode); procedure TAstVisitor.VisitRecurNode(const Node: IRecurNode);
begin begin
for var arg in Node.Arguments do Accept(Node.Arguments);
Accept(arg);
end; end;
procedure TAstVisitor.VisitNop(const Node: INopNode); // --- TAstVisitor (Non-Generic) Bridge Implementations ---
begin
// Leaf node
end;
// ... [Private Bridge Methods implementation remains unchanged] ...
function TAstVisitor.DoVisitConstant(const Node: IConstantNode): TDataValue; function TAstVisitor.DoVisitConstant(const Node: IConstantNode): TDataValue;
begin begin
VisitConstant(Node); VisitConstant(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function TAstVisitor.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin begin
VisitIdentifier(Node); VisitIdentifier(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitKeyword(const Node: IKeywordNode): TDataValue; function TAstVisitor.DoVisitKeyword(const Node: IKeywordNode): TDataValue;
begin begin
VisitKeyword(Node); VisitKeyword(Node);
Result := TDataValue.Void;
end;
function TAstVisitor.DoVisitParameterList(const Node: IParameterList): TDataValue;
begin
VisitParameterList(Node);
Result := TDataValue.Void;
end;
function TAstVisitor.DoVisitArgumentList(const Node: IArgumentList): TDataValue;
begin
VisitArgumentList(Node);
Result := TDataValue.Void;
end;
function TAstVisitor.DoVisitExpressionList(const Node: IExpressionList): TDataValue;
begin
VisitExpressionList(Node);
Result := TDataValue.Void;
end;
function TAstVisitor.DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
begin
VisitRecordFieldList(Node);
Result := TDataValue.Void;
end;
function TAstVisitor.DoVisitRecordField(const Node: IRecordFieldNode): TDataValue;
begin
VisitRecordField(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function TAstVisitor.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin begin
VisitIfExpression(Node); VisitIfExpression(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function TAstVisitor.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin begin
VisitTernaryExpression(Node); VisitTernaryExpression(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function TAstVisitor.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin begin
VisitLambdaExpression(Node); VisitLambdaExpression(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function TAstVisitor.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
begin begin
VisitFunctionCall(Node); VisitFunctionCall(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; function TAstVisitor.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
begin begin
VisitMacroExpansionNode(Node); VisitMacroExpansionNode(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function TAstVisitor.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
begin begin
VisitBlockExpression(Node); VisitBlockExpression(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function TAstVisitor.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin begin
VisitVariableDeclaration(Node); VisitVariableDeclaration(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitAssignment(const Node: IAssignmentNode): TDataValue; function TAstVisitor.DoVisitAssignment(const Node: IAssignmentNode): TDataValue;
begin begin
VisitAssignment(Node); VisitAssignment(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; function TAstVisitor.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin begin
VisitMacroDefinition(Node); VisitMacroDefinition(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; function TAstVisitor.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin begin
VisitQuasiquote(Node); VisitQuasiquote(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitUnquote(const Node: IUnquoteNode): TDataValue; function TAstVisitor.DoVisitUnquote(const Node: IUnquoteNode): TDataValue;
begin begin
VisitUnquote(Node); VisitUnquote(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; function TAstVisitor.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin begin
VisitUnquoteSplicing(Node); VisitUnquoteSplicing(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitIndexer(const Node: IIndexerNode): TDataValue; function TAstVisitor.DoVisitIndexer(const Node: IIndexerNode): TDataValue;
begin begin
VisitIndexer(Node); VisitIndexer(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; function TAstVisitor.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin begin
VisitMemberAccess(Node); VisitMemberAccess(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; function TAstVisitor.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
begin begin
VisitRecordLiteral(Node); VisitRecordLiteral(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; function TAstVisitor.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin begin
VisitCreateSeries(Node); VisitCreateSeries(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; function TAstVisitor.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin begin
VisitAddSeriesItem(Node); VisitAddSeriesItem(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; function TAstVisitor.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin begin
VisitSeriesLength(Node); VisitSeriesLength(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitRecurNode(const Node: IRecurNode): TDataValue; function TAstVisitor.DoVisitRecurNode(const Node: IRecurNode): TDataValue;
begin begin
VisitRecurNode(Node); VisitRecurNode(Node);
Result := TDataValue.Void;
end; end;
function TAstVisitor.DoVisitNop(const Node: INopNode): TDataValue; function TAstVisitor.DoVisitNop(const Node: INopNode): TDataValue;
begin begin
VisitNop(Node); VisitNop(Node);
Result := TDataValue.Void;
end; end;
end. end.
+71 -79
View File
@@ -124,7 +124,7 @@ type
class function LambdaExpr( class function LambdaExpr(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode; const ABody: IAstNode;
const ALayout: IScopeLayout = nil; const ALayout: IScopeLayout = nil;
const ADescriptor: IScopeDescriptor = nil; const ADescriptor: IScopeDescriptor = nil;
@@ -145,7 +145,7 @@ type
class function MacroDef( class function MacroDef(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode const ABody: IAstNode
): IMacroDefinitionNode; overload; static; ): IMacroDefinitionNode; overload; static;
@@ -175,7 +175,7 @@ type
class function FunctionCall( class function FunctionCall(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const ACallee: IAstNode; const ACallee: IAstNode;
const AArguments: TArray<IAstNode>; const AArguments: IArgumentList;
const AStaticType: IStaticType = nil; const AStaticType: IStaticType = nil;
const AIsTailCall: Boolean = False; const AIsTailCall: Boolean = False;
const AStaticTarget: TDataValue.TFunc = nil; const AStaticTarget: TDataValue.TFunc = nil;
@@ -183,7 +183,6 @@ type
): IFunctionCallNode; overload; static; ): IFunctionCallNode; overload; static;
// --- MACRO EXPANSION --- // --- MACRO EXPANSION ---
// Note: MacroExpansion is usually created during transformation, but conceptually it's a new node wrapping the original call.
class function MacroExpansionNode( class function MacroExpansionNode(
const AOriginalCallNode: IFunctionCallNode; const AOriginalCallNode: IFunctionCallNode;
const AExpandedBody: IAstNode; const AExpandedBody: IAstNode;
@@ -201,7 +200,7 @@ type
class function Recur( class function Recur(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AArguments: TArray<IAstNode>; const AArguments: IArgumentList;
const AStaticType: IStaticType = nil const AStaticType: IStaticType = nil
): IRecurNode; overload; static; ): IRecurNode; overload; static;
@@ -213,7 +212,7 @@ type
class function Block( class function Block(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AExpressions: TArray<IAstNode>; const AExpressions: IExpressionList;
const AStaticType: IStaticType = nil const AStaticType: IStaticType = nil
): IBlockExpressionNode; overload; static; ): IBlockExpressionNode; overload; static;
@@ -241,10 +240,6 @@ type
const AStaticType: IStaticType = nil const AStaticType: IStaticType = nil
): IAssignmentNode; overload; static; ): IAssignmentNode; overload; static;
// --- ASSIGN RESULT (Helper) ---
// Special case: Creates implicit nodes. No explicit "Transformation" overload needed as it maps to Assign.
class function AssignResult(const AValue: IAstNode; const Loc: ISourceLocation = nil): IAssignmentNode; static; deprecated;
// --- INDEXER --- // --- INDEXER ---
class function Indexer( class function Indexer(
const ABase: IAstNode; const ABase: IAstNode;
@@ -273,15 +268,28 @@ type
const AStaticType: IStaticType = nil const AStaticType: IStaticType = nil
): IMemberAccessNode; overload; static; ): IMemberAccessNode; overload; static;
// --- RECORD LITERAL --- // --- RECORD FIELD & LITERAL ---
class function RecordField(
const AKey: IKeywordNode;
const AValue: IAstNode;
const Loc: ISourceLocation = nil
): IRecordFieldNode; overload; static;
// Neuer Overload für Identitäts-Erhalt
class function RecordField(
const Identity: IAstIdentity;
const AKey: IKeywordNode;
const AValue: IAstNode
): IRecordFieldNode; overload; static;
class function RecordLiteral( class function RecordLiteral(
const AFields: TArray<TRecordFieldLiteral>; const AFields: TArray<IRecordFieldNode>;
const Loc: ISourceLocation = nil const Loc: ISourceLocation = nil
): IRecordLiteralNode; overload; static; ): IRecordLiteralNode; overload; static;
class function RecordLiteral( class function RecordLiteral(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AFields: TArray<TRecordFieldLiteral>; const AFields: IRecordFieldList;
const AScalarDefinition: IScalarRecordDefinition = nil; const AScalarDefinition: IScalarRecordDefinition = nil;
const AGenericDefinition: IGenericRecordDefinition = nil; const AGenericDefinition: IGenericRecordDefinition = nil;
const AStaticType: IStaticType = nil const AStaticType: IStaticType = nil
@@ -355,11 +363,9 @@ begin
end; end;
// ============================================================================= // =============================================================================
// IMPLEMENTATION: DATA NODES // DATA NODES
// ============================================================================= // =============================================================================
// --- Identifier ---
class function TAst.Identifier(const AName: string; const Loc: ISourceLocation): IIdentifierNode; class function TAst.Identifier(const AName: string; const Loc: ISourceLocation): IIdentifierNode;
begin begin
var id := TIdentities.Identifier(AName, Loc); var id := TIdentities.Identifier(AName, Loc);
@@ -381,8 +387,6 @@ begin
); );
end; end;
// --- Constant ---
class function TAst.Constant(const AValue: TDataValue; const Loc: ISourceLocation): IConstantNode; class function TAst.Constant(const AValue: TDataValue; const Loc: ISourceLocation): IConstantNode;
begin begin
var constType: IStaticType; var constType: IStaticType;
@@ -413,8 +417,6 @@ begin
); );
end; end;
// --- Keyword ---
class function TAst.Keyword(const AName: string; const Loc: ISourceLocation): IKeywordNode; class function TAst.Keyword(const AName: string; const Loc: ISourceLocation): IKeywordNode;
begin begin
var val := TKeywordRegistry.Intern(AName); var val := TKeywordRegistry.Intern(AName);
@@ -427,8 +429,6 @@ begin
Result := TKeywordNode.Create(Identity); Result := TKeywordNode.Create(Identity);
end; end;
// --- CreateSeries ---
class function TAst.CreateSeries(const ADefinition: String; const Loc: ISourceLocation): ICreateSeriesNode; class function TAst.CreateSeries(const ADefinition: String; const Loc: ISourceLocation): ICreateSeriesNode;
begin begin
var id := TIdentities.Definition(ADefinition, Loc); var id := TIdentities.Definition(ADefinition, Loc);
@@ -446,11 +446,9 @@ begin
end; end;
// ============================================================================= // =============================================================================
// IMPLEMENTATION: STRUCTURAL NODES // STRUCTURAL NODES
// ============================================================================= // =============================================================================
// --- NOP ---
class function TAst.Nop(const Loc: ISourceLocation): IAstNode; class function TAst.Nop(const Loc: ISourceLocation): IAstNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -467,8 +465,6 @@ begin
); );
end; end;
// --- IfExpr ---
class function TAst.IfExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): IIfExpressionNode; class function TAst.IfExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): IIfExpressionNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -492,8 +488,6 @@ begin
); );
end; end;
// --- TernaryExpr ---
class function TAst.TernaryExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): ITernaryExpressionNode; class function TAst.TernaryExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): ITernaryExpressionNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -517,21 +511,22 @@ begin
); );
end; end;
// --- LambdaExpr ---
class function TAst.LambdaExpr( class function TAst.LambdaExpr(
const AParameters: TArray<IIdentifierNode>; const AParameters: TArray<IIdentifierNode>;
const ABody: IAstNode; const ABody: IAstNode;
const Loc: ISourceLocation const Loc: ISourceLocation
): ILambdaExpressionNode; ): ILambdaExpressionNode;
begin begin
var listId := TIdentities.List('[', ']', ' ', Loc);
var paramList := TParameterList.Create(AParameters, listId);
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
Result := TLambdaExpressionNode.Create(AParameters, ABody, TTypes.Unknown, nil, nil, nil, False, False, id); Result := TLambdaExpressionNode.Create(paramList, ABody, TTypes.Unknown, nil, nil, nil, False, False, id);
end; end;
class function TAst.LambdaExpr( class function TAst.LambdaExpr(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode; const ABody: IAstNode;
const ALayout: IScopeLayout; const ALayout: IScopeLayout;
const ADescriptor: IScopeDescriptor; const ADescriptor: IScopeDescriptor;
@@ -555,8 +550,6 @@ begin
); );
end; end;
// --- MacroDef ---
class function TAst.MacroDef( class function TAst.MacroDef(
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: TArray<IIdentifierNode>;
@@ -564,22 +557,23 @@ class function TAst.MacroDef(
const Loc: ISourceLocation const Loc: ISourceLocation
): IMacroDefinitionNode; ): IMacroDefinitionNode;
begin begin
var listId := TIdentities.List('[', ']', ' ', Loc);
var paramList := TParameterList.Create(AParameters, listId);
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
Result := TMacroDefinitionNode.Create(AName, AParameters, ABody, id); Result := TMacroDefinitionNode.Create(AName, paramList, ABody, id);
end; end;
class function TAst.MacroDef( class function TAst.MacroDef(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: IParameterList;
const ABody: IAstNode const ABody: IAstNode
): IMacroDefinitionNode; ): IMacroDefinitionNode;
begin begin
Result := TMacroDefinitionNode.Create(AName, AParameters, ABody, Identity); Result := TMacroDefinitionNode.Create(AName, AParameters, ABody, Identity);
end; end;
// --- Quotes ---
class function TAst.Quasiquote(const AExpression: IAstNode; const Loc: ISourceLocation): IQuasiquoteNode; class function TAst.Quasiquote(const AExpression: IAstNode; const Loc: ISourceLocation): IQuasiquoteNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -613,22 +607,23 @@ begin
Result := TUnquoteSplicingNode.Create(AExpression, Identity); Result := TUnquoteSplicingNode.Create(AExpression, Identity);
end; end;
// --- FunctionCall ---
class function TAst.FunctionCall( class function TAst.FunctionCall(
const ACallee: IAstNode; const ACallee: IAstNode;
const AArguments: TArray<IAstNode>; const AArguments: TArray<IAstNode>;
const Loc: ISourceLocation const Loc: ISourceLocation
): IFunctionCallNode; ): IFunctionCallNode;
begin begin
var listId := TIdentities.List('', '', ' ', Loc);
var argList := TArgumentList.Create(AArguments, listId);
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
Result := TFunctionCallNode.Create(ACallee, AArguments, TTypes.Unknown, False, nil, False, id); Result := TFunctionCallNode.Create(ACallee, argList, TTypes.Unknown, False, nil, False, id);
end; end;
class function TAst.FunctionCall( class function TAst.FunctionCall(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const ACallee: IAstNode; const ACallee: IAstNode;
const AArguments: TArray<IAstNode>; const AArguments: IArgumentList;
const AStaticType: IStaticType; const AStaticType: IStaticType;
const AIsTailCall: Boolean; const AIsTailCall: Boolean;
const AStaticTarget: TDataValue.TFunc; const AStaticTarget: TDataValue.TFunc;
@@ -648,8 +643,6 @@ begin
); );
end; end;
// --- MacroExpansion ---
class function TAst.MacroExpansionNode( class function TAst.MacroExpansionNode(
const AOriginalCallNode: IFunctionCallNode; const AOriginalCallNode: IFunctionCallNode;
const AExpandedBody: IAstNode; const AExpandedBody: IAstNode;
@@ -669,8 +662,6 @@ begin
Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody, Identity); Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody, Identity);
end; end;
// --- Recur ---
class function TAst.Recur(const AArguments: array of IAstNode; const Loc: ISourceLocation): IRecurNode; class function TAst.Recur(const AArguments: array of IAstNode; const Loc: ISourceLocation): IRecurNode;
var var
args: TArray<IAstNode>; args: TArray<IAstNode>;
@@ -679,11 +670,15 @@ begin
SetLength(args, Length(AArguments)); SetLength(args, Length(AArguments));
for i := 0 to High(AArguments) do for i := 0 to High(AArguments) do
args[i] := AArguments[i]; args[i] := AArguments[i];
var listId := TIdentities.List('', '', ' ', Loc);
var argList := TArgumentList.Create(args, listId);
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
Result := TRecurNode.Create(args, TTypes.Void, id); Result := TRecurNode.Create(argList, TTypes.Void, id);
end; end;
class function TAst.Recur(const Identity: IAstIdentity; const AArguments: TArray<IAstNode>; const AStaticType: IStaticType): IRecurNode; class function TAst.Recur(const Identity: IAstIdentity; const AArguments: IArgumentList; const AStaticType: IStaticType): IRecurNode;
begin begin
Result := Result :=
TRecurNode.Create( TRecurNode.Create(
@@ -694,8 +689,6 @@ begin
); );
end; end;
// --- Block ---
class function TAst.Block(const AExpressions: array of IAstNode; const Loc: ISourceLocation): IBlockExpressionNode; class function TAst.Block(const AExpressions: array of IAstNode; const Loc: ISourceLocation): IBlockExpressionNode;
var var
exprs: TArray<IAstNode>; exprs: TArray<IAstNode>;
@@ -704,13 +697,17 @@ begin
SetLength(exprs, Length(AExpressions)); SetLength(exprs, Length(AExpressions));
for i := 0 to High(AExpressions) do for i := 0 to High(AExpressions) do
exprs[i] := AExpressions[i]; exprs[i] := AExpressions[i];
var listId := TIdentities.List('', '', ' ', Loc);
var exprList := TExpressionList.Create(exprs, listId);
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
Result := TBlockExpressionNode.Create(exprs, TTypes.Unknown, id); Result := TBlockExpressionNode.Create(exprList, TTypes.Unknown, id);
end; end;
class function TAst.Block( class function TAst.Block(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AExpressions: TArray<IAstNode>; const AExpressions: IExpressionList;
const AStaticType: IStaticType const AStaticType: IStaticType
): IBlockExpressionNode; ): IBlockExpressionNode;
begin begin
@@ -723,8 +720,6 @@ begin
); );
end; end;
// --- VarDecl ---
class function TAst.VarDecl(const AIdentifier: IAstNode; AInitializer: IAstNode; const Loc: ISourceLocation): IVariableDeclarationNode; class function TAst.VarDecl(const AIdentifier: IAstNode; AInitializer: IAstNode; const Loc: ISourceLocation): IVariableDeclarationNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -750,8 +745,6 @@ begin
); );
end; end;
// --- Assign ---
class function TAst.Assign(const ATarget, AValue: IAstNode; const Loc: ISourceLocation): IAssignmentNode; class function TAst.Assign(const ATarget, AValue: IAstNode; const Loc: ISourceLocation): IAssignmentNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -770,15 +763,6 @@ begin
); );
end; end;
class function TAst.AssignResult(const AValue: IAstNode; const Loc: ISourceLocation): IAssignmentNode;
begin
// Helper: Creates an implicit Identifier "Result" with new Identity
var resultId := TAst.Identifier('Result', Loc);
Result := TAst.Assign(resultId, AValue, Loc);
end;
// --- Indexer ---
class function TAst.Indexer(const ABase, AIndex: IAstNode; const Loc: ISourceLocation): IIndexerNode; class function TAst.Indexer(const ABase, AIndex: IAstNode; const Loc: ISourceLocation): IIndexerNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -797,8 +781,6 @@ begin
); );
end; end;
// --- MemberAccess ---
class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode; const Loc: ISourceLocation): IMemberAccessNode; class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode; const Loc: ISourceLocation): IMemberAccessNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
@@ -822,17 +804,29 @@ begin
); );
end; end;
// --- RecordLiteral --- class function TAst.RecordField(const AKey: IKeywordNode; const AValue: IAstNode; const Loc: ISourceLocation): IRecordFieldNode;
class function TAst.RecordLiteral(const AFields: TArray<TRecordFieldLiteral>; const Loc: ISourceLocation): IRecordLiteralNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
Result := TRecordLiteralNode.Create(AFields, nil, nil, TTypes.Unknown, id); Result := TRecordFieldNode.Create(AKey, AValue, id);
end;
class function TAst.RecordField(const Identity: IAstIdentity; const AKey: IKeywordNode; const AValue: IAstNode): IRecordFieldNode;
begin
Result := TRecordFieldNode.Create(AKey, AValue, Identity);
end;
class function TAst.RecordLiteral(const AFields: TArray<IRecordFieldNode>; const Loc: ISourceLocation): IRecordLiteralNode;
begin
var listId := TIdentities.List('{', '}', ' ', Loc);
var fieldList := TRecordFieldList.Create(AFields, listId);
var id := TIdentities.Structural(Loc);
Result := TRecordLiteralNode.Create(fieldList, nil, nil, TTypes.Unknown, id);
end; end;
class function TAst.RecordLiteral( class function TAst.RecordLiteral(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const AFields: TArray<TRecordFieldLiteral>; const AFields: IRecordFieldList;
const AScalarDefinition: IScalarRecordDefinition; const AScalarDefinition: IScalarRecordDefinition;
const AGenericDefinition: IGenericRecordDefinition; const AGenericDefinition: IGenericRecordDefinition;
const AStaticType: IStaticType const AStaticType: IStaticType
@@ -849,11 +843,10 @@ begin
); );
end; end;
// --- AddSeriesItem ---
class function TAst.AddSeriesItem( class function TAst.AddSeriesItem(
const ASeries: IIdentifierNode; const ASeries: IIdentifierNode;
const AValue, ALookback: IAstNode; const AValue: IAstNode;
const ALookback: IAstNode;
const Loc: ISourceLocation const Loc: ISourceLocation
): IAddSeriesItemNode; ): IAddSeriesItemNode;
begin begin
@@ -864,7 +857,8 @@ end;
class function TAst.AddSeriesItem( class function TAst.AddSeriesItem(
const Identity: IAstIdentity; const Identity: IAstIdentity;
const ASeries: IIdentifierNode; const ASeries: IIdentifierNode;
const AValue, ALookback: IAstNode; const AValue: IAstNode;
const ALookback: IAstNode;
const AStaticType: IStaticType const AStaticType: IStaticType
): IAddSeriesItemNode; ): IAddSeriesItemNode;
begin begin
@@ -879,8 +873,6 @@ begin
); );
end; end;
// --- SeriesLength ---
class function TAst.SeriesLength(const ASeries: IIdentifierNode; const Loc: ISourceLocation): ISeriesLengthNode; class function TAst.SeriesLength(const ASeries: IIdentifierNode; const Loc: ISourceLocation): ISeriesLengthNode;
begin begin
var id := TIdentities.Structural(Loc); var id := TIdentities.Structural(Loc);
+12 -5
View File
@@ -577,15 +577,22 @@ var
effBorderWidth: Single; effBorderWidth: Single;
effDash: TStrokeDash; effDash: TStrokeDash;
isHovering: Boolean; isHovering: Boolean;
isBlock: Boolean; shouldIgnoreHover: Boolean;
begin begin
inherited; inherited;
// Check if this is a block node (blocks should not highlight on hover) shouldIgnoreHover := False;
isBlock := Assigned(Node) and (Node.Kind = TAstNodeKind.akBlockExpression); if Assigned(Node) then
begin
case Node.Kind of
// Lists and Blocks should generally not be highlighted as a whole on hover
// because they are containers for other selectable items.
akBlockExpression, akParameterList, akArgumentList, akExpressionList, akRecordFieldList: shouldIgnoreHover := True;
end;
end;
// Determine hover state: active only if mouse is over AND it is not a block // Determine hover state: active only if mouse is over AND it is not a container type
isHovering := IsMouseOver and (not isBlock); isHovering := IsMouseOver and (not shouldIgnoreHover);
// 1. Set base values // 1. Set base values
if FFrameless then if FFrameless then
+294 -228
View File
@@ -20,7 +20,62 @@ uses
Myc.Fmx.AstEditor.Core; Myc.Fmx.AstEditor.Core;
type type
// --- Basic Handlers --- // --- Abstract List Base ---
// Handles layout, brackets (from Identity), and child iteration
TNodeListHandler<T: IAstNode> = class(TBaseNodeHandler<INodeList<T>>)
protected
FChildNodes: TList<TAstViewNode>;
function GetOrientation: TLayoutOrientation; virtual; abstract;
function GetAlignment: TLayoutAlignment; virtual;
public
constructor Create(const ANode: INodeList<T>);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; abstract;
end;
// --- Concrete List Handlers ---
TParameterListHandler = class(TNodeListHandler<IIdentifierNode>)
protected
function GetOrientation: TLayoutOrientation; override;
public
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
TArgumentListHandler = class(TNodeListHandler<IAstNode>)
protected
function GetOrientation: TLayoutOrientation; override;
public
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
TExpressionListHandler = class(TNodeListHandler<IAstNode>)
protected
function GetOrientation: TLayoutOrientation; override;
function GetAlignment: TLayoutAlignment; override;
public
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
TRecordFieldListHandler = class(TNodeListHandler<IRecordFieldNode>)
protected
function GetOrientation: TLayoutOrientation; override;
function GetAlignment: TLayoutAlignment; override;
public
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
// --- Node Handlers ---
TRecordFieldHandler = class(TBaseNodeHandler<IRecordFieldNode>)
private
FKeyLabel: TLabel;
FValueNode: TAstViewNode;
public
procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
TConstantNodeHandler = class(TBaseNodeHandler<IConstantNode>) TConstantNodeHandler = class(TBaseNodeHandler<IConstantNode>)
public public
@@ -50,10 +105,8 @@ type
TBlockExpressionNodeHandler = class(TBaseNodeHandler<IBlockExpressionNode>) TBlockExpressionNodeHandler = class(TBaseNodeHandler<IBlockExpressionNode>)
private private
FChildNodes: TList<TAstViewNode>; FExpressionsNode: TAstViewNode;
public public
constructor Create(const ANode: IBlockExpressionNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override; procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end; end;
@@ -82,11 +135,9 @@ type
TLambdaExpressionNodeHandler = class(TBaseNodeHandler<ILambdaExpressionNode>) TLambdaExpressionNodeHandler = class(TBaseNodeHandler<ILambdaExpressionNode>)
private private
FParamsNode: TAstViewNode;
FBodyNode: TAstViewNode; FBodyNode: TAstViewNode;
FParamLabels: TList<TLabel>;
public public
constructor Create(const ANode: ILambdaExpressionNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override; procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end; end;
@@ -94,10 +145,8 @@ type
TFunctionCallNodeHandler = class(TBaseNodeHandler<IFunctionCallNode>) TFunctionCallNodeHandler = class(TBaseNodeHandler<IFunctionCallNode>)
private private
FCalleeNode: TAstViewNode; FCalleeNode: TAstViewNode;
FArgumentNodes: TList<TAstViewNode>; FArgumentsNode: TAstViewNode;
public public
constructor Create(const ANode: IFunctionCallNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override; procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end; end;
@@ -112,10 +161,8 @@ type
TRecurNodeHandler = class(TBaseNodeHandler<IRecurNode>) TRecurNodeHandler = class(TBaseNodeHandler<IRecurNode>)
private private
FArgumentNodes: TList<TAstViewNode>; FArgumentsNode: TAstViewNode;
public public
constructor Create(const ANode: IRecurNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override; procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end; end;
@@ -142,6 +189,7 @@ type
TMacroDefinitionNodeHandler = class(TBaseNodeHandler<IMacroDefinitionNode>) TMacroDefinitionNodeHandler = class(TBaseNodeHandler<IMacroDefinitionNode>)
private private
FParamsNode: TAstViewNode;
FBodyNode: TAstViewNode; FBodyNode: TAstViewNode;
public public
procedure BuildUI(OwnerNode: TAstViewNode); override; procedure BuildUI(OwnerNode: TAstViewNode); override;
@@ -195,10 +243,8 @@ type
TRecordLiteralNodeHandler = class(TBaseNodeHandler<IRecordLiteralNode>) TRecordLiteralNodeHandler = class(TBaseNodeHandler<IRecordLiteralNode>)
private private
FFieldNodes: TDictionary<IKeyword, TAstViewNode>; FFieldsNode: TAstViewNode;
public public
constructor Create(const ANode: IRecordLiteralNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override; procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end; end;
@@ -228,6 +274,200 @@ type
implementation implementation
{ TNodeListHandler<T> }
constructor TNodeListHandler<T>.Create(const ANode: INodeList<T>);
begin
inherited Create(ANode);
FChildNodes := TList<TAstViewNode>.Create;
end;
destructor TNodeListHandler<T>.Destroy;
begin
FChildNodes.Free;
inherited;
end;
function TNodeListHandler<T>.GetAlignment: TLayoutAlignment;
begin
Result := TLayoutAlignment.laCenter;
end;
procedure TNodeListHandler<T>.BuildUI(OwnerNode: TAstViewNode);
var
visu: IAstVisualizer;
i: Integer;
childView: TAstViewNode;
openTok, closeTok, sep: string;
listId: IListIdentity;
begin
if (FNode.Identity <> nil) and (FNode.Identity.Kind = ikList) then
begin
listId := FNode.Identity.AsList;
openTok := listId.OpenToken;
closeTok := listId.CloseToken;
sep := listId.Separator;
end
else
begin
openTok := '';
closeTok := '';
sep := ' ';
end;
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
OwnerNode.BeginUpdate;
try
OwnerNode.Frameless := True;
OwnerNode.Orientation := GetOrientation;
OwnerNode.Alignment := GetAlignment;
if openTok <> '' then
OwnerNode.AddLabel(OwnerNode, openTok);
for i := 0 to FNode.Count - 1 do
begin
childView := visu.CallAccept(FNode[i]);
FChildNodes.Add(childView);
if (i < FNode.Count - 1) and (sep <> '') and (sep <> ' ') then
OwnerNode.AddLabel(OwnerNode, sep);
end;
if closeTok <> '' then
OwnerNode.AddLabel(OwnerNode, closeTok);
if FNode.Count = 0 then
begin
if (openTok = '') and (closeTok = '') then
begin
var lbl := OwnerNode.AddLabel(OwnerNode, 'ø');
lbl.Opacity := 0.5;
end;
end;
finally
OwnerNode.EndUpdate;
end;
end;
{ TParameterListHandler }
function TParameterListHandler.GetOrientation: TLayoutOrientation;
begin
Result := loHorizontal;
end;
function TParameterListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
arr: TArray<IIdentifierNode>;
i: Integer;
begin
SetLength(arr, FChildNodes.Count);
for i := 0 to FChildNodes.Count - 1 do
arr[i] := FChildNodes[i].CreateAst.AsIdentifier;
Result := TParameterList.Create(arr, FNode.Identity);
end;
{ TArgumentListHandler }
function TArgumentListHandler.GetOrientation: TLayoutOrientation;
begin
Result := loHorizontal;
end;
function TArgumentListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
arr: TArray<IAstNode>;
i: Integer;
begin
SetLength(arr, FChildNodes.Count);
for i := 0 to FChildNodes.Count - 1 do
arr[i] := FChildNodes[i].CreateAst;
Result := TArgumentList.Create(arr, FNode.Identity);
end;
{ TExpressionListHandler }
function TExpressionListHandler.GetOrientation: TLayoutOrientation;
begin
Result := loVertical;
end;
function TExpressionListHandler.GetAlignment: TLayoutAlignment;
begin
Result := laFlush;
end;
function TExpressionListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
arr: TArray<IAstNode>;
i: Integer;
begin
SetLength(arr, FChildNodes.Count);
for i := 0 to FChildNodes.Count - 1 do
arr[i] := FChildNodes[i].CreateAst;
Result := TExpressionList.Create(arr, FNode.Identity);
end;
{ TRecordFieldListHandler }
function TRecordFieldListHandler.GetOrientation: TLayoutOrientation;
begin
Result := loVertical;
end;
function TRecordFieldListHandler.GetAlignment: TLayoutAlignment;
begin
Result := laFlush;
end;
function TRecordFieldListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
arr: TArray<IRecordFieldNode>;
i: Integer;
begin
SetLength(arr, FChildNodes.Count);
for i := 0 to FChildNodes.Count - 1 do
arr[i] := FChildNodes[i].CreateAst.AsRecordField;
Result := TRecordFieldList.Create(arr, FNode.Identity);
end;
{ TRecordFieldHandler }
procedure TRecordFieldHandler.BuildUI(OwnerNode: TAstViewNode);
var
visu: IAstVisualizer;
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
OwnerNode.BeginUpdate;
try
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
OwnerNode.Alignment := laCenter;
FKeyLabel := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Key.Value.Name);
FKeyLabel.Font.Style := FKeyLabel.Font.Style + [TFontStyle.fsBold];
FKeyLabel.StyledSettings := FKeyLabel.StyledSettings - [TStyledSetting.FontColor];
FKeyLabel.FontColor := TAlphaColors.Mediumvioletred;
FValueNode := visu.CallAccept(FNode.Value);
finally
OwnerNode.EndUpdate;
end;
end;
function TRecordFieldHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
// Updated to use new Factory Overload to preserve Identity
Result := TAst.RecordField(FNode.Identity, FNode.Key, FValueNode.CreateAst);
end;
{ TConstantNodeHandler } { TConstantNodeHandler }
procedure TConstantNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TConstantNodeHandler.BuildUI(OwnerNode: TAstViewNode);
@@ -335,76 +575,31 @@ end;
{ TBlockExpressionNodeHandler } { TBlockExpressionNodeHandler }
constructor TBlockExpressionNodeHandler.Create(const ANode: IBlockExpressionNode);
begin
inherited Create(ANode);
FChildNodes := TList<TAstViewNode>.Create;
end;
destructor TBlockExpressionNodeHandler.Destroy;
begin
FChildNodes.Free;
inherited;
end;
procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var var
visu: IAstVisualizer; visu: IAstVisualizer;
childNode: TAstViewNode;
expr: IAstNode;
titleLabel: TLabel; titleLabel: TLabel;
i: Integer;
returnContainer: TAutoFitControl;
visuReturn: IAstVisualizer;
begin begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.BeginUpdate; OwnerNode.BeginUpdate;
try try
OwnerNode.Frameless := True; OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical; OwnerNode.Orientation := loVertical;
OwnerNode.Alignment := laFlush; OwnerNode.Alignment := laFlush;
for i := 0 to High(FNode.Expressions) do titleLabel := OwnerNode.AddLabel(OwnerNode, 'do');
begin titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold];
expr := FNode.Expressions[i];
if i = High(FNode.Expressions) then FExpressionsNode := visu.CallAccept(FNode.Expressions);
begin FExpressionsNode.Frameless := True;
returnContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
titleLabel := OwnerNode.AddLabel(returnContainer, 'return');
titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold];
visuReturn := OwnerNode.Visualizer.Clone(returnContainer, OwnerNode.Visualizer.ExprDepth + 1);
childNode := visuReturn.CallAccept(expr);
FChildNodes.Add(childNode);
end
else
begin
childNode := visu.CallAccept(expr);
FChildNodes.Add(childNode);
end;
end;
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
end; end;
end; end;
function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
exprs: TArray<IAstNode>;
childNode: TAstViewNode;
i: Integer;
begin begin
SetLength(exprs, FChildNodes.Count); Result := TAst.Block(FNode.Identity, FExpressionsNode.CreateAst.AsExpressionList, FNode.StaticType);
for i := 0 to FChildNodes.Count - 1 do
begin
childNode := FChildNodes[i];
if Assigned(childNode) then
exprs[i] := childNode.CreateAst
else
exprs[i] := TAst.Nop;
end;
Result := TAst.Block(FNode.Identity, exprs, FNode.StaticType);
end; end;
{ TIfExpressionNodeHandler } { TIfExpressionNodeHandler }
@@ -466,24 +661,11 @@ end;
{ TLambdaExpressionNodeHandler } { TLambdaExpressionNodeHandler }
constructor TLambdaExpressionNodeHandler.Create(const ANode: ILambdaExpressionNode);
begin
inherited Create(ANode);
FParamLabels := TList<TLabel>.Create;
end;
destructor TLambdaExpressionNodeHandler.Destroy;
begin
FParamLabels.Free;
inherited;
end;
procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var var
visu: IAstVisualizer; visu: IAstVisualizer;
titleContainer: TAutoFitControl; titleContainer: TAutoFitControl;
paramLabel: TLabel; lbl: TLabel;
i: Integer;
begin begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, 0); visu := OwnerNode.Visualizer.Clone(OwnerNode, 0);
OwnerNode.BeginUpdate; OwnerNode.BeginUpdate;
@@ -494,32 +676,16 @@ begin
OwnerNode.BackgroundColor := $090000ff; OwnerNode.BackgroundColor := $090000ff;
titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
lbl := OwnerNode.AddLabel(titleContainer, 'fn');
lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold];
paramLabel := OwnerNode.AddLabel(titleContainer, 'fn'); // Parameters: Delegate to List Handler
paramLabel.Font.Style := paramLabel.Font.Style + [TFontStyle.fsBold]; var paramVisu := visu.Clone(titleContainer, 0);
FParamLabels.Add(paramLabel); FParamsNode := paramVisu.CallAccept(FNode.Parameters);
paramLabel := OwnerNode.AddLabel(titleContainer, '(');
FParamLabels.Add(paramLabel);
for i := 0 to High(FNode.Parameters) do
begin
paramLabel := OwnerNode.AddLabel(titleContainer, FNode.Parameters[i].Name);
FParamLabels.Add(paramLabel);
if i < High(FNode.Parameters) then
begin
paramLabel := OwnerNode.AddLabel(titleContainer, ',');
FParamLabels.Add(paramLabel);
end;
end;
paramLabel := OwnerNode.AddLabel(titleContainer, ')');
FParamLabels.Add(paramLabel);
// Body
FBodyNode := visu.CallAccept(FNode.Body); FBodyNode := visu.CallAccept(FNode.Body);
FBodyNode.Frameless := False; FBodyNode.Frameless := False;
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
end; end;
@@ -530,7 +696,7 @@ begin
Result := Result :=
TAst.LambdaExpr( TAst.LambdaExpr(
FNode.Identity, FNode.Identity,
FNode.Parameters, FParamsNode.CreateAst.AsParameterList,
FBodyNode.CreateAst, FBodyNode.CreateAst,
FNode.Layout, FNode.Layout,
FNode.Descriptor, FNode.Descriptor,
@@ -543,23 +709,9 @@ end;
{ TFunctionCallNodeHandler } { TFunctionCallNodeHandler }
constructor TFunctionCallNodeHandler.Create(const ANode: IFunctionCallNode);
begin
inherited Create(ANode);
FArgumentNodes := TList<TAstViewNode>.Create;
end;
destructor TFunctionCallNodeHandler.Destroy;
begin
FArgumentNodes.Free;
inherited;
end;
procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var var
visu: IAstVisualizer; visu: IAstVisualizer;
i: Integer;
argNode: TAstViewNode;
callLabel: TLabel; callLabel: TLabel;
begin begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
@@ -573,37 +725,19 @@ begin
FCalleeNode := visu.CallAccept(FNode.Callee); FCalleeNode := visu.CallAccept(FNode.Callee);
if Length(FNode.Arguments) > 0 then FArgumentsNode := visu.CallAccept(FNode.Arguments);
begin
OwnerNode.AddLabel(OwnerNode, '(');
for i := 0 to High(FNode.Arguments) do
begin
argNode := visu.CallAccept(FNode.Arguments[i]);
FArgumentNodes.Add(argNode);
if i < High(FNode.Arguments) then
OwnerNode.AddLabel(OwnerNode, ',');
end;
OwnerNode.AddLabel(OwnerNode, ')');
end;
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
end; end;
end; end;
function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
args: TArray<IAstNode>;
i: Integer;
begin begin
SetLength(args, FArgumentNodes.Count);
for i := 0 to FArgumentNodes.Count - 1 do
args[i] := FArgumentNodes[i].CreateAst;
Result := Result :=
TAst.FunctionCall( TAst.FunctionCall(
FNode.Identity, FNode.Identity,
FCalleeNode.CreateAst, FCalleeNode.CreateAst,
args, FArgumentsNode.CreateAst.AsArgumentList,
FNode.StaticType, FNode.StaticType,
FNode.IsTailCall, FNode.IsTailCall,
FNode.StaticTarget, FNode.StaticTarget,
@@ -638,23 +772,9 @@ end;
{ TRecurNodeHandler } { TRecurNodeHandler }
constructor TRecurNodeHandler.Create(const ANode: IRecurNode);
begin
inherited Create(ANode);
FArgumentNodes := TList<TAstViewNode>.Create;
end;
destructor TRecurNodeHandler.Destroy;
begin
FArgumentNodes.Free;
inherited;
end;
procedure TRecurNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TRecurNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var var
visu: IAstVisualizer; visu: IAstVisualizer;
i: Integer;
argNode: TAstViewNode;
titleLabel: TLabel; titleLabel: TLabel;
begin begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
@@ -666,29 +786,15 @@ begin
titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur'); titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur');
titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold];
OwnerNode.AddLabel(OwnerNode, '('); FArgumentsNode := visu.CallAccept(FNode.Arguments);
for i := 0 to High(FNode.Arguments) do
begin
argNode := visu.CallAccept(FNode.Arguments[i]);
FArgumentNodes.Add(argNode);
if i < High(FNode.Arguments) then
OwnerNode.AddLabel(OwnerNode, ',');
end;
OwnerNode.AddLabel(OwnerNode, ')');
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
end; end;
end; end;
function TRecurNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; function TRecurNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
args: TArray<IAstNode>;
i: Integer;
begin begin
SetLength(args, FArgumentNodes.Count); Result := TAst.Recur(FNode.Identity, FArgumentsNode.CreateAst.AsArgumentList, FNode.StaticType);
for i := 0 to FArgumentNodes.Count - 1 do
args[i] := FArgumentNodes[i].CreateAst;
Result := TAst.Recur(FNode.Identity, args, FNode.StaticType);
end; end;
{ TVariableDeclarationNodeHandler } { TVariableDeclarationNodeHandler }
@@ -762,8 +868,7 @@ procedure TMacroDefinitionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var var
visu: IAstVisualizer; visu: IAstVisualizer;
titleLabel: TLabel; titleLabel: TLabel;
paramStr: string; titleContainer: TAutoFitControl;
i: Integer;
begin begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.BeginUpdate; OwnerNode.BeginUpdate;
@@ -771,17 +876,14 @@ begin
OwnerNode.Frameless := False; OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical; OwnerNode.Orientation := loVertical;
paramStr := ''; titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
for i := 0 to High(FNode.Parameters) do titleLabel := OwnerNode.AddLabel(titleContainer, 'Macro Def: ' + FNode.Name.Name);
begin
if i > 0 then
paramStr := paramStr + ', ';
paramStr := paramStr + FNode.Parameters[i].Name;
end;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Def: ' + FNode.Name.Name + ' (' + paramStr + ')');
titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold];
// Parameters List
var paramVisu := visu.Clone(titleContainer, visu.ExprDepth);
FParamsNode := paramVisu.CallAccept(FNode.Parameters);
FBodyNode := visu.CallAccept(FNode.Body); FBodyNode := visu.CallAccept(FNode.Body);
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
@@ -790,7 +892,7 @@ end;
function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin begin
Result := TAst.MacroDef(FNode.Identity, FNode.Name, FNode.Parameters, FBodyNode.CreateAst); Result := TAst.MacroDef(FNode.Identity, FNode.Name, FParamsNode.CreateAst.AsParameterList, FBodyNode.CreateAst);
end; end;
{ TQuasiquoteNodeHandler } { TQuasiquoteNodeHandler }
@@ -927,70 +1029,34 @@ end;
{ TRecordLiteralNodeHandler } { TRecordLiteralNodeHandler }
constructor TRecordLiteralNodeHandler.Create(const ANode: IRecordLiteralNode);
begin
inherited Create(ANode);
FFieldNodes := TDictionary<IKeyword, TAstViewNode>.Create;
end;
destructor TRecordLiteralNodeHandler.Destroy;
begin
FFieldNodes.Free;
inherited;
end;
procedure TRecordLiteralNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TRecordLiteralNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var var
field: TRecordFieldLiteral; visu: IAstVisualizer;
fieldContainer: TAutoFitControl;
valueNode: TAstViewNode;
keyLabel: TLabel;
begin begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.BeginUpdate; OwnerNode.BeginUpdate;
try try
OwnerNode.Frameless := False; OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical; OwnerNode.Orientation := loVertical;
OwnerNode.Alignment := laFlush; OwnerNode.Alignment := laFlush;
if Length(FNode.Fields) = 0 then // Delegate to RecordFieldList
begin FFieldsNode := visu.CallAccept(FNode.Fields);
OwnerNode.AddLabel(OwnerNode, '{}');
end
else
begin
for field in FNode.Fields do
begin
fieldContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
keyLabel := OwnerNode.AddLabel(fieldContainer, ':' + field.Key.Value.Name);
keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold];
keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor];
keyLabel.FontColor := TAlphaColors.Mediumvioletred;
valueNode := OwnerNode.Visualizer.Clone(fieldContainer, OwnerNode.Visualizer.ExprDepth + 1).CallAccept(field.Value);
FFieldNodes.Add(field.Key.Value, valueNode);
end;
end;
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
end; end;
end; end;
function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
fields: TArray<TRecordFieldLiteral>;
i: Integer;
valueNode: TAstViewNode;
pair: TPair<IKeyword, TAstViewNode>;
begin begin
SetLength(fields, FFieldNodes.Count); Result :=
i := 0; TAst.RecordLiteral(
for pair in FFieldNodes do FNode.Identity,
begin FFieldsNode.CreateAst.AsRecordFieldList,
valueNode := pair.Value; FNode.ScalarDefinition,
fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(pair.Key.Name), valueNode.CreateAst); FNode.GenericDefinition,
inc(i); FNode.StaticType
end; );
Result := TAst.RecordLiteral(FNode.Identity, fields, FNode.ScalarDefinition, FNode.GenericDefinition, FNode.StaticType);
end; end;
{ TCreateSeriesNodeHandler } { TCreateSeriesNodeHandler }
+37
View File
@@ -31,6 +31,14 @@ type
function VisitConstant(const Node: IConstantNode): TAstViewNode; override; function VisitConstant(const Node: IConstantNode): TAstViewNode; override;
function VisitIdentifier(const Node: IIdentifierNode): TAstViewNode; override; function VisitIdentifier(const Node: IIdentifierNode): TAstViewNode; override;
function VisitKeyword(const Node: IKeywordNode): TAstViewNode; override; function VisitKeyword(const Node: IKeywordNode): TAstViewNode; override;
// --- List Visitors (NEW) ---
function VisitParameterList(const Node: IParameterList): TAstViewNode; override;
function VisitArgumentList(const Node: IArgumentList): TAstViewNode; override;
function VisitExpressionList(const Node: IExpressionList): TAstViewNode; override;
function VisitRecordFieldList(const Node: IRecordFieldList): TAstViewNode; override;
function VisitRecordField(const Node: IRecordFieldNode): TAstViewNode; override;
function VisitIfExpression(const Node: IIfExpressionNode): TAstViewNode; override; function VisitIfExpression(const Node: IIfExpressionNode): TAstViewNode; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstViewNode; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstViewNode; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstViewNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstViewNode; override;
@@ -146,6 +154,35 @@ begin
Result := TAstViewNode.Create(Self, TKeywordNodeHandler.Create(Node)); Result := TAstViewNode.Create(Self, TKeywordNodeHandler.Create(Node));
end; end;
// --- List Visitors ---
function TAstVisualizer.VisitParameterList(const Node: IParameterList): TAstViewNode;
begin
Result := TAstViewNode.Create(Self, TParameterListHandler.Create(Node));
end;
function TAstVisualizer.VisitArgumentList(const Node: IArgumentList): TAstViewNode;
begin
Result := TAstViewNode.Create(Self, TArgumentListHandler.Create(Node));
end;
function TAstVisualizer.VisitExpressionList(const Node: IExpressionList): TAstViewNode;
begin
Result := TAstViewNode.Create(Self, TExpressionListHandler.Create(Node));
end;
function TAstVisualizer.VisitRecordFieldList(const Node: IRecordFieldList): TAstViewNode;
begin
Result := TAstViewNode.Create(Self, TRecordFieldListHandler.Create(Node));
end;
function TAstVisualizer.VisitRecordField(const Node: IRecordFieldNode): TAstViewNode;
begin
Result := TAstViewNode.Create(Self, TRecordFieldHandler.Create(Node));
end;
// --- Node Visitors ---
function TAstVisualizer.VisitBlockExpression(const Node: IBlockExpressionNode): TAstViewNode; function TAstVisualizer.VisitBlockExpression(const Node: IBlockExpressionNode): TAstViewNode;
begin begin
Result := TAstViewNode.Create(Self, TBlockExpressionNodeHandler.Create(Node)); Result := TAstViewNode.Create(Self, TBlockExpressionNodeHandler.Create(Node));
+30 -1
View File
@@ -110,6 +110,9 @@ constructor TAstWorkspace.Create(AOwner: TComponent);
begin begin
inherited; inherited;
FZoom := 1.0; FZoom := 1.0;
// Standard-Eigenschaften für einen Arbeitsbereich
ClipChildren := True;
HitTest := True;
end; end;
procedure TAstWorkspace.Build(const RootNode: IAstNode; const Position: TPointF); procedure TAstWorkspace.Build(const RootNode: IAstNode; const Position: TPointF);
@@ -117,10 +120,20 @@ var
visu: IAstVisualizer; visu: IAstVisualizer;
node: TAstViewNode; node: TAstViewNode;
begin begin
// Löscht alle bestehenden visuellen Knoten
DeleteChildren;
FConnections := nil;
if not Assigned(RootNode) then
Exit;
// Erstellt den Visualizer mit dem Workspace als Kontext
visu := TAstVisualizer.Create(Self, Self, 0); visu := TAstVisualizer.Create(Self, Self, 0);
node := visu.CallAccept(RootNode); node := visu.CallAccept(RootNode);
if Assigned(node) then if Assigned(node) then
begin
node.Position.Point := Position; node.Position.Point := Position;
end;
end; end;
procedure TAstWorkspace.DoDeleteChildren; procedure TAstWorkspace.DoDeleteChildren;
@@ -204,7 +217,12 @@ end;
procedure TAstWorkspace.DblClick; procedure TAstWorkspace.DblClick;
begin begin
inherited; inherited;
Zoom(1.0); // Reset Zoom/Pan on double click
FZoom := 1.0;
FPanning := TSizeF.Create(0, 0);
RecalcAbsolute;
RecalcUpdateRect;
Repaint;
end; end;
procedure TAstWorkspace.Paint; procedure TAstWorkspace.Paint;
@@ -224,6 +242,13 @@ begin
for connection in FConnections do for connection in FConnections do
begin begin
// Safety check if pins are still valid/visible
if (connection.OutputPin = nil)
or (connection.InputPin = nil)
or (connection.OutputPin.Root <> Self.Root)
or (connection.InputPin.Root <> Self.Root) then
continue;
pinCenter := TPointF.Create(connection.OutputPin.Width / 2, connection.OutputPin.Height / 2); pinCenter := TPointF.Create(connection.OutputPin.Width / 2, connection.OutputPin.Height / 2);
absoluteStart := connection.OutputPin.LocalToAbsolute(pinCenter); absoluteStart := connection.OutputPin.LocalToAbsolute(pinCenter);
@@ -263,9 +288,13 @@ begin
begin begin
mousePos := ScreenToLocal(mouseService.GetMousePos); mousePos := ScreenToLocal(mouseService.GetMousePos);
Factor := Max(0.2, Min(3.0, Factor)); Factor := Max(0.2, Min(3.0, Factor));
// Adjust panning to zoom towards mouse position
FPanning.cx := mousePos.X * (1 - Factor / FZoom) + FPanning.cx * (Factor / FZoom); FPanning.cx := mousePos.X * (1 - Factor / FZoom) + FPanning.cx * (Factor / FZoom);
FPanning.cy := mousePos.Y * (1 - Factor / FZoom) + FPanning.cy * (Factor / FZoom); FPanning.cy := mousePos.Y * (1 - Factor / FZoom) + FPanning.cy * (Factor / FZoom);
FZoom := Factor; FZoom := Factor;
RecalcAbsolute; RecalcAbsolute;
RecalcUpdateRect; RecalcUpdateRect;
Repaint; Repaint;
+10 -7
View File
@@ -209,7 +209,8 @@ begin
call := node.AsFunctionCall; call := node.AsFunctionCall;
Assert.AreEqual<string>('add', call.Callee.AsIdentifier.Name); Assert.AreEqual<string>('add', call.Callee.AsIdentifier.Name);
Assert.AreEqual<Integer>(2, Length(call.Arguments)); // Use Count instead of Length
Assert.AreEqual<Integer>(2, call.Arguments.Count);
Assert.AreEqual<Int64>(1, call.Arguments[0].AsConstant.Value.AsScalar.Value.AsInt64); Assert.AreEqual<Int64>(1, call.Arguments[0].AsConstant.Value.AsScalar.Value.AsInt64);
Assert.AreEqual<Int64>(2, call.Arguments[1].AsConstant.Value.AsScalar.Value.AsInt64); Assert.AreEqual<Int64>(2, call.Arguments[1].AsConstant.Value.AsScalar.Value.AsInt64);
@@ -225,7 +226,9 @@ begin
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akRecordLiteral, node.Kind); Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akRecordLiteral, node.Kind);
rec := node.AsRecordLiteral; rec := node.AsRecordLiteral;
Assert.AreEqual<Integer>(2, Length(rec.Fields)); Assert.AreEqual<Integer>(2, rec.Fields.Count);
// Accessing fields via IRecordFieldNode
Assert.AreEqual<string>('a', rec.Fields[0].Key.Value.Name); Assert.AreEqual<string>('a', rec.Fields[0].Key.Value.Name);
Assert.AreEqual<Int64>(1, rec.Fields[0].Value.AsConstant.Value.AsScalar.Value.AsInt64); Assert.AreEqual<Int64>(1, rec.Fields[0].Value.AsConstant.Value.AsScalar.Value.AsInt64);
@@ -239,7 +242,7 @@ var
begin begin
node := Parse('{}'); node := Parse('{}');
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akRecordLiteral, node.Kind); Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akRecordLiteral, node.Kind);
Assert.AreEqual<Integer>(0, Length(node.AsRecordLiteral.Fields)); Assert.AreEqual<Integer>(0, node.AsRecordLiteral.Fields.Count);
end; end;
// --- Special Forms --- // --- Special Forms ---
@@ -268,7 +271,7 @@ begin
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akLambdaExpression, node.Kind); Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akLambdaExpression, node.Kind);
lam := node.AsLambdaExpression; lam := node.AsLambdaExpression;
Assert.AreEqual<Integer>(2, Length(lam.Parameters)); Assert.AreEqual<Integer>(2, lam.Parameters.Count);
Assert.AreEqual<string>('a', lam.Parameters[0].Name); Assert.AreEqual<string>('a', lam.Parameters[0].Name);
Assert.AreEqual<string>('b', lam.Parameters[1].Name); Assert.AreEqual<string>('b', lam.Parameters[1].Name);
@@ -317,7 +320,7 @@ begin
call := node.AsFunctionCall; call := node.AsFunctionCall;
Assert.AreEqual<string>('quote', call.Callee.AsIdentifier.Name); Assert.AreEqual<string>('quote', call.Callee.AsIdentifier.Name);
Assert.AreEqual<Integer>(1, Length(call.Arguments)); Assert.AreEqual<Integer>(1, call.Arguments.Count);
Assert.AreEqual<string>('foo', call.Arguments[0].AsIdentifier.Name); Assert.AreEqual<string>('foo', call.Arguments[0].AsIdentifier.Name);
end; end;
@@ -343,8 +346,8 @@ procedure TTestMycAstScript.Parser_UnquoteSplicing_CreatesNode;
var var
node: IAstNode; node: IAstNode;
begin begin
// ~@x // Note: Parser requires backtick after ~@ currently due to cast in Myc.Ast.Script:
// There's something off here - we'll fix this later // Result.Node := TAst.UnquoteSplicing(expr.Node.AsQuasiquote, startLoc);
node := Parse('~@`x'); node := Parse('~@`x');
Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akUnquoteSplicing, node.Kind); Assert.AreEqual<TAstNodeKind>(TAstNodeKind.akUnquoteSplicing, node.Kind);
+2 -1
View File
@@ -104,7 +104,7 @@ end;
function TTestAstBinder.Unwrap(const Node: IAstNode): IAstNode; function TTestAstBinder.Unwrap(const Node: IAstNode): IAstNode;
begin begin
if (Node.Kind = akBlockExpression) and (Length(Node.AsBlockExpression.Expressions) = 1) then if (Node.Kind = akBlockExpression) and (Node.AsBlockExpression.Expressions.Count = 1) then
Result := Node.AsBlockExpression.Expressions[0] Result := Node.AsBlockExpression.Expressions[0]
else else
Result := Node; Result := Node;
@@ -236,6 +236,7 @@ begin
Assert.IsFalse(log.HasErrors); Assert.IsFalse(log.HasErrors);
lambda := bound.AsLambdaExpression; lambda := bound.AsLambdaExpression;
// Access parameter list via index
Assert.AreEqual<Integer>(1, lambda.Parameters[0].Address.SlotIndex); // Slot 0 is reserved for <self> Assert.AreEqual<Integer>(1, lambda.Parameters[0].Address.SlotIndex); // Slot 0 is reserved for <self>
end; end;