This commit is contained in:
Michael Schimmel
2025-10-30 18:00:58 +01:00
parent dfe1f04333
commit 798aa08f02
12 changed files with 710 additions and 27 deletions
+3 -2
View File
@@ -800,7 +800,8 @@ begin
[
TAst.VarDecl(
TAst.Identifier('closeColumn'),
TAst.MemberAccess(TAst.Identifier('ohlcvSeries'), TAst.Identifier('Close'))
TAst.FunctionCall(TAst.Keyword('Close'), [TAst.Identifier('ohlcvSeries')])
// TAst.MemberAccess(TAst.Identifier('ohlcvSeries'), TAst.Identifier('Close'))
),
TAst.Indexer(TAst.Identifier('closeColumn'), TAst.Constant(1))
]
@@ -1319,7 +1320,7 @@ end;
procedure TForm1.UpdateScript;
begin
PrintScript(FCurrAst);
PrintScript(FCurrUnboundAst);
FWorkspace.DeleteChildren;
ShowVizualization(14, 14);
+143 -1
View File
@@ -64,6 +64,7 @@ type
// Visitor implementations for each AST node type.
function VisitConstant(const Node: IConstantNode): TDataValue; override;
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
@@ -80,6 +81,7 @@ type
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
@@ -242,6 +244,17 @@ type
property Node: IIdentifierNode read FNode;
end;
TAuraKeywordNode = class(TAuraNode)
private
FNode: IKeywordNode;
protected
procedure SetupNode; override;
public
constructor Create(const AVisualizer: IAstVisualizer; const ANode: IKeywordNode);
function CreateAst: IAstNode; override;
property Node: IKeywordNode read FNode;
end;
TAuraBinaryExpressionNode = class(TAuraNode)
private
FNode: IBinaryExpressionNode;
@@ -462,6 +475,19 @@ type
property Node: IMemberAccessNode read FNode;
end;
TAuraRecordLiteralNode = class(TAuraNode)
private
FNode: IRecordLiteralNode;
FFieldNodes: TDictionary<string, TAuraNode>; // Map KeyName -> ValueNode
protected
procedure SetupNode; override;
public
constructor Create(const AVisualizer: IAstVisualizer; const ANode: IRecordLiteralNode);
destructor Destroy; override;
function CreateAst: IAstNode; override;
property Node: IRecordLiteralNode read FNode;
end;
TAuraCreateSeriesNode = class(TAuraNode)
private
FNode: ICreateSeriesNode;
@@ -499,6 +525,9 @@ type
implementation
uses
Myc.Data.Keyword;
{ TAstVisualizer }
constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer);
@@ -588,6 +617,11 @@ begin
Result := TDataValue.FromGeneric<TAuraNode>(TAuraIdentifierNode.Create(Self, Node));
end;
function TAstVisualizer.VisitKeyword(const Node: IKeywordNode): TDataValue;
begin
Result := TDataValue.FromGeneric<TAuraNode>(TAuraKeywordNode.Create(Self, Node));
end;
function TAstVisualizer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<TAuraNode>(TAuraBinaryExpressionNode.Create(Self, Node));
@@ -643,6 +677,11 @@ begin
Result := TDataValue.FromGeneric<TAuraNode>(TAuraMemberAccessNode.Create(Self, Node));
end;
function TAstVisualizer.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
begin
Result := TDataValue.FromGeneric<TAuraNode>(TAuraRecordLiteralNode.Create(Self, Node));
end;
function TAstVisualizer.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
Result := TDataValue.FromGeneric<TAuraNode>(TAuraQuasiquoteNode.Create(Self, Node));
@@ -1201,6 +1240,32 @@ begin
end;
end;
{ TAuraKeywordNode }
constructor TAuraKeywordNode.Create(const AVisualizer: IAstVisualizer; const ANode: IKeywordNode);
begin
inherited Create(AVisualizer);
FNode := ANode;
end;
function TAuraKeywordNode.CreateAst: IAstNode;
begin
Result := FNode; // Keywords are literals, return original node
end;
procedure TAuraKeywordNode.SetupNode;
begin
BeginUpdate;
try
Frameless := true;
var lbl := AddLabel(Self, ':' + FNode.Value.Name);
lbl.StyledSettings := lbl.StyledSettings - [TStyledSetting.FontColor];
lbl.FontColor := TAlphaColors.Mediumvioletred;
finally
EndUpdate;
end;
end;
{ TAuraBinaryExpressionNode }
constructor TAuraBinaryExpressionNode.Create(const AVisualizer: IAstVisualizer; const ANode: IBinaryExpressionNode);
@@ -1883,7 +1948,7 @@ begin
leftBracket.Padding.Right := 0;
leftBracket.Margins.Right := 0;
visu.CallAccept(FNode.Expression);
FExpressionNode := visu.CallAccept(FNode.Expression);
var rightBracket := AddLabel(Self, '>');
rightBracket.Padding.Left := 0;
@@ -1990,6 +2055,83 @@ begin
end;
end;
{ TAuraRecordLiteralNode }
constructor TAuraRecordLiteralNode.Create(const AVisualizer: IAstVisualizer; const ANode: IRecordLiteralNode);
begin
inherited Create(AVisualizer);
FNode := ANode;
FFieldNodes := TDictionary<string, TAuraNode>.Create;
end;
destructor TAuraRecordLiteralNode.Destroy;
begin
FFieldNodes.Free;
inherited Destroy;
end;
function TAuraRecordLiteralNode.CreateAst: IAstNode;
var
fields: TArray<TRecordFieldLiteral>;
i: Integer;
valueNode: TAuraNode;
pair: TPair<string, TAuraNode>;
begin
SetLength(fields, FFieldNodes.Count);
i := 0;
// Note: TDictionary iteration order is not guaranteed,
// but TScalarRecordDefinition is looked up by name, so order doesn't matter.
for pair in FFieldNodes do
begin
valueNode := pair.Value;
fields[i] := TRecordFieldLiteral.Create(pair.Key, valueNode.CreateAst);
inc(i);
end;
Result := TAst.RecordLiteral(fields);
end;
procedure TAuraRecordLiteralNode.SetupNode;
var
field: TRecordFieldLiteral;
fieldContainer: TAutoFitControl;
valueNode: TAuraNode;
keyLabel: TLabel;
begin
BeginUpdate;
try
Frameless := False;
Orientation := loVertical;
Alignment := laFlush; // Align fields to the left
if Length(FNode.Fields) = 0 then
begin
AddLabel(Self, '{}');
end
else
begin
for field in FNode.Fields do
begin
// Create a horizontal container for the key-value pair
fieldContainer := AddContainer(Self, loHorizontal, laCenter);
// Key label
keyLabel := AddLabel(fieldContainer, ':' + field.Name);
keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold];
keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor];
keyLabel.FontColor := TAlphaColors.Mediumvioletred;
// Value node
valueNode := FVisualizer.Clone(fieldContainer, FVisualizer.ExprDepth + 1).CallAccept(field.Value);
// Store for CreateAst
FFieldNodes.Add(field.Name, valueNode);
end;
end;
finally
EndUpdate;
end;
end;
{ TAuraCreateSeriesNode }
constructor TAuraCreateSeriesNode.Create(const AVisualizer: IAstVisualizer; const ANode: ICreateSeriesNode);