new-Series with tuple record def
This commit is contained in:
File diff suppressed because one or more lines are too long
+462
-1044
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 :=
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -89,7 +89,8 @@ var
|
||||
resultVal: TDataValue;
|
||||
begin
|
||||
// Chained Access: (get (.data (if false ...)) 0)
|
||||
script := '(do ' + ' (def root (if false {:data (new-series "ordinal")}))' + ' (get (.data root) 0)' + ')';
|
||||
// Updated: Use :Ordinal instead of "ordinal"
|
||||
script := '(do ' + ' (def root (if false {:data (new-series :Ordinal)}))' + ' (get (.data root) 0)' + ')';
|
||||
|
||||
resultVal := FEnv.Run(TAstScript.Parse(script));
|
||||
|
||||
@@ -103,7 +104,8 @@ var
|
||||
begin
|
||||
// 1. Define 's' as Optional<Series>
|
||||
// 2. Access via Indexer
|
||||
script := '(do ' + ' (def s (if false (new-series "ordinal")))' + ' (get s 42)' + ')';
|
||||
// Updated: Use :Ordinal instead of "ordinal"
|
||||
script := '(do ' + ' (def s (if false (new-series :Ordinal)))' + ' (get s 42)' + ')';
|
||||
|
||||
// FIX: Parse String to AST Node
|
||||
resultVal := FEnv.Run(TAstScript.Parse(script));
|
||||
@@ -120,11 +122,11 @@ begin
|
||||
FEnv.Run(
|
||||
TAstScript.Parse(
|
||||
'''
|
||||
(do
|
||||
(def a (if true 10)) ; a is Optional<Ordinal>
|
||||
(+ a 5) ; Error: Operator + not defined for Optional
|
||||
)
|
||||
'''
|
||||
(do
|
||||
(def a (if true 10)) ; a is Optional<Ordinal>
|
||||
(+ a 5) ; Error: Operator + not defined for Optional
|
||||
)
|
||||
'''
|
||||
)
|
||||
);
|
||||
end,
|
||||
|
||||
@@ -33,7 +33,7 @@ type
|
||||
destructor Destroy; override;
|
||||
|
||||
// Manual trigger
|
||||
procedure Emit(CycleID: Integer);
|
||||
procedure Emit(CycleID: Int64);
|
||||
|
||||
// IStream implementation
|
||||
function Subscribe(const Observer: IStreamObserver): TSubscriptionTag;
|
||||
@@ -122,7 +122,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestStream.Emit(CycleID: Integer);
|
||||
procedure TTestStream.Emit(CycleID: Int64);
|
||||
var
|
||||
obs: IStreamObserver;
|
||||
observersCopy: TArray<IStreamObserver>;
|
||||
@@ -227,7 +227,8 @@ begin
|
||||
|
||||
FEnv.RootScope.Define('src', mockStream, TTypes.CreateRecordSeries(source.Def));
|
||||
|
||||
script := '(pipe [src [:non_existent]] (fn [x] {:res x}))';
|
||||
// Notice double bracket [[ ... ]] to correctly form the input vector
|
||||
script := '(pipe [[src [:non_existent]]] (fn [x] {:res x}))';
|
||||
|
||||
Assert.WillRaise(procedure begin FEnv.Run(TAstScript.Parse(script)); end, ECompilationFailed);
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user