new-Series with tuple record def

This commit is contained in:
Michael Schimmel
2026-01-06 13:38:06 +01:00
parent fb2fc8f6f9
commit 3b3966b2f7
13 changed files with 729 additions and 1131 deletions
+79 -8
View File
@@ -816,17 +816,88 @@ end;
function TTypeChecker.VisitCreateSeries(const Node: IAstNode): IAstNode;
var
C: ICreateSeriesNode;
elemType: IStaticType;
def: string;
defNode: IAstNode;
recDef: IScalarRecordDefinition;
resType: IStaticType;
elemKind: TScalar.TKind;
fields: TArray<TPair<IKeyword, TScalar.TKind>>;
tuple: ITupleNode;
elements: TArray<IAstNode>;
fieldTuple: ITupleNode;
keyNode: IKeywordNode;
typeNode: IKeywordNode;
i: Integer;
begin
C := Node.AsCreateSeries;
def := C.Definition;
if def.StartsWith('[') then
elemType := TTypes.CreateRecord(nil)
else
elemType := TTypes.FromScalarKind(TScalar.StringToKind(def));
// The definition node comes from the parser and is likely raw (untyped keywords/tuples).
// We don't necessarily need to "Visit" it for type checking children,
// but we need to analyze its structure.
defNode := C.DefinitionNode;
Result := TAst.CreateSeries(Node.Identity.AsDefinition, TTypes.CreateSeries(elemType));
recDef := nil;
resType := TTypes.Unknown;
case defNode.Kind of
akKeyword:
begin
// Case 1: Simple Series, e.g. (new-series :Float)
// DefinitionNode is a single Keyword
elemKind := TScalar.StringToKind(defNode.AsKeyword.Value.Name);
resType := TTypes.CreateSeries(TTypes.FromScalarKind(elemKind));
end;
akTuple:
begin
// Case 2: Record Series, e.g. (new-series [[:Price :Float] [:Vol :Ordinal]])
tuple := defNode.AsTuple;
elements := tuple.Elements;
SetLength(fields, Length(elements));
for i := 0 to High(elements) do
begin
if elements[i].Kind <> akTuple then
begin
if Assigned(FLog) then
FLog.AddError('Record definition elements must be vectors [Key Type]', elements[i]);
continue;
end;
fieldTuple := elements[i].AsTuple;
if Length(fieldTuple.Elements) <> 2 then
begin
if Assigned(FLog) then
FLog.AddError('Record definition entry must have exactly 2 elements [Key Type]', fieldTuple);
continue;
end;
if (fieldTuple.Elements[0].Kind <> akKeyword) or (fieldTuple.Elements[1].Kind <> akKeyword) then
begin
if Assigned(FLog) then
FLog.AddError('Record definition keys and types must be keywords', fieldTuple);
continue;
end;
keyNode := fieldTuple.Elements[0].AsKeyword;
typeNode := fieldTuple.Elements[1].AsKeyword;
elemKind := TScalar.StringToKind(typeNode.Value.Name);
fields[i] := TPair<IKeyword, TScalar.TKind>.Create(keyNode.Value, elemKind);
end;
if Length(fields) > 0 then
begin
recDef := TKeywordMappingRegistry<TScalar.TKind>.Intern(fields);
resType := TTypes.CreateRecordSeries(recDef);
end;
end
else
begin
if Assigned(FLog) then
FLog.AddError('Invalid series definition format. Expected :Type or [[:Key :Type] ...]', defNode);
end;
end;
// Return updated node with RecordDefinition (if any) and StaticType
Result := TAst.CreateSeries(Node.Identity, defNode, recDef, resType);
end;
function TTypeChecker.VisitSeriesLength(const Node: IAstNode): IAstNode;
+6 -1
View File
@@ -490,7 +490,12 @@ end;
function TAstDumper.VisitCreateSeries(const Node: IAstNode): TVoid;
begin
LogFmt('CreateSeries: %s', [Node.AsCreateSeries.Definition], Node);
// REFACTORED: Log the structure of the definition
Log('CreateSeries', Node);
Indent;
Log('Definition:');
Visit(Node.AsCreateSeries.DefinitionNode);
Unindent;
end;
function TAstDumper.VisitAddSeriesItem(const Node: IAstNode): TVoid;
+59 -6
View File
@@ -64,7 +64,6 @@ uses
Myc.Data.Series,
Myc.Data.Stream,
Myc.Data.Stream.Pipes,
Myc.Data.Scalar.JSON,
Myc.Ast.Types;
type
@@ -359,7 +358,7 @@ begin
vkSeries:
begin
var i: Integer := idx.AsScalar.Value.AsInt64;
Result := base.AsSeries.Items[i];
Result := base.AsSeries[i];
end;
vkRecordSeries:
begin
@@ -432,11 +431,59 @@ begin
end;
function TEvaluatorVisitor.VisitCreateSeries(const N: ICreateSeriesNode): TDataValue;
var
defNode: IAstNode;
kind: TScalar.TKind;
fields: TArray<TPair<IKeyword, TScalar.TKind>>;
i: Integer;
tupleElements: TArray<IAstNode>;
entry: TArray<IAstNode>;
k: IKeyword;
t: TScalar.TKind;
begin
if N.Definition.Trim.StartsWith('[') then
Result := TScalarRecordSeries.Create(TRttiAstHelper.JsonToRecordDefinition(N.Definition))
else
Result := TScalarSeries.Create(TScalar.StringToKind(N.Definition));
// 1. If TypeChecker ran, we have the Definition ready (Fast Path)
if Assigned(N.RecordDefinition) then
Exit(TScalarRecordSeries.Create(N.RecordDefinition));
defNode := N.DefinitionNode;
// 2. Simple Series (Keyword) e.g. (new-series :Float)
if defNode.Kind = akKeyword then
begin
kind := TScalar.StringToKind(defNode.AsKeyword.Value.Name);
Exit(TScalarSeries.Create(kind));
end;
// 3. Record Series (Tuple of [Key Type]) - Dynamic Parsing Fallback
// e.g. (new-series [[:Price :Float] [:Vol :Ordinal]])
if defNode.Kind = akTuple then
begin
tupleElements := defNode.AsTuple.Elements;
SetLength(fields, Length(tupleElements));
for i := 0 to High(tupleElements) do
begin
// Each element MUST be a tuple of 2 elements [Key, Type]
if tupleElements[i].Kind <> akTuple then
raise EEvaluatorException.Create('Invalid record definition: Expected vector [Key Type].');
entry := tupleElements[i].AsTuple.Elements;
if Length(entry) <> 2 then
raise EEvaluatorException.Create('Invalid record definition entry: Expected 2 elements.');
if (entry[0].Kind <> akKeyword) or (entry[1].Kind <> akKeyword) then
raise EEvaluatorException.Create('Invalid record definition: Key and Type must be keywords.');
k := entry[0].AsKeyword.Value;
t := TScalar.StringToKind(entry[1].AsKeyword.Value.Name);
fields[i] := TPair<IKeyword, TScalar.TKind>.Create(k, t);
end;
var def := TKeywordMappingRegistry<TScalar.TKind>.Intern(fields);
Exit(TScalarRecordSeries.Create(def));
end;
raise EEvaluatorException.Create('Invalid CreateSeries definition node.');
end;
function TEvaluatorVisitor.VisitAddSeriesItem(const N: IAddSeriesItemNode): TDataValue;
@@ -515,6 +562,12 @@ begin
// Compile the transformation function
lambdaFunc := Visit(N.Transformation).AsMethod();
// WARNING: If this is executing dynamically (without TypeChecker), StaticType is Unknown.
// Pipe creation REQUIRES the output definition.
// Fixed: Allow both stRecord and stRecordSeries (as TypeChecker correctly assigns stRecordSeries for Pipe nodes)
if (N.StaticType.Kind <> stRecordSeries) and (N.StaticType.Kind <> stRecord) then
raise EEvaluatorException.Create('Pipe requires Type Checking to determine output structure (RecordDefinition).');
var outputDef := N.StaticType.AsRecord.Definition;
var pipeAdapter: TPipeStream.TPipeLambda :=
+4 -9
View File
@@ -209,7 +209,6 @@ begin
Result.AddPair('NodeType', TJSONString.Create('Tuple'));
elemsArray := TJSONArray.Create;
// Updated: Use Elements array directly
elements := T.Elements;
for i := 0 to High(elements) do
elemsArray.Add(Visit(elements[i]));
@@ -412,7 +411,8 @@ function TJsonAstConverter.VisitCreateSeries(const Node: IAstNode): TJSONObject;
begin
Result := TJSONObject.Create;
Result.AddPair('NodeType', TJSONString.Create('CreateSeries'));
Result.AddPair('Definition', TJSONString.Create(Node.AsCreateSeries.Definition));
// REFACTORED: Now serialize the DefinitionNode structure instead of a raw string
Result.AddPair('DefinitionNode', Visit(Node.AsCreateSeries.DefinitionNode));
end;
function TJsonAstConverter.VisitAddSeriesItem(const Node: IAstNode): TJSONObject;
@@ -616,7 +616,6 @@ var
begin
identNodes := TList<IIdentifierNode>.Create;
try
// Updated: Use Elements instead of ToArray (or iterate if ToArray is missing)
for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.Elements do
identNodes.Add(node.AsIdentifier);
Result := TAst.LambdaExpr(identNodes.ToArray, JsonToNode(AObj.GetValue('Body')));
@@ -632,7 +631,6 @@ var
begin
identNodes := TList<IIdentifierNode>.Create;
try
// Updated: Use Elements
for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.Elements do
identNodes.Add(node.AsIdentifier);
Result :=
@@ -663,7 +661,6 @@ end;
function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
begin
// Updated: Use Elements
Result := TAst.FunctionCall(JsonToNode(AObj.GetValue('Callee')), JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements);
end;
@@ -675,19 +672,16 @@ begin
callee := JsonToNode(AObj.GetValue('Callee'));
expandedBody := JsonToNode(AObj.GetValue('ExpandedBody'));
argsTuple := JsonToNode(AObj.GetValue('Arguments')).AsTuple;
// Updated: Use Elements
Result := TAst.MacroExpansionNode(TAst.FunctionCall(callee, argsTuple.Elements), expandedBody);
end;
function TJsonAstConverter.JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
begin
// Updated: Use Elements
Result := TAst.Recur(JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements);
end;
function TJsonAstConverter.JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
begin
// Updated: Use Elements
Result := TAst.Block(JsonToNode(AObj.GetValue('Expressions')).AsTuple.Elements);
end;
@@ -739,7 +733,8 @@ end;
function TJsonAstConverter.JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
begin
Result := TAst.CreateSeries(AObj.GetValue<string>('Definition'));
// REFACTORED: Use the definition node from JSON
Result := TAst.CreateSeries(JsonToNode(AObj.GetValue('DefinitionNode')));
end;
function TJsonAstConverter.JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
+29 -9
View File
@@ -422,9 +422,11 @@ type
ICreateSeriesNode = interface(IAstTypedNode)
{$region 'private'}
function GetDefinition: String;
function GetDefinitionNode: IAstNode;
function GetRecordDefinition: IScalarRecordDefinition;
{$endregion}
property Definition: String read GetDefinition;
property DefinitionNode: IAstNode read GetDefinitionNode;
property RecordDefinition: IScalarRecordDefinition read GetRecordDefinition;
end;
IAddSeriesItemNode = interface(IAstTypedNode)
@@ -589,12 +591,19 @@ type
TCreateSeriesNode = class(TAstTypedNode, ICreateSeriesNode)
private
FDefIdentity: IDefinitionIdentity;
function GetDefinition: String;
FDefinitionNode: IAstNode;
FRecordDefinition: IScalarRecordDefinition;
function GetDefinitionNode: IAstNode;
function GetRecordDefinition: IScalarRecordDefinition;
protected
function GetKind: TAstNodeKind; override;
public
constructor Create(const AIdentity: IDefinitionIdentity; const AStaticType: IStaticType);
constructor Create(
const ADefinitionNode: IAstNode;
const ARecordDefinition: IScalarRecordDefinition;
const AStaticType: IStaticType;
const AIdentity: IAstIdentity
);
function AsCreateSeries: ICreateSeriesNode; override;
end;
@@ -1379,10 +1388,16 @@ end;
{ TCreateSeriesNode }
constructor TCreateSeriesNode.Create(const AIdentity: IDefinitionIdentity; const AStaticType: IStaticType);
constructor TCreateSeriesNode.Create(
const ADefinitionNode: IAstNode;
const ARecordDefinition: IScalarRecordDefinition;
const AStaticType: IStaticType;
const AIdentity: IAstIdentity
);
begin
inherited Create(AStaticType, AIdentity);
FDefIdentity := AIdentity;
FDefinitionNode := ADefinitionNode;
FRecordDefinition := ARecordDefinition;
end;
function TCreateSeriesNode.AsCreateSeries: ICreateSeriesNode;
@@ -1390,9 +1405,14 @@ begin
Result := Self;
end;
function TCreateSeriesNode.GetDefinition: String;
function TCreateSeriesNode.GetDefinitionNode: IAstNode;
begin
Result := FDefIdentity.Definition;
Result := FDefinitionNode;
end;
function TCreateSeriesNode.GetRecordDefinition: IScalarRecordDefinition;
begin
Result := FRecordDefinition;
end;
function TCreateSeriesNode.GetKind: TAstNodeKind;
+3 -1
View File
@@ -458,7 +458,9 @@ end;
function TPrettyPrintVisitor.VisitCreateSeries(const N: IAstNode): TVoid;
begin
Append(Format('(new-series "%s")', [N.AsCreateSeries.Definition]));
Append('(new-series ');
Visit(N.AsCreateSeries.DefinitionNode);
Append(')');
end;
function TPrettyPrintVisitor.VisitAddSeriesItem(const N: IAstNode): TVoid;
+5 -4
View File
@@ -612,10 +612,11 @@ begin
end
else if SameText(head.Token.Text, 'new-series') then
begin
if (tailNodes[0].Kind = akConstant) and (tailNodes[0].AsConstant.Value.Kind = vkText) then
Result := TAst.CreateSeries(tailNodes[0].AsConstant.Value.AsText, startLoc)
else
Error('Syntax Error: ''new-series'' argument must be a string literal.');
if Length(tailNodes) <> 1 then
Error('Syntax Error: ''new-series'' requires exactly one argument (the definition vector).');
// UPDATED: Accept any node (usually a vector) as definition
Result := TAst.CreateSeries(tailNodes[0], startLoc);
end
else if SameText(head.Token.Text, 'add-item') then
begin
+18 -8
View File
@@ -54,9 +54,11 @@ type
const AStaticType: IStaticType = nil
): ITupleNode; overload; static;
class function CreateSeries(const ADefinition: String; const Loc: ISourceLocation = nil): ICreateSeriesNode; overload; static;
class function CreateSeries(const ADefinitionNode: IAstNode; const Loc: ISourceLocation = nil): ICreateSeriesNode; overload; static;
class function CreateSeries(
const Identity: IDefinitionIdentity;
const Identity: IAstIdentity;
const ADefinitionNode: IAstNode;
const ARecordDefinition: IScalarRecordDefinition = nil;
const AStaticType: IStaticType = nil
): ICreateSeriesNode; overload; static;
@@ -402,19 +404,27 @@ begin
);
end;
class function TAst.CreateSeries(const ADefinition: String; const Loc: ISourceLocation): ICreateSeriesNode;
class function TAst.CreateSeries(const ADefinitionNode: IAstNode; const Loc: ISourceLocation): ICreateSeriesNode;
begin
var id := TIdentities.Definition(ADefinition, Loc);
Result := TCreateSeriesNode.Create(id, TTypes.Unknown);
var id := TIdentities.Structural(Loc);
// RecordDefinition is nil initially, populated by TypeChecker
Result := TCreateSeriesNode.Create(ADefinitionNode, nil, TTypes.Unknown, id);
end;
class function TAst.CreateSeries(const Identity: IDefinitionIdentity; const AStaticType: IStaticType): ICreateSeriesNode;
class function TAst.CreateSeries(
const Identity: IAstIdentity;
const ADefinitionNode: IAstNode;
const ARecordDefinition: IScalarRecordDefinition;
const AStaticType: IStaticType
): ICreateSeriesNode;
begin
Result :=
TCreateSeriesNode.Create(
Identity,
ADefinitionNode,
ARecordDefinition,
if AStaticType <> nil then AStaticType
else TTypes.Unknown
else TTypes.Unknown,
Identity
);
end;
+50 -30
View File
@@ -97,6 +97,8 @@ type
// --- Series Operations ---
TCreateSeriesNodeHandler = class(TBaseNodeHandler<ICreateSeriesNode>)
private
FDefNode: TAstViewNode;
public
procedure BuildUI(OwnerNode: TAstViewNode); override;
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override;
@@ -131,14 +133,15 @@ begin
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
varLabel := OwnerNode.AddLabel(OwnerNode, 'var');
varLabel := OwnerNode.AddLabel(OwnerNode, 'def'); // Changed 'var' to 'def' to match syntax
varLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
FTargetNode := visu.CallAccept(FNode.Target);
if Assigned(FNode.Initializer) then
begin
OwnerNode.AddLabel(OwnerNode, ':=');
// Space before value
OwnerNode.AddLabel(OwnerNode, ' ');
FInitializerNode := visu.CallAccept(FNode.Initializer);
end
else
@@ -166,8 +169,9 @@ begin
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
OwnerNode.AddLabel(OwnerNode, 'assign ');
FTargetNode := visu.CallAccept(FNode.Target);
OwnerNode.AddLabel(OwnerNode, ':=');
OwnerNode.AddLabel(OwnerNode, ' ');
FValueNode := visu.CallAccept(FNode.Value);
end;
@@ -185,9 +189,9 @@ var
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Quasiquote');
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
titleLabel := OwnerNode.AddLabel(OwnerNode, '`');
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
FExpressionNode := visu.CallAccept(FNode.Expression);
end;
@@ -202,25 +206,19 @@ end;
procedure TUnquoteNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
visu: IAstVisualizer;
leftBracket, rightBracket: TTextNode;
leftBracket: TTextNode;
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
leftBracket := OwnerNode.AddLabel(OwnerNode, '<');
// We cannot assign to fields of record properties directly.
// Replace the entire margin record.
// Default from AddLabel is (cNodePadding, cTitleTopPadding, cNodePadding, cTitleBottomPadding)
// We want Right Margin = 0.
leftBracket := OwnerNode.AddLabel(OwnerNode, '~');
leftBracket.FontSettings.Font.Style := [TFontStyle.fsBold];
// Remove right margin to stick to expression
leftBracket.Margins := TMarginRect.Create(cNodePadding, cTitleTopPadding, 0, cTitleBottomPadding);
FExpressionNode := visu.CallAccept(FNode.Expression);
rightBracket := OwnerNode.AddLabel(OwnerNode, '>');
// We want Left Margin = 0.
rightBracket.Margins := TMarginRect.Create(0, cTitleTopPadding, cNodePadding, cTitleBottomPadding);
end;
function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
@@ -237,10 +235,13 @@ var
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing');
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
titleLabel := OwnerNode.AddLabel(OwnerNode, '~@');
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
// Remove right margin
titleLabel.Margins := TMarginRect.Create(cNodePadding, cTitleTopPadding, 0, cTitleBottomPadding);
FExpressionNode := visu.CallAccept(FNode.Expression);
end;
@@ -259,10 +260,10 @@ begin
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
OwnerNode.AddLabel(OwnerNode, 'get ');
FBaseNode := visu.CallAccept(FNode.Base);
OwnerNode.AddLabel(OwnerNode, '[');
OwnerNode.AddLabel(OwnerNode, ' ');
FIndexNode := visu.CallAccept(FNode.Index);
OwnerNode.AddLabel(OwnerNode, ']');
end;
function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
@@ -280,9 +281,10 @@ begin
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
FBaseNode := visu.CallAccept(FNode.Base);
OwnerNode.AddLabel(OwnerNode, '.');
OwnerNode.AddLabel(OwnerNode, FNode.Member.Value.Name);
OwnerNode.AddLabel(OwnerNode, ' ');
FBaseNode := visu.CallAccept(FNode.Base);
end;
function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
@@ -306,6 +308,7 @@ begin
FKeyLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
FKeyLabel.Color := TAlphaColors.Mediumvioletred;
OwnerNode.AddLabel(OwnerNode, ' ');
FValueNode := visu.CallAccept(FNode.Value);
end;
@@ -319,15 +322,22 @@ end;
procedure TRecordLiteralNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
visu: IAstVisualizer;
braceL: TTextNode;
begin
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1);
OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical;
OwnerNode.Alignment := laFlush;
OwnerNode.Alignment := laFlush; // Align left
// Visual hint: Curly braces for record
braceL := OwnerNode.AddLabel(OwnerNode, '{');
braceL.FontSettings.Font.Style := [TFontStyle.fsBold];
// Delegate to Fields Tuple (previously RecordFieldList)
FFieldsNode := visu.CallAccept(FNode.Fields);
OwnerNode.AddLabel(OwnerNode, '}');
end;
function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
@@ -346,17 +356,24 @@ end;
procedure TCreateSeriesNodeHandler.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, 'Create Series: ' + FNode.Definition);
titleLabel := OwnerNode.AddLabel(OwnerNode, 'new-series');
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
// Now visualize the definition node (likely a Tuple or Keyword)
FDefNode := visu.CallAccept(FNode.DefinitionNode);
end;
function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
begin
Result := TAst.CreateSeries(FNode.Identity.AsDefinition, FNode.StaticType);
Result := TAst.CreateSeries(FNode.Identity, FDefNode.CreateAst, FNode.RecordDefinition, FNode.StaticType);
end;
{ TAddSeriesItemNodeHandler }
@@ -371,12 +388,15 @@ begin
OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Add Item to: ' + FNode.Series.Name);
titleLabel := OwnerNode.AddLabel(OwnerNode, 'add-item: ' + FNode.Series.Name);
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
FValueNode := visu.CallAccept(FNode.Value);
if Assigned(FNode.Lookback) then
FLookbackNode := visu.CallAccept(FNode.Lookback)
begin
OwnerNode.AddLabel(OwnerNode, 'Lookback:');
FLookbackNode := visu.CallAccept(FNode.Lookback);
end
else
FLookbackNode := nil;
end;
@@ -406,9 +426,9 @@ procedure TSeriesLengthNodeHandler.BuildUI(OwnerNode: TAstViewNode);
var
titleLabel: TTextNode;
begin
OwnerNode.Frameless := False;
OwnerNode.Orientation := loVertical;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'Length of: ' + FNode.Series.Name);
OwnerNode.Frameless := True;
OwnerNode.Orientation := loHorizontal;
titleLabel := OwnerNode.AddLabel(OwnerNode, 'count ' + FNode.Series.Name);
titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold];
end;