New visualizer
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -20,8 +20,7 @@ uses
|
|||||||
Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas',
|
Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas',
|
||||||
Myc.Utils in '..\Src\Myc.Utils.pas',
|
Myc.Utils in '..\Src\Myc.Utils.pas',
|
||||||
Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas',
|
Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas',
|
||||||
Myc.Ast.Types in '..\Src\AST\Myc.Ast.Types.pas',
|
Myc.Ast.Types in '..\Src\AST\Myc.Ast.Types.pas';
|
||||||
Myc.Fmx.AstVisualizer in 'Myc.Fmx.AstVisualizer.pas';
|
|
||||||
|
|
||||||
{$R *.res}
|
{$R *.res}
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,6 @@
|
|||||||
<DCCReference Include="..\Src\Myc.Utils.pas"/>
|
<DCCReference Include="..\Src\Myc.Utils.pas"/>
|
||||||
<DCCReference Include="..\Src\AST\Myc.Ast.Script.pas"/>
|
<DCCReference Include="..\Src\AST\Myc.Ast.Script.pas"/>
|
||||||
<DCCReference Include="..\Src\AST\Myc.Ast.Types.pas"/>
|
<DCCReference Include="..\Src\AST\Myc.Ast.Types.pas"/>
|
||||||
<DCCReference Include="Myc.Fmx.AstVisualizer.pas"/>
|
|
||||||
<BuildConfiguration Include="Base">
|
<BuildConfiguration Include="Base">
|
||||||
<Key>Base</Key>
|
<Key>Base</Key>
|
||||||
</BuildConfiguration>
|
</BuildConfiguration>
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ uses
|
|||||||
FMX.Layouts,
|
FMX.Layouts,
|
||||||
FMX.Objects,
|
FMX.Objects,
|
||||||
Myc.Ast.Debugger,
|
Myc.Ast.Debugger,
|
||||||
Myc.Fmx.AstVisualizer,
|
|
||||||
Myc.Fmx.AstEditor.Node,
|
Myc.Fmx.AstEditor.Node,
|
||||||
Myc.Fmx.AstEditor.Workspace,
|
Myc.Fmx.AstEditor.Workspace,
|
||||||
FMX.DialogService,
|
FMX.DialogService,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -91,7 +91,7 @@ implementation
|
|||||||
uses
|
uses
|
||||||
System.Math,
|
System.Math,
|
||||||
FMX.Platform,
|
FMX.Platform,
|
||||||
Myc.Fmx.AstVisualizer;
|
Myc.Fmx.AstEditor.Node;
|
||||||
|
|
||||||
{ TPinConnection }
|
{ TPinConnection }
|
||||||
|
|
||||||
@@ -111,7 +111,8 @@ end;
|
|||||||
|
|
||||||
procedure TAuraWorkspace.Build(const RootNode: IAstNode; const Position: TPointF);
|
procedure TAuraWorkspace.Build(const RootNode: IAstNode; const Position: TPointF);
|
||||||
begin
|
begin
|
||||||
RootNode.Accept(TAstVisualizer.CreateVisitor(Self, Position));
|
var visu := TAstVisualizer.Create(Self, Self, 0) as IAstVisualizer;
|
||||||
|
visu.CallAccept(RootNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAuraWorkspace.DoDeleteChildren;
|
procedure TAuraWorkspace.DoDeleteChildren;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit Myc.Fmx.AstVisualizer;
|
unit Myc.Fmx.AstVisualizer deprecated;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
@@ -25,14 +25,13 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
// Visits the AST and creates visual TAuraNode representations on a TAuraWorkspace.
|
// Visits the AST and creates visual TAuraNode representations on a TAuraWorkspace.
|
||||||
TAstVisualizer = class(TAstVisitor)
|
TAstVisualizer = class(TAstVisitor, IAstVisualizer)
|
||||||
private
|
private
|
||||||
FWorkspace: TAuraWorkspace;
|
FCurrentPos: TPointF;
|
||||||
FParentControl: TControl; // The current parent FMX control for newly created nodes
|
|
||||||
FCurrentPos: TPointF; // Current position for the next node relative to FParentControl
|
|
||||||
FNodeVerticalGap: Single; // Vertical gap between nodes
|
|
||||||
FExprDepth: Integer;
|
FExprDepth: Integer;
|
||||||
|
FWorkspace: TAuraWorkspace;
|
||||||
|
FNodeVerticalGap: Single;
|
||||||
|
FParentControl: TControl;
|
||||||
// Helper to create and initialize a TAuraNode for a given AST node.
|
// Helper to create and initialize a TAuraNode for a given AST node.
|
||||||
function CreateNode(const Node: IAstNode): TAuraNode;
|
function CreateNode(const Node: IAstNode): TAuraNode;
|
||||||
function AddLabel(const ParentNode: TAuraNode; const Txt: String): TLabel;
|
function AddLabel(const ParentNode: TAuraNode; const Txt: String): TLabel;
|
||||||
@@ -44,7 +43,12 @@ type
|
|||||||
|
|
||||||
// Calls Accept on the node and returns the resulting TAuraNode.
|
// Calls Accept on the node and returns the resulting TAuraNode.
|
||||||
function CallAccept(const Node: IAstNode): TAuraNode;
|
function CallAccept(const Node: IAstNode): TAuraNode;
|
||||||
|
function GetCurrentPos: TPointF;
|
||||||
|
function GetExprDepth: Integer;
|
||||||
|
function GetParentControl: TControl;
|
||||||
|
procedure SetCurrentPos(const Value: TPointF);
|
||||||
|
procedure SetExprDepth(const Value: Integer);
|
||||||
|
procedure SetParentControl(const Value: TControl);
|
||||||
protected
|
protected
|
||||||
// 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;
|
||||||
@@ -71,10 +75,22 @@ type
|
|||||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; const AStartPosition: TPointF);
|
constructor Create(
|
||||||
|
AWorkspace: TAuraWorkspace;
|
||||||
|
AParentControl: TControl;
|
||||||
|
const AStartPosition: TPointF;
|
||||||
|
ANodeVerticalGap: Single = 15;
|
||||||
|
AExprDepth: Integer = 0
|
||||||
|
);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
function Clone: IAstVisualizer;
|
||||||
|
|
||||||
class function CreateVisitor(AWorkspace: TAuraWorkspace; const StartPosition: TPointF): IAstVisitor;
|
class function CreateVisitor(AWorkspace: TAuraWorkspace; const StartPosition: TPointF): IAstVisitor;
|
||||||
|
|
||||||
|
property CurrentPos: TPointF read GetCurrentPos write SetCurrentPos;
|
||||||
|
property ExprDepth: Integer read GetExprDepth write SetExprDepth;
|
||||||
|
property ParentControl: TControl read GetParentControl write SetParentControl;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -89,24 +105,25 @@ uses
|
|||||||
Myc.Fmx.AstEditor.Text;
|
Myc.Fmx.AstEditor.Text;
|
||||||
|
|
||||||
const
|
const
|
||||||
cNodePadding = 10; // Reduced padding
|
|
||||||
cTitleTopPadding = 2;
|
|
||||||
cTitleBottomPadding = 4;
|
|
||||||
cChildAreaTopPadding = 5;
|
cChildAreaTopPadding = 5;
|
||||||
cNodeVerticalGap = 10; // Reduced gap
|
cNodeVerticalGap = 10; // Reduced gap
|
||||||
cMinNodeWidth = 10;
|
|
||||||
cMinNodeHeight = 10;
|
|
||||||
|
|
||||||
{ TAstVisualizer }
|
{ TAstVisualizer }
|
||||||
|
|
||||||
constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; const AStartPosition: TPointF);
|
constructor TAstVisualizer.Create(
|
||||||
|
AWorkspace: TAuraWorkspace;
|
||||||
|
AParentControl: TControl;
|
||||||
|
const AStartPosition: TPointF;
|
||||||
|
ANodeVerticalGap: Single = 15;
|
||||||
|
AExprDepth: Integer = 0
|
||||||
|
);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FWorkspace := AWorkspace;
|
FWorkspace := AWorkspace;
|
||||||
FParentControl := AParentControl;
|
FParentControl := AParentControl;
|
||||||
FCurrentPos := AStartPosition;
|
FCurrentPos := AStartPosition;
|
||||||
FNodeVerticalGap := 15; // Vertical gap between child nodes
|
FNodeVerticalGap := ANodeVerticalGap;
|
||||||
FExprDepth := 0;
|
FExprDepth := AExprDepth;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TAstVisualizer.Destroy;
|
destructor TAstVisualizer.Destroy;
|
||||||
@@ -264,6 +281,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstVisualizer.Clone: IAstVisualizer;
|
||||||
|
begin
|
||||||
|
Result := TAstVisualizer.Create(FWorkspace, FParentControl, FCurrentPos, FNodeVerticalGap, FExprDepth);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAstVisualizer.GetCurrentPos: TPointF;
|
||||||
|
begin
|
||||||
|
Result := FCurrentPos;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAstVisualizer.GetExprDepth: Integer;
|
||||||
|
begin
|
||||||
|
Result := FExprDepth;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAstVisualizer.GetParentControl: TControl;
|
||||||
|
begin
|
||||||
|
Result := FParentControl;
|
||||||
|
end;
|
||||||
|
|
||||||
// Generic processing logic for AST nodes with children. Returns the created TAuraNode.
|
// Generic processing logic for AST nodes with children. Returns the created TAuraNode.
|
||||||
function TAstVisualizer.ProcessStub(const ATitle: string; const ANode: IAstNode; const AChildren: TArray<IAstNode>): TAuraNode;
|
function TAstVisualizer.ProcessStub(const ATitle: string; const ANode: IAstNode; const AChildren: TArray<IAstNode>): TAuraNode;
|
||||||
var
|
var
|
||||||
@@ -308,157 +345,62 @@ begin
|
|||||||
Result := auraNode; // Return the created node
|
Result := auraNode; // Return the created node
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TAstVisualizer.SetCurrentPos(const Value: TPointF);
|
||||||
|
begin
|
||||||
|
FCurrentPos := Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstVisualizer.SetExprDepth(const Value: Integer);
|
||||||
|
begin
|
||||||
|
FExprDepth := Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAstVisualizer.SetParentControl(const Value: TControl);
|
||||||
|
begin
|
||||||
|
FParentControl := Value;
|
||||||
|
end;
|
||||||
|
|
||||||
// --- Visitor Implementations ---
|
// --- Visitor Implementations ---
|
||||||
|
|
||||||
function TAstVisualizer.VisitConstant(const Node: IConstantNode): TDataValue;
|
function TAstVisualizer.VisitConstant(const Node: IConstantNode): TDataValue;
|
||||||
var
|
|
||||||
auraNode: TAuraNode;
|
|
||||||
valueStr: string;
|
|
||||||
isConcise: Boolean;
|
|
||||||
begin
|
begin
|
||||||
valueStr := Node.Value.ToString;
|
var auraNode := TAuraConstantNode.CreateConstantNode(FWorkspace, Node, Self);
|
||||||
// Check if it's a number or a single-line text and not excessively long
|
|
||||||
isConcise := ((Node.Value.Kind = TDataValueKind.vkScalar) or (Pos(sLineBreak, valueStr) = 0)) and (Length(valueStr) < 40);
|
|
||||||
|
|
||||||
auraNode := CreateNode(Node); // Create node without title
|
|
||||||
auraNode.BeginUpdate;
|
|
||||||
try
|
|
||||||
if isConcise then
|
|
||||||
begin
|
|
||||||
// Display value directly in a centered label, frameless node
|
|
||||||
auraNode.Frameless := true;
|
|
||||||
AddLabel(auraNode, valueStr);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
// Use standard framed node with Title label + Value label
|
|
||||||
auraNode.Frameless := False;
|
|
||||||
|
|
||||||
// Title Label
|
|
||||||
var titleLabelHeight := AddTitleLabel(auraNode, 'Constant');
|
|
||||||
|
|
||||||
// Value Label
|
|
||||||
var valueLabel := AddLabel(auraNode, valueStr);
|
|
||||||
valueLabel.Position.Y := valueLabel.Position.Y + titleLabelHeight;
|
|
||||||
valueLabel.AutoSize := False; // ***Important: Disable AutoSize when Align=Client***
|
|
||||||
valueLabel.WordWrap := True; // Allow wrapping for long text
|
|
||||||
end;
|
|
||||||
|
|
||||||
AdjustParentNodeSize(auraNode, []); // Adjust based on labels' sizes
|
|
||||||
finally
|
|
||||||
auraNode.EndUpdate;
|
|
||||||
end;
|
|
||||||
// Move current position down for the next sibling node
|
// Move current position down for the next sibling node
|
||||||
FCurrentPos.Y := FCurrentPos.Y + auraNode.Height + FNodeVerticalGap;
|
FCurrentPos.Y := FCurrentPos.Y + auraNode.Height + FNodeVerticalGap;
|
||||||
|
|
||||||
Result := TDataValue.FromGeneric<TAuraNode>(auraNode); // Return the created node
|
Result := TDataValue.FromGeneric<TAuraNode>(auraNode); // Return the created node
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstVisualizer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
function TAstVisualizer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||||
var
|
var
|
||||||
auraNode: TAuraNode;
|
auraNode: TAuraIdentifierNode; // Use specific type
|
||||||
begin
|
begin
|
||||||
// Leaf node, direct creation without ProcessStub
|
// Create the specific node type using its factory
|
||||||
auraNode := CreateNode(Node);
|
auraNode := TAuraIdentifierNode.CreateIdentifierNode(FWorkspace, Node, Self);
|
||||||
auraNode.Frameless := True; // Make identifiers frameless like concise constants
|
|
||||||
auraNode.BeginUpdate;
|
// Move current position down for the next sibling node
|
||||||
try
|
|
||||||
auraNode.Frameless := true;
|
|
||||||
AddLabel(auraNode, Node.Name);
|
|
||||||
AdjustParentNodeSize(auraNode, []); // Fallback just in case
|
|
||||||
finally
|
|
||||||
auraNode.EndUpdate;
|
|
||||||
end;
|
|
||||||
FCurrentPos.Y := FCurrentPos.Y + auraNode.Height + FNodeVerticalGap;
|
FCurrentPos.Y := FCurrentPos.Y + auraNode.Height + FNodeVerticalGap;
|
||||||
Result := TDataValue.FromGeneric<TAuraNode>(auraNode); // Return the created node
|
|
||||||
|
Result := TDataValue.FromGeneric<TAuraNode>(auraNode); // Return as generic TAuraNode
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstVisualizer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
function TAstVisualizer.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||||
var
|
var
|
||||||
auraNode: TAuraNode;
|
auraNode: TAuraBinaryExpressionNode; // Use specific type
|
||||||
leftNode: TAuraNode; // Use TAuraNode directly
|
|
||||||
operatorLabel: TLabel;
|
|
||||||
rightNode: TAuraNode; // Use TAuraNode directly
|
|
||||||
savedParent: TControl;
|
|
||||||
savedPos: TPointF;
|
savedPos: TPointF;
|
||||||
currentX: Single; // Track horizontal position
|
|
||||||
maxHeightInRow: Single; // Track max height for row alignment
|
|
||||||
yPos: Single; // Y position for elements in this row
|
|
||||||
begin
|
begin
|
||||||
// Create the main node, frameless as it primarily serves as a container
|
// Store position before creating the node
|
||||||
auraNode := CreateNode(Node);
|
savedPos := FCurrentPos;
|
||||||
auraNode.BeginUpdate;
|
|
||||||
inc(FExprDepth);
|
|
||||||
try
|
|
||||||
auraNode.Frameless := true;
|
|
||||||
|
|
||||||
// Start position for children inside the node
|
// Create the specific node type using its factory
|
||||||
currentX := cNodePadding;
|
auraNode := TAuraBinaryExpressionNode.CreateBinaryExpressionNode(FWorkspace, Node, Self);
|
||||||
yPos := cNodePadding; // Initial Y position
|
|
||||||
maxHeightInRow := 0;
|
|
||||||
|
|
||||||
// 1. Left Expression Node (Visited Recursively)
|
// Move current position down for the next sibling node
|
||||||
savedParent := FParentControl;
|
// Use the position saved *before* creating this node, plus the node's final height
|
||||||
savedPos := FCurrentPos; // Store original position for siblings
|
FCurrentPos.Y := savedPos.Y + auraNode.Height + FNodeVerticalGap;
|
||||||
FParentControl := auraNode; // Children are added to this node
|
|
||||||
FCurrentPos := TPointF.Create(currentX, yPos); // Set position for the child node
|
|
||||||
|
|
||||||
leftNode := CallAccept(Node.Left); // Use CallAccept and store result
|
Result := TDataValue.FromGeneric<TAuraNode>(auraNode); // Return as generic TAuraNode
|
||||||
|
|
||||||
if Assigned(leftNode) then
|
|
||||||
begin
|
|
||||||
// Update currentX based on the right edge of the left control + gap
|
|
||||||
currentX := leftNode.Position.X + leftNode.Width + leftNode.Margins.Right + cNodePadding;
|
|
||||||
maxHeightInRow := Max(maxHeightInRow, leftNode.Height + leftNode.Margins.Top + leftNode.Margins.Bottom);
|
|
||||||
end;
|
|
||||||
|
|
||||||
// 2. Operator Label
|
|
||||||
operatorLabel := AddLabel(auraNode, Node.Operator.ToString);
|
|
||||||
operatorLabel.Position.Point := TPointF.Create(currentX, yPos); // Position next to left operand
|
|
||||||
currentX := operatorLabel.Position.X + operatorLabel.Width + operatorLabel.Margins.Right + cNodePadding; // Update X pos
|
|
||||||
maxHeightInRow := Max(maxHeightInRow, operatorLabel.Height + operatorLabel.Margins.Top + operatorLabel.Margins.Bottom);
|
|
||||||
|
|
||||||
// 3. Right Expression Node (Visited Recursively)
|
|
||||||
// FParentControl is already auraNode
|
|
||||||
FCurrentPos := TPointF.Create(currentX, yPos); // Set position for the child node
|
|
||||||
|
|
||||||
rightNode := CallAccept(Node.Right); // Use CallAccept and store result
|
|
||||||
|
|
||||||
if Assigned(rightNode) then
|
|
||||||
begin
|
|
||||||
// Update currentX based on the right edge of the right control
|
|
||||||
currentX := rightNode.Position.X + rightNode.Width + rightNode.Margins.Right;
|
|
||||||
maxHeightInRow := Max(maxHeightInRow, rightNode.Height + rightNode.Margins.Top + rightNode.Margins.Bottom);
|
|
||||||
end;
|
|
||||||
|
|
||||||
FParentControl := savedParent; // Restore parent for siblings
|
|
||||||
FCurrentPos := savedPos; // Restore position for siblings
|
|
||||||
|
|
||||||
// --- Adjust parent size ---
|
|
||||||
auraNode.Width := Max(cMinNodeWidth, currentX + cNodePadding); // Total width needed + right padding
|
|
||||||
auraNode.Height := Max(cMinNodeHeight, maxHeightInRow + 2 * cNodePadding); // Max height + top/bottom padding
|
|
||||||
|
|
||||||
// --- Optional Vertical Centering ---
|
|
||||||
var centerOffsetY: Single := (auraNode.Height / 2);
|
|
||||||
if Assigned(leftNode) then
|
|
||||||
leftNode.Position.Y :=
|
|
||||||
centerOffsetY - (leftNode.Height + leftNode.Margins.Top + leftNode.Margins.Bottom) / 2 + leftNode.Margins.Top;
|
|
||||||
if Assigned(operatorLabel) then
|
|
||||||
operatorLabel.Position.Y :=
|
|
||||||
centerOffsetY
|
|
||||||
- (operatorLabel.Height + operatorLabel.Margins.Top + operatorLabel.Margins.Bottom) / 2
|
|
||||||
+ operatorLabel.Margins.Top;
|
|
||||||
if Assigned(rightNode) then
|
|
||||||
rightNode.Position.Y :=
|
|
||||||
centerOffsetY - (rightNode.Height + rightNode.Margins.Top + rightNode.Margins.Bottom) / 2 + rightNode.Margins.Top;
|
|
||||||
// --- End Optional Vertical Centering ---
|
|
||||||
|
|
||||||
finally
|
|
||||||
dec(FExprDepth);
|
|
||||||
auraNode.EndUpdate;
|
|
||||||
end;
|
|
||||||
// Move current position down for the next sibling node in the outer scope
|
|
||||||
FCurrentPos.Y := savedPos.Y + auraNode.Height + FNodeVerticalGap; // Use savedPos.Y for vertical alignment with siblings
|
|
||||||
Result := TDataValue.FromGeneric<TAuraNode>(auraNode); // Return the created node
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstVisualizer.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
function TAstVisualizer.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
||||||
|
|||||||
+2
-2
@@ -105,7 +105,7 @@ type
|
|||||||
function GetOperator: TScalar.TBinaryOp;
|
function GetOperator: TScalar.TBinaryOp;
|
||||||
function GetRight: IAstNode;
|
function GetRight: IAstNode;
|
||||||
public
|
public
|
||||||
constructor Create(ALeft: IAstNode; AOperator: TScalar.TBinaryOp; ARight: IAstNode);
|
constructor Create(const ALeft: IAstNode; AOperator: TScalar.TBinaryOp; const ARight: IAstNode);
|
||||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ end;
|
|||||||
|
|
||||||
{ TBinaryExpressionNode }
|
{ TBinaryExpressionNode }
|
||||||
|
|
||||||
constructor TBinaryExpressionNode.Create(ALeft: IAstNode; AOperator: TScalar.TBinaryOp; ARight: IAstNode);
|
constructor TBinaryExpressionNode.Create(const ALeft: IAstNode; AOperator: TScalar.TBinaryOp; const ARight: IAstNode);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FLeft := ALeft;
|
FLeft := ALeft;
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ begin
|
|||||||
if FKind <> vkGeneric then
|
if FKind <> vkGeneric then
|
||||||
raise EInvalidCast.Create('Cannot read value as generic of ' + String(PTypeInfo(TypeInfo(T)).Name) + '.');
|
raise EInvalidCast.Create('Cannot read value as generic of ' + String(PTypeInfo(TypeInfo(T)).Name) + '.');
|
||||||
{$ifdef DEBUG}
|
{$ifdef DEBUG}
|
||||||
if TVal<T>(FInterface).TypeHandle <> TypeInfo(T) then
|
var val := TVal<T>(FInterface);
|
||||||
|
if val.TypeHandle <> TypeInfo(T) then
|
||||||
raise EInvalidCast.Create('Generic type is not a ' + String(PTypeInfo(TypeInfo(T)).Name) + '.');
|
raise EInvalidCast.Create('Generic type is not a ' + String(PTypeInfo(TypeInfo(T)).Name) + '.');
|
||||||
{$endif}
|
{$endif}
|
||||||
Result := TVal<T>(FInterface).Value;
|
Result := TVal<T>(FInterface).Value;
|
||||||
|
|||||||
Reference in New Issue
Block a user