Anonymous recursions

This commit is contained in:
Michael Schimmel
2025-09-19 23:53:48 +02:00
parent 28558614f0
commit e03155179a
7 changed files with 126 additions and 49 deletions
+4 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+45
View File
@@ -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.