Ast environments
This commit is contained in:
@@ -26,7 +26,6 @@ type
|
||||
type
|
||||
TUpvalueMapping = TDictionary<TResolvedAddress, Integer>;
|
||||
private
|
||||
FInitialScope: IExecutionScope;
|
||||
FCurrentDescriptor: IScopeDescriptor;
|
||||
FUpvalueStack: TStack<TUpvalueMapping>;
|
||||
FNestedLambdaCount: Integer;
|
||||
@@ -54,12 +53,12 @@ type
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode; override;
|
||||
|
||||
public
|
||||
constructor Create(const AInitialScope: IExecutionScope);
|
||||
constructor Create(const AInitialDescriptor: IScopeDescriptor);
|
||||
destructor Destroy; override;
|
||||
function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
|
||||
class function Bind(
|
||||
const InitialScope: IExecutionScope;
|
||||
const InitialDescriptor: IScopeDescriptor;
|
||||
const RootNode: IAstNode;
|
||||
out Descriptor: IScopeDescriptor
|
||||
): IAstNode; static;
|
||||
@@ -96,13 +95,12 @@ end;
|
||||
|
||||
{ TAstBinder }
|
||||
|
||||
constructor TAstBinder.Create(const AInitialScope: IExecutionScope);
|
||||
constructor TAstBinder.Create(const AInitialDescriptor: IScopeDescriptor);
|
||||
begin
|
||||
inherited Create;
|
||||
Assert(Assigned(AInitialScope));
|
||||
Assert(Assigned(AInitialDescriptor));
|
||||
|
||||
FInitialScope := AInitialScope;
|
||||
FCurrentDescriptor := AInitialScope.CreateDescriptor;
|
||||
FCurrentDescriptor := AInitialDescriptor;
|
||||
FUpvalueStack := TObjectStack<TUpvalueMapping>.Create(True); // Use Comparer
|
||||
FNestedLambdaCount := 0;
|
||||
FBoxedDeclarations := nil;
|
||||
@@ -115,9 +113,13 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
class function TAstBinder.Bind(const InitialScope: IExecutionScope; const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
class function TAstBinder.Bind(
|
||||
const InitialDescriptor: IScopeDescriptor;
|
||||
const RootNode: IAstNode;
|
||||
out Descriptor: IScopeDescriptor
|
||||
): IAstNode;
|
||||
begin
|
||||
var binder := TAstBinder.Create(InitialScope) as IAstBinder;
|
||||
var binder := TAstBinder.Create(InitialDescriptor) as IAstBinder;
|
||||
Result := binder.Execute(RootNode, Descriptor);
|
||||
end;
|
||||
|
||||
@@ -155,7 +157,6 @@ begin
|
||||
try
|
||||
EnterScope;
|
||||
try
|
||||
// Main pass: Run the mutator
|
||||
Result := Accept(RootNode); // Accept returns IAstNode
|
||||
if not Assigned(Result) then
|
||||
Result := TAst.Block([]);
|
||||
|
||||
@@ -12,11 +12,12 @@ uses
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Types,
|
||||
Myc.Ast;
|
||||
Myc.Ast,
|
||||
Myc.Ast.Environment; // Added for IMacroRegistry
|
||||
|
||||
type
|
||||
IAstMacroExpander = interface(IAstVisitor)
|
||||
// Signatur geändert: Descriptor wird nicht mehr zurückgegeben
|
||||
// Signatur geaendert: Descriptor wird nicht mehr zurueckgegeben
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
end;
|
||||
|
||||
@@ -46,28 +47,10 @@ type
|
||||
// This transformer traverses the entire AST *before* the binder,
|
||||
// to find and expand macros.
|
||||
TMacroExpander = class(TAstTransformer, IAstMacroExpander)
|
||||
type
|
||||
TMacroRegistry = class
|
||||
private
|
||||
FParent: TMacroRegistry;
|
||||
FMacros: TDictionary<string, IMacroDefinitionNode>;
|
||||
public
|
||||
constructor Create(AParent: TMacroRegistry);
|
||||
destructor Destroy; override;
|
||||
procedure Define(const Node: IMacroDefinitionNode);
|
||||
function Find(const Name: string): IMacroDefinitionNode;
|
||||
end;
|
||||
|
||||
strict private
|
||||
class var
|
||||
FGlobalMacroRegistry: TMacroRegistry;
|
||||
class constructor CreateClass;
|
||||
class destructor DestroyClass;
|
||||
|
||||
private
|
||||
FInitialScope: IExecutionScope;
|
||||
|
||||
FCurrentMacroRegistry: TMacroRegistry;
|
||||
FCurrentMacroRegistry: IMacroRegistry; // Changed from TMacroRegistry
|
||||
|
||||
FEvaluatorFactory: TEvaluatorFactory;
|
||||
|
||||
@@ -87,18 +70,23 @@ type
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
|
||||
|
||||
public
|
||||
constructor Create(const AInitialScope: IExecutionScope; const AEvaluatorFactory: TEvaluatorFactory);
|
||||
destructor Destroy; override;
|
||||
// Updated Constructor
|
||||
constructor Create(
|
||||
const ARootRegistry: IMacroRegistry;
|
||||
const AInitialScope: IExecutionScope;
|
||||
const AEvaluatorFactory: TEvaluatorFactory
|
||||
);
|
||||
destructor Destroy; override; // Modified
|
||||
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
|
||||
// Updated static helper
|
||||
class function ExpandMacros(
|
||||
const InitialScope: IExecutionScope;
|
||||
const ARootRegistry: IMacroRegistry; // Added
|
||||
const AInitialScope: IExecutionScope;
|
||||
const RootNode: IAstNode;
|
||||
const EvaluatorFactory: TEvaluatorFactory
|
||||
): IAstNode; static;
|
||||
|
||||
class property GlobalMacroRegistry: TMacroRegistry read FGlobalMacroRegistry;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -109,40 +97,6 @@ uses
|
||||
Myc.Ast.Evaluator, // Required for TEvaluatorVisitor.Execute
|
||||
Myc.Data.Keyword;
|
||||
|
||||
{ TMacroRegistry }
|
||||
|
||||
constructor TMacroExpander.TMacroRegistry.Create(AParent: TMacroRegistry);
|
||||
begin
|
||||
inherited Create;
|
||||
FParent := AParent;
|
||||
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
|
||||
end;
|
||||
|
||||
destructor TMacroExpander.TMacroRegistry.Destroy;
|
||||
begin
|
||||
FMacros.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TMacroExpander.TMacroRegistry.Define(const Node: IMacroDefinitionNode);
|
||||
begin
|
||||
FMacros.AddOrSetValue(Node.Name.Name, Node);
|
||||
end;
|
||||
|
||||
function TMacroExpander.TMacroRegistry.Find(const Name: string): IMacroDefinitionNode;
|
||||
var
|
||||
current: TMacroRegistry;
|
||||
begin
|
||||
current := Self;
|
||||
while Assigned(current) do
|
||||
begin
|
||||
if current.FMacros.TryGetValue(Name, Result) then
|
||||
exit;
|
||||
current := current.FParent;
|
||||
end;
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
{ TExpansionVisitor }
|
||||
|
||||
constructor TExpansionVisitor.Create(const AMacroScope: IExecutionScope; const AEvaluate: TEvaluateProc);
|
||||
@@ -288,57 +242,52 @@ end;
|
||||
|
||||
{ TMacroExpander }
|
||||
|
||||
constructor TMacroExpander.Create(const AInitialScope: IExecutionScope; const AEvaluatorFactory: TEvaluatorFactory);
|
||||
constructor TMacroExpander.Create(
|
||||
const ARootRegistry: IMacroRegistry;
|
||||
const AInitialScope: IExecutionScope;
|
||||
const AEvaluatorFactory: TEvaluatorFactory
|
||||
);
|
||||
begin
|
||||
inherited Create;
|
||||
Assert(Assigned(ARootRegistry));
|
||||
Assert(Assigned(AInitialScope));
|
||||
Assert(Assigned(AEvaluatorFactory));
|
||||
|
||||
FInitialScope := AInitialScope;
|
||||
FEvaluatorFactory := AEvaluatorFactory;
|
||||
|
||||
// Erzeugt die Root-Registry für Makros
|
||||
FCurrentMacroRegistry := TMacroRegistry.Create(FGlobalMacroRegistry);
|
||||
end;
|
||||
|
||||
class constructor TMacroExpander.CreateClass;
|
||||
begin
|
||||
FGlobalMacroRegistry := TMacroRegistry.Create(nil);
|
||||
// Creates the root registry for this specific compilation run,
|
||||
// parented to the global registry from the environment.
|
||||
FCurrentMacroRegistry := ARootRegistry.CreateChildRegistry;
|
||||
end;
|
||||
|
||||
destructor TMacroExpander.Destroy;
|
||||
begin
|
||||
FCurrentMacroRegistry.Free;
|
||||
// FCurrentMacroRegistry is an interface, managed by ARC
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
class destructor TMacroExpander.DestroyClass;
|
||||
begin
|
||||
FGlobalMacroRegistry.Free;
|
||||
end;
|
||||
|
||||
procedure TMacroExpander.EnterMacroScope;
|
||||
begin
|
||||
// Erstellt eine neue Registry mit der aktuellen als Parent
|
||||
FCurrentMacroRegistry := TMacroRegistry.Create(FCurrentMacroRegistry);
|
||||
// Creates a new registry with the current as Parent
|
||||
FCurrentMacroRegistry := FCurrentMacroRegistry.CreateChildRegistry;
|
||||
end;
|
||||
|
||||
procedure TMacroExpander.ExitMacroScope;
|
||||
var
|
||||
oldRegistry: TMacroRegistry;
|
||||
begin
|
||||
oldRegistry := FCurrentMacroRegistry;
|
||||
FCurrentMacroRegistry := oldRegistry.FParent;
|
||||
oldRegistry.Free;
|
||||
// Revert to parent registry. ARC will free the old child.
|
||||
FCurrentMacroRegistry := FCurrentMacroRegistry.Parent;
|
||||
end;
|
||||
|
||||
class function TMacroExpander.ExpandMacros(
|
||||
const InitialScope: IExecutionScope;
|
||||
const ARootRegistry: IMacroRegistry;
|
||||
const AInitialScope: IExecutionScope;
|
||||
const RootNode: IAstNode;
|
||||
const EvaluatorFactory: TEvaluatorFactory
|
||||
): IAstNode;
|
||||
begin
|
||||
// IAstMacroExpander.Execute gibt keinen Descriptor mehr zurück
|
||||
var expander := TMacroExpander.Create(InitialScope, EvaluatorFactory) as IAstMacroExpander;
|
||||
// IAstMacroExpander.Execute gibt keinen Descriptor mehr zurueck
|
||||
var expander := TMacroExpander.Create(ARootRegistry, AInitialScope, EvaluatorFactory) as IAstMacroExpander;
|
||||
Result := expander.Execute(RootNode);
|
||||
end;
|
||||
|
||||
@@ -400,7 +349,7 @@ begin
|
||||
// --- It is a macro, expand it ---
|
||||
|
||||
// 1. Create the temporary scope for the macro parameters
|
||||
// It must be parented to the *initial* scope to find other macros/globals.
|
||||
// It must be parented to the *initial* scope to find other globals.
|
||||
var expansionScope := TAst.CreateScope(FInitialScope);
|
||||
var params := macroDef.Parameters;
|
||||
if Length(Node.Arguments) <> Length(params) then
|
||||
@@ -422,8 +371,8 @@ begin
|
||||
boundSubAst: IAstNode;
|
||||
begin
|
||||
// This is the compile-time evaluation (Binder + Evaluator)
|
||||
// Es wird der 'expansionScope' verwendet, der die AST-Argumente enthält
|
||||
boundSubAst := TAstBinder.Bind(expansionScope, ANodeToEvaluate, subDescriptor);
|
||||
// Es wird der 'expansionScope' verwendet, der die AST-Argumente enthaelt
|
||||
boundSubAst := TAstBinder.Bind(expansionScope.CreateDescriptor, ANodeToEvaluate, subDescriptor);
|
||||
|
||||
// Create eval scope from the new descriptor, parented to the expansion scope
|
||||
evalScope := subDescriptor.CreateScope(expansionScope);
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
unit Myc.Ast.Environment;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Scope;
|
||||
|
||||
type
|
||||
IMacroRegistry = interface; // Forward
|
||||
IEnvironment = interface; // Forward
|
||||
IExecutionStrategy = interface; // Forward
|
||||
IExecutable = interface; // Forward
|
||||
|
||||
// Defines the Strategy for creating an Evaluator.
|
||||
IExecutionStrategy = interface
|
||||
function CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||
end;
|
||||
|
||||
// Defines the compile-time macro storage.
|
||||
IMacroRegistry = interface
|
||||
{$region 'private'}
|
||||
function GetParent: IMacroRegistry;
|
||||
{$endregion}
|
||||
|
||||
procedure Define(const Node: IMacroDefinitionNode);
|
||||
function Find(const Name: string): IMacroDefinitionNode;
|
||||
function CreateChildRegistry: IMacroRegistry;
|
||||
property Parent: IMacroRegistry read GetParent;
|
||||
end;
|
||||
|
||||
// Represents a compiled, ready-to-run script.
|
||||
// This encapsulates the compiled AST and its internal layout (Descriptor).
|
||||
IExecutable = interface
|
||||
{$region 'private'}
|
||||
function GetCompiledAst: IAstNode;
|
||||
function GetDescriptor: IScopeDescriptor;
|
||||
{$endregion}
|
||||
|
||||
// The final, compiled AST (for debugging, serialization, etc.)
|
||||
property CompiledAst: IAstNode read GetCompiledAst;
|
||||
// The internal layout (hidden from TForm1, used by IEnvironment.Execute)
|
||||
property Descriptor: IScopeDescriptor read GetDescriptor;
|
||||
end;
|
||||
|
||||
// Defines the central environment for compilation and execution.
|
||||
IEnvironment = interface
|
||||
{$region 'private'}
|
||||
function GetRootScope: IExecutionScope;
|
||||
function GetMacroRegistry: IMacroRegistry;
|
||||
{$endregion}
|
||||
|
||||
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
||||
|
||||
// Compiles source AST into a runnable script.
|
||||
function Compile(const ANode: IAstNode): IExecutable; // Changed return type
|
||||
|
||||
// Executes a previously compiled script.
|
||||
function Execute(const AScript: IExecutable): TDataValue;
|
||||
|
||||
function CreateEnvironment: IEnvironment;
|
||||
|
||||
property RootScope: IExecutionScope read GetRootScope;
|
||||
property MacroRegistry: IMacroRegistry read GetMacroRegistry;
|
||||
end;
|
||||
|
||||
// Interface Helper for IEnvironment
|
||||
TAstEnvironment = record
|
||||
private
|
||||
FEnvironment: IEnvironment;
|
||||
function GetRootScope: IExecutionScope; inline;
|
||||
function GetMacroRegistry: IMacroRegistry; inline;
|
||||
public
|
||||
constructor Create(const AEnvironment: IEnvironment);
|
||||
|
||||
class operator Initialize(out Dest: TAstEnvironment);
|
||||
class operator Implicit(const A: IEnvironment): TAstEnvironment;
|
||||
class operator Implicit(const A: TAstEnvironment): IEnvironment;
|
||||
|
||||
function CreateEnvironment: TAstEnvironment;
|
||||
|
||||
procedure SetStandardMode;
|
||||
procedure SetDebugMode(ALog: TStrings; AShowScope: Boolean);
|
||||
|
||||
function Compile(const ANode: IAstNode): IExecutable;
|
||||
function Execute(const AScript: IExecutable): TDataValue;
|
||||
|
||||
function CompileAndExecute(const AScript: IAstNode): TDataValue;
|
||||
|
||||
procedure Define(const Name: String; const AScript: IAstNode);
|
||||
|
||||
property RootScope: IExecutionScope read GetRootScope;
|
||||
property MacroRegistry: IMacroRegistry read GetMacroRegistry;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
Myc.Ast.RTL,
|
||||
Myc.Ast.Evaluator,
|
||||
Myc.Ast.Debugger,
|
||||
Myc.Ast.Compiler.Macros,
|
||||
Myc.Ast.Compiler.Binder,
|
||||
Myc.Ast.Compiler.TypeChecker,
|
||||
Myc.Ast.Compiler.Lowering,
|
||||
Myc.Ast.Compiler.TCO;
|
||||
|
||||
type
|
||||
{ TStandardExecutionStrategy }
|
||||
TStandardExecutionStrategy = class(TInterfacedObject, IExecutionStrategy)
|
||||
public
|
||||
function CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||
end;
|
||||
|
||||
{ TDebugExecutionStrategy }
|
||||
TDebugExecutionStrategy = class(TInterfacedObject, IExecutionStrategy)
|
||||
private
|
||||
FLog: TStrings;
|
||||
FShowScope: Boolean;
|
||||
public
|
||||
constructor Create(ALog: TStrings; AShowScope: Boolean);
|
||||
function CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||
end;
|
||||
|
||||
{ TMacroRegistryImpl }
|
||||
TMacroRegistryImpl = class(TInterfacedObject, IMacroRegistry)
|
||||
private
|
||||
FParent: IMacroRegistry;
|
||||
FMacros: TDictionary<string, IMacroDefinitionNode>;
|
||||
function GetParent: IMacroRegistry;
|
||||
public
|
||||
constructor Create(AParent: IMacroRegistry);
|
||||
destructor Destroy; override;
|
||||
procedure Define(const Node: IMacroDefinitionNode);
|
||||
function Find(const Name: string): IMacroDefinitionNode;
|
||||
function CreateChildRegistry: IMacroRegistry;
|
||||
end;
|
||||
|
||||
{ TExecutable }
|
||||
TExecutable = class(TInterfacedObject, IExecutable)
|
||||
private
|
||||
FCompiledAst: IAstNode;
|
||||
FDescriptor: IScopeDescriptor;
|
||||
function GetCompiledAst: IAstNode;
|
||||
function GetDescriptor: IScopeDescriptor;
|
||||
public
|
||||
constructor Create(ACompiledAst: IAstNode; ADescriptor: IScopeDescriptor);
|
||||
end;
|
||||
|
||||
{ TEnvironment }
|
||||
TEnvironment = class(TInterfacedObject, IEnvironment)
|
||||
private
|
||||
FRootScope: IExecutionScope;
|
||||
FMacroRegistry: IMacroRegistry;
|
||||
FExecutionStrategy: IExecutionStrategy;
|
||||
function GetRootScope: IExecutionScope;
|
||||
function GetMacroRegistry: IMacroRegistry;
|
||||
public
|
||||
constructor Create(
|
||||
const ARootScope: IExecutionScope;
|
||||
const AMacroRegistry: IMacroRegistry;
|
||||
const AExecutionStrategy: IExecutionStrategy
|
||||
);
|
||||
destructor Destroy; override;
|
||||
|
||||
function CreateEnvironment: IEnvironment;
|
||||
|
||||
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
||||
|
||||
function Compile(const ANode: IAstNode): IExecutable;
|
||||
function Execute(const AScript: IExecutable): TDataValue;
|
||||
end;
|
||||
|
||||
// --- Factory Implementations ---
|
||||
|
||||
{ TAstEnvironment }
|
||||
|
||||
class operator TAstEnvironment.Initialize(out Dest: TAstEnvironment);
|
||||
begin
|
||||
Dest.FEnvironment :=
|
||||
TEnvironment.Create(TScope.CreateScope(nil, nil, nil), TMacroRegistryImpl.Create(nil), TStandardExecutionStrategy.Create);
|
||||
end;
|
||||
|
||||
constructor TAstEnvironment.Create(const AEnvironment: IEnvironment);
|
||||
begin
|
||||
FEnvironment := AEnvironment;
|
||||
end;
|
||||
|
||||
procedure TAstEnvironment.SetStandardMode;
|
||||
begin
|
||||
FEnvironment.SetExecutionStrategy(TStandardExecutionStrategy.Create);
|
||||
end;
|
||||
|
||||
procedure TAstEnvironment.SetDebugMode(ALog: TStrings; AShowScope: Boolean);
|
||||
begin
|
||||
FEnvironment.SetExecutionStrategy(TDebugExecutionStrategy.Create(ALog, AShowScope));
|
||||
end;
|
||||
|
||||
class operator TAstEnvironment.Implicit(const A: IEnvironment): TAstEnvironment;
|
||||
begin
|
||||
Result.FEnvironment := A;
|
||||
end;
|
||||
|
||||
class operator TAstEnvironment.Implicit(const A: TAstEnvironment): IEnvironment;
|
||||
begin
|
||||
Result := A.FEnvironment;
|
||||
end;
|
||||
|
||||
function TAstEnvironment.Compile(const ANode: IAstNode): IExecutable;
|
||||
begin
|
||||
Result := FEnvironment.Compile(ANode);
|
||||
end;
|
||||
|
||||
function TAstEnvironment.CompileAndExecute(const AScript: IAstNode): TDataValue;
|
||||
begin
|
||||
Result := Execute(Compile(AScript));
|
||||
end;
|
||||
|
||||
function TAstEnvironment.CreateEnvironment: TAstEnvironment;
|
||||
begin
|
||||
Result := FEnvironment.CreateEnvironment;
|
||||
end;
|
||||
|
||||
procedure TAstEnvironment.Define(const Name: String; const AScript: IAstNode);
|
||||
begin
|
||||
RootScope.Define(Name, CompileAndExecute(AScript));
|
||||
end;
|
||||
|
||||
function TAstEnvironment.Execute(const AScript: IExecutable): TDataValue;
|
||||
begin
|
||||
Result := FEnvironment.Execute(AScript);
|
||||
end;
|
||||
|
||||
function TAstEnvironment.GetRootScope: IExecutionScope;
|
||||
begin
|
||||
Result := FEnvironment.GetRootScope;
|
||||
end;
|
||||
|
||||
function TAstEnvironment.GetMacroRegistry: IMacroRegistry;
|
||||
begin
|
||||
Result := FEnvironment.GetMacroRegistry;
|
||||
end;
|
||||
|
||||
{ TStandardExecutionStrategy }
|
||||
|
||||
function TStandardExecutionStrategy.CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||
begin
|
||||
Result := TEvaluatorVisitor.Create(AScope);
|
||||
end;
|
||||
|
||||
{ TDebugExecutionStrategy }
|
||||
|
||||
constructor TDebugExecutionStrategy.Create(ALog: TStrings; AShowScope: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
FLog := ALog;
|
||||
FShowScope := AShowScope;
|
||||
end;
|
||||
|
||||
function TDebugExecutionStrategy.CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||
begin
|
||||
Result := TDebugEvaluatorVisitor.Create(AScope, FLog, FShowScope, 0);
|
||||
end;
|
||||
|
||||
{ TMacroRegistryImpl }
|
||||
|
||||
constructor TMacroRegistryImpl.Create(AParent: IMacroRegistry);
|
||||
begin
|
||||
inherited Create;
|
||||
FParent := AParent;
|
||||
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
|
||||
end;
|
||||
|
||||
destructor TMacroRegistryImpl.Destroy;
|
||||
begin
|
||||
FMacros.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TMacroRegistryImpl.GetParent: IMacroRegistry;
|
||||
begin
|
||||
Result := FParent;
|
||||
end;
|
||||
|
||||
procedure TMacroRegistryImpl.Define(const Node: IMacroDefinitionNode);
|
||||
begin
|
||||
FMacros.AddOrSetValue(Node.Name.Name, Node);
|
||||
end;
|
||||
|
||||
function TMacroRegistryImpl.Find(const Name: string): IMacroDefinitionNode;
|
||||
var
|
||||
current: IMacroRegistry;
|
||||
begin
|
||||
current := Self;
|
||||
while Assigned(current) do
|
||||
begin
|
||||
if (current as TMacroRegistryImpl).FMacros.TryGetValue(Name, Result) then
|
||||
exit;
|
||||
current := current.Parent;
|
||||
end;
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TMacroRegistryImpl.CreateChildRegistry: IMacroRegistry;
|
||||
begin
|
||||
Result := TMacroRegistryImpl.Create(Self);
|
||||
end;
|
||||
|
||||
{ TExecutable }
|
||||
|
||||
constructor TExecutable.Create(ACompiledAst: IAstNode; ADescriptor: IScopeDescriptor);
|
||||
begin
|
||||
inherited Create;
|
||||
FCompiledAst := ACompiledAst;
|
||||
FDescriptor := ADescriptor;
|
||||
end;
|
||||
|
||||
function TExecutable.GetCompiledAst: IAstNode;
|
||||
begin
|
||||
Result := FCompiledAst;
|
||||
end;
|
||||
|
||||
function TExecutable.GetDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
Result := FDescriptor;
|
||||
end;
|
||||
|
||||
{ TEnvironment }
|
||||
|
||||
constructor TEnvironment.Create(
|
||||
const ARootScope: IExecutionScope;
|
||||
const AMacroRegistry: IMacroRegistry;
|
||||
const AExecutionStrategy: IExecutionStrategy
|
||||
);
|
||||
begin
|
||||
inherited Create;
|
||||
FRootScope := ARootScope;
|
||||
FMacroRegistry := AMacroRegistry;
|
||||
FExecutionStrategy := AExecutionStrategy;
|
||||
end;
|
||||
|
||||
destructor TEnvironment.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TEnvironment.GetMacroRegistry: IMacroRegistry;
|
||||
begin
|
||||
Result := FMacroRegistry;
|
||||
end;
|
||||
|
||||
function TEnvironment.GetRootScope: IExecutionScope;
|
||||
begin
|
||||
Result := FRootScope;
|
||||
end;
|
||||
|
||||
procedure TEnvironment.SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
||||
begin
|
||||
FExecutionStrategy := AStrategy;
|
||||
end;
|
||||
|
||||
function TEnvironment.Compile(const ANode: IAstNode): IExecutable;
|
||||
var
|
||||
expandedAst, boundAst, typedAst, loweredAst: IAstNode;
|
||||
descriptor: IScopeDescriptor;
|
||||
begin
|
||||
// Step 1: Expand macros
|
||||
expandedAst :=
|
||||
TMacroExpander.ExpandMacros(
|
||||
FMacroRegistry,
|
||||
FRootScope,
|
||||
ANode,
|
||||
function(const Scope: IExecutionScope): IEvaluatorVisitor begin Result := FExecutionStrategy.CreateVisitor(Scope); end
|
||||
);
|
||||
|
||||
// Step 2: Bind names
|
||||
boundAst := TAstBinder.Bind(FRootScope.CreateDescriptor, expandedAst, descriptor);
|
||||
|
||||
// Step 3: Check types
|
||||
typedAst := TTypeChecker.CheckTypes(boundAst, descriptor);
|
||||
|
||||
// Step 4: Lowering
|
||||
loweredAst := TAstLowerer.Lower(typedAst);
|
||||
|
||||
// Step 5: TCO
|
||||
var compiledAst := TAstTCO.Optimize(loweredAst);
|
||||
|
||||
// Step 6: Create the executable package
|
||||
Result := TExecutable.Create(compiledAst, descriptor);
|
||||
end;
|
||||
|
||||
function TEnvironment.CreateEnvironment: IEnvironment;
|
||||
begin
|
||||
Result := TEnvironment.Create(TScope.CreateScope(FRootScope, nil, nil), TMacroRegistryImpl.Create(FMacroRegistry), FExecutionStrategy);
|
||||
end;
|
||||
|
||||
function TEnvironment.Execute(const AScript: IExecutable): TDataValue;
|
||||
var
|
||||
evalScope: IExecutionScope;
|
||||
visitor: IEvaluatorVisitor;
|
||||
begin
|
||||
// 1. Create the runtime scope *directly from the descriptor*.
|
||||
// This creates the raw scope with the correct slot count for local variables,
|
||||
// parented to FRootScope.
|
||||
evalScope := AScript.Descriptor.CreateScope(FRootScope);
|
||||
|
||||
// 2. Use the strategy to create the final evaluator
|
||||
visitor := FExecutionStrategy.CreateVisitor(evalScope);
|
||||
|
||||
// 3. Execute the compiled AST
|
||||
Result := visitor.Execute(AScript.CompiledAst);
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -399,7 +399,7 @@ type
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
end;
|
||||
|
||||
// A factory for creating visitors, primarily used by the debugger subsystem.
|
||||
// A factory for creating visitors
|
||||
TEvaluatorFactory = reference to function(const Scope: IExecutionScope): IEvaluatorVisitor;
|
||||
|
||||
implementation
|
||||
|
||||
@@ -10,6 +10,7 @@ uses
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Nodes;
|
||||
|
||||
type
|
||||
@@ -21,12 +22,13 @@ type
|
||||
constructor Create(const AName: string);
|
||||
end;
|
||||
|
||||
procedure RegisterRtlFunctions(const AScope: IExecutionScope);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Rtti,
|
||||
System.TypInfo,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.RTL.Core;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -49,7 +49,8 @@ type
|
||||
procedure SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
||||
{$endregion}
|
||||
|
||||
procedure Define(const Name: string; const Value: TDataValue);
|
||||
// Defines a symbol and returns its runtime address
|
||||
function Define(const Name: string; const Value: TDataValue): TResolvedAddress;
|
||||
|
||||
// Defines a variable at a given address and stores it directly in a shared cell (boxing).
|
||||
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||
@@ -59,6 +60,8 @@ type
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
|
||||
function GetNameID(const Name: String): Integer;
|
||||
// Resolves a name to an address by searching the runtime scope chain.
|
||||
function Resolve(const Name: string): TResolvedAddress;
|
||||
|
||||
function CreateDescriptor: IScopeDescriptor;
|
||||
|
||||
@@ -143,8 +146,9 @@ type
|
||||
destructor Destroy; override;
|
||||
procedure Clear;
|
||||
function GetNameID(const Name: String): Integer;
|
||||
function Resolve(const Name: string): TResolvedAddress;
|
||||
function Dump: string;
|
||||
procedure Define(const Name: string; const Value: TDataValue);
|
||||
function Define(const Name: string; const Value: TDataValue): TResolvedAddress;
|
||||
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
function CreateDescriptor: IScopeDescriptor;
|
||||
@@ -336,7 +340,7 @@ begin
|
||||
Result := TScopeDescriptor.CreateDescriptor(Self);
|
||||
end;
|
||||
|
||||
procedure TExecutionScope.Define(const Name: string; const Value: TDataValue);
|
||||
function TExecutionScope.Define(const Name: string; const Value: TDataValue): TResolvedAddress;
|
||||
var
|
||||
id: Integer;
|
||||
index: Integer;
|
||||
@@ -351,6 +355,11 @@ begin
|
||||
FValues[index].Value := Value;
|
||||
FValues[index].IsBoxed := False;
|
||||
FNameToIndex.Add(id, index);
|
||||
|
||||
// Return the address
|
||||
Result.Kind := akLocalOrParent;
|
||||
Result.ScopeDepth := 0;
|
||||
Result.SlotIndex := index;
|
||||
end;
|
||||
|
||||
procedure TExecutionScope.DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||
@@ -480,6 +489,42 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExecutionScope.Resolve(const Name: string): TResolvedAddress;
|
||||
var
|
||||
nameID: Integer;
|
||||
slotIndex: Integer;
|
||||
currentScope: IExecutionScope;
|
||||
depth: Integer;
|
||||
begin
|
||||
currentScope := Self;
|
||||
depth := 0;
|
||||
// GetNameID is shared (or recreated) across the scope chain
|
||||
nameID := GetNameID(Name);
|
||||
|
||||
while Assigned(currentScope) do
|
||||
begin
|
||||
// We must cast to the implementation class to access 'NameToIndex'
|
||||
var execScopeImpl := (currentScope as TExecutionScope);
|
||||
|
||||
// Accessing .NameToIndex property ensures NeedNameToIndex is called
|
||||
if execScopeImpl.NameToIndex.TryGetValue(nameID, slotIndex) then
|
||||
begin
|
||||
// Found in this scope
|
||||
Result.Kind := akLocalOrParent;
|
||||
Result.ScopeDepth := depth;
|
||||
Result.SlotIndex := slotIndex;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Not found, go to parent
|
||||
inc(depth);
|
||||
currentScope := currentScope.Parent;
|
||||
end;
|
||||
|
||||
// Not found in the entire chain
|
||||
Result := Default(TResolvedAddress); // Kind = akUnresolved
|
||||
end;
|
||||
|
||||
procedure TExecutionScope.SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
||||
var
|
||||
targetScope: TExecutionScope;
|
||||
|
||||
Reference in New Issue
Block a user