475 lines
15 KiB
ObjectPascal
475 lines
15 KiB
ObjectPascal
unit Myc.Fmx.AstEditor.Handlers.Control;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.UITypes,
|
|
System.Generics.Collections,
|
|
Myc.Ast,
|
|
Myc.Ast.Nodes,
|
|
Myc.Fmx.AstEditor.Render,
|
|
Myc.Fmx.AstEditor.Node;
|
|
|
|
type
|
|
// --- Logic & Control Flow ---
|
|
|
|
TBlockExpressionNodeHandler = class(TBaseNodeHandler<IBlockExpressionNode>)
|
|
private
|
|
FExpressionsNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
TIfExpressionNodeHandler = class(TBaseNodeHandler<IIfExpressionNode>)
|
|
private
|
|
FConditionNode: TAstViewNode;
|
|
FThenNode: TAstViewNode;
|
|
FElseNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
// Handles the 'cond' expression (multi-branch if/else)
|
|
TCondExpressionNodeHandler = class(TBaseNodeHandler<ICondExpressionNode>)
|
|
private
|
|
type
|
|
TBranchView = record
|
|
Condition: TAstViewNode;
|
|
Branch: TAstViewNode;
|
|
end;
|
|
private
|
|
FBranchNodes: TList<TBranchView>;
|
|
FElseNode: TAstViewNode;
|
|
public
|
|
constructor Create(const ANode: ICondExpressionNode);
|
|
destructor Destroy; override;
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
// --- Functions & Calls ---
|
|
|
|
TLambdaExpressionNodeHandler = class(TBaseNodeHandler<ILambdaExpressionNode>)
|
|
private
|
|
FParamsNode: TAstViewNode;
|
|
FBodyNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
TFunctionCallNodeHandler = class(TBaseNodeHandler<IFunctionCallNode>)
|
|
private
|
|
FCalleeNode: TAstViewNode;
|
|
FArgumentsNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
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>)
|
|
private
|
|
FExpandedBodyNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
TRecurNodeHandler = class(TBaseNodeHandler<IRecurNode>)
|
|
private
|
|
FArgumentsNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
TMacroDefinitionNodeHandler = class(TBaseNodeHandler<IMacroDefinitionNode>)
|
|
private
|
|
FParamsNode: TAstViewNode;
|
|
FBodyNode: TAstViewNode;
|
|
public
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TBlockExpressionNodeHandler }
|
|
|
|
procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
titleLabel: TTextNode;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
|
|
|
OwnerNode.Frameless := False;
|
|
OwnerNode.Orientation := loVertical;
|
|
OwnerNode.Alignment := laFlush;
|
|
|
|
titleLabel := OwnerNode.AddLabel(OwnerNode, 'do');
|
|
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
|
|
FExpressionsNode := visu.CallAccept(FNode.Expressions);
|
|
FExpressionsNode.Frameless := True;
|
|
end;
|
|
|
|
function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
begin
|
|
Result := TAst.Block(FNode.Identity, FExpressionsNode.CreateAst.AsTuple, FNode.StaticType);
|
|
end;
|
|
|
|
{ TIfExpressionNodeHandler }
|
|
|
|
procedure TIfExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
begin
|
|
OwnerNode.Frameless := False;
|
|
OwnerNode.Orientation := loVertical;
|
|
OwnerNode.Alignment := laFlush;
|
|
|
|
FConditionNode := OwnerNode.AddExpr(OwnerNode, 'if', FNode.Condition);
|
|
FThenNode := OwnerNode.AddExpr(OwnerNode, 'then', FNode.ThenBranch);
|
|
if Assigned(FNode.ElseBranch) then
|
|
FElseNode := OwnerNode.AddExpr(OwnerNode, 'else', FNode.ElseBranch);
|
|
end;
|
|
|
|
function TIfExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
var
|
|
elseAst: IAstNode;
|
|
begin
|
|
if Assigned(FElseNode) then
|
|
elseAst := FElseNode.CreateAst
|
|
else
|
|
elseAst := nil;
|
|
|
|
Result := TAst.IfExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, elseAst, FNode.StaticType);
|
|
end;
|
|
|
|
{ TCondExpressionNodeHandler }
|
|
|
|
constructor TCondExpressionNodeHandler.Create(const ANode: ICondExpressionNode);
|
|
begin
|
|
inherited Create(ANode);
|
|
FBranchNodes := TList<TBranchView>.Create;
|
|
end;
|
|
|
|
destructor TCondExpressionNodeHandler.Destroy;
|
|
begin
|
|
FBranchNodes.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCondExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
pair: TCondPair;
|
|
i: Integer;
|
|
row: TAutoFitLayout;
|
|
bv: TBranchView;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
|
|
|
OwnerNode.Frameless := False;
|
|
OwnerNode.Orientation := loVertical;
|
|
OwnerNode.Alignment := laFlush;
|
|
|
|
var title := OwnerNode.AddLabel(OwnerNode, '?');
|
|
title.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
|
|
for i := 0 to High(FNode.Pairs) do
|
|
begin
|
|
pair := FNode.Pairs[i];
|
|
row := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
|
|
row.Margins := TMarginRect.Create(0, 2, 0, 2);
|
|
|
|
bv.Condition := visu.CallAccept(pair.Condition);
|
|
row.AddChild(bv.Condition);
|
|
|
|
OwnerNode.AddLabel(row, '->');
|
|
bv.Branch := visu.CallAccept(pair.Branch);
|
|
row.AddChild(bv.Branch);
|
|
|
|
FBranchNodes.Add(bv);
|
|
end;
|
|
|
|
// Else Branch
|
|
var elseRow := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
|
|
elseRow.Margins := TMarginRect.Create(0, 4, 0, 0); // Extra spacing
|
|
OwnerNode.AddLabel(elseRow, 'else ->');
|
|
FElseNode := visu.CallAccept(FNode.ElseBranch);
|
|
// FIX: Use AddChild instead of assigning Parent directly
|
|
elseRow.AddChild(FElseNode);
|
|
end;
|
|
|
|
function TCondExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
var
|
|
newPairs: TArray<TCondPair>;
|
|
i: Integer;
|
|
begin
|
|
SetLength(newPairs, FBranchNodes.Count);
|
|
for i := 0 to FBranchNodes.Count - 1 do
|
|
begin
|
|
newPairs[i] := TCondPair.Create(FBranchNodes[i].Condition.CreateAst, FBranchNodes[i].Branch.CreateAst);
|
|
end;
|
|
|
|
Result := TAst.CondExpr(FNode.Identity, newPairs, FElseNode.CreateAst, FNode.StaticType);
|
|
end;
|
|
|
|
{ TLambdaExpressionNodeHandler }
|
|
|
|
procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
titleContainer: TAutoFitLayout;
|
|
lbl: TTextNode;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, 0);
|
|
|
|
OwnerNode.Frameless := False;
|
|
OwnerNode.Orientation := loVertical;
|
|
OwnerNode.Alignment := laFlush;
|
|
OwnerNode.BackgroundColor := $090000ff;
|
|
|
|
titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
|
|
lbl := OwnerNode.AddLabel(titleContainer, 'fn');
|
|
lbl.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
|
|
// Parameters: Delegate to List Handler
|
|
var paramVisu := visu.Clone(titleContainer, 0);
|
|
FParamsNode := paramVisu.CallAccept(FNode.Parameters);
|
|
|
|
// Body
|
|
FBodyNode := visu.CallAccept(FNode.Body);
|
|
FBodyNode.Frameless := False;
|
|
end;
|
|
|
|
function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
begin
|
|
Result :=
|
|
TAst.LambdaExpr(
|
|
FNode.Identity,
|
|
FParamsNode.CreateAst.AsTuple,
|
|
FBodyNode.CreateAst,
|
|
FNode.Layout,
|
|
FNode.Descriptor,
|
|
FNode.Upvalues,
|
|
FNode.HasNestedLambdas,
|
|
FNode.IsPure,
|
|
FNode.StaticType
|
|
);
|
|
end;
|
|
|
|
{ TFunctionCallNodeHandler }
|
|
|
|
procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
callLabel: TTextNode;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
|
|
|
OwnerNode.Frameless := True;
|
|
OwnerNode.Orientation := loHorizontal;
|
|
|
|
callLabel := OwnerNode.AddLabel(OwnerNode, 'call ');
|
|
callLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
|
|
FCalleeNode := visu.CallAccept(FNode.Callee);
|
|
|
|
FArgumentsNode := visu.CallAccept(FNode.Arguments);
|
|
end;
|
|
|
|
function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
begin
|
|
Result :=
|
|
TAst.FunctionCall(
|
|
FNode.Identity,
|
|
FCalleeNode.CreateAst,
|
|
FArgumentsNode.CreateAst.AsTuple,
|
|
FNode.StaticType,
|
|
FNode.IsTailCall,
|
|
FNode.StaticTarget,
|
|
FNode.IsTargetPure
|
|
);
|
|
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;
|
|
opLabel.Margins := TMarginRect.Create(2, 0, 2, 0);
|
|
|
|
argView := visu.CallAccept(FNode.Arguments.Items[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;
|
|
// Compact spacing for operators
|
|
opLabel.Margins := TMarginRect.Create(0, 0, 0, 0);
|
|
end;
|
|
|
|
argView := visu.CallAccept(FNode.Arguments.Items[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,
|
|
TAst.Tuple(FNode.Arguments.Identity, newArgs),
|
|
FNode.StaticType,
|
|
FNode.IsTailCall,
|
|
FNode.StaticTarget,
|
|
FNode.IsTargetPure
|
|
);
|
|
end;
|
|
|
|
{ TMacroExpansionNodeHandler }
|
|
|
|
procedure TMacroExpansionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
titleLabel: TTextNode;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
|
|
|
OwnerNode.Frameless := False;
|
|
OwnerNode.Orientation := loVertical;
|
|
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Expansion');
|
|
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
FExpandedBodyNode := visu.CallAccept(FNode.ExpandedBody);
|
|
end;
|
|
|
|
function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
begin
|
|
Result := TAst.MacroExpansionNode(FNode.Identity, FNode.CallNode, FExpandedBodyNode.CreateAst.AsTypedNode);
|
|
end;
|
|
|
|
{ TRecurNodeHandler }
|
|
|
|
procedure TRecurNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
titleLabel: TTextNode;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
|
|
|
OwnerNode.Frameless := True;
|
|
OwnerNode.Orientation := loHorizontal;
|
|
|
|
titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur');
|
|
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
|
|
FArgumentsNode := visu.CallAccept(FNode.Arguments);
|
|
end;
|
|
|
|
function TRecurNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
begin
|
|
Result := TAst.Recur(FNode.Identity, FArgumentsNode.CreateAst.AsTuple, FNode.StaticType);
|
|
end;
|
|
|
|
{ TMacroDefinitionNodeHandler }
|
|
|
|
procedure TMacroDefinitionNodeHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
titleLabel: TTextNode;
|
|
titleContainer: TAutoFitLayout;
|
|
begin
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
|
|
|
|
OwnerNode.Frameless := False;
|
|
OwnerNode.Orientation := loVertical;
|
|
|
|
titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter);
|
|
titleLabel := OwnerNode.AddLabel(titleContainer, 'Macro Def: ' + FNode.Name.Name);
|
|
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
|
|
|
|
// Parameters List
|
|
var paramVisu := visu.Clone(titleContainer, visu.ExprDepth);
|
|
FParamsNode := paramVisu.CallAccept(FNode.Parameters);
|
|
|
|
FBodyNode := visu.CallAccept(FNode.Body);
|
|
end;
|
|
|
|
function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
begin
|
|
Result := TAst.MacroDef(FNode.Identity, FNode.Name, FParamsNode.CreateAst.AsTuple, FBodyNode.CreateAst);
|
|
end;
|
|
|
|
end.
|