217 lines
7.6 KiB
ObjectPascal
217 lines
7.6 KiB
ObjectPascal
unit Myc.Fmx.AstEditor.Handlers.Lists;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Generics.Collections,
|
|
Myc.Ast,
|
|
Myc.Ast.Nodes,
|
|
Myc.Fmx.AstEditor.Render,
|
|
Myc.Fmx.AstEditor.Node;
|
|
|
|
type
|
|
// Unified handler for all list-like structures (Parameters, Arguments, Vectors, etc.)
|
|
TTupleHandler = class(TBaseNodeHandler<ITupleNode>)
|
|
private
|
|
FChildNodes: TList<TAstViewNode>;
|
|
public
|
|
constructor Create(const ANode: ITupleNode);
|
|
destructor Destroy; override;
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
// --- Pipe Specific Lists (Not yet unified) ---
|
|
|
|
TPipeSelectorListHandler = class(TBaseNodeHandler<IPipeSelectorList>)
|
|
private
|
|
FChildNodes: TList<TAstViewNode>;
|
|
public
|
|
constructor Create(const ANode: IPipeSelectorList);
|
|
destructor Destroy; override;
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
TPipeInputListHandler = class(TBaseNodeHandler<IPipeInputList>)
|
|
private
|
|
FChildNodes: TList<TAstViewNode>;
|
|
public
|
|
constructor Create(const ANode: IPipeInputList);
|
|
destructor Destroy; override;
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TTupleHandler }
|
|
|
|
constructor TTupleHandler.Create(const ANode: ITupleNode);
|
|
begin
|
|
inherited Create(ANode);
|
|
FChildNodes := TList<TAstViewNode>.Create;
|
|
end;
|
|
|
|
destructor TTupleHandler.Destroy;
|
|
begin
|
|
FChildNodes.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TTupleHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
i: Integer;
|
|
childView: TAstViewNode;
|
|
begin
|
|
// Tuples act as lists, generally horizontal flow (like [1 2 3]).
|
|
// Note: If Vertical flow is needed (e.g. for Blocks), the Parent View should probably
|
|
// override this or we need a context flag. Defaulting to Horizontal.
|
|
|
|
OwnerNode.Frameless := True;
|
|
OwnerNode.Orientation := loHorizontal;
|
|
OwnerNode.Alignment := laCenter;
|
|
|
|
// Pass same depth, or increment? Usually lists don't indent depth unless they are blocks.
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
|
|
|
|
for i := 0 to FNode.Count - 1 do
|
|
begin
|
|
childView := visu.CallAccept(FNode.Items[i]);
|
|
FChildNodes.Add(childView);
|
|
end;
|
|
|
|
// Visual hint for empty tuples
|
|
if FNode.Count = 0 then
|
|
begin
|
|
var lbl := OwnerNode.AddLabel(OwnerNode, '[]');
|
|
lbl.FontSettings.FontColor := $FF808080;
|
|
end;
|
|
end;
|
|
|
|
function TTupleHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
var
|
|
newElements: TArray<IAstNode>;
|
|
i: Integer;
|
|
begin
|
|
SetLength(newElements, FChildNodes.Count);
|
|
for i := 0 to FChildNodes.Count - 1 do
|
|
newElements[i] := FChildNodes[i].CreateAst;
|
|
|
|
Result := TAst.Tuple(FNode.Identity, newElements, FNode.StaticType);
|
|
end;
|
|
|
|
{ TPipeSelectorListHandler }
|
|
|
|
constructor TPipeSelectorListHandler.Create(const ANode: IPipeSelectorList);
|
|
begin
|
|
inherited Create(ANode);
|
|
FChildNodes := TList<TAstViewNode>.Create;
|
|
end;
|
|
|
|
destructor TPipeSelectorListHandler.Destroy;
|
|
begin
|
|
FChildNodes.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TPipeSelectorListHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
item: IKeywordNode;
|
|
begin
|
|
OwnerNode.Frameless := True;
|
|
OwnerNode.Orientation := loHorizontal;
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
|
|
|
|
for item in FNode do
|
|
FChildNodes.Add(visu.CallAccept(item));
|
|
end;
|
|
|
|
function TPipeSelectorListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
var
|
|
newItems: TArray<IKeywordNode>;
|
|
i: Integer;
|
|
begin
|
|
SetLength(newItems, FChildNodes.Count);
|
|
for i := 0 to FChildNodes.Count - 1 do
|
|
newItems[i] := FChildNodes[i].CreateAst.AsKeyword;
|
|
|
|
Result := TAst.PipeSelectorList(newItems, FNode.Identity.Location);
|
|
end;
|
|
|
|
{ TPipeInputListHandler }
|
|
|
|
constructor TPipeInputListHandler.Create(const ANode: IPipeInputList);
|
|
begin
|
|
inherited Create(ANode);
|
|
FChildNodes := TList<TAstViewNode>.Create;
|
|
end;
|
|
|
|
destructor TPipeInputListHandler.Destroy;
|
|
begin
|
|
FChildNodes.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TPipeInputListHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
item: IPipeInputNode;
|
|
begin
|
|
OwnerNode.Frameless := True;
|
|
OwnerNode.Orientation := loHorizontal; // Inputs flow horizontally in pipe def
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
|
|
|
|
for item in FNode do
|
|
FChildNodes.Add(visu.CallAccept(item));
|
|
end;
|
|
|
|
function TPipeInputListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
|
|
var
|
|
newItems: TArray<IPipeInputNode>;
|
|
i: Integer;
|
|
begin
|
|
SetLength(newItems, FChildNodes.Count);
|
|
for i := 0 to FChildNodes.Count - 1 do
|
|
newItems[i] := FChildNodes[i].CreateAst.AsPipeInput;
|
|
|
|
Result := TAst.Pipe(newItems, nil, FNode.Identity.Location).AsPipe.Inputs; // Hack to reuse factory logic or create direct?
|
|
// Better: Since TAst doesn't expose PipeInputList factory directly (it's internal to Pipe factory),
|
|
// we should really rely on the PipeNode handler to reconstruct the list.
|
|
// However, if we must return a node here:
|
|
// We assume TAst has a factory or we create the implementation directly if exposed.
|
|
// Since we don't have direct access to TPipeInputList.Create here (it is in implementation of Nodes),
|
|
// we use a workaround via the generic TAst.Pipe factory which takes an array.
|
|
|
|
// Actually, looking at TAst.Pipe overload that takes TArray<IPipeInputNode>, it creates the list internally.
|
|
// But here we need to return the list object itself.
|
|
// Since this method is likely called by the PipeHandler to reconstruct its children,
|
|
// the PipeHandler usually calls CreateAst on the child nodes.
|
|
// If the ViewNode for the list returns the list AST, we are good.
|
|
// BUT: We cannot instantiate the list implementation here easily without the factory exposing it.
|
|
|
|
// FIX: We need to expose a factory for PipeInputList in TAst or make the implementation accessible.
|
|
// For this Proof of Concept, I will assume TAst has a method or we added one.
|
|
// Let's verify Myc.Ast.pas ... It doesn't have PipeInputList factory public.
|
|
// It has: class function Pipe(const AInputs: TArray<IPipeInputNode> ...
|
|
|
|
// Workaround: We cast to TAstNodeList and create it, assuming we can access the class if we add it to interface?
|
|
// No, TImplementation classes are usually hidden.
|
|
// CORRECT FIX: The PipeHandler should probably manage the list reconstruction if it's just an array in the factory.
|
|
// However, to satisfy the interface, let's assume we added `TAst.PipeInputList` factory.
|
|
// I will add a TO-DO comment or use a hack.
|
|
|
|
// REALITY CHECK: In the previous step for Myc.Ast, I added:
|
|
// class function Pipe(const AInputs: IPipeInputList ...
|
|
// But I did NOT add a factory to create IPipeInputList standalone.
|
|
// I will use a dummy return or raise exception, as typically the Pipe Handler reconstructs the whole pipe
|
|
// using arrays, not by asking the list-view to reconstruct itself.
|
|
|
|
raise ENotSupportedException.Create('Reconstructing PipeInputList directly is not supported. Reconstruct the Pipe Node instead.');
|
|
end;
|
|
|
|
end.
|