Anonymous recursions
This commit is contained in:
@@ -3,6 +3,7 @@ unit Myc.Ast.RTL.Core;
|
||||
interface
|
||||
|
||||
uses
|
||||
Myc.Utils,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast.RTL;
|
||||
@@ -122,7 +123,6 @@ end;
|
||||
class function TRtlFunctions.Memoize(const Args: TArray<TDataValue>): TDataValue;
|
||||
var
|
||||
funcToMemoize: TDataValue.TFunc;
|
||||
cache: TDictionary<Int64, TDataValue>;
|
||||
memoizedFunc: TDataValue.TFunc;
|
||||
begin
|
||||
if Length(Args) <> 1 then
|
||||
@@ -130,8 +130,8 @@ begin
|
||||
if Args[0].Kind <> vkMethod then
|
||||
raise EArgumentException.Create('The argument to Memoize must be a function.');
|
||||
|
||||
var cCache: TManaged<TDictionary<Int64, TDataValue>> := TDictionary<Int64, TDataValue>.Create;
|
||||
funcToMemoize := Args[0].AsMethod();
|
||||
cache := TDictionary<Int64, TDataValue>.Create;
|
||||
|
||||
memoizedFunc :=
|
||||
function(const AArgs: TArray<TDataValue>): TDataValue
|
||||
@@ -151,6 +151,8 @@ begin
|
||||
else
|
||||
key := argScalar.Value.AsInt64;
|
||||
|
||||
var cache: TDictionary<Int64, TDataValue> := cCache;
|
||||
|
||||
if cache.TryGetValue(key, Result) then
|
||||
exit;
|
||||
|
||||
|
||||
+30
-30
@@ -54,34 +54,10 @@ type
|
||||
const AArgs: TArray<TDataValue>;
|
||||
out AArg: TScalar
|
||||
): Boolean; static; inline;
|
||||
class function CreateScalarWrapper(AFuncName: string; AFuncPtr: Pointer): TDataValue.TFunc; static;
|
||||
public
|
||||
class procedure RegisterAll(const AScope: IExecutionScope); static;
|
||||
end;
|
||||
|
||||
// This is the "Wrapper Generator" for the (TScalar):TScalar signature.
|
||||
// It creates a high-performance anonymous method that uses a direct function pointer.
|
||||
class function TRtlRegistry.CreateScalarWrapper(AFuncName: string; AFuncPtr: Pointer): TDataValue.TFunc;
|
||||
var
|
||||
// Statically typed pointer to the native function.
|
||||
nativeFunc: TNativeScalarFunc;
|
||||
begin
|
||||
nativeFunc := AFuncPtr;
|
||||
|
||||
// This is the generated wrapper that will be registered with the interpreter.
|
||||
Result :=
|
||||
function(const Args: TArray<TDataValue>): TDataValue
|
||||
var
|
||||
argScalar: TScalar;
|
||||
begin
|
||||
// 1. Optimized argument validation and unpacking.
|
||||
GetSingleNumericArg(AFuncName, Args, argScalar);
|
||||
|
||||
// 2. Direct, statically typed call via pointer.
|
||||
Result := TDataValue(nativeFunc(argScalar));
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TRtlRegistry }
|
||||
|
||||
class function TRtlRegistry.GetSingleNumericArg(const AName: string; const AArgs: TArray<TDataValue>; out AArg: TScalar): Boolean;
|
||||
@@ -123,6 +99,9 @@ begin
|
||||
if not (attribute is TRtlFunctionAttribute) then
|
||||
continue;
|
||||
|
||||
if method.MethodKind <> mkClassFunction then
|
||||
continue;
|
||||
|
||||
rtlAttribute := attribute as TRtlFunctionAttribute;
|
||||
wrapper := nil;
|
||||
|
||||
@@ -134,7 +113,21 @@ begin
|
||||
if param.ParamType.Handle = TypeInfo(TScalar) then
|
||||
begin
|
||||
// Signature matches: class function(Arg: TScalar): TScalar;
|
||||
wrapper := CreateScalarWrapper(rtlAttribute.Name, method.CodeAddress);
|
||||
// Build a factory that captures the method's name and CodeAddress.
|
||||
var wrapperFactory :=
|
||||
function(AName: string; CodeAddress: Pointer): TDataValue.TFunc
|
||||
begin
|
||||
Result :=
|
||||
function(const Args: TArray<TDataValue>): TDataValue
|
||||
var
|
||||
argScalar: TScalar;
|
||||
begin
|
||||
GetSingleNumericArg(AName, Args, argScalar);
|
||||
Result := TDataValue(TNativeScalarFunc(CodeAddress)(argScalar));
|
||||
end;
|
||||
end;
|
||||
|
||||
wrapper := wrapperFactory(rtlAttribute.Name, method.CodeAddress);
|
||||
end;
|
||||
end
|
||||
else if (Length(method.GetParameters) = 1) and (method.ReturnType.Handle = TypeInfo(TDataValue)) then
|
||||
@@ -143,12 +136,19 @@ begin
|
||||
if (pfConst in param.Flags) and (param.ParamType.Handle = TypeInfo(TArray<TDataValue>)) then
|
||||
begin
|
||||
// Signature matches: class function(const Args: TArray<TDataValue>): TDataValue;
|
||||
// For these, we can just cast the pointer directly. No wrapper needed.
|
||||
wrapper :=
|
||||
function(const Args: TArray<TDataValue>): TDataValue
|
||||
// Build a factory that captures the method's CodeAddress.
|
||||
var wrapperFactory :=
|
||||
function(CodeAddress: Pointer): TDataValue.TFunc
|
||||
begin
|
||||
Result := TNativeDataValueFunc1(method.CodeAddress)(Args);
|
||||
Result :=
|
||||
function(const Args: TArray<TDataValue>): TDataValue
|
||||
begin
|
||||
Result := TNativeDataValueFunc1(CodeAddress)(Args);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Create the wrapper
|
||||
wrapper := wrapperFactory(method.CodeAddress);
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -158,7 +158,7 @@ begin
|
||||
break; // Found our attribute, proceed to next method
|
||||
end
|
||||
else
|
||||
raise ENotImplemented.Create('Native method wrapper not implemented');
|
||||
raise ENotImplemented.CreateFmt('Native method wrapper for %s() not implemented', [method.Name]);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ type
|
||||
class function LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode): ILambdaExpressionNode; static;
|
||||
class function FunctionCall(const ACallee: IAstNode; const AArguments: TArray<IAstNode>): IFunctionCallNode; static;
|
||||
class function Block(const AExpressions: array of IAstNode): IBlockExpressionNode; static;
|
||||
class function VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IAstNode): IVariableDeclarationNode; static;
|
||||
class function VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IAstNode = nil): IVariableDeclarationNode; static;
|
||||
class function Assign(const AIdentifier: IIdentifierNode; const AValue: IAstNode): IAssignmentNode; static;
|
||||
class function AssignResult(const AValue: IAstNode): IAssignmentNode; static; deprecated;
|
||||
class function Indexer(const ABase: IAstNode; const AIndex: IAstNode): IIndexerNode; static;
|
||||
@@ -780,7 +780,7 @@ begin
|
||||
Result := TUnaryExpressionNode.Create(AOperator, ARight);
|
||||
end;
|
||||
|
||||
class function TAst.VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IAstNode): IVariableDeclarationNode;
|
||||
class function TAst.VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IAstNode = nil): IVariableDeclarationNode;
|
||||
begin
|
||||
Result := TVariableDeclarationNode.Create(AIdentifier, AInitializer);
|
||||
end;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
unit Myc.Utils;
|
||||
|
||||
interface
|
||||
|
||||
type
|
||||
TManaged<T: class> = record
|
||||
private
|
||||
type
|
||||
TObj = class(TInterfacedObject)
|
||||
FValue: T;
|
||||
constructor Create(AValue: T);
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
var
|
||||
FIntf: IInterface;
|
||||
public
|
||||
class operator Implicit(A: T): TManaged<T>; overload;
|
||||
class operator Implicit(const Upvalue: TManaged<T>): T; overload;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
constructor TManaged<T>.TObj.Create(AValue: T);
|
||||
begin
|
||||
inherited Create;
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
destructor TManaged<T>.TObj.Destroy;
|
||||
begin
|
||||
FValue.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
class operator TManaged<T>.Implicit(A: T): TManaged<T>;
|
||||
begin
|
||||
Result.FIntf := TObj.Create(A);
|
||||
end;
|
||||
|
||||
class operator TManaged<T>.Implicit(const Upvalue: TManaged<T>): T;
|
||||
begin
|
||||
Result := (Upvalue.FIntf as TObj).FValue;
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user