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) private FExpressionsNode: TAstViewNode; public procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; TIfExpressionNodeHandler = class(TBaseNodeHandler) 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) private type TBranchView = record Condition: TAstViewNode; Branch: TAstViewNode; end; private FBranchNodes: TList; 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) private FParamsNode: TAstViewNode; FBodyNode: TAstViewNode; public procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; TFunctionCallNodeHandler = class(TBaseNodeHandler) 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) private FArgumentNodes: TList; 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) private FExpandedBodyNode: TAstViewNode; public procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; TRecurNodeHandler = class(TBaseNodeHandler) private FArgumentsNode: TAstViewNode; public procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; TMacroDefinitionNodeHandler = class(TBaseNodeHandler) 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.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; 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.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; argsElements: TArray; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); OwnerNode.Frameless := True; OwnerNode.Orientation := loHorizontal; OwnerNode.Alignment := laCenter; // Optimization: Access Elements directly argsElements := FNode.Arguments.Elements; var argCount := Length(argsElements); if argCount = 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(argsElements[0]); FArgumentNodes.Add(argView); end else begin for i := 0 to argCount - 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(argsElements[i]); FArgumentNodes.Add(argView); end; end; if argCount = 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; 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.