Operator-Visualization in Ast editor

This commit is contained in:
Michael Schimmel
2025-12-06 19:48:15 +01:00
parent e0ceeeb7b0
commit f03d250d2b
2 changed files with 146 additions and 1 deletions
+100
View File
@@ -154,6 +154,18 @@ type
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end; end;
// Renders function calls as infix operators (e.g. "A + B" instead of "call + A B")
TOperatorCallHandler = class(TBaseNodeHandler<IFunctionCallNode>)
private
FArgumentNodes: TList<TAstViewNode>;
FCalleeName: string;
public
constructor Create(const ANode: IFunctionCallNode);
destructor Destroy; override;
procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
end;
TMacroExpansionNodeHandler = class(TBaseNodeHandler<IMacroExpansionNode>) TMacroExpansionNodeHandler = class(TBaseNodeHandler<IMacroExpansionNode>)
private private
FExpandedBodyNode: TAstViewNode; FExpandedBodyNode: TAstViewNode;
@@ -726,6 +738,94 @@ begin
); );
end; end;
{ TOperatorCallHandler }
constructor TOperatorCallHandler.Create(const ANode: IFunctionCallNode);
begin
inherited Create(ANode);
FArgumentNodes := TList<TAstViewNode>.Create;
if ANode.Callee.Kind = akIdentifier then
FCalleeName := ANode.Callee.AsIdentifier.Name
else if ANode.Callee.Kind = akKeyword then
FCalleeName := ANode.Callee.AsKeyword.Value.Name
else
FCalleeName := '?';
end;
destructor TOperatorCallHandler.Destroy;
begin
FArgumentNodes.Free;
inherited;
end;
procedure TOperatorCallHandler.BuildUI(OwnerNode: TAstViewNode);
var
visu: IAstVisualizer;
i: Integer;
argView: TAstViewNode;
opLabel: TTextNode;
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
OwnerNode.Alignment := laCenter;
if FNode.Arguments.Count = 1 then
begin
opLabel := OwnerNode.AddLabel(OwnerNode, FCalleeName);
opLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
opLabel.Color := TAlphaColors.Darkorange;
argView := visu.CallAccept(FNode.Arguments[0]);
FArgumentNodes.Add(argView);
end
else
begin
for i := 0 to FNode.Arguments.Count - 1 do
begin
if i > 0 then
begin
opLabel := OwnerNode.AddLabel(OwnerNode, ' ' + FCalleeName + ' ');
opLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
opLabel.Color := TAlphaColors.Darkorange;
opLabel.Margins := TMarginRect.Create(2, 2, 2, 2);
end;
argView := visu.CallAccept(FNode.Arguments[i]);
FArgumentNodes.Add(argView);
end;
end;
if FNode.Arguments.Count = 0 then
begin
opLabel := OwnerNode.AddLabel(OwnerNode, FCalleeName);
opLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
end;
end;
function TOperatorCallHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
var
newArgs: TArray<IAstNode>;
i: Integer;
begin
SetLength(newArgs, FArgumentNodes.Count);
for i := 0 to FArgumentNodes.Count - 1 do
newArgs[i] := FArgumentNodes[i].CreateAst;
Result :=
TAst.FunctionCall(
FNode.Identity,
FNode.Callee,
TArgumentList.Create(newArgs, FNode.Arguments.Identity),
FNode.StaticType,
FNode.IsTailCall,
FNode.StaticTarget,
FNode.IsTargetPure
);
end;
{ TMacroExpansionNodeHandler } { TMacroExpansionNodeHandler }
procedure TMacroExpansionNodeHandler.BuildUI(OwnerNode: TAstViewNode); procedure TMacroExpansionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
+46 -1
View File
@@ -87,6 +87,31 @@ type
implementation implementation
// Helper to identify standard operators
function IsStandardOperator(const Name: string): Boolean;
begin
// You can extend this list based on your RTL
Result :=
(Name = '+')
or (Name = '-')
or (Name = '*')
or (Name = '/')
or (Name = 'div')
or (Name = 'mod')
or (Name = '=')
or (Name = '<>')
or (Name = '<')
or (Name = '>')
or (Name = '<=')
or (Name = '>=')
or (Name = 'and')
or (Name = 'or')
or (Name = 'xor')
or (Name = 'not')
or (Name = 'shl')
or (Name = 'shr');
end;
{ TAstVisualizer } { TAstVisualizer }
constructor TAstVisualizer.Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer); constructor TAstVisualizer.Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer);
@@ -217,8 +242,28 @@ begin
end; end;
function TAstVisualizer.VisitFunctionCall(const Node: IFunctionCallNode): TAstViewNode; function TAstVisualizer.VisitFunctionCall(const Node: IFunctionCallNode): TAstViewNode;
var
calleeName: string;
isOp: Boolean;
begin begin
Result := TAstViewNode.Create(Self, TFunctionCallNodeHandler.Create(Node)); isOp := False;
// Check if callee is a simple identifier or keyword that matches an operator
if Node.Callee.Kind = akIdentifier then
begin
calleeName := Node.Callee.AsIdentifier.Name;
isOp := IsStandardOperator(calleeName);
end
else if Node.Callee.Kind = akKeyword then
begin
calleeName := Node.Callee.AsKeyword.Value.Name;
isOp := IsStandardOperator(calleeName);
end;
if isOp then
Result := TAstViewNode.Create(Self, TOperatorCallHandler.Create(Node))
else
Result := TAstViewNode.Create(Self, TFunctionCallNodeHandler.Create(Node));
end; end;
function TAstVisualizer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAstViewNode; function TAstVisualizer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAstViewNode;