AST Identities

This commit is contained in:
Michael Schimmel
2025-11-25 20:19:43 +01:00
parent 874c0d9adf
commit 65342c99aa
+83 -25
View File
@@ -21,6 +21,7 @@ uses
Myc.Data.Keyword,
Myc.Ast.Nodes,
Myc.Ast.Visitor,
Myc.Ast.Identities, // NEU: Für Casts
Myc.Ast,
Myc.Fmx.AstEditor.Workspace;
@@ -597,7 +598,6 @@ begin
end;
// --- Visitor Implementations ---
// *** CHANGED: All visitor methods now create a Handler and inject it into a generic TAuraNode ***
function TAstVisualizer.VisitConstant(const Node: IConstantNode): TAuraNode;
var
@@ -1298,7 +1298,8 @@ end;
function TConstantNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := FNode; // Literals are immutable
// Reuse Identity: FNode.Identity.AsConstant
Result := TAst.Constant(FNode.Identity.AsConstant, FNode.StaticType);
end;
{ TIdentifierNodeHandler }
@@ -1327,9 +1328,8 @@ end;
function TIdentifierNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
// Find the label text if needed, but for now, re-use FNode's data
// In a real editor, you'd fetch text from the TEdit/TLabel
Result := TAst.Identifier(FNode.Name);
// Reusing identity guarantees the same name and source location
Result := TAst.Identifier(FNode.Identity.AsNamed, FNode.Address, FNode.StaticType);
end;
{ TKeywordNodeHandler }
@@ -1360,7 +1360,7 @@ end;
function TKeywordNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := FNode; // Keywords are literals
Result := TAst.Keyword(FNode.Identity.AsKeyword);
end;
{ TBlockExpressionNodeHandler }
@@ -1439,7 +1439,9 @@ begin
else
exprs[i] := TAst.Nop; // Use Nop as placeholder
end;
Result := TAst.Block(exprs);
// Reuse structural identity
Result := TAst.Block(FNode.Identity, exprs, FNode.StaticType);
end;
{ TIfExpressionNodeHandler }
@@ -1482,7 +1484,7 @@ begin
else
elseAst := nil;
Result := TAst.IfExpr(FConditionNode.CreateAst, FThenNode.CreateAst, elseAst);
Result := TAst.IfExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, elseAst, FNode.StaticType);
end;
{ TTernaryExpressionNodeHandler }
@@ -1519,7 +1521,7 @@ end;
function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.TernaryExpr(FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst);
Result := TAst.TernaryExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst, FNode.StaticType);
end;
{ TLambdaExpressionNodeHandler }
@@ -1592,7 +1594,19 @@ end;
function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
// Params are read from FNode (assuming they are not editable via UI labels for now)
Result := TAst.LambdaExpr(FNode.Parameters, FBodyNode.CreateAst);
// Reuse Identity & Metadata
Result :=
TAst.LambdaExpr(
FNode.Identity,
FNode.Parameters,
FBodyNode.CreateAst,
FNode.Layout,
FNode.Descriptor,
FNode.Upvalues,
FNode.HasNestedLambdas,
FNode.IsPure,
FNode.StaticType
);
end;
{ TFunctionCallNodeHandler }
@@ -1658,7 +1672,16 @@ begin
for i := 0 to FArgumentNodes.Count - 1 do
args[i] := FArgumentNodes[i].CreateAst;
Result := TAst.FunctionCall(FCalleeNode.CreateAst, args);
Result :=
TAst.FunctionCall(
FNode.Identity,
FCalleeNode.CreateAst,
args,
FNode.StaticType,
FNode.IsTailCall,
FNode.StaticTarget,
FNode.IsTargetPure
);
end;
{ TMacroExpansionNodeHandler }
@@ -1694,7 +1717,12 @@ end;
function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.MacroExpansionNode(FNode.CallNode, FExpandedBodyNode.CreateAst.AsTypedNode);
Result :=
TAst.MacroExpansionNode(
FNode.Identity,
FNode.CallNode,
FExpandedBodyNode.CreateAst.AsTypedNode // TODO: Check if AsTypedNode is correct/safe
);
end;
{ TRecurNodeHandler }
@@ -1755,7 +1783,7 @@ begin
SetLength(args, FArgumentNodes.Count);
for i := 0 to FArgumentNodes.Count - 1 do
args[i] := FArgumentNodes[i].CreateAst;
Result := TAst.Recur(args);
Result := TAst.Recur(FNode.Identity, args, FNode.StaticType);
end;
{ TVariableDeclarationNodeHandler }
@@ -1806,7 +1834,7 @@ begin
initAst := FInitializerNode.CreateAst
else
initAst := nil;
Result := TAst.VarDecl(FTargetNode.CreateAst, initAst);
Result := TAst.VarDecl(FNode.Identity, FTargetNode.CreateAst, initAst, FNode.StaticType, FNode.IsBoxed);
end;
{ TAssignmentNodeHandler }
@@ -1841,7 +1869,7 @@ end;
function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.Assign(FTargetNode.CreateAst, FValueNode.CreateAst);
Result := TAst.Assign(FNode.Identity, FTargetNode.CreateAst, FValueNode.CreateAst, FNode.StaticType);
end;
{ TMacroDefinitionNodeHandler }
@@ -1889,7 +1917,16 @@ end;
function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.MacroDef(TAst.Identifier(FNode.Name.Name), FNode.Parameters, FBodyNode.CreateAst);
// Note: Identifier is recreated from raw name here, losing Location if we don't be careful.
// Ideally FNode.Name would be reused.
// For now, we reconstruct the MacroDef using the original identity and parameters.
Result :=
TAst.MacroDef(
FNode.Identity,
FNode.Name, // Reuse Identifier Node
FNode.Parameters, // Reuse Parameters
FBodyNode.CreateAst
);
end;
{ TQuasiquoteNodeHandler }
@@ -1925,7 +1962,7 @@ end;
function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.Quasiquote(FExpressionNode.CreateAst);
Result := TAst.Quasiquote(FNode.Identity, FExpressionNode.CreateAst);
end;
{ TUnquoteNodeHandler }
@@ -1967,7 +2004,7 @@ end;
function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.Unquote(FExpressionNode.CreateAst);
Result := TAst.Unquote(FNode.Identity, FExpressionNode.CreateAst);
end;
{ TUnquoteSplicingNodeHandler }
@@ -1995,6 +2032,7 @@ begin
OwnerNode.Orientation := loVertical;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing');
titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold];
// Note: FNode.Expression is a IQuasiquoteNode
FExpressionNode := visu.CallAccept(FNode.Expression);
finally
OwnerNode.EndUpdate;
@@ -2003,7 +2041,9 @@ end;
function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.UnquoteSplicing(FExpressionNode.CreateAst.AsQuasiquote);
// Note: We assume the child node is still a QuasiquoteNode. If user changed it to something else,
// this cast might fail or we need validation logic.
Result := TAst.UnquoteSplicing(FNode.Identity, FExpressionNode.CreateAst.AsQuasiquote);
end;
{ TIndexerNodeHandler }
@@ -2039,7 +2079,7 @@ end;
function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.Indexer(FBaseNode.CreateAst, FIndexNode.CreateAst);
Result := TAst.Indexer(FNode.Identity, FBaseNode.CreateAst, FIndexNode.CreateAst, FNode.StaticType);
end;
{ TMemberAccessNodeHandler }
@@ -2074,7 +2114,8 @@ end;
function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.MemberAccess(FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Value.Name));
// Reuse Identifier, Reuse Member Keyword (via TAst.Keyword with Identity)
Result := TAst.MemberAccess(FNode.Identity, FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Identity.AsKeyword), FNode.StaticType);
end;
{ TRecordLiteralNodeHandler }
@@ -2145,10 +2186,12 @@ begin
for pair in FFieldNodes do
begin
valueNode := pair.Value;
// Note: We construct a new keyword node here for the key, losing location unless we stored it.
// For simplicity, we use Creation Path for the Key, but Reuse Identity for the RecordLiteral itself.
fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(pair.Key.Name), valueNode.CreateAst);
inc(i);
end;
Result := TAst.RecordLiteral(fields);
Result := TAst.RecordLiteral(FNode.Identity, fields, FNode.ScalarDefinition, FNode.GenericDefinition, FNode.StaticType);
end;
{ TCreateSeriesNodeHandler }
@@ -2181,7 +2224,8 @@ end;
function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.CreateSeries(FNode.Definition);
// Identity.AsDefinition check needed? Or trust CreateSeries overload
Result := TAst.CreateSeries(FNode.Identity.AsDefinition, FNode.StaticType);
end;
{ TAddSeriesItemNodeHandler }
@@ -2229,7 +2273,21 @@ begin
else
lookbackAst := nil;
Result := TAst.AddSeriesItem(TAst.Identifier(FNode.Series.Name), FValueNode.CreateAst, lookbackAst);
// Reusing identifier identity requires access to it.
// Here we create a new identifier with same name but lose location of series ident.
// Optimization: FNode.Series is available, we can reuse it!
// Wait, TAst.AddSeriesItem takes IIdentifierNode. We can just reuse FNode.Series?
// Yes, if the series name is not editable in UI.
Result :=
TAst.AddSeriesItem(
FNode.Identity,
FNode.Series, // Reuse original Series Identifier Node
FValueNode.CreateAst,
lookbackAst,
FNode.StaticType
);
end;
{ TSeriesLengthNodeHandler }
@@ -2262,7 +2320,7 @@ end;
function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin
Result := TAst.SeriesLength(TAst.Identifier(FNode.Series.Name));
Result := TAst.SeriesLength(FNode.Identity, FNode.Series, FNode.StaticType);
end;
{ TNopNodeHandler }