AST refactoring
This commit is contained in:
@@ -5,7 +5,10 @@ uses
|
|||||||
FMX.Forms,
|
FMX.Forms,
|
||||||
MainForm in 'MainForm.pas' {Form1},
|
MainForm in 'MainForm.pas' {Form1},
|
||||||
Myc.Ast.Evaluator in '..\Src\AST\Myc.Ast.Evaluator.pas',
|
Myc.Ast.Evaluator in '..\Src\AST\Myc.Ast.Evaluator.pas',
|
||||||
Myc.Ast.Printer in '..\Src\AST\Myc.Ast.Printer.pas';
|
Myc.Ast.Printer in '..\Src\AST\Myc.Ast.Printer.pas',
|
||||||
|
Myc.Ast.Types in '..\Src\AST\Myc.Ast.Types.pas',
|
||||||
|
Myc.Ast.Scope in '..\Src\AST\Myc.Ast.Scope.pas',
|
||||||
|
Myc.Ast.Closure in '..\Src\AST\Myc.Ast.Closure.pas';
|
||||||
|
|
||||||
{$R *.res}
|
{$R *.res}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
|
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
|
||||||
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
|
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
|
||||||
<SanitizedProjectName>ASTPlayground</SanitizedProjectName>
|
<SanitizedProjectName>ASTPlayground</SanitizedProjectName>
|
||||||
<DCC_UnitSearchPath>T:\Myc\Src\Data;T:\Myc\Src\AST;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
|
<DCC_UnitSearchPath>T:\Myc\Src\Data;T:\Myc\Src\AST;T:\Myc\Src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
|
||||||
<VerInfo_Locale>1031</VerInfo_Locale>
|
<VerInfo_Locale>1031</VerInfo_Locale>
|
||||||
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -137,6 +137,9 @@
|
|||||||
</DCCReference>
|
</DCCReference>
|
||||||
<DCCReference Include="..\Src\AST\Myc.Ast.Evaluator.pas"/>
|
<DCCReference Include="..\Src\AST\Myc.Ast.Evaluator.pas"/>
|
||||||
<DCCReference Include="..\Src\AST\Myc.Ast.Printer.pas"/>
|
<DCCReference Include="..\Src\AST\Myc.Ast.Printer.pas"/>
|
||||||
|
<DCCReference Include="..\Src\AST\Myc.Ast.Types.pas"/>
|
||||||
|
<DCCReference Include="..\Src\AST\Myc.Ast.Scope.pas"/>
|
||||||
|
<DCCReference Include="..\Src\AST\Myc.Ast.Closure.pas"/>
|
||||||
<BuildConfiguration Include="Base">
|
<BuildConfiguration Include="Base">
|
||||||
<Key>Base</Key>
|
<Key>Base</Key>
|
||||||
</BuildConfiguration>
|
</BuildConfiguration>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ uses
|
|||||||
FMX.Controls.Presentation,
|
FMX.Controls.Presentation,
|
||||||
Myc.Data.Types,
|
Myc.Data.Types,
|
||||||
Myc.Ast,
|
Myc.Ast,
|
||||||
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.Evaluator,
|
Myc.Ast.Evaluator,
|
||||||
Myc.Ast.Printer;
|
Myc.Ast.Printer;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
unit Myc.Ast.Closure;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.Classes,
|
||||||
|
System.Generics.Collections,
|
||||||
|
Myc.Data.Types,
|
||||||
|
Myc.Ast,
|
||||||
|
Myc.Ast.Scope;
|
||||||
|
|
||||||
|
type
|
||||||
|
// A closure is a specific kind of method value that is defined by the evaluator.
|
||||||
|
// It holds the AST body and its captured scope.
|
||||||
|
IDataClosureValue = interface(IDataMethodValue)
|
||||||
|
['{2704586B-E4BD-47AA-B05D-FD441AE6D818}']
|
||||||
|
{$region 'private'}
|
||||||
|
function GetBody: IExpressionNode;
|
||||||
|
function GetParameters: TList<IIdentifierNode>;
|
||||||
|
function GetClosureScope: TExecutionScope;
|
||||||
|
{$endregion}
|
||||||
|
property Body: IExpressionNode read GetBody;
|
||||||
|
property Parameters: TList<IIdentifierNode> read GetParameters;
|
||||||
|
property ClosureScope: TExecutionScope read GetClosureScope;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Factory function to create a new closure value.
|
||||||
|
function CreateDataClosureValue(
|
||||||
|
AMethodType: IDataMethodType;
|
||||||
|
ABody: IExpressionNode;
|
||||||
|
AParameters: TList<IIdentifierNode>;
|
||||||
|
AClosureScope: TExecutionScope
|
||||||
|
): IDataClosureValue;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ TDataClosureValueImpl }
|
||||||
|
// Concrete implementation of the IDataClosureValue interface.
|
||||||
|
TDataClosureValueImpl = class(TInterfacedObject, IDataValue, IDataClosureValue)
|
||||||
|
private
|
||||||
|
FMethodType: IDataMethodType;
|
||||||
|
FBody: IExpressionNode;
|
||||||
|
FParameters: TList<IIdentifierNode>;
|
||||||
|
FClosureScope: TExecutionScope;
|
||||||
|
// IDataValue
|
||||||
|
function GetDataType: IDataType;
|
||||||
|
function GetAsString: string;
|
||||||
|
// IDataMethodValue
|
||||||
|
function GetValue: TDataMethodProc;
|
||||||
|
// IDataClosureValue
|
||||||
|
function GetBody: IExpressionNode;
|
||||||
|
function GetParameters: TList<IIdentifierNode>;
|
||||||
|
function GetClosureScope: TExecutionScope;
|
||||||
|
public
|
||||||
|
constructor Create(
|
||||||
|
AMethodType: IDataMethodType;
|
||||||
|
ABody: IExpressionNode;
|
||||||
|
AParameters: TList<IIdentifierNode>;
|
||||||
|
ACClosureScope: TExecutionScope
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateDataClosureValue(
|
||||||
|
AMethodType: IDataMethodType;
|
||||||
|
ABody: IExpressionNode;
|
||||||
|
AParameters: TList<IIdentifierNode>;
|
||||||
|
AClosureScope: TExecutionScope
|
||||||
|
): IDataClosureValue;
|
||||||
|
begin
|
||||||
|
Result := TDataClosureValueImpl.Create(AMethodType, ABody, AParameters, AClosureScope);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDataClosureValueImpl }
|
||||||
|
|
||||||
|
constructor TDataClosureValueImpl.Create(
|
||||||
|
AMethodType: IDataMethodType;
|
||||||
|
ABody: IExpressionNode;
|
||||||
|
AParameters: TList<IIdentifierNode>;
|
||||||
|
ACClosureScope: TExecutionScope
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FMethodType := AMethodType;
|
||||||
|
FBody := ABody;
|
||||||
|
FParameters := AParameters; // Note: We are taking ownership of the list reference
|
||||||
|
FClosureScope := ACClosureScope;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataClosureValueImpl.GetAsString: string;
|
||||||
|
begin
|
||||||
|
Result := '<CLOSURE>';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataClosureValueImpl.GetBody: IExpressionNode;
|
||||||
|
begin
|
||||||
|
Result := FBody;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataClosureValueImpl.GetClosureScope: TExecutionScope;
|
||||||
|
begin
|
||||||
|
Result := FClosureScope;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataClosureValueImpl.GetDataType: IDataType;
|
||||||
|
begin
|
||||||
|
Result := FMethodType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataClosureValueImpl.GetParameters: TList<IIdentifierNode>;
|
||||||
|
begin
|
||||||
|
Result := FParameters;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDataClosureValueImpl.GetValue: TDataMethodProc;
|
||||||
|
begin
|
||||||
|
// This direct execution path is no longer used for closures.
|
||||||
|
raise ENotSupportedException.Create('Cannot get raw method proc from a closure object.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
// https://g.co/gemini/share/f8965e72f968
|
|
||||||
|
|
||||||
unit Myc.Ast.Evaluator;
|
unit Myc.Ast.Evaluator;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
@@ -9,39 +7,11 @@ uses
|
|||||||
System.Classes, // For TStrings
|
System.Classes, // For TStrings
|
||||||
System.Generics.Collections,
|
System.Generics.Collections,
|
||||||
Myc.Data.Types,
|
Myc.Data.Types,
|
||||||
Myc.Ast;
|
Myc.Ast,
|
||||||
|
Myc.Ast.Scope,
|
||||||
|
Myc.Ast.Closure;
|
||||||
|
|
||||||
type
|
type
|
||||||
// Manages the scope of execution, holding variables and their values.
|
|
||||||
TExecutionScope = class
|
|
||||||
private
|
|
||||||
FParent: TExecutionScope;
|
|
||||||
FVariables: TDictionary<string, IDataValue>;
|
|
||||||
// Added for recursive dumping
|
|
||||||
procedure DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
|
||||||
public
|
|
||||||
constructor Create(AParent: TExecutionScope = nil);
|
|
||||||
destructor Destroy; override;
|
|
||||||
function FindValue(const Name: string; out Value: IDataValue): Boolean;
|
|
||||||
procedure SetValue(const Name: string; const Value: IDataValue);
|
|
||||||
// Dumps the content of this scope and all parent scopes to a string.
|
|
||||||
function Dump: string;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// A closure is a specific kind of method value that is defined by the evaluator.
|
|
||||||
// It holds the AST body and its captured scope.
|
|
||||||
IDataClosureValue = interface(IDataMethodValue)
|
|
||||||
['{2704586B-E4BD-47AA-B05D-FD441AE6D818}']
|
|
||||||
{$region 'private'}
|
|
||||||
function GetBody: IExpressionNode;
|
|
||||||
function GetParameters: TList<IIdentifierNode>;
|
|
||||||
function GetClosureScope: TExecutionScope;
|
|
||||||
{$endregion}
|
|
||||||
property Body: IExpressionNode read GetBody;
|
|
||||||
property Parameters: TList<IIdentifierNode> read GetParameters;
|
|
||||||
property ClosureScope: TExecutionScope read GetClosureScope;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// TEvaluatorVisitor is the base implementation for evaluating an AST.
|
// TEvaluatorVisitor is the base implementation for evaluating an AST.
|
||||||
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor)
|
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor)
|
||||||
protected // Changed to protected to be accessible by descendants
|
protected // Changed to protected to be accessible by descendants
|
||||||
@@ -91,145 +61,6 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
type
|
|
||||||
{ TDataClosureValueImpl }
|
|
||||||
// Concrete implementation of the IDataClosureValue interface.
|
|
||||||
TDataClosureValueImpl = class(TInterfacedObject, IDataValue, IDataClosureValue)
|
|
||||||
private
|
|
||||||
FMethodType: IDataMethodType;
|
|
||||||
FBody: IExpressionNode;
|
|
||||||
FParameters: TList<IIdentifierNode>;
|
|
||||||
FClosureScope: TExecutionScope;
|
|
||||||
// IDataValue
|
|
||||||
function GetDataType: IDataType;
|
|
||||||
function GetAsString: string;
|
|
||||||
// IDataMethodValue
|
|
||||||
function GetValue: TDataMethodProc;
|
|
||||||
// IDataClosureValue
|
|
||||||
function GetBody: IExpressionNode;
|
|
||||||
function GetParameters: TList<IIdentifierNode>;
|
|
||||||
function GetClosureScope: TExecutionScope;
|
|
||||||
public
|
|
||||||
constructor Create(
|
|
||||||
AMethodType: IDataMethodType;
|
|
||||||
ABody: IExpressionNode;
|
|
||||||
AParameters: TList<IIdentifierNode>;
|
|
||||||
ACClosureScope: TExecutionScope
|
|
||||||
);
|
|
||||||
end;
|
|
||||||
|
|
||||||
constructor TDataClosureValueImpl.Create(
|
|
||||||
AMethodType: IDataMethodType;
|
|
||||||
ABody: IExpressionNode;
|
|
||||||
AParameters: TList<IIdentifierNode>;
|
|
||||||
ACClosureScope: TExecutionScope
|
|
||||||
);
|
|
||||||
begin
|
|
||||||
inherited Create;
|
|
||||||
FMethodType := AMethodType;
|
|
||||||
FBody := ABody;
|
|
||||||
FParameters := AParameters; // Note: We are taking ownership of the list reference
|
|
||||||
FClosureScope := ACClosureScope;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataClosureValueImpl.GetAsString: string;
|
|
||||||
begin
|
|
||||||
Result := '<CLOSURE>';
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataClosureValueImpl.GetBody: IExpressionNode;
|
|
||||||
begin
|
|
||||||
Result := FBody;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataClosureValueImpl.GetClosureScope: TExecutionScope;
|
|
||||||
begin
|
|
||||||
Result := FClosureScope;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataClosureValueImpl.GetDataType: IDataType;
|
|
||||||
begin
|
|
||||||
Result := FMethodType;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataClosureValueImpl.GetParameters: TList<IIdentifierNode>;
|
|
||||||
begin
|
|
||||||
Result := FParameters;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataClosureValueImpl.GetValue: TDataMethodProc;
|
|
||||||
begin
|
|
||||||
// This direct execution path is no longer used for closures.
|
|
||||||
raise ENotSupportedException.Create('Cannot get raw method proc from a closure object.');
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TExecutionScope }
|
|
||||||
|
|
||||||
constructor TExecutionScope.Create(AParent: TExecutionScope = nil);
|
|
||||||
begin
|
|
||||||
inherited Create;
|
|
||||||
FParent := AParent;
|
|
||||||
FVariables := TDictionary<string, IDataValue>.Create;
|
|
||||||
end;
|
|
||||||
|
|
||||||
destructor TExecutionScope.Destroy;
|
|
||||||
begin
|
|
||||||
FVariables.Free;
|
|
||||||
inherited Destroy;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TExecutionScope.DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
|
||||||
var
|
|
||||||
pair: TPair<string, IDataValue>;
|
|
||||||
indentStr: string;
|
|
||||||
begin
|
|
||||||
indentStr := ''.PadLeft(AIndent);
|
|
||||||
if FVariables.Count > 0 then
|
|
||||||
begin
|
|
||||||
for pair in FVariables do
|
|
||||||
ABuilder.AppendLine(indentStr + Format(' %s: %s', [pair.Key, pair.Value.AsString]));
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
ABuilder.AppendLine(indentStr + ' (empty)');
|
|
||||||
end;
|
|
||||||
|
|
||||||
if Assigned(FParent) then
|
|
||||||
begin
|
|
||||||
ABuilder.AppendLine(indentStr + '[Parent Scope]');
|
|
||||||
FParent.DumpScope(ABuilder, AIndent + 2);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TExecutionScope.Dump: string;
|
|
||||||
var
|
|
||||||
builder: TStringBuilder;
|
|
||||||
begin
|
|
||||||
builder := TStringBuilder.Create;
|
|
||||||
try
|
|
||||||
builder.AppendLine('[Current Scope]');
|
|
||||||
DumpScope(builder, 0);
|
|
||||||
Result := builder.ToString.TrimRight;
|
|
||||||
finally
|
|
||||||
builder.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TExecutionScope.FindValue(const Name: string; out Value: IDataValue): Boolean;
|
|
||||||
begin
|
|
||||||
Result := FVariables.TryGetValue(Name, Value);
|
|
||||||
if not Result and Assigned(FParent) then
|
|
||||||
begin
|
|
||||||
Result := FParent.FindValue(Name, Value);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TExecutionScope.SetValue(const Name: string; const Value: IDataValue);
|
|
||||||
begin
|
|
||||||
// This defines a variable in the current scope. It can shadow a parent variable.
|
|
||||||
FVariables.AddOrSetValue(Name, Value);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TEvaluatorVisitor }
|
{ TEvaluatorVisitor }
|
||||||
|
|
||||||
constructor TEvaluatorVisitor.Create(AScope: TExecutionScope);
|
constructor TEvaluatorVisitor.Create(AScope: TExecutionScope);
|
||||||
@@ -252,7 +83,8 @@ begin
|
|||||||
// Instead of creating an anonymous method, we now create a data object
|
// Instead of creating an anonymous method, we now create a data object
|
||||||
// that holds all information required to execute the lambda later.
|
// that holds all information required to execute the lambda later.
|
||||||
methodType := TDataType.MethodOf(TDataType.Ordinal, TDataType.Ordinal); // TODO: Infer this
|
methodType := TDataType.MethodOf(TDataType.Ordinal, TDataType.Ordinal); // TODO: Infer this
|
||||||
Result := TDataClosureValueImpl.Create(methodType, Node.Body, Node.Parameters, FScope);
|
// Use the factory function from the Myc.Ast.Closure unit.
|
||||||
|
Result := CreateDataClosureValue(methodType, Node.Body, Node.Parameters, FScope);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IDataValue;
|
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IDataValue;
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
unit Myc.Ast.Scope;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.SysUtils,
|
||||||
|
System.Classes,
|
||||||
|
System.Generics.Collections,
|
||||||
|
Myc.Data.Types;
|
||||||
|
|
||||||
|
type
|
||||||
|
// Manages the scope of execution, holding variables and their values.
|
||||||
|
TExecutionScope = class
|
||||||
|
private
|
||||||
|
FParent: TExecutionScope;
|
||||||
|
FVariables: TDictionary<string, IDataValue>;
|
||||||
|
// Added for recursive dumping
|
||||||
|
procedure DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
||||||
|
public
|
||||||
|
constructor Create(AParent: TExecutionScope = nil);
|
||||||
|
destructor Destroy; override;
|
||||||
|
function FindValue(const Name: string; out Value: IDataValue): Boolean;
|
||||||
|
procedure SetValue(const Name: string; const Value: IDataValue);
|
||||||
|
// Dumps the content of this scope and all parent scopes to a string.
|
||||||
|
function Dump: string;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TExecutionScope }
|
||||||
|
|
||||||
|
constructor TExecutionScope.Create(AParent: TExecutionScope = nil);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FParent := AParent;
|
||||||
|
FVariables := TDictionary<string, IDataValue>.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TExecutionScope.Destroy;
|
||||||
|
begin
|
||||||
|
FVariables.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TExecutionScope.DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
||||||
|
var
|
||||||
|
pair: TPair<string, IDataValue>;
|
||||||
|
indentStr: string;
|
||||||
|
begin
|
||||||
|
indentStr := ''.PadLeft(AIndent);
|
||||||
|
if (FVariables.Count > 0) then
|
||||||
|
begin
|
||||||
|
for pair in FVariables do
|
||||||
|
ABuilder.AppendLine(indentStr + Format(' %s: %s', [pair.Key, pair.Value.AsString]));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
ABuilder.AppendLine(indentStr + ' (empty)');
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Assigned(FParent) then
|
||||||
|
begin
|
||||||
|
ABuilder.AppendLine(indentStr + '[Parent Scope]');
|
||||||
|
FParent.DumpScope(ABuilder, AIndent + 2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TExecutionScope.Dump: string;
|
||||||
|
var
|
||||||
|
builder: TStringBuilder;
|
||||||
|
begin
|
||||||
|
builder := TStringBuilder.Create;
|
||||||
|
try
|
||||||
|
builder.AppendLine('[Current Scope]');
|
||||||
|
DumpScope(builder, 0);
|
||||||
|
Result := builder.ToString.TrimRight;
|
||||||
|
finally
|
||||||
|
builder.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TExecutionScope.FindValue(const Name: string; out Value: IDataValue): Boolean;
|
||||||
|
begin
|
||||||
|
Result := FVariables.TryGetValue(Name, Value);
|
||||||
|
if not Result and Assigned(FParent) then
|
||||||
|
begin
|
||||||
|
Result := FParent.FindValue(Name, Value);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TExecutionScope.SetValue(const Name: string; const Value: IDataValue);
|
||||||
|
begin
|
||||||
|
// This defines a variable in the current scope. It can shadow a parent variable.
|
||||||
|
FVariables.AddOrSetValue(Name, Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
Reference in New Issue
Block a user