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.Data.Keyword,
Myc.Ast.Nodes, Myc.Ast.Nodes,
Myc.Ast.Visitor, Myc.Ast.Visitor,
Myc.Ast.Identities, // NEU: Für Casts
Myc.Ast, Myc.Ast,
Myc.Fmx.AstEditor.Workspace; Myc.Fmx.AstEditor.Workspace;
@@ -597,7 +598,6 @@ begin
end; end;
// --- Visitor Implementations --- // --- Visitor Implementations ---
// *** CHANGED: All visitor methods now create a Handler and inject it into a generic TAuraNode ***
function TAstVisualizer.VisitConstant(const Node: IConstantNode): TAuraNode; function TAstVisualizer.VisitConstant(const Node: IConstantNode): TAuraNode;
var var
@@ -1298,7 +1298,8 @@ end;
function TConstantNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TConstantNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := FNode; // Literals are immutable // Reuse Identity: FNode.Identity.AsConstant
Result := TAst.Constant(FNode.Identity.AsConstant, FNode.StaticType);
end; end;
{ TIdentifierNodeHandler } { TIdentifierNodeHandler }
@@ -1327,9 +1328,8 @@ end;
function TIdentifierNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TIdentifierNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
// Find the label text if needed, but for now, re-use FNode's data // Reusing identity guarantees the same name and source location
// In a real editor, you'd fetch text from the TEdit/TLabel Result := TAst.Identifier(FNode.Identity.AsNamed, FNode.Address, FNode.StaticType);
Result := TAst.Identifier(FNode.Name);
end; end;
{ TKeywordNodeHandler } { TKeywordNodeHandler }
@@ -1360,7 +1360,7 @@ end;
function TKeywordNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TKeywordNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := FNode; // Keywords are literals Result := TAst.Keyword(FNode.Identity.AsKeyword);
end; end;
{ TBlockExpressionNodeHandler } { TBlockExpressionNodeHandler }
@@ -1439,7 +1439,9 @@ begin
else else
exprs[i] := TAst.Nop; // Use Nop as placeholder exprs[i] := TAst.Nop; // Use Nop as placeholder
end; end;
Result := TAst.Block(exprs);
// Reuse structural identity
Result := TAst.Block(FNode.Identity, exprs, FNode.StaticType);
end; end;
{ TIfExpressionNodeHandler } { TIfExpressionNodeHandler }
@@ -1482,7 +1484,7 @@ begin
else else
elseAst := nil; elseAst := nil;
Result := TAst.IfExpr(FConditionNode.CreateAst, FThenNode.CreateAst, elseAst); Result := TAst.IfExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, elseAst, FNode.StaticType);
end; end;
{ TTernaryExpressionNodeHandler } { TTernaryExpressionNodeHandler }
@@ -1519,7 +1521,7 @@ end;
function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.TernaryExpr(FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst); Result := TAst.TernaryExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst, FNode.StaticType);
end; end;
{ TLambdaExpressionNodeHandler } { TLambdaExpressionNodeHandler }
@@ -1592,7 +1594,19 @@ end;
function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
// Params are read from FNode (assuming they are not editable via UI labels for now) // 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; end;
{ TFunctionCallNodeHandler } { TFunctionCallNodeHandler }
@@ -1658,7 +1672,16 @@ begin
for i := 0 to FArgumentNodes.Count - 1 do for i := 0 to FArgumentNodes.Count - 1 do
args[i] := FArgumentNodes[i].CreateAst; 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; end;
{ TMacroExpansionNodeHandler } { TMacroExpansionNodeHandler }
@@ -1694,7 +1717,12 @@ end;
function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin 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; end;
{ TRecurNodeHandler } { TRecurNodeHandler }
@@ -1755,7 +1783,7 @@ begin
SetLength(args, FArgumentNodes.Count); SetLength(args, FArgumentNodes.Count);
for i := 0 to FArgumentNodes.Count - 1 do for i := 0 to FArgumentNodes.Count - 1 do
args[i] := FArgumentNodes[i].CreateAst; args[i] := FArgumentNodes[i].CreateAst;
Result := TAst.Recur(args); Result := TAst.Recur(FNode.Identity, args, FNode.StaticType);
end; end;
{ TVariableDeclarationNodeHandler } { TVariableDeclarationNodeHandler }
@@ -1806,7 +1834,7 @@ begin
initAst := FInitializerNode.CreateAst initAst := FInitializerNode.CreateAst
else else
initAst := nil; initAst := nil;
Result := TAst.VarDecl(FTargetNode.CreateAst, initAst); Result := TAst.VarDecl(FNode.Identity, FTargetNode.CreateAst, initAst, FNode.StaticType, FNode.IsBoxed);
end; end;
{ TAssignmentNodeHandler } { TAssignmentNodeHandler }
@@ -1841,7 +1869,7 @@ end;
function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.Assign(FTargetNode.CreateAst, FValueNode.CreateAst); Result := TAst.Assign(FNode.Identity, FTargetNode.CreateAst, FValueNode.CreateAst, FNode.StaticType);
end; end;
{ TMacroDefinitionNodeHandler } { TMacroDefinitionNodeHandler }
@@ -1889,7 +1917,16 @@ end;
function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin 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; end;
{ TQuasiquoteNodeHandler } { TQuasiquoteNodeHandler }
@@ -1925,7 +1962,7 @@ end;
function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.Quasiquote(FExpressionNode.CreateAst); Result := TAst.Quasiquote(FNode.Identity, FExpressionNode.CreateAst);
end; end;
{ TUnquoteNodeHandler } { TUnquoteNodeHandler }
@@ -1967,7 +2004,7 @@ end;
function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.Unquote(FExpressionNode.CreateAst); Result := TAst.Unquote(FNode.Identity, FExpressionNode.CreateAst);
end; end;
{ TUnquoteSplicingNodeHandler } { TUnquoteSplicingNodeHandler }
@@ -1995,6 +2032,7 @@ begin
OwnerNode.Orientation := loVertical; OwnerNode.Orientation := loVertical;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing'); titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing');
titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold];
// Note: FNode.Expression is a IQuasiquoteNode
FExpressionNode := visu.CallAccept(FNode.Expression); FExpressionNode := visu.CallAccept(FNode.Expression);
finally finally
OwnerNode.EndUpdate; OwnerNode.EndUpdate;
@@ -2003,7 +2041,9 @@ end;
function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin 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; end;
{ TIndexerNodeHandler } { TIndexerNodeHandler }
@@ -2039,7 +2079,7 @@ end;
function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.Indexer(FBaseNode.CreateAst, FIndexNode.CreateAst); Result := TAst.Indexer(FNode.Identity, FBaseNode.CreateAst, FIndexNode.CreateAst, FNode.StaticType);
end; end;
{ TMemberAccessNodeHandler } { TMemberAccessNodeHandler }
@@ -2074,7 +2114,8 @@ end;
function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin 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; end;
{ TRecordLiteralNodeHandler } { TRecordLiteralNodeHandler }
@@ -2145,10 +2186,12 @@ begin
for pair in FFieldNodes do for pair in FFieldNodes do
begin begin
valueNode := pair.Value; 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); fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(pair.Key.Name), valueNode.CreateAst);
inc(i); inc(i);
end; end;
Result := TAst.RecordLiteral(fields); Result := TAst.RecordLiteral(FNode.Identity, fields, FNode.ScalarDefinition, FNode.GenericDefinition, FNode.StaticType);
end; end;
{ TCreateSeriesNodeHandler } { TCreateSeriesNodeHandler }
@@ -2181,7 +2224,8 @@ end;
function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.CreateSeries(FNode.Definition); // Identity.AsDefinition check needed? Or trust CreateSeries overload
Result := TAst.CreateSeries(FNode.Identity.AsDefinition, FNode.StaticType);
end; end;
{ TAddSeriesItemNodeHandler } { TAddSeriesItemNodeHandler }
@@ -2229,7 +2273,21 @@ begin
else else
lookbackAst := nil; 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; end;
{ TSeriesLengthNodeHandler } { TSeriesLengthNodeHandler }
@@ -2262,7 +2320,7 @@ end;
function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode;
begin begin
Result := TAst.SeriesLength(TAst.Identifier(FNode.Series.Name)); Result := TAst.SeriesLength(FNode.Identity, FNode.Series, FNode.StaticType);
end; end;
{ TNopNodeHandler } { TNopNodeHandler }