Binding
This commit is contained in:
+16
-25
@@ -46,11 +46,8 @@ type
|
||||
): IAddSeriesItemNode; static;
|
||||
class function SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode; static;
|
||||
|
||||
// --- Static method to run the binder ---
|
||||
// Traverses the AST and resolves all identifiers. Returns a scope descriptor for the script's top-level variables.
|
||||
class function CreateScopeDescriptor(const Parent: IScopeDescriptor): IScopeDescriptor; static;
|
||||
class function CreateBinding(const Scope: IExecutionScope): IScopeDescriptor; static;
|
||||
class function Bind(const RootNode: IExpressionNode; const ParentScope: IExecutionScope): IScopeDescriptor; static;
|
||||
class function CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor; static;
|
||||
class function Bind(const RootNode: IExpressionNode; const ParentScope: IExecutionScope): IExecutionScope; static;
|
||||
end;
|
||||
|
||||
// TAstTraverser provides a default AST traversal implementation.
|
||||
@@ -89,8 +86,9 @@ type
|
||||
destructor Destroy; override;
|
||||
function Define(const Name: string): Integer;
|
||||
function FindSymbol(const Name: string; out Index: Integer; out Depth: Integer): Boolean;
|
||||
function Instantiate(const AParent: IExecutionScope): IExecutionScope;
|
||||
function CreateScope(const AParent: IExecutionScope): IExecutionScope;
|
||||
procedure PopulateFromScope(const AScope: IExecutionScope);
|
||||
property Symbols: TDictionary<string, Integer> read FSymbols;
|
||||
end;
|
||||
|
||||
{ TAstNode }
|
||||
@@ -119,14 +117,15 @@ type
|
||||
FResolvedAddress: TResolvedAddress;
|
||||
function GetName: string;
|
||||
function GetIsResolved: Boolean; inline;
|
||||
function GetAddress: TResolvedAddress; inline;
|
||||
public
|
||||
constructor Create(AName: string);
|
||||
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
||||
|
||||
function Resolve: TResolvedAddress;
|
||||
property IsResolved: Boolean read GetIsResolved;
|
||||
|
||||
property Name: string read FName;
|
||||
property Address: TResolvedAddress read GetAddress;
|
||||
end;
|
||||
|
||||
{ TBinaryExpressionNode }
|
||||
@@ -371,16 +370,13 @@ begin
|
||||
Result := FSymbols;
|
||||
end;
|
||||
|
||||
function TScopeDescriptor.Instantiate(const AParent: IExecutionScope): IExecutionScope;
|
||||
function TScopeDescriptor.CreateScope(const AParent: IExecutionScope): IExecutionScope;
|
||||
begin
|
||||
Result := TExecutionScope.CreateFromDescriptor(AParent, Self);
|
||||
Result := TExecutionScope.Create(AParent, Self);
|
||||
end;
|
||||
|
||||
procedure TScopeDescriptor.PopulateFromScope(const AScope: IExecutionScope);
|
||||
begin
|
||||
if not Assigned(AScope) then
|
||||
Exit;
|
||||
|
||||
for var pair in (AScope as TExecutionScope).NameToIndex do
|
||||
if not FSymbols.ContainsKey(pair.Key) then
|
||||
FSymbols.Add(pair.Key, pair.Value);
|
||||
@@ -429,7 +425,7 @@ begin
|
||||
Result := FName;
|
||||
end;
|
||||
|
||||
function TIdentifierNode.Resolve: TResolvedAddress;
|
||||
function TIdentifierNode.GetAddress: TResolvedAddress;
|
||||
begin
|
||||
if not IsResolved then
|
||||
raise EInvalidOpException.Create('Identifier not bound');
|
||||
@@ -810,7 +806,7 @@ end;
|
||||
constructor TBinder.Create(const AInitialScope: IExecutionScope);
|
||||
begin
|
||||
inherited Create;
|
||||
FCurrentDescriptor := TAst.CreateBinding(AInitialScope);
|
||||
FCurrentDescriptor := TAst.CreateDescriptor(AInitialScope);
|
||||
end;
|
||||
|
||||
procedure TBinder.EnterScope;
|
||||
@@ -869,7 +865,7 @@ end;
|
||||
|
||||
{ TAst }
|
||||
|
||||
class function TAst.Bind(const RootNode: IExpressionNode; const ParentScope: IExecutionScope): IScopeDescriptor;
|
||||
class function TAst.Bind(const RootNode: IExpressionNode; const ParentScope: IExecutionScope): IExecutionScope;
|
||||
var
|
||||
binder: TBinder;
|
||||
visitor: IAstVisitor;
|
||||
@@ -884,7 +880,7 @@ begin
|
||||
// Traverse the AST. This annotates all nodes AND populates the new descriptor.
|
||||
RootNode.Accept(visitor);
|
||||
// Return the completed descriptor for the script's scope.
|
||||
Result := binder.FCurrentDescriptor;
|
||||
Result := binder.CurrentDescriptor.CreateScope(ParentScope);
|
||||
finally
|
||||
// Restore the binder's internal state.
|
||||
binder.ExitScope;
|
||||
@@ -930,22 +926,17 @@ begin
|
||||
Result := TBinaryExpressionNode.Create(ALeft, AOperator, ARight);
|
||||
end;
|
||||
|
||||
class function TAst.CreateBinding(const Scope: IExecutionScope): IScopeDescriptor;
|
||||
class function TAst.CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor;
|
||||
begin
|
||||
if Assigned(Scope) then
|
||||
if Scope is TExecutionScope then
|
||||
begin
|
||||
Result := CreateScopeDescriptor(CreateBinding(Scope.Parent));
|
||||
Result.PopulateFromScope(Scope);
|
||||
Result := TScopeDescriptor.Create(CreateDescriptor(Scope.Parent));
|
||||
(Result as TScopeDescriptor).PopulateFromScope(Scope);
|
||||
end
|
||||
else
|
||||
Result := TScopeDescriptor.Create(nil);
|
||||
end;
|
||||
|
||||
class function TAst.CreateScopeDescriptor(const Parent: IScopeDescriptor): IScopeDescriptor;
|
||||
begin
|
||||
Result := TScopeDescriptor.Create(Parent);
|
||||
end;
|
||||
|
||||
class function TAst.FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode;
|
||||
begin
|
||||
Result := TFunctionCallNode.Create(ACallee, AArguments);
|
||||
|
||||
Reference in New Issue
Block a user