Added user library
This commit is contained in:
+14
-29
@@ -51,8 +51,6 @@ type
|
||||
|
||||
function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
|
||||
class function CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor; static;
|
||||
|
||||
// The binder overrides specific transform methods to enrich the AST.
|
||||
function TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; override;
|
||||
function TransformVariableDeclaration(const Node: IVariableDeclarationNode): IVariableDeclarationNode; override;
|
||||
@@ -186,22 +184,10 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
class function TAstBinder.CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor;
|
||||
begin
|
||||
if Scope is TExecutionScope then
|
||||
begin
|
||||
var res := TScopeDescriptor.Create(CreateDescriptor(Scope.Parent));
|
||||
res.PopulateFromScope(Scope as TExecutionScope);
|
||||
Result := res;
|
||||
end
|
||||
else
|
||||
Result := TScopeDescriptor.Create(nil);
|
||||
end;
|
||||
|
||||
constructor TAstBinder.Create(const AInitialScope: IExecutionScope);
|
||||
begin
|
||||
inherited Create;
|
||||
FCurrentDescriptor := CreateDescriptor(AInitialScope);
|
||||
FCurrentDescriptor := AInitialScope.CreateDescriptor;
|
||||
FUpvalueStack := TObjectStack<TUpvalueMapping>.Create(True);
|
||||
FNestedLambdaCount := 0;
|
||||
FIsTailStack := TStack<Boolean>.Create;
|
||||
@@ -230,7 +216,7 @@ end;
|
||||
|
||||
procedure TAstBinder.EnterScope;
|
||||
begin
|
||||
FCurrentDescriptor := TScopeDescriptor.Create(FCurrentDescriptor);
|
||||
FCurrentDescriptor := TScope.CreateDescriptor(FCurrentDescriptor);
|
||||
end;
|
||||
|
||||
function TAstBinder.Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
@@ -270,30 +256,29 @@ end;
|
||||
|
||||
function TAstBinder.TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode;
|
||||
var
|
||||
depth, idx: Integer;
|
||||
adr: TResolvedAddress;
|
||||
begin
|
||||
if FCurrentDescriptor.FindSymbol(Node.Name, depth, idx) then
|
||||
adr := FCurrentDescriptor.FindSymbol(Node.Name);
|
||||
if adr.Kind = akLocalOrParent then
|
||||
begin
|
||||
if (depth > 0) and (FUpvalueStack.Count > 0) then
|
||||
if (adr.ScopeDepth > 0) and (FUpvalueStack.Count > 0) then
|
||||
begin
|
||||
var upvalue := FUpvalueStack.Peek;
|
||||
dec(depth);
|
||||
var originalAddress := TResolvedAddress.Create(akLocalOrParent, depth, idx);
|
||||
|
||||
// up to outer scope
|
||||
dec(adr.ScopeDepth);
|
||||
|
||||
var upvalueIndex: Integer;
|
||||
if not upvalue.Map.TryGetValue(originalAddress, upvalueIndex) then
|
||||
if not upvalue.Map.TryGetValue(adr, upvalueIndex) then
|
||||
begin
|
||||
upvalueIndex := upvalue.Map.Count;
|
||||
upvalue.Map.Add(originalAddress, upvalueIndex);
|
||||
upvalue.Map.Add(adr, upvalueIndex);
|
||||
end;
|
||||
var address := TResolvedAddress.Create(akUpvalue, 0, upvalueIndex);
|
||||
Result := TBoundIdentifierNode.Create(Node, address);
|
||||
|
||||
Result := TBoundIdentifierNode.Create(Node, TResolvedAddress.Create(akUpvalue, 0, upvalueIndex));
|
||||
end
|
||||
else
|
||||
begin
|
||||
var address := TResolvedAddress.Create(akLocalOrParent, depth, idx);
|
||||
Result := TBoundIdentifierNode.Create(Node, address);
|
||||
end
|
||||
Result := TBoundIdentifierNode.Create(Node, adr);
|
||||
end
|
||||
else
|
||||
raise Exception.CreateFmt('Undefined identifier: "%s"', [Node.Name]);
|
||||
|
||||
@@ -27,16 +27,8 @@ type
|
||||
procedure Log(const Text: string); overload;
|
||||
procedure LogFmt(const Fmt: string; const Args: array of const); overload;
|
||||
function FormatAddress(const Addr: TResolvedAddress): string;
|
||||
public
|
||||
// Creates a new instance of the AST dumper.
|
||||
constructor Create(const AOutput: TStrings);
|
||||
|
||||
// Traverses the given root node and writes the structural information into the output.
|
||||
class procedure Dump(const RootNode: IAstNode; const Output: TStrings);
|
||||
|
||||
procedure Execute(const RootNode: IAstNode);
|
||||
|
||||
// IAstVisitor implementation
|
||||
protected
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||
@@ -54,6 +46,15 @@ type
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
|
||||
public
|
||||
// Creates a new instance of the AST dumper.
|
||||
constructor Create(const AOutput: TStrings);
|
||||
|
||||
// Traverses the given root node and writes the structural information into the output.
|
||||
class procedure Dump(const RootNode: IAstNode; const Output: TStrings);
|
||||
|
||||
procedure Execute(const RootNode: IAstNode);
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
@@ -28,18 +28,6 @@ type
|
||||
procedure HandleTCO(var ResultValue: TDataValue);
|
||||
|
||||
protected
|
||||
function IsTruthy(const AValue: TDataValue): Boolean; inline;
|
||||
|
||||
// Returns a closure that can create the correct type of visitor for a lambda's body.
|
||||
function CreateVisitorFactory: TVisitorFactory; virtual;
|
||||
|
||||
property Scope: IExecutionScope read FScope;
|
||||
public
|
||||
constructor Create(const AScope: IExecutionScope);
|
||||
|
||||
// Executes an AST with proper TCO handling. This is the main entry point.
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||
@@ -57,6 +45,18 @@ type
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||
|
||||
function IsTruthy(const AValue: TDataValue): Boolean; inline;
|
||||
|
||||
// Returns a closure that can create the correct type of visitor for a lambda's body.
|
||||
function CreateVisitorFactory: TVisitorFactory; virtual;
|
||||
|
||||
property Scope: IExecutionScope read FScope;
|
||||
public
|
||||
constructor Create(const AScope: IExecutionScope);
|
||||
|
||||
// Executes an AST with proper TCO handling. This is the main entry point.
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
end;
|
||||
|
||||
// Registers native Delphi functions into a scope.
|
||||
@@ -207,7 +207,7 @@ begin
|
||||
if (Length(ArgValues) <> Length(params)) then
|
||||
raise EArgumentException.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(params), Length(ArgValues)]);
|
||||
|
||||
lambdaScope := TExecutionScope.Create(closureScope, scopeDescriptor, capturedCells);
|
||||
lambdaScope := TScope.CreateScope(closureScope, scopeDescriptor, capturedCells);
|
||||
|
||||
adr.Kind := akLocalOrParent;
|
||||
adr.ScopeDepth := 0;
|
||||
|
||||
+44
-99
@@ -4,29 +4,23 @@ interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Generics.Collections,
|
||||
System.JSON,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast,
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Ast.Nodes;
|
||||
|
||||
type
|
||||
// TAstJson provides static methods for serializing and deserializing an AST to/from JSON.
|
||||
TAstJson = record
|
||||
public
|
||||
class function Serialize(const ANode: IAstNode): string; static;
|
||||
class function Deserialize(const AJson: string): IAstNode; static;
|
||||
IJsonAstConverter = interface
|
||||
function Serialize(const RootNode: IAstNode): TJSONObject;
|
||||
function Deserialize(const AJson: TJSONObject): IAstNode;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.JSON,
|
||||
System.Generics.Collections,
|
||||
Myc.Ast,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value;
|
||||
|
||||
type
|
||||
// TJsonAstConverter implements the visitor pattern for serialization
|
||||
// and uses factory functions for deserialization.
|
||||
TJsonAstConverter = class(TInterfacedObject, IAstVisitor)
|
||||
TJsonAstConverter = class(TAstVisitor, IJsonAstConverter)
|
||||
private
|
||||
FJsonObjectStack: TStack<TJSONObject>;
|
||||
procedure DataValueToJson(const AValue: TDataValue; const AParent: TJSONObject; const AName: string);
|
||||
@@ -52,31 +46,33 @@ type
|
||||
function JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode;
|
||||
protected
|
||||
// IAstVisitor implementation for serialization
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
|
||||
function Serialize(const RootNode: IAstNode): TJSONObject;
|
||||
function Deserialize(const AJson: TJSONObject): IAstNode;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
function Serialize(const ANode: IAstNode): string;
|
||||
function Deserialize(const AJson: string): IAstNode;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TJsonAstConverter }
|
||||
|
||||
constructor TJsonAstConverter.Create;
|
||||
@@ -91,48 +87,9 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.Serialize(const ANode: IAstNode): string;
|
||||
var
|
||||
rootObj: TJSONObject;
|
||||
function TJsonAstConverter.Deserialize(const AJson: TJSONObject): IAstNode;
|
||||
begin
|
||||
if not Assigned(ANode) then
|
||||
exit('');
|
||||
|
||||
FJsonObjectStack.Clear;
|
||||
ANode.Accept(Self);
|
||||
|
||||
if FJsonObjectStack.Count <> 1 then
|
||||
raise EInvalidOpException.Create('JSON serialization stack is corrupt.');
|
||||
|
||||
rootObj := FJsonObjectStack.Pop;
|
||||
try
|
||||
Result := rootObj.Format(4);
|
||||
finally
|
||||
rootObj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.Deserialize(const AJson: string): IAstNode;
|
||||
var
|
||||
jsonValue: TJSONValue;
|
||||
begin
|
||||
if AJson.IsEmpty then
|
||||
exit(nil);
|
||||
|
||||
jsonValue := TJSONObject.ParseJSONValue(AJson);
|
||||
if jsonValue = nil then
|
||||
raise EJSONParseException.Create('Invalid JSON format.');
|
||||
|
||||
try
|
||||
Result := JsonToNode(jsonValue);
|
||||
finally
|
||||
jsonValue.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TJsonAstConverter.Execute(const RootNode: IAstNode): TDataValue;
|
||||
begin
|
||||
Result := RootNode.Accept(Self);
|
||||
Result := JsonToNode(AJson);
|
||||
end;
|
||||
|
||||
{ TJsonAstConverter - IAstVisitor for Serialization }
|
||||
@@ -782,30 +739,18 @@ begin
|
||||
raise ENotSupportedException.CreateFmt('Unsupported NodeType "%s" for JSON deserialization.', [nodeType]);
|
||||
end;
|
||||
|
||||
{ TAstJson }
|
||||
|
||||
class function TAstJson.Deserialize(const AJson: string): IAstNode;
|
||||
var
|
||||
converter: TJsonAstConverter;
|
||||
function TJsonAstConverter.Serialize(const RootNode: IAstNode): TJSONObject;
|
||||
begin
|
||||
converter := TJsonAstConverter.Create;
|
||||
try
|
||||
Result := converter.Deserialize(AJson);
|
||||
finally
|
||||
converter.Free;
|
||||
end;
|
||||
end;
|
||||
FJsonObjectStack.Clear;
|
||||
if not Assigned(RootNode) then
|
||||
exit(nil);
|
||||
|
||||
class function TAstJson.Serialize(const ANode: IAstNode): string;
|
||||
var
|
||||
converter: TJsonAstConverter;
|
||||
begin
|
||||
converter := TJsonAstConverter.Create;
|
||||
try
|
||||
Result := converter.Serialize(ANode);
|
||||
finally
|
||||
converter.Free;
|
||||
end;
|
||||
RootNode.Accept(Self);
|
||||
|
||||
if FJsonObjectStack.Count <> 1 then
|
||||
raise EInvalidOpException.Create('JSON serialization stack is corrupt.');
|
||||
|
||||
Result := FJsonObjectStack.Pop;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -29,8 +29,6 @@ type
|
||||
IAddSeriesItemNode = interface;
|
||||
ISeriesLengthNode = interface;
|
||||
IRecurNode = interface;
|
||||
IExecutionScope = interface;
|
||||
IScopeDescriptor = interface;
|
||||
|
||||
// --- Concrete Type Definitions ---
|
||||
|
||||
@@ -55,36 +53,6 @@ type
|
||||
property Value: TDataValue read GetValue write SetValue;
|
||||
end;
|
||||
|
||||
IExecutionScope = interface
|
||||
{$region 'private'}
|
||||
function GetParent: IExecutionScope;
|
||||
function GetValues(const Address: TResolvedAddress): TDataValue;
|
||||
procedure SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
||||
{$endregion}
|
||||
|
||||
procedure Define(const Name: string; const Value: TDataValue);
|
||||
function Dump: string;
|
||||
procedure Clear;
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
|
||||
property Values[const Address: TResolvedAddress]: TDataValue read GetValues write SetValues; default;
|
||||
property Parent: IExecutionScope read GetParent;
|
||||
end;
|
||||
|
||||
IScopeDescriptor = interface
|
||||
{$region 'private'}
|
||||
function GetParent: IScopeDescriptor;
|
||||
function GetSlotCount: Integer;
|
||||
function GetSymbols: TDictionary<string, Integer>;
|
||||
{$endregion}
|
||||
function CreateScope(const AParent: IExecutionScope): IExecutionScope;
|
||||
function Define(const Name: string): Integer;
|
||||
function FindSymbol(const Name: string; out Depth, Index: Integer): Boolean;
|
||||
property Parent: IScopeDescriptor read GetParent;
|
||||
property SlotCount: Integer read GetSlotCount;
|
||||
property Symbols: TDictionary<string, Integer> read GetSymbols;
|
||||
end;
|
||||
|
||||
IAstVisitor = interface
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
|
||||
@@ -26,6 +26,7 @@ implementation
|
||||
uses
|
||||
System.Rtti,
|
||||
System.TypInfo,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.RTL.Core;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
+95
-14
@@ -9,6 +9,58 @@ uses
|
||||
Myc.Data.Value,
|
||||
Myc.Ast.Nodes;
|
||||
|
||||
type
|
||||
IExecutionScope = interface;
|
||||
IScopeDescriptor = interface;
|
||||
|
||||
IExecutionScope = interface
|
||||
{$region 'private'}
|
||||
function GetParent: IExecutionScope;
|
||||
function GetValues(const Address: TResolvedAddress): TDataValue;
|
||||
procedure SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
||||
{$endregion}
|
||||
|
||||
procedure Define(const Name: string; const Value: TDataValue);
|
||||
function Dump: string;
|
||||
procedure Clear;
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
|
||||
function CreateDescriptor: IScopeDescriptor;
|
||||
|
||||
property Values[const Address: TResolvedAddress]: TDataValue read GetValues write SetValues; default;
|
||||
property Parent: IExecutionScope read GetParent;
|
||||
end;
|
||||
|
||||
// Describes the layout of a scope: variable names and their slot indices.
|
||||
// This is generated by the binder and used to create TExecutionScope instances at runtime.
|
||||
IScopeDescriptor = interface
|
||||
{$region 'private'}
|
||||
function GetParent: IScopeDescriptor;
|
||||
function GetSlotCount: Integer;
|
||||
function GetSymbols: TDictionary<string, Integer>;
|
||||
{$endregion}
|
||||
function CreateScope(const AParent: IExecutionScope): IExecutionScope;
|
||||
function Define(const Name: string): Integer;
|
||||
function FindSymbol(const Name: string): TResolvedAddress;
|
||||
property Parent: IScopeDescriptor read GetParent;
|
||||
property SlotCount: Integer read GetSlotCount;
|
||||
property Symbols: TDictionary<string, Integer> read GetSymbols;
|
||||
end;
|
||||
|
||||
TScope = record
|
||||
class function CreateScope(
|
||||
const Parent: IExecutionScope;
|
||||
const Descriptor: IScopeDescriptor;
|
||||
const CapturedUpvalues: TArray<IValueCell>
|
||||
): IExecutionScope; static;
|
||||
class function CreateDescriptor(const Parent: IScopeDescriptor): IScopeDescriptor; static;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Generics.Defaults;
|
||||
|
||||
type
|
||||
TExecutionScope = class(TInterfacedObject, IExecutionScope)
|
||||
type
|
||||
@@ -54,14 +106,13 @@ type
|
||||
function Dump: string;
|
||||
procedure Define(const Name: string; const Value: TDataValue);
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
function CreateDescriptor: IScopeDescriptor;
|
||||
property Names: TDictionary<string, Integer> read FNames;
|
||||
property NameStrings: TList<string> read FNameStrings;
|
||||
property NameToIndex: TDictionary<Integer, Integer> read GetNameToIndex;
|
||||
property Parent: IExecutionScope read FParent;
|
||||
end;
|
||||
|
||||
// Describes the layout of a scope: variable names and their slot indices.
|
||||
// This is generated by the binder and used to create TExecutionScope instances at runtime.
|
||||
TScopeDescriptor = class(TInterfacedObject, IScopeDescriptor)
|
||||
private
|
||||
FParent: IScopeDescriptor;
|
||||
@@ -72,18 +123,14 @@ type
|
||||
public
|
||||
constructor Create(const AParent: IScopeDescriptor);
|
||||
destructor Destroy; override;
|
||||
class function CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor; static;
|
||||
function Define(const Name: string): Integer;
|
||||
function FindSymbol(const Name: string; out Depth, Index: Integer): Boolean;
|
||||
function FindSymbol(const Name: string): TResolvedAddress;
|
||||
function CreateScope(const Parent: IExecutionScope): IExecutionScope;
|
||||
procedure PopulateFromScope(Scope: TExecutionScope);
|
||||
property Symbols: TDictionary<string, Integer> read FSymbols;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Generics.Defaults;
|
||||
|
||||
{ TValueCell }
|
||||
|
||||
constructor TExecutionScope.TValueCell.Create(const AValue: TDataValue);
|
||||
@@ -185,6 +232,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExecutionScope.CreateDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
Result := TScopeDescriptor.CreateDescriptor(Self);
|
||||
end;
|
||||
|
||||
procedure TExecutionScope.Define(const Name: string; const Value: TDataValue);
|
||||
var
|
||||
id: Integer;
|
||||
@@ -373,6 +425,18 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
class function TScopeDescriptor.CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor;
|
||||
begin
|
||||
if Scope is TExecutionScope then
|
||||
begin
|
||||
var res := TScopeDescriptor.Create(CreateDescriptor(Scope.Parent));
|
||||
res.PopulateFromScope(Scope as TExecutionScope);
|
||||
Result := res;
|
||||
end
|
||||
else
|
||||
Result := TScopeDescriptor.Create(nil);
|
||||
end;
|
||||
|
||||
function TScopeDescriptor.CreateScope(const Parent: IExecutionScope): IExecutionScope;
|
||||
begin
|
||||
// Creates a runtime scope instance based on this descriptor's layout.
|
||||
@@ -385,20 +449,23 @@ begin
|
||||
FSymbols.Add(Name, Result);
|
||||
end;
|
||||
|
||||
function TScopeDescriptor.FindSymbol(const Name: string; out Depth, Index: Integer): Boolean;
|
||||
function TScopeDescriptor.FindSymbol(const Name: string): TResolvedAddress;
|
||||
var
|
||||
currentDescriptor: TScopeDescriptor;
|
||||
begin
|
||||
Depth := 0;
|
||||
Result.Kind := akUnresolved;
|
||||
Result.ScopeDepth := 0;
|
||||
currentDescriptor := Self;
|
||||
while currentDescriptor <> nil do
|
||||
begin
|
||||
if currentDescriptor.FSymbols.TryGetValue(Name, Index) then
|
||||
exit(True);
|
||||
inc(Depth);
|
||||
if currentDescriptor.FSymbols.TryGetValue(Name, Result.SlotIndex) then
|
||||
begin
|
||||
Result.Kind := akLocalOrParent;
|
||||
exit;
|
||||
end;
|
||||
inc(Result.ScopeDepth);
|
||||
currentDescriptor := currentDescriptor.FParent as TScopeDescriptor;
|
||||
end;
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TScopeDescriptor.GetParent: IScopeDescriptor;
|
||||
@@ -428,4 +495,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TScope.CreateDescriptor(const Parent: IScopeDescriptor): IScopeDescriptor;
|
||||
begin
|
||||
Result := TScopeDescriptor.Create(Parent);
|
||||
end;
|
||||
|
||||
class function TScope.CreateScope(
|
||||
const Parent: IExecutionScope;
|
||||
const Descriptor: IScopeDescriptor;
|
||||
const CapturedUpvalues: TArray<IValueCell>
|
||||
): IExecutionScope;
|
||||
begin
|
||||
Result := TExecutionScope.Create(Parent, Descriptor, CapturedUpvalues);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
+20
-20
@@ -12,7 +12,7 @@ uses
|
||||
type
|
||||
// A fully abstract base class for any visitor of the AST.
|
||||
TAstVisitor = class abstract(TInterfacedObject, IAstVisitor)
|
||||
public
|
||||
protected
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; virtual; abstract;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual; abstract;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; virtual; abstract;
|
||||
@@ -45,6 +45,25 @@ type
|
||||
FDone: Boolean;
|
||||
|
||||
protected
|
||||
// Final Visit methods - these should not be overridden. They call the virtual Transform methods.
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override; final;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override; final;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override; final;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override; final;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override; final;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; final;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; final;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; final;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; final;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; final;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; final;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; final;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; final;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; final;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; final;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; final;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override; final;
|
||||
|
||||
// Dispatch methods for each node type. Derived classes override these to change the transformation.
|
||||
function TransformConstant(const Node: IConstantNode): IConstantNode; virtual;
|
||||
function TransformIdentifier(const Node: IIdentifierNode): IIdentifierNode; virtual;
|
||||
@@ -73,25 +92,6 @@ type
|
||||
public
|
||||
// This is the main entry point for the transformer, returning a transformed node.
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
|
||||
// Final Visit methods - these should not be overridden. They call the virtual Transform methods.
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override; final;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override; final;
|
||||
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override; final;
|
||||
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override; final;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override; final;
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; final;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; final;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; final;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; final;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; final;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; final;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override; final;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; final;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; final;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; final;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; final;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override; final;
|
||||
end;
|
||||
|
||||
// TAstTraverser simply inherits the identity-transform (cloning) behavior from TAstTransformer.
|
||||
|
||||
+4
-1
@@ -171,6 +171,7 @@ type
|
||||
constructor Create(const AExpressions: array of IAstNode);
|
||||
destructor Destroy; override;
|
||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||
property Expressions: TList<IAstNode> read FExpressions;
|
||||
end;
|
||||
|
||||
TVariableDeclarationNode = class(TAstNode, IVariableDeclarationNode)
|
||||
@@ -182,6 +183,8 @@ type
|
||||
public
|
||||
constructor Create(const AIdentifier: IIdentifierNode; AInitializer: IAstNode);
|
||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||
property Identifier: IIdentifierNode read FIdentifier;
|
||||
property Initializer: IAstNode read FInitializer;
|
||||
end;
|
||||
|
||||
TAssignmentNode = class(TAstNode, IAssignmentNode)
|
||||
@@ -731,7 +734,7 @@ class function TAst.CreateScope(Parent: IExecutionScope; const Descriptor: IScop
|
||||
var
|
||||
proc: TRegisterLibraryProc;
|
||||
begin
|
||||
Result := TExecutionScope.Create(Parent, Descriptor, nil);
|
||||
Result := TScope.CreateScope(Parent, Descriptor, nil);
|
||||
|
||||
if Parent = nil then
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user