Keywords
This commit is contained in:
@@ -800,7 +800,8 @@ begin
|
|||||||
[
|
[
|
||||||
TAst.VarDecl(
|
TAst.VarDecl(
|
||||||
TAst.Identifier('closeColumn'),
|
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))
|
TAst.Indexer(TAst.Identifier('closeColumn'), TAst.Constant(1))
|
||||||
]
|
]
|
||||||
@@ -1319,7 +1320,7 @@ end;
|
|||||||
|
|
||||||
procedure TForm1.UpdateScript;
|
procedure TForm1.UpdateScript;
|
||||||
begin
|
begin
|
||||||
PrintScript(FCurrAst);
|
PrintScript(FCurrUnboundAst);
|
||||||
|
|
||||||
FWorkspace.DeleteChildren;
|
FWorkspace.DeleteChildren;
|
||||||
ShowVizualization(14, 14);
|
ShowVizualization(14, 14);
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ type
|
|||||||
// Visitor implementations for each AST node type.
|
// Visitor implementations for each AST node type.
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -80,6 +81,7 @@ type
|
|||||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -242,6 +244,17 @@ type
|
|||||||
property Node: IIdentifierNode read FNode;
|
property Node: IIdentifierNode read FNode;
|
||||||
end;
|
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)
|
TAuraBinaryExpressionNode = class(TAuraNode)
|
||||||
private
|
private
|
||||||
FNode: IBinaryExpressionNode;
|
FNode: IBinaryExpressionNode;
|
||||||
@@ -462,6 +475,19 @@ type
|
|||||||
property Node: IMemberAccessNode read FNode;
|
property Node: IMemberAccessNode read FNode;
|
||||||
end;
|
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)
|
TAuraCreateSeriesNode = class(TAuraNode)
|
||||||
private
|
private
|
||||||
FNode: ICreateSeriesNode;
|
FNode: ICreateSeriesNode;
|
||||||
@@ -499,6 +525,9 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
{ TAstVisualizer }
|
{ TAstVisualizer }
|
||||||
|
|
||||||
constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer);
|
constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer);
|
||||||
@@ -588,6 +617,11 @@ begin
|
|||||||
Result := TDataValue.FromGeneric<TAuraNode>(TAuraIdentifierNode.Create(Self, Node));
|
Result := TDataValue.FromGeneric<TAuraNode>(TAuraIdentifierNode.Create(Self, Node));
|
||||||
end;
|
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;
|
function TAstVisualizer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
Result := TDataValue.FromGeneric<TAuraNode>(TAuraBinaryExpressionNode.Create(Self, Node));
|
Result := TDataValue.FromGeneric<TAuraNode>(TAuraBinaryExpressionNode.Create(Self, Node));
|
||||||
@@ -643,6 +677,11 @@ begin
|
|||||||
Result := TDataValue.FromGeneric<TAuraNode>(TAuraMemberAccessNode.Create(Self, Node));
|
Result := TDataValue.FromGeneric<TAuraNode>(TAuraMemberAccessNode.Create(Self, Node));
|
||||||
end;
|
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;
|
function TAstVisualizer.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
Result := TDataValue.FromGeneric<TAuraNode>(TAuraQuasiquoteNode.Create(Self, Node));
|
Result := TDataValue.FromGeneric<TAuraNode>(TAuraQuasiquoteNode.Create(Self, Node));
|
||||||
@@ -1201,6 +1240,32 @@ begin
|
|||||||
end;
|
end;
|
||||||
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 }
|
{ TAuraBinaryExpressionNode }
|
||||||
|
|
||||||
constructor TAuraBinaryExpressionNode.Create(const AVisualizer: IAstVisualizer; const ANode: IBinaryExpressionNode);
|
constructor TAuraBinaryExpressionNode.Create(const AVisualizer: IAstVisualizer; const ANode: IBinaryExpressionNode);
|
||||||
@@ -1883,7 +1948,7 @@ begin
|
|||||||
leftBracket.Padding.Right := 0;
|
leftBracket.Padding.Right := 0;
|
||||||
leftBracket.Margins.Right := 0;
|
leftBracket.Margins.Right := 0;
|
||||||
|
|
||||||
visu.CallAccept(FNode.Expression);
|
FExpressionNode := visu.CallAccept(FNode.Expression);
|
||||||
|
|
||||||
var rightBracket := AddLabel(Self, '>');
|
var rightBracket := AddLabel(Self, '>');
|
||||||
rightBracket.Padding.Left := 0;
|
rightBracket.Padding.Left := 0;
|
||||||
@@ -1990,6 +2055,83 @@ begin
|
|||||||
end;
|
end;
|
||||||
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 }
|
{ TAuraCreateSeriesNode }
|
||||||
|
|
||||||
constructor TAuraCreateSeriesNode.Create(const AVisualizer: IAstVisualizer; const ANode: ICreateSeriesNode);
|
constructor TAuraCreateSeriesNode.Create(const AVisualizer: IAstVisualizer; const ANode: ICreateSeriesNode);
|
||||||
|
|||||||
+109
-8
@@ -12,7 +12,7 @@ uses
|
|||||||
Myc.Ast.Visitor,
|
Myc.Ast.Visitor,
|
||||||
Myc.Ast.Scope,
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.Analyzer,
|
Myc.Ast.Analyzer,
|
||||||
Myc.Ast.Types, // Added
|
Myc.Ast.Types,
|
||||||
Myc.Ast;
|
Myc.Ast;
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -35,6 +35,7 @@ type
|
|||||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
||||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
public
|
public
|
||||||
constructor Create(const AMacroScope: IExecutionScope; const AEvaluate: TEvaluateProc);
|
constructor Create(const AMacroScope: IExecutionScope; const AEvaluate: TEvaluateProc);
|
||||||
class function Expand(const MacroScope: IExecutionScope; const RootNode: IAstNode; const AEvaluate: TEvaluateProc): IAstNode;
|
class function Expand(const MacroScope: IExecutionScope; const RootNode: IAstNode; const AEvaluate: TEvaluateProc): IAstNode;
|
||||||
@@ -70,6 +71,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function Accept(const Node: IAstNode): TDataValue; override;
|
function Accept(const Node: IAstNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||||
@@ -82,10 +84,10 @@ type
|
|||||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
// Added for type inference
|
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -151,11 +153,20 @@ type
|
|||||||
property IsTailCall: Boolean read FIsTailCall;
|
property IsTailCall: Boolean read FIsTailCall;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TBoundRecordLiteralNode = class(TRecordLiteralNode)
|
||||||
|
private
|
||||||
|
FDefinition: TScalarRecordDefinition;
|
||||||
|
public
|
||||||
|
constructor Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: TScalarRecordDefinition);
|
||||||
|
property Definition: TScalarRecordDefinition read FDefinition;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
System.Generics.Defaults,
|
System.Generics.Defaults,
|
||||||
System.Character;
|
System.Character,
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
type
|
type
|
||||||
TResolvedAddressComparer = class(TEqualityComparer<TResolvedAddress>)
|
TResolvedAddressComparer = class(TEqualityComparer<TResolvedAddress>)
|
||||||
@@ -248,7 +259,7 @@ begin
|
|||||||
// externally evaluate the expression using the injected evaluator
|
// externally evaluate the expression using the injected evaluator
|
||||||
value := FEvaluate(expr);
|
value := FEvaluate(expr);
|
||||||
|
|
||||||
if value.Kind in [vkScalar, vkText, vkVoid] then
|
if value.Kind in [vkScalar, vkText, vkVoid, vkKeyword] then
|
||||||
Result := TDataValue.FromIntf<IAstNode>(TAst.Constant(value))
|
Result := TDataValue.FromIntf<IAstNode>(TAst.Constant(value))
|
||||||
else
|
else
|
||||||
raise Exception.CreateFmt('Cannot unquote complex value of type %s at compile time.', [value.Kind.ToString]);
|
raise Exception.CreateFmt('Cannot unquote complex value of type %s at compile time.', [value.Kind.ToString]);
|
||||||
@@ -277,6 +288,13 @@ begin
|
|||||||
Result := TDataValue.FromIntf<IBlockExpressionNode>(TAst.Block(newExprs));
|
Result := TDataValue.FromIntf<IBlockExpressionNode>(TAst.Block(newExprs));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
begin
|
||||||
|
// This node type does not support splicing, so we use the default
|
||||||
|
// TAstTransformer implementation which just transforms child values.
|
||||||
|
Result := inherited VisitRecordLiteral(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TBoundIdentifierNode }
|
{ TBoundIdentifierNode }
|
||||||
constructor TBoundIdentifierNode.Create(const AUnboundNode: IIdentifierNode; const AAddress: TResolvedAddress);
|
constructor TBoundIdentifierNode.Create(const AUnboundNode: IIdentifierNode; const AAddress: TResolvedAddress);
|
||||||
begin
|
begin
|
||||||
@@ -319,6 +337,13 @@ begin
|
|||||||
FIsTailCall := AIsTailCall;
|
FIsTailCall := AIsTailCall;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TBoundRecordLiteralNode }
|
||||||
|
constructor TBoundRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: TScalarRecordDefinition);
|
||||||
|
begin
|
||||||
|
inherited Create(AFields);
|
||||||
|
FDefinition := ADef;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TResolvedAddressComparer }
|
{ TResolvedAddressComparer }
|
||||||
function TResolvedAddressComparer.Equals(const Left, Right: TResolvedAddress): Boolean;
|
function TResolvedAddressComparer.Equals(const Left, Right: TResolvedAddress): Boolean;
|
||||||
begin
|
begin
|
||||||
@@ -474,6 +499,31 @@ var
|
|||||||
args: TArray<IAstNode>;
|
args: TArray<IAstNode>;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
|
// --- Transformation: Keyword-as-Function ---
|
||||||
|
if (Node.Callee is TKeywordNode) then
|
||||||
|
begin
|
||||||
|
var keywordNode := (Node.Callee as TKeywordNode);
|
||||||
|
var keywordName := keywordNode.Value.Name;
|
||||||
|
|
||||||
|
// 1. Validate argument count
|
||||||
|
if Length(Node.Arguments) <> 1 then
|
||||||
|
raise ETypeException
|
||||||
|
.CreateFmt('Keyword :%s expects exactly one argument (the record), but got %d', [keywordName, Length(Node.Arguments)]);
|
||||||
|
|
||||||
|
// 2. Bind the base (the record)
|
||||||
|
FNextIsTail := False; // Accessing a member is not a tail call
|
||||||
|
var baseNode := Accept(Node.Arguments[0]).AsIntf<IAstNode>;
|
||||||
|
|
||||||
|
// 3. Create a synthetic IMemberAccessNode
|
||||||
|
var memberIdentifier := TAst.Identifier(keywordName);
|
||||||
|
var memberAccessNode := TAst.MemberAccess(baseNode, memberIdentifier);
|
||||||
|
|
||||||
|
// 4. Re-bind the synthetic node by calling Accept (which dispatches to VisitMemberAccess)
|
||||||
|
// This ensures type checking and type inference for member access is done in one place.
|
||||||
|
Result := Accept(memberAccessNode);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if (Node.Callee is TIdentifierNode) then
|
if (Node.Callee is TIdentifierNode) then
|
||||||
begin
|
begin
|
||||||
calleeIdentifier := Node.Callee as TIdentifierNode;
|
calleeIdentifier := Node.Callee as TIdentifierNode;
|
||||||
@@ -592,10 +642,10 @@ begin
|
|||||||
// Check argument types (param types are not yet inferred, so skip check for now)
|
// Check argument types (param types are not yet inferred, so skip check for now)
|
||||||
// for i := 0 to High(args) do
|
// for i := 0 to High(args) do
|
||||||
// begin
|
// begin
|
||||||
// var argType := (args[i] as TAstNode).StaticType;
|
// var argType := (args[i] as TAstNode).StaticType;
|
||||||
// var paramType := signature.ParamTypes[i];
|
// var paramType := signature.ParamTypes[i];
|
||||||
// if not TTypeRules.CanAssign(paramType, argType) then
|
// if not TTypeRules.CanAssign(paramType, argType) then
|
||||||
// raise ETypeException.CreateFmt('Cannot assign argument %d (type %s) to parameter (type %s)', [i, argType.ToString, paramType.ToString]);
|
// raise ETypeException.CreateFmt('Cannot assign argument %d (type %s) to parameter (type %s)', [i, argType.ToString, paramType.ToString]);
|
||||||
// end;
|
// end;
|
||||||
|
|
||||||
boundCall := TBoundFunctionCallNode.Create(Node, callee, args, isTailCall);
|
boundCall := TBoundFunctionCallNode.Create(Node, callee, args, isTailCall);
|
||||||
@@ -738,12 +788,19 @@ begin
|
|||||||
Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.FromScalarKind(Node.Value.AsScalar.Kind));
|
Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.FromScalarKind(Node.Value.AsScalar.Kind));
|
||||||
TDataValueKind.vkText: Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Text);
|
TDataValueKind.vkText: Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Text);
|
||||||
TDataValueKind.vkVoid: Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Void);
|
TDataValueKind.vkVoid: Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Void);
|
||||||
|
TDataValueKind.vkKeyword: Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Keyword);
|
||||||
else
|
else
|
||||||
// Handle other constant types if they become supported
|
// Handle other constant types if they become supported
|
||||||
Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Unknown);
|
Result := SetType(TDataValue.FromIntf<IConstantNode>(Node), TTypes.Unknown);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstBinder.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
begin
|
||||||
|
// Keywords are literals. Their type is set in TKeywordNode.Create.
|
||||||
|
Result := TDataValue.FromIntf<IKeywordNode>(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstBinder.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TAstBinder.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
var
|
var
|
||||||
elemType: IStaticType;
|
elemType: IStaticType;
|
||||||
@@ -892,6 +949,50 @@ begin
|
|||||||
Result := SetType(TDataValue.FromIntf<IMemberAccessNode>(boundNode), elemType);
|
Result := SetType(TDataValue.FromIntf<IMemberAccessNode>(boundNode), elemType);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstBinder.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
boundFields: TArray<TRecordFieldLiteral>;
|
||||||
|
defFields: TArray<TScalarRecordField>;
|
||||||
|
def: TScalarRecordDefinition;
|
||||||
|
staticType: IStaticType;
|
||||||
|
boundNode: IRecordLiteralNode;
|
||||||
|
valNode: IAstNode;
|
||||||
|
valType: IStaticType;
|
||||||
|
begin
|
||||||
|
FNextIsTail := False;
|
||||||
|
SetLength(boundFields, Length(Node.Fields));
|
||||||
|
SetLength(defFields, Length(Node.Fields));
|
||||||
|
|
||||||
|
for i := 0 to High(Node.Fields) do
|
||||||
|
begin
|
||||||
|
valNode := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
||||||
|
valType := (valNode as TAstNode).StaticType;
|
||||||
|
|
||||||
|
// Records can only store scalar values
|
||||||
|
if not (valType.Kind in [stOrdinal, stFloat]) then
|
||||||
|
raise ETypeException.CreateFmt(
|
||||||
|
'Record fields must be scalar (Ordinal or Float), but field "%s" is %s',
|
||||||
|
[Node.Fields[i].Name, valType.ToString]);
|
||||||
|
|
||||||
|
boundFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Name, valNode);
|
||||||
|
|
||||||
|
var scalarKind: TScalar.TKind;
|
||||||
|
if valType.Kind = stOrdinal then
|
||||||
|
scalarKind := TScalar.TKind.Ordinal
|
||||||
|
else
|
||||||
|
scalarKind := TScalar.TKind.Float;
|
||||||
|
|
||||||
|
defFields[i] := TScalarRecordField.Create(Node.Fields[i].Name, scalarKind);
|
||||||
|
end;
|
||||||
|
|
||||||
|
def := TScalarRecordDefinition.Create(defFields);
|
||||||
|
staticType := TTypes.CreateRecord(def);
|
||||||
|
boundNode := TBoundRecordLiteralNode.Create(boundFields, def);
|
||||||
|
|
||||||
|
Result := SetType(TDataValue.FromIntf<IRecordLiteralNode>(boundNode), staticType);
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
function TAstBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||||
var
|
var
|
||||||
i: integer;
|
i: integer;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type
|
|||||||
// The logging overrides for other Visit... methods
|
// The logging overrides for other Visit... methods
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -44,6 +45,7 @@ type
|
|||||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -52,7 +54,8 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
System.TypInfo;
|
System.TypInfo,
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
{ TDebugEvaluatorVisitor }
|
{ TDebugEvaluatorVisitor }
|
||||||
|
|
||||||
@@ -156,8 +159,14 @@ end;
|
|||||||
|
|
||||||
function TDebugEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
|
function TDebugEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
AppendLine(Format('Constant (%s)', [Node.Value.ToString]));
|
|
||||||
Result := inherited VisitConstant(Node);
|
Result := inherited VisitConstant(Node);
|
||||||
|
AppendLine(Format('Constant (%s)', [Result.ToString]));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDebugEvaluatorVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
begin
|
||||||
|
Result := inherited VisitKeyword(Node);
|
||||||
|
AppendLine(Format('Keyword (%s)', [Result.ToString]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDebugEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TDebugEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
@@ -238,6 +247,18 @@ begin
|
|||||||
AppendLine(Format('} -> %s', [Result.ToString]));
|
AppendLine(Format('} -> %s', [Result.ToString]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDebugEvaluatorVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
begin
|
||||||
|
AppendLine('RecordLiteral {');
|
||||||
|
Indent;
|
||||||
|
try
|
||||||
|
Result := inherited VisitRecordLiteral(Node);
|
||||||
|
finally
|
||||||
|
Unindent;
|
||||||
|
end;
|
||||||
|
AppendLine(Format('} -> %s', [Result.ToString]));
|
||||||
|
end;
|
||||||
|
|
||||||
function TDebugEvaluatorVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
function TDebugEvaluatorVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
AppendLine('TernaryExpr{');
|
AppendLine('TernaryExpr{');
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -48,6 +49,7 @@ type
|
|||||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -65,6 +67,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
Myc.Data.Keyword,
|
||||||
Myc.Ast.Binding; // For TBound...Node classes
|
Myc.Ast.Binding; // For TBound...Node classes
|
||||||
|
|
||||||
{ TAstDumper }
|
{ TAstDumper }
|
||||||
@@ -144,6 +147,12 @@ begin
|
|||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstDumper.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
begin
|
||||||
|
LogFmt('Keyword: :%s', [Node.Value.Name]);
|
||||||
|
Result := TDataValue.Void;
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstDumper.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function TAstDumper.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
LogFmt('BinaryExpression: %s', [Node.Operator.ToString]);
|
LogFmt('BinaryExpression: %s', [Node.Operator.ToString]);
|
||||||
@@ -432,6 +441,23 @@ begin
|
|||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstDumper.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
var
|
||||||
|
field: TRecordFieldLiteral;
|
||||||
|
begin
|
||||||
|
LogFmt('RecordLiteral (%d fields)', [Length(Node.Fields)]);
|
||||||
|
Indent;
|
||||||
|
for field in Node.Fields do
|
||||||
|
begin
|
||||||
|
LogFmt('Field :%s', [field.Name]);
|
||||||
|
Indent;
|
||||||
|
field.Value.Accept(Self);
|
||||||
|
Unindent;
|
||||||
|
end;
|
||||||
|
Unindent;
|
||||||
|
Result := TDataValue.Void;
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstDumper.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TAstDumper.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
LogFmt('CreateSeries: %s', [Node.Definition]);
|
LogFmt('CreateSeries: %s', [Node.Definition]);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -39,6 +40,7 @@ type
|
|||||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -65,6 +67,7 @@ implementation
|
|||||||
uses
|
uses
|
||||||
System.TypInfo,
|
System.TypInfo,
|
||||||
System.Generics.Defaults,
|
System.Generics.Defaults,
|
||||||
|
Myc.Data.Keyword,
|
||||||
Myc.Data.Decimal,
|
Myc.Data.Decimal,
|
||||||
Myc.Data.Series,
|
Myc.Data.Series,
|
||||||
Myc.Data.Scalar.JSON;
|
Myc.Data.Scalar.JSON;
|
||||||
@@ -363,6 +366,12 @@ begin
|
|||||||
Result := Node.Value;
|
Result := Node.Value;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TEvaluatorVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
begin
|
||||||
|
// Return the shared, interned IKeyword interface as a TDataValue
|
||||||
|
Result := TDataValue.FromKeyword(Node.Value);
|
||||||
|
end;
|
||||||
|
|
||||||
function TEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
var
|
var
|
||||||
def: string;
|
def: string;
|
||||||
@@ -441,6 +450,30 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TEvaluatorVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
var
|
||||||
|
boundNode: TBoundRecordLiteralNode;
|
||||||
|
values: TArray<TScalar.TValue>;
|
||||||
|
i: Integer;
|
||||||
|
valData: TDataValue;
|
||||||
|
begin
|
||||||
|
// The node must be a bound node from the binder
|
||||||
|
boundNode := Node as TBoundRecordLiteralNode;
|
||||||
|
SetLength(values, Length(boundNode.Fields));
|
||||||
|
|
||||||
|
for i := 0 to High(boundNode.Fields) do
|
||||||
|
begin
|
||||||
|
// Evaluate the value expression for this field
|
||||||
|
valData := boundNode.Fields[i].Value.Accept(Self);
|
||||||
|
// The binder already validated this is a scalar
|
||||||
|
values[i] := valData.AsScalar.Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Create the TScalarRecord using the definition from the binder
|
||||||
|
var rec := TScalarRecord.Create(boundNode.Definition, values);
|
||||||
|
Result := TDataValue.FromRecord(rec);
|
||||||
|
end;
|
||||||
|
|
||||||
function TEvaluatorVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
function TEvaluatorVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||||
var
|
var
|
||||||
address: TResolvedAddress;
|
address: TResolvedAddress;
|
||||||
@@ -473,22 +506,46 @@ end;
|
|||||||
function TEvaluatorVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function TEvaluatorVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
var
|
var
|
||||||
leftValue, rightValue: TDataValue;
|
leftValue, rightValue: TDataValue;
|
||||||
|
resScalar: TScalar;
|
||||||
begin
|
begin
|
||||||
leftValue := Node.Left.Accept(Self);
|
leftValue := Node.Left.Accept(Self);
|
||||||
rightValue := Node.Right.Accept(Self);
|
rightValue := Node.Right.Accept(Self);
|
||||||
|
|
||||||
if (leftValue.Kind <> vkScalar) or (rightValue.Kind <> vkScalar) then
|
// Handle Keyword equality
|
||||||
raise ENotSupportedException.Create('Binary operations are only supported for scalar types.');
|
if (leftValue.Kind = vkKeyword) or (rightValue.Kind = vkKeyword) then
|
||||||
|
begin
|
||||||
|
if not (leftValue.Kind = rightValue.Kind) then
|
||||||
|
begin
|
||||||
|
// Comparing keyword to non-keyword
|
||||||
|
if Node.Operator = TScalar.TBinaryOp.NotEqual then
|
||||||
|
Result := TScalar.FromInt64(1)
|
||||||
|
else
|
||||||
|
Result := TScalar.FromInt64(0);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
var res: TScalar;
|
// Both are keywords, compare interfaces
|
||||||
if not TScalar.TryBinaryOperation(Node.Operator, leftValue.AsScalar, rightValue.AsScalar, res) then
|
case Node.Operator of
|
||||||
|
TScalar.TBinaryOp.Equal: Result := TScalar.FromInt64(Ord(leftValue.AsKeyword = rightValue.AsKeyword));
|
||||||
|
TScalar.TBinaryOp.NotEqual: Result := TScalar.FromInt64(Ord(leftValue.AsKeyword <> rightValue.AsKeyword));
|
||||||
|
else
|
||||||
|
raise ENotSupportedException.Create('Only = and <> operations are supported for Keywords.');
|
||||||
|
end;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Standard scalar operations
|
||||||
|
if (leftValue.Kind <> vkScalar) or (rightValue.Kind <> vkScalar) then
|
||||||
|
raise ENotSupportedException.Create('Binary operations are only supported for scalar or keyword types.');
|
||||||
|
|
||||||
|
if not TScalar.TryBinaryOperation(Node.Operator, leftValue.AsScalar, rightValue.AsScalar, resScalar) then
|
||||||
raise ENotSupportedException.Create(
|
raise ENotSupportedException.Create(
|
||||||
'Binary operation not supported for scalar types '
|
'Binary operation not supported for scalar types '
|
||||||
+ leftValue.AsScalar.Kind.ToString
|
+ leftValue.AsScalar.Kind.ToString
|
||||||
+ ' and '
|
+ ' and '
|
||||||
+ rightValue.AsScalar.Kind.ToString
|
+ rightValue.AsScalar.Kind.ToString
|
||||||
+ ' .');
|
+ ' .');
|
||||||
Result := res;
|
Result := resScalar;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TEvaluatorVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
function TEvaluatorVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type
|
|||||||
|
|
||||||
function JsonToConstantNode(const AObj: TJSONObject): IConstantNode;
|
function JsonToConstantNode(const AObj: TJSONObject): IConstantNode;
|
||||||
function JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode;
|
function JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode;
|
||||||
|
function JsonToKeywordNode(const AObj: TJSONObject): IKeywordNode;
|
||||||
function JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode;
|
function JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode;
|
||||||
function JsonToUnaryExprNode(const AObj: TJSONObject): IUnaryExpressionNode;
|
function JsonToUnaryExprNode(const AObj: TJSONObject): IUnaryExpressionNode;
|
||||||
function JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode;
|
function JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode;
|
||||||
@@ -46,6 +47,7 @@ type
|
|||||||
function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode;
|
function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode;
|
||||||
function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode;
|
function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode;
|
||||||
function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
|
function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
|
||||||
|
function JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
|
||||||
function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
|
function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
|
||||||
function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
|
function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
|
||||||
function JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode;
|
function JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode;
|
||||||
@@ -53,6 +55,7 @@ type
|
|||||||
// IAstVisitor implementation for serialization
|
// IAstVisitor implementation for serialization
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -70,6 +73,7 @@ type
|
|||||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -83,6 +87,9 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
{ TJsonAstConverter }
|
{ TJsonAstConverter }
|
||||||
|
|
||||||
constructor TJsonAstConverter.Create;
|
constructor TJsonAstConverter.Create;
|
||||||
@@ -123,6 +130,7 @@ begin
|
|||||||
valObj.AddPair('Value', scalarObj);
|
valObj.AddPair('Value', scalarObj);
|
||||||
end;
|
end;
|
||||||
vkText: valObj.AddPair('Value', TJSONString.Create(AValue.AsText));
|
vkText: valObj.AddPair('Value', TJSONString.Create(AValue.AsText));
|
||||||
|
vkKeyword: valObj.AddPair('Value', TJSONString.Create(AValue.AsKeyword.Name));
|
||||||
vkVoid:; // No value to add
|
vkVoid:; // No value to add
|
||||||
else
|
else
|
||||||
raise ENotSupportedException.Create('Unsupported TDataValue kind for constant serialization.');
|
raise ENotSupportedException.Create('Unsupported TDataValue kind for constant serialization.');
|
||||||
@@ -153,6 +161,17 @@ begin
|
|||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
var
|
||||||
|
obj: TJSONObject;
|
||||||
|
begin
|
||||||
|
obj := TJSONObject.Create;
|
||||||
|
obj.AddPair('NodeType', TJSONString.Create('Keyword'));
|
||||||
|
obj.AddPair('Name', TJSONString.Create(Node.Value.Name));
|
||||||
|
FJsonObjectStack.Push(obj);
|
||||||
|
Result := TDataValue.Void;
|
||||||
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function TJsonAstConverter.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
var
|
var
|
||||||
obj, leftObj, rightObj: TJSONObject;
|
obj, leftObj, rightObj: TJSONObject;
|
||||||
@@ -544,6 +563,31 @@ begin
|
|||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
var
|
||||||
|
obj, fieldObj: TJSONObject;
|
||||||
|
fieldsArray: TJSONArray;
|
||||||
|
field: TRecordFieldLiteral;
|
||||||
|
begin
|
||||||
|
obj := TJSONObject.Create;
|
||||||
|
obj.AddPair('NodeType', TJSONString.Create('RecordLiteral'));
|
||||||
|
|
||||||
|
fieldsArray := TJSONArray.Create;
|
||||||
|
for field in Node.Fields do
|
||||||
|
begin
|
||||||
|
field.Value.Accept(Self); // This pushes the value JSON onto the stack
|
||||||
|
|
||||||
|
fieldObj := TJSONObject.Create;
|
||||||
|
fieldObj.AddPair('Name', TJSONString.Create(field.Name));
|
||||||
|
fieldObj.AddPair('Value', FJsonObjectStack.Pop);
|
||||||
|
fieldsArray.Add(fieldObj);
|
||||||
|
end;
|
||||||
|
|
||||||
|
obj.AddPair('Fields', fieldsArray);
|
||||||
|
FJsonObjectStack.Push(obj);
|
||||||
|
Result := TDataValue.Void;
|
||||||
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TJsonAstConverter.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
var
|
var
|
||||||
obj: TJSONObject;
|
obj: TJSONObject;
|
||||||
@@ -622,6 +666,10 @@ begin
|
|||||||
begin
|
begin
|
||||||
Result := valObj.GetValue<string>('Value');
|
Result := valObj.GetValue<string>('Value');
|
||||||
end
|
end
|
||||||
|
else if SameText(kindStr, 'Keyword') then
|
||||||
|
begin
|
||||||
|
Result := TDataValue.FromKeyword(TKeywordRegistry.Intern(valObj.GetValue<string>('Value')));
|
||||||
|
end
|
||||||
else if SameText(kindStr, 'Void') then
|
else if SameText(kindStr, 'Void') then
|
||||||
begin
|
begin
|
||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
@@ -640,6 +688,11 @@ begin
|
|||||||
Result := TAst.Identifier(AObj.GetValue<string>('Name'));
|
Result := TAst.Identifier(AObj.GetValue<string>('Name'));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.JsonToKeywordNode(const AObj: TJSONObject): IKeywordNode;
|
||||||
|
begin
|
||||||
|
Result := TAst.Keyword(AObj.GetValue<string>('Name'));
|
||||||
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode;
|
function TJsonAstConverter.JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode;
|
||||||
var
|
var
|
||||||
opStr: string;
|
opStr: string;
|
||||||
@@ -850,6 +903,23 @@ begin
|
|||||||
Result := TAst.MemberAccess(JsonToNode(AObj.GetValue('Base')), JsonToIdentifierNode(AObj.GetValue('Member') as TJSONObject));
|
Result := TAst.MemberAccess(JsonToNode(AObj.GetValue('Base')), JsonToIdentifierNode(AObj.GetValue('Member') as TJSONObject));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
|
||||||
|
var
|
||||||
|
fields: TArray<TRecordFieldLiteral>;
|
||||||
|
fieldsArray: TJSONArray;
|
||||||
|
fieldObj: TJSONObject;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
fieldsArray := AObj.GetValue<TJSONArray>('Fields');
|
||||||
|
SetLength(fields, fieldsArray.Count);
|
||||||
|
for i := 0 to fieldsArray.Count - 1 do
|
||||||
|
begin
|
||||||
|
fieldObj := fieldsArray.Items[i] as TJSONObject;
|
||||||
|
fields[i] := TRecordFieldLiteral.Create(fieldObj.GetValue<string>('Name'), JsonToNode(fieldObj.GetValue('Value')));
|
||||||
|
end;
|
||||||
|
Result := TAst.RecordLiteral(fields);
|
||||||
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
|
function TJsonAstConverter.JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
|
||||||
begin
|
begin
|
||||||
Result := TAst.CreateSeries(AObj.GetValue<string>('Definition'));
|
Result := TAst.CreateSeries(AObj.GetValue<string>('Definition'));
|
||||||
@@ -891,6 +961,8 @@ begin
|
|||||||
Result := JsonToConstantNode(obj)
|
Result := JsonToConstantNode(obj)
|
||||||
else if nodeType = 'Identifier' then
|
else if nodeType = 'Identifier' then
|
||||||
Result := JsonToIdentifierNode(obj)
|
Result := JsonToIdentifierNode(obj)
|
||||||
|
else if nodeType = 'Keyword' then
|
||||||
|
Result := JsonToKeywordNode(obj)
|
||||||
else if nodeType = 'BinaryExpr' then
|
else if nodeType = 'BinaryExpr' then
|
||||||
Result := JsonToBinaryExprNode(obj)
|
Result := JsonToBinaryExprNode(obj)
|
||||||
else if nodeType = 'UnaryExpr' then
|
else if nodeType = 'UnaryExpr' then
|
||||||
@@ -925,6 +997,8 @@ begin
|
|||||||
Result := JsonToIndexerNode(obj)
|
Result := JsonToIndexerNode(obj)
|
||||||
else if nodeType = 'MemberAccess' then
|
else if nodeType = 'MemberAccess' then
|
||||||
Result := JsonToMemberAccessNode(obj)
|
Result := JsonToMemberAccessNode(obj)
|
||||||
|
else if nodeType = 'RecordLiteral' then
|
||||||
|
Result := JsonToRecordLiteralNode(obj)
|
||||||
else if nodeType = 'CreateSeries' then
|
else if nodeType = 'CreateSeries' then
|
||||||
Result := JsonToCreateSeriesNode(obj)
|
Result := JsonToCreateSeriesNode(obj)
|
||||||
else if nodeType = 'AddSeriesItem' then
|
else if nodeType = 'AddSeriesItem' then
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ uses
|
|||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
System.Generics.Collections,
|
System.Generics.Collections,
|
||||||
Myc.Data.Scalar,
|
Myc.Data.Scalar,
|
||||||
Myc.Data.Value;
|
Myc.Data.Value,
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
type
|
type
|
||||||
// --- Forward Declarations to break cycles ---
|
// --- Forward Declarations to break cycles ---
|
||||||
@@ -14,6 +15,7 @@ type
|
|||||||
IAstNode = interface;
|
IAstNode = interface;
|
||||||
IIdentifierNode = interface;
|
IIdentifierNode = interface;
|
||||||
IConstantNode = interface;
|
IConstantNode = interface;
|
||||||
|
IKeywordNode = interface;
|
||||||
IBinaryExpressionNode = interface;
|
IBinaryExpressionNode = interface;
|
||||||
IUnaryExpressionNode = interface;
|
IUnaryExpressionNode = interface;
|
||||||
IIfExpressionNode = interface;
|
IIfExpressionNode = interface;
|
||||||
@@ -30,6 +32,7 @@ type
|
|||||||
IUnquoteSplicingNode = interface;
|
IUnquoteSplicingNode = interface;
|
||||||
IIndexerNode = interface;
|
IIndexerNode = interface;
|
||||||
IMemberAccessNode = interface;
|
IMemberAccessNode = interface;
|
||||||
|
IRecordLiteralNode = interface;
|
||||||
ICreateSeriesNode = interface;
|
ICreateSeriesNode = interface;
|
||||||
IAddSeriesItemNode = interface;
|
IAddSeriesItemNode = interface;
|
||||||
ISeriesLengthNode = interface;
|
ISeriesLengthNode = interface;
|
||||||
@@ -50,9 +53,17 @@ type
|
|||||||
class operator Equal(const A: TResolvedAddress; B: TResolvedAddress): Boolean;
|
class operator Equal(const A: TResolvedAddress; B: TResolvedAddress): Boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// A single field in a record literal
|
||||||
|
TRecordFieldLiteral = record
|
||||||
|
Name: string; // The field name (from keyword :name)
|
||||||
|
Value: IAstNode;
|
||||||
|
constructor Create(const AName: string; const AValue: IAstNode);
|
||||||
|
end;
|
||||||
|
|
||||||
IAstVisitor = interface
|
IAstVisitor = interface
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue;
|
function VisitConstant(const Node: IConstantNode): TDataValue;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||||
@@ -69,6 +80,7 @@ type
|
|||||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
|
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
||||||
@@ -94,6 +106,15 @@ type
|
|||||||
property Name: string read GetName;
|
property Name: string read GetName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Represents a keyword literal in the AST (e.g., :foo)
|
||||||
|
IKeywordNode = interface(IAstNode)
|
||||||
|
{$region 'private'}
|
||||||
|
function GetValue: IKeyword;
|
||||||
|
{$endregion}
|
||||||
|
// The interned keyword object
|
||||||
|
property Value: IKeyword read GetValue;
|
||||||
|
end;
|
||||||
|
|
||||||
IBinaryExpressionNode = interface(IAstNode)
|
IBinaryExpressionNode = interface(IAstNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetLeft: IAstNode;
|
function GetLeft: IAstNode;
|
||||||
@@ -249,6 +270,14 @@ type
|
|||||||
property Member: IIdentifierNode read GetMember;
|
property Member: IIdentifierNode read GetMember;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Represents a record literal, e.g., {:a 1 :b 2}
|
||||||
|
IRecordLiteralNode = interface(IAstNode)
|
||||||
|
{$region 'private'}
|
||||||
|
function GetFields: TArray<TRecordFieldLiteral>;
|
||||||
|
{$endregion}
|
||||||
|
property Fields: TArray<TRecordFieldLiteral> read GetFields;
|
||||||
|
end;
|
||||||
|
|
||||||
ICreateSeriesNode = interface(IAstNode)
|
ICreateSeriesNode = interface(IAstNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetDefinition: String;
|
function GetDefinition: String;
|
||||||
@@ -304,4 +333,12 @@ begin
|
|||||||
Dest.SlotIndex := -1;
|
Dest.SlotIndex := -1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TRecordFieldLiteral }
|
||||||
|
|
||||||
|
constructor TRecordFieldLiteral.Create(const AName: string; const AValue: IAstNode);
|
||||||
|
begin
|
||||||
|
Name := AName;
|
||||||
|
Value := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
+102
-1
@@ -24,6 +24,7 @@ uses
|
|||||||
System.Math,
|
System.Math,
|
||||||
Myc.Data.Scalar,
|
Myc.Data.Scalar,
|
||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
|
Myc.Data.Keyword,
|
||||||
Myc.Ast;
|
Myc.Ast;
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -35,11 +36,14 @@ type
|
|||||||
tkRightParen, // )
|
tkRightParen, // )
|
||||||
tkLeftBracket, // [
|
tkLeftBracket, // [
|
||||||
tkRightBracket, // ]
|
tkRightBracket, // ]
|
||||||
|
tkLeftBrace, // {
|
||||||
|
tkRightBrace, // }
|
||||||
tkQuote, // '
|
tkQuote, // '
|
||||||
tkBacktick, // `
|
tkBacktick, // `
|
||||||
tkTilde, // ~
|
tkTilde, // ~
|
||||||
tkAt, // @
|
tkAt, // @
|
||||||
tkIdentifier,
|
tkIdentifier,
|
||||||
|
tkKeyword,
|
||||||
tkNumber,
|
tkNumber,
|
||||||
tkString,
|
tkString,
|
||||||
tkEOF,
|
tkEOF,
|
||||||
@@ -82,6 +86,7 @@ type
|
|||||||
procedure Consume(AExpectedKind: TTokenKind);
|
procedure Consume(AExpectedKind: TTokenKind);
|
||||||
procedure NextToken;
|
procedure NextToken;
|
||||||
function ParseList: IAstNode;
|
function ParseList: IAstNode;
|
||||||
|
function ParseRecordLiteral: IAstNode;
|
||||||
function ParseParameterList: TArray<IIdentifierNode>;
|
function ParseParameterList: TArray<IIdentifierNode>;
|
||||||
function ParseExpression: TExpr;
|
function ParseExpression: TExpr;
|
||||||
public
|
public
|
||||||
@@ -108,6 +113,7 @@ type
|
|||||||
function Execute(const RootNode: IAstNode): TDataValue;
|
function Execute(const RootNode: IAstNode): TDataValue;
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -124,6 +130,7 @@ type
|
|||||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -158,7 +165,7 @@ var
|
|||||||
begin
|
begin
|
||||||
startPos := FCurrentPos;
|
startPos := FCurrentPos;
|
||||||
// Reader macro characters are now also delimiters for identifiers.
|
// Reader macro characters are now also delimiters for identifiers.
|
||||||
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '''', '`', '~']))) do
|
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '{', '}', '''', '`', '~']))) do
|
||||||
Advance;
|
Advance;
|
||||||
Result := Copy(FSource, startPos, FCurrentPos - startPos);
|
Result := Copy(FSource, startPos, FCurrentPos - startPos);
|
||||||
end;
|
end;
|
||||||
@@ -237,6 +244,16 @@ begin
|
|||||||
Result.Kind := tkRightBracket;
|
Result.Kind := tkRightBracket;
|
||||||
Advance;
|
Advance;
|
||||||
end;
|
end;
|
||||||
|
'{':
|
||||||
|
begin
|
||||||
|
Result.Kind := tkLeftBrace;
|
||||||
|
Advance;
|
||||||
|
end;
|
||||||
|
'}':
|
||||||
|
begin
|
||||||
|
Result.Kind := tkRightBrace;
|
||||||
|
Advance;
|
||||||
|
end;
|
||||||
'''':
|
'''':
|
||||||
begin
|
begin
|
||||||
Result.Kind := tkQuote;
|
Result.Kind := tkQuote;
|
||||||
@@ -262,6 +279,14 @@ begin
|
|||||||
Result.Kind := tkString;
|
Result.Kind := tkString;
|
||||||
Result.Text := ReadString;
|
Result.Text := ReadString;
|
||||||
end;
|
end;
|
||||||
|
':':
|
||||||
|
begin
|
||||||
|
Advance; // Skip :
|
||||||
|
Result.Kind := tkKeyword;
|
||||||
|
Result.Text := ReadIdentifier;
|
||||||
|
if Result.Text.IsEmpty then
|
||||||
|
Result.Kind := tkError;
|
||||||
|
end;
|
||||||
else
|
else
|
||||||
if c.IsDigit or ((c = '-') and (FCurrentPos < Length(FSource)) and FSource[FCurrentPos + 1].IsDigit) then
|
if c.IsDigit or ((c = '-') and (FCurrentPos < Length(FSource)) and FSource[FCurrentPos + 1].IsDigit) then
|
||||||
begin
|
begin
|
||||||
@@ -326,6 +351,41 @@ begin
|
|||||||
Consume(tkRightBracket);
|
Consume(tkRightBracket);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TParser.ParseRecordLiteral: IAstNode;
|
||||||
|
var
|
||||||
|
fields: TList<TRecordFieldLiteral>;
|
||||||
|
fieldName: string;
|
||||||
|
fieldValue: IAstNode;
|
||||||
|
begin
|
||||||
|
Consume(tkLeftBrace);
|
||||||
|
fields := TList<TRecordFieldLiteral>.Create;
|
||||||
|
try
|
||||||
|
while FCurrentToken.Kind <> tkRightBrace do
|
||||||
|
begin
|
||||||
|
if FCurrentToken.Kind = tkEOF then
|
||||||
|
raise Exception.Create('Syntax Error: Unexpected end of file in record literal.');
|
||||||
|
|
||||||
|
// Key must be a keyword
|
||||||
|
if FCurrentToken.Kind <> tkKeyword then
|
||||||
|
raise Exception.Create('Syntax Error: Expected keyword (e.g., :key) as field name in record literal.');
|
||||||
|
fieldName := FCurrentToken.Text;
|
||||||
|
NextToken;
|
||||||
|
|
||||||
|
// Value can be any expression
|
||||||
|
if FCurrentToken.Kind = tkRightBrace then
|
||||||
|
raise Exception.Create('Syntax Error: Missing value for key ' + fieldName + ' in record literal.');
|
||||||
|
fieldValue := ParseExpression.Node;
|
||||||
|
|
||||||
|
fields.Add(TRecordFieldLiteral.Create(fieldName, fieldValue));
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := TAst.RecordLiteral(fields.ToArray);
|
||||||
|
finally
|
||||||
|
fields.Free;
|
||||||
|
end;
|
||||||
|
Consume(tkRightBrace);
|
||||||
|
end;
|
||||||
|
|
||||||
function TParser.ParseList: IAstNode;
|
function TParser.ParseList: IAstNode;
|
||||||
|
|
||||||
var
|
var
|
||||||
@@ -504,6 +564,11 @@ begin
|
|||||||
Result.Node := TAst.Constant(FCurrentToken.Text);
|
Result.Node := TAst.Constant(FCurrentToken.Text);
|
||||||
NextToken;
|
NextToken;
|
||||||
end;
|
end;
|
||||||
|
tkKeyword:
|
||||||
|
begin
|
||||||
|
Result.Node := TAst.Keyword(FCurrentToken.Text);
|
||||||
|
NextToken;
|
||||||
|
end;
|
||||||
tkIdentifier:
|
tkIdentifier:
|
||||||
begin
|
begin
|
||||||
Result.Node := TAst.Identifier(FCurrentToken.Text);
|
Result.Node := TAst.Identifier(FCurrentToken.Text);
|
||||||
@@ -511,6 +576,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
tkLeftParen: Result.Node := ParseList;
|
tkLeftParen: Result.Node := ParseList;
|
||||||
tkLeftBracket: Result.Params := ParseParameterList;
|
tkLeftBracket: Result.Params := ParseParameterList;
|
||||||
|
tkLeftBrace: Result.Node := ParseRecordLiteral;
|
||||||
tkEOF: {nop};
|
tkEOF: {nop};
|
||||||
else
|
else
|
||||||
raise Exception.CreateFmt('Syntax Error: Unexpected token %s', [FCurrentToken.Kind.ToString]);
|
raise Exception.CreateFmt('Syntax Error: Unexpected token %s', [FCurrentToken.Kind.ToString]);
|
||||||
@@ -590,6 +656,12 @@ begin
|
|||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPrettyPrintVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
begin
|
||||||
|
Append(':' + Node.Value.Name);
|
||||||
|
Result := TDataValue.Void;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
Append('(' + Node.Operator.ToString);
|
Append('(' + Node.Operator.ToString);
|
||||||
@@ -829,6 +901,31 @@ begin
|
|||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPrettyPrintVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
var
|
||||||
|
field: TRecordFieldLiteral;
|
||||||
|
begin
|
||||||
|
if Length(Node.Fields) = 0 then
|
||||||
|
begin
|
||||||
|
Append('{}');
|
||||||
|
exit(TDataValue.Void);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Append('{');
|
||||||
|
Indent;
|
||||||
|
for field in Node.Fields do
|
||||||
|
begin
|
||||||
|
NewLine;
|
||||||
|
Append(':' + field.Name);
|
||||||
|
Append(' ');
|
||||||
|
field.Value.Accept(Self);
|
||||||
|
end;
|
||||||
|
Unindent;
|
||||||
|
NewLine;
|
||||||
|
Append('}');
|
||||||
|
Result := TDataValue.Void;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPrettyPrintVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TPrettyPrintVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
Append(Format('(new-series "%s")', [Node.Definition]));
|
Append(Format('(new-series "%s")', [Node.Definition]));
|
||||||
@@ -896,10 +993,14 @@ begin
|
|||||||
tkRightParen: Result := ')';
|
tkRightParen: Result := ')';
|
||||||
tkLeftBracket: Result := '[';
|
tkLeftBracket: Result := '[';
|
||||||
tkRightBracket: Result := ']';
|
tkRightBracket: Result := ']';
|
||||||
|
tkLeftBrace: Result := '{';
|
||||||
|
tkRightBrace: Result := '}';
|
||||||
tkQuote: Result := '''';
|
tkQuote: Result := '''';
|
||||||
tkBacktick: Result := '`';
|
tkBacktick: Result := '`';
|
||||||
tkTilde: Result := '~';
|
tkTilde: Result := '~';
|
||||||
|
tkAt: Result := '@';
|
||||||
tkIdentifier: Result := '<identifier>';
|
tkIdentifier: Result := '<identifier>';
|
||||||
|
tkKeyword: Result := '<keyword>';
|
||||||
tkNumber: Result := '<number>';
|
tkNumber: Result := '<number>';
|
||||||
tkString: Result := '<string>';
|
tkString: Result := '<string>';
|
||||||
tkEOF: Result := '<EOF>';
|
tkEOF: Result := '<EOF>';
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ interface
|
|||||||
uses
|
uses
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
System.Generics.Collections,
|
System.Generics.Collections,
|
||||||
Myc.Data.Scalar;
|
Myc.Data.Scalar,
|
||||||
|
Myc.Data.Keyword;
|
||||||
|
|
||||||
type
|
type
|
||||||
IStaticType = interface;
|
IStaticType = interface;
|
||||||
@@ -17,6 +18,7 @@ type
|
|||||||
stOrdinal, // Int64
|
stOrdinal, // Int64
|
||||||
stFloat, // Double
|
stFloat, // Double
|
||||||
stText,
|
stText,
|
||||||
|
stKeyword,
|
||||||
stMethod,
|
stMethod,
|
||||||
stSeries,
|
stSeries,
|
||||||
stRecord,
|
stRecord,
|
||||||
@@ -77,6 +79,8 @@ type
|
|||||||
FFloat: IStaticType;
|
FFloat: IStaticType;
|
||||||
class var
|
class var
|
||||||
FText: IStaticType;
|
FText: IStaticType;
|
||||||
|
class var
|
||||||
|
FKeyword: IStaticType;
|
||||||
class constructor Create;
|
class constructor Create;
|
||||||
public
|
public
|
||||||
// Flyweight accessors for simple types
|
// Flyweight accessors for simple types
|
||||||
@@ -85,6 +89,7 @@ type
|
|||||||
class property Ordinal: IStaticType read FOrdinal;
|
class property Ordinal: IStaticType read FOrdinal;
|
||||||
class property Float: IStaticType read FFloat;
|
class property Float: IStaticType read FFloat;
|
||||||
class property Text: IStaticType read FText;
|
class property Text: IStaticType read FText;
|
||||||
|
class property Keyword: IStaticType read FKeyword;
|
||||||
|
|
||||||
// Factory functions for complex types
|
// Factory functions for complex types
|
||||||
class function CreateSeries(const AElementType: IStaticType): IStaticType; static;
|
class function CreateSeries(const AElementType: IStaticType): IStaticType; static;
|
||||||
@@ -124,6 +129,7 @@ begin
|
|||||||
stOrdinal: Result := 'Ordinal';
|
stOrdinal: Result := 'Ordinal';
|
||||||
stFloat: Result := 'Float';
|
stFloat: Result := 'Float';
|
||||||
stText: Result := 'Text';
|
stText: Result := 'Text';
|
||||||
|
stKeyword: Result := 'Keyword';
|
||||||
stMethod: Result := 'Method';
|
stMethod: Result := 'Method';
|
||||||
stSeries: Result := 'Series';
|
stSeries: Result := 'Series';
|
||||||
stRecord: Result := 'Record';
|
stRecord: Result := 'Record';
|
||||||
@@ -411,6 +417,7 @@ begin
|
|||||||
FOrdinal := TSimpleStaticType.Create(stOrdinal);
|
FOrdinal := TSimpleStaticType.Create(stOrdinal);
|
||||||
FFloat := TSimpleStaticType.Create(stFloat);
|
FFloat := TSimpleStaticType.Create(stFloat);
|
||||||
FText := TSimpleStaticType.Create(stText);
|
FText := TSimpleStaticType.Create(stText);
|
||||||
|
FKeyword := TSimpleStaticType.Create(stKeyword);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TTypes.CreateMethod(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType): IStaticType;
|
class function TTypes.CreateMethod(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType): IStaticType;
|
||||||
@@ -541,12 +548,24 @@ begin
|
|||||||
Result := TTypes.Float;
|
Result := TTypes.Float;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TScalar.TBinaryOp.Equal,
|
TScalar.TBinaryOp.Equal, TScalar.TBinaryOp.NotEqual:
|
||||||
TScalar.TBinaryOp.NotEqual,
|
begin
|
||||||
TScalar.TBinaryOp.Less,
|
// Allow equality checks for Keywords
|
||||||
TScalar.TBinaryOp.Greater,
|
if (promotedKind = stKeyword) then
|
||||||
TScalar.TBinaryOp.LessOrEqual,
|
begin
|
||||||
TScalar.TBinaryOp.GreaterOrEqual:
|
Result := TTypes.Ordinal;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Comparison requires Ordinal or Float, but *always* results in Ordinal (boolean)
|
||||||
|
if not (promotedKind in [stOrdinal, stFloat]) then
|
||||||
|
raise ETypeException.CreateFmt(
|
||||||
|
'Comparison operator %s requires Ordinal, Float, or Keyword, but got %s after promotion',
|
||||||
|
[Op.ToString, promotedType.ToString]);
|
||||||
|
Result := TTypes.Ordinal;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TScalar.TBinaryOp.Less, TScalar.TBinaryOp.Greater, TScalar.TBinaryOp.LessOrEqual, TScalar.TBinaryOp.GreaterOrEqual:
|
||||||
begin
|
begin
|
||||||
// Comparison requires Ordinal or Float, but *always* results in Ordinal (boolean)
|
// Comparison requires Ordinal or Float, but *always* results in Ordinal (boolean)
|
||||||
if not (promotedKind in [stOrdinal, stFloat]) then
|
if not (promotedKind in [stOrdinal, stFloat]) then
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; virtual; abstract;
|
function VisitConstant(const Node: IConstantNode): TDataValue; virtual; abstract;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual; abstract;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual; abstract;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; virtual; abstract;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; virtual; abstract;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; virtual; abstract;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; virtual; abstract;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; virtual; abstract;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual; abstract;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual; abstract;
|
||||||
@@ -31,6 +32,7 @@ type
|
|||||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; virtual; abstract;
|
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; virtual; abstract;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; virtual; abstract;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; virtual; abstract;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; virtual; abstract;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; virtual; abstract;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; virtual; abstract;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; virtual; abstract;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; virtual; abstract;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; virtual; abstract;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; virtual; abstract;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; virtual; abstract;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; virtual; abstract;
|
||||||
@@ -51,6 +53,7 @@ type
|
|||||||
// These virtual methods implement the default identity-transformation (cloning) behavior.
|
// These virtual methods implement the default identity-transformation (cloning) behavior.
|
||||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||||
|
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||||
@@ -67,6 +70,7 @@ type
|
|||||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
||||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||||
|
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||||
@@ -126,6 +130,12 @@ begin
|
|||||||
Result := TDataValue.FromIntf<IIdentifierNode>(Node);
|
Result := TDataValue.FromIntf<IIdentifierNode>(Node);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstTransformer.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||||
|
begin
|
||||||
|
// Keywords are interned and immutable
|
||||||
|
Result := TDataValue.FromIntf<IKeywordNode>(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstTransformer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function TAstTransformer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
var left := Accept(Node.Left).AsIntf<IAstNode>;
|
var left := Accept(Node.Left).AsIntf<IAstNode>;
|
||||||
@@ -316,6 +326,30 @@ begin
|
|||||||
Result := TDataValue.FromIntf<IMemberAccessNode>(TAst.MemberAccess(base, member));
|
Result := TDataValue.FromIntf<IMemberAccessNode>(TAst.MemberAccess(base, member));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
hasChanged: Boolean;
|
||||||
|
newFields: TArray<TRecordFieldLiteral>;
|
||||||
|
newValue: IAstNode;
|
||||||
|
begin
|
||||||
|
hasChanged := False;
|
||||||
|
SetLength(newFields, Length(Node.Fields));
|
||||||
|
|
||||||
|
for i := 0 to High(Node.Fields) do
|
||||||
|
begin
|
||||||
|
newValue := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
||||||
|
if newValue <> Node.Fields[i].Value then
|
||||||
|
hasChanged := True;
|
||||||
|
newFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Name, newValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if hasChanged then
|
||||||
|
Result := TDataValue.FromIntf<IRecordLiteralNode>(TAst.RecordLiteral(newFields))
|
||||||
|
else
|
||||||
|
Result := TDataValue.FromIntf<IRecordLiteralNode>(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
Result := TDataValue.FromIntf<ICreateSeriesNode>(Node);
|
Result := TDataValue.FromIntf<ICreateSeriesNode>(Node);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ uses
|
|||||||
System.Generics.Defaults,
|
System.Generics.Defaults,
|
||||||
Myc.Data.Scalar,
|
Myc.Data.Scalar,
|
||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
|
Myc.Data.Keyword,
|
||||||
Myc.Ast.Nodes,
|
Myc.Ast.Nodes,
|
||||||
Myc.Ast.Types,
|
Myc.Ast.Types,
|
||||||
Myc.Ast.Scope;
|
Myc.Ast.Scope;
|
||||||
@@ -31,6 +32,7 @@ type
|
|||||||
// --- Factory functions ---
|
// --- Factory functions ---
|
||||||
class function Constant(const AValue: TDataValue): IConstantNode; overload; static;
|
class function Constant(const AValue: TDataValue): IConstantNode; overload; static;
|
||||||
class function Constant(const AValue: String): IConstantNode; overload; static;
|
class function Constant(const AValue: String): IConstantNode; overload; static;
|
||||||
|
class function Keyword(const AName: string): IKeywordNode; static;
|
||||||
class function Identifier(AName: string): IIdentifierNode; static;
|
class function Identifier(AName: string): IIdentifierNode; static;
|
||||||
class function BinaryExpr(ALeft: IAstNode; AOperator: TScalar.TBinaryOp; ARight: IAstNode): IBinaryExpressionNode; static;
|
class function BinaryExpr(ALeft: IAstNode; AOperator: TScalar.TBinaryOp; ARight: IAstNode): IBinaryExpressionNode; static;
|
||||||
class function UnaryExpr(const AOperator: TScalar.TUnaryOp; const ARight: IAstNode): IUnaryExpressionNode; static;
|
class function UnaryExpr(const AOperator: TScalar.TUnaryOp; const ARight: IAstNode): IUnaryExpressionNode; static;
|
||||||
@@ -57,6 +59,7 @@ type
|
|||||||
class function AssignResult(const AValue: IAstNode): IAssignmentNode; static; deprecated;
|
class function AssignResult(const AValue: IAstNode): IAssignmentNode; static; deprecated;
|
||||||
class function Indexer(const ABase: IAstNode; const AIndex: IAstNode): IIndexerNode; static;
|
class function Indexer(const ABase: IAstNode; const AIndex: IAstNode): IIndexerNode; static;
|
||||||
class function MemberAccess(const ABase: IAstNode; const AMember: IIdentifierNode): IMemberAccessNode; static;
|
class function MemberAccess(const ABase: IAstNode; const AMember: IIdentifierNode): IMemberAccessNode; static;
|
||||||
|
class function RecordLiteral(const AFields: TArray<TRecordFieldLiteral>): IRecordLiteralNode; static;
|
||||||
class function CreateSeries(const ADefinition: String): ICreateSeriesNode; static;
|
class function CreateSeries(const ADefinition: String): ICreateSeriesNode; static;
|
||||||
class function AddSeriesItem(
|
class function AddSeriesItem(
|
||||||
const ASeries: IIdentifierNode;
|
const ASeries: IIdentifierNode;
|
||||||
@@ -96,6 +99,16 @@ type
|
|||||||
property Name: string read FName;
|
property Name: string read FName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TKeywordNode = class(TAstNode, IKeywordNode)
|
||||||
|
private
|
||||||
|
FValue: IKeyword;
|
||||||
|
function GetValue: IKeyword;
|
||||||
|
public
|
||||||
|
constructor Create(const AName: string);
|
||||||
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
|
property Value: IKeyword read FValue;
|
||||||
|
end;
|
||||||
|
|
||||||
TBinaryExpressionNode = class(TAstNode, IBinaryExpressionNode)
|
TBinaryExpressionNode = class(TAstNode, IBinaryExpressionNode)
|
||||||
private
|
private
|
||||||
FLeft: IAstNode;
|
FLeft: IAstNode;
|
||||||
@@ -287,6 +300,16 @@ type
|
|||||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TRecordLiteralNode = class(TAstNode, IRecordLiteralNode)
|
||||||
|
private
|
||||||
|
FFields: TArray<TRecordFieldLiteral>;
|
||||||
|
function GetFields: TArray<TRecordFieldLiteral>;
|
||||||
|
public
|
||||||
|
constructor Create(const AFields: TArray<TRecordFieldLiteral>);
|
||||||
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
|
property Fields: TArray<TRecordFieldLiteral> read FFields;
|
||||||
|
end;
|
||||||
|
|
||||||
TCreateSeriesNode = class(TAstNode, ICreateSeriesNode)
|
TCreateSeriesNode = class(TAstNode, ICreateSeriesNode)
|
||||||
private
|
private
|
||||||
FDefinition: String;
|
FDefinition: String;
|
||||||
@@ -367,6 +390,25 @@ begin
|
|||||||
Result := FName;
|
Result := FName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TKeywordNode }
|
||||||
|
|
||||||
|
constructor TKeywordNode.Create(const AName: string);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FValue := TKeywordRegistry.Intern(AName);
|
||||||
|
StaticType := TTypes.Keyword;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TKeywordNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
||||||
|
begin
|
||||||
|
Result := Visitor.VisitKeyword(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TKeywordNode.GetValue: IKeyword;
|
||||||
|
begin
|
||||||
|
Result := FValue;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TBinaryExpressionNode }
|
{ TBinaryExpressionNode }
|
||||||
|
|
||||||
constructor TBinaryExpressionNode.Create(const ALeft: IAstNode; AOperator: TScalar.TBinaryOp; const ARight: IAstNode);
|
constructor TBinaryExpressionNode.Create(const ALeft: IAstNode; AOperator: TScalar.TBinaryOp; const ARight: IAstNode);
|
||||||
@@ -768,6 +810,24 @@ begin
|
|||||||
Result := FMember;
|
Result := FMember;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TRecordLiteralNode }
|
||||||
|
|
||||||
|
constructor TRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FFields := AFields;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRecordLiteralNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
||||||
|
begin
|
||||||
|
Result := Visitor.VisitRecordLiteral(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRecordLiteralNode.GetFields: TArray<TRecordFieldLiteral>;
|
||||||
|
begin
|
||||||
|
Result := FFields;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TCreateSeriesNode }
|
{ TCreateSeriesNode }
|
||||||
|
|
||||||
constructor TCreateSeriesNode.Create(const ADefinition: String);
|
constructor TCreateSeriesNode.Create(const ADefinition: String);
|
||||||
@@ -930,6 +990,11 @@ begin
|
|||||||
Result := TIndexerNode.Create(ABase, AIndex);
|
Result := TIndexerNode.Create(ABase, AIndex);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TAst.Keyword(const AName: string): IKeywordNode;
|
||||||
|
begin
|
||||||
|
Result := TKeywordNode.Create(AName);
|
||||||
|
end;
|
||||||
|
|
||||||
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode;
|
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode;
|
||||||
begin
|
begin
|
||||||
Result := TLambdaExpressionNode.Create(AParameters, ABody);
|
Result := TLambdaExpressionNode.Create(AParameters, ABody);
|
||||||
@@ -965,6 +1030,11 @@ begin
|
|||||||
Result := TRecurNode.Create(args);
|
Result := TRecurNode.Create(args);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TAst.RecordLiteral(const AFields: TArray<TRecordFieldLiteral>): IRecordLiteralNode;
|
||||||
|
begin
|
||||||
|
Result := TRecordLiteralNode.Create(AFields);
|
||||||
|
end;
|
||||||
|
|
||||||
class function TAst.SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode;
|
class function TAst.SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode;
|
||||||
begin
|
begin
|
||||||
Result := TSeriesLengthNode.Create(ASeries);
|
Result := TSeriesLengthNode.Create(ASeries);
|
||||||
|
|||||||
Reference in New Issue
Block a user