Browse Source

* Extension registry

Michael Van Canneyt 4 months ago
parent
commit
03bcc90936
1 changed files with 219 additions and 0 deletions
  1. 219 0
      packages/wasi/src/wasienv.pas

+ 219 - 0
packages/wasi/src/wasienv.pas

@@ -272,11 +272,39 @@ type
   Public
     Constructor Create(aEnv : TPas2JSWASIEnvironment); virtual;
     Destructor Destroy; override;
+    class procedure register;
+    class function RegisterName : string; virtual;
     Procedure FillImportObject(aObject : TJSObject); virtual; abstract;
     Function ImportName : String; virtual; abstract;
     Property Env : TPas2JSWASIEnvironment Read FEnv;
     Property InstanceExports : TWASIExports Read FInstanceExports Write SetInstanceExports;
   end;
+  TImportExtensionArray = Array of TImportExtension;
+
+  TImportExtensionClass = class of TImportExtension;
+  TImportExtensionClassArray = Array of TImportExtensionClass;
+
+  { TImportExtensionRegistry }
+
+  TImportExtensionRegistry = class(TObject)
+  Private
+    class var _Instance : TImportExtensionRegistry;
+  Private
+    FExtensions : TImportExtensionClassArray;
+    FExtensionCount : Integer;
+    procedure Grow;
+  Public
+    class constructor init;
+    class destructor done;
+    constructor create; virtual;
+    destructor destroy; override;
+    function Find(const aExtension: String): TImportExtensionClass;
+    function IndexOf(const aExtension: String): Integer;
+    Function GetExtensions : TImportExtensionClassArray;
+    Procedure RegisterExtension(aExtension : TImportExtensionClass);
+    Procedure UnRegisterExtension(aExtension : TImportExtensionClass);
+    class property instance : TImportExtensionRegistry Read _Instance;
+  end;
 
   TRunWebassemblyProc = reference to Procedure(aExports : TWASIExports);
   TWebAssemblyStartDescriptor = record
@@ -310,6 +338,7 @@ type
 
   TConsoleReadEvent = Procedure(Sender : TObject; Var AInput : String) of object;
   TConsoleWriteEvent = Procedure (Sender : TObject; aOutput : string) of object;
+  TCreateExtensionEvent = procedure (sender : TObject; aExtension : TImportExtension) of object;
 
   { TWASIHost }
 
@@ -317,10 +346,14 @@ type
   Private
     FAfterInstantation: TNotifyEvent;
     FAfterStart: TAfterStartEvent;
+    FAutoCreateExtensions: Boolean;
     FBeforeInstantation: TNotifyEvent;
     FBeforeStart: TBeforeStartEvent;
     FEnv: TPas2JSWASIEnvironment;
+    FExcludeExtensions: TStrings;
     FExported: TWASIExports;
+    FOnAllExtensionsCreated: TNotifyEvent;
+    FOnExtensionCreated: TCreateExtensionEvent;
     FOnInstantiateFail: TFailEvent;
     FOnLoadFail: TFailEvent;
     FPreparedStartDescriptor: TWebAssemblyStartDescriptor;
@@ -331,15 +364,23 @@ type
     FReadLineCount : Integer;
     FRunEntryFunction: String;
     FTableDescriptor : TJSWebAssemblyTableDescriptor;
+    FExtensions : TImportExtensionArray;
     function GetEnv: TPas2JSWASIEnvironment;
     function GetIsLibrary: Boolean;
     function GetIsProgram: Boolean;
     function GetStartDescriptorReady: Boolean;
     function GetUseSharedMemory: Boolean;
+    procedure SetExcludeExtensions(AValue: TStrings);
     procedure SetPredefinedConsoleInput(AValue: TStrings);
     procedure SetUseSharedMemory(AValue: Boolean);
   protected
     class function NeedSharedMemory : Boolean; virtual;
+    // Delete all created extensions
+    procedure DeleteExtensions;
+    // Create registered extensions
+    procedure DoCreateStandardExtensions; virtual;
+    // Create a standard extension, call OnExtensionCreated callback
+    function CreateStandardExtension(aClass: TImportExtensionClass): TImportExtension;
     // Called after instantiation was OK.
     Procedure DoAfterInstantiate; virtual;
     // Called before instantiation starts.
@@ -366,6 +407,12 @@ type
   public
     Constructor Create(aOwner : TComponent); override;
     Destructor Destroy; override;
+    // Create all registered extensions. Called automatically when the environment is created and AutoCreateExtensions is true.
+    procedure CreateStandardExtensions;
+    // Find an extension by registered or class name.
+    Function FindExtension(const aExtension : string) : TImportExtension;
+    // Get an extension by registered or class name. Raises exception if it does not exist or has wrong class
+    Generic Function GetExtension<T : TImportExtension>(const aExtension : string) : T;
     // Will call OnConsoleWrite or write to console
     procedure WriteOutput(const aOutput: String); virtual;
     // Prepare start descriptor
@@ -416,6 +463,15 @@ type
     Property AfterInstantation : TNotifyEvent Read FAfterInstantation Write FAfterInstantation;
     // Executed before instantiation
     Property BeforeInstantation : TNotifyEvent Read FBeforeInstantation Write FBeforeInstantation;
+    // Create all registered extensions
+    property AutoCreateExtensions : Boolean Read FAutoCreateExtensions Write FAutoCreateExtensions;
+    // Extensions not to create
+    // Create all registered extensions
+    property ExcludeExtensions : TStrings Read FExcludeExtensions Write SetExcludeExtensions;
+    // Called for each auto-created extension
+    Property OnExtensionCreated : TCreateExtensionEvent Read FOnExtensionCreated Write FOnExtensionCreated;
+    // Called for each auto-created extension
+    Property OnAllExtensionsCreated : TNotifyEvent Read FOnAllExtensionsCreated Write FOnAllExtensionsCreated;
   end;
   TWASIHostClass = class of TWASIHost;
 
@@ -462,6 +518,12 @@ begin
     Result:=False;
 end;
 
+procedure TWASIHost.SetExcludeExtensions(AValue: TStrings);
+begin
+  if FExcludeExtensions=AValue then Exit;
+  FExcludeExtensions.Assign(AValue);
+end;
+
 function TWASIHost.GetStartDescriptorReady: Boolean;
 begin
   With FPreparedStartDescriptor do
@@ -481,6 +543,8 @@ begin
     FEnv.OnStdErrorWrite:=@DoStdWrite;
     FEnv.OnStdOutputWrite:=@DoStdWrite;
     Fenv.OnGetConsoleInputString:=@DoStdRead;
+    if AutoCreateExtensions then
+      CreateStandardExtensions;
     end;
   Result:=FEnv;
 end;
@@ -668,15 +732,85 @@ begin
   FTableDescriptor.maximum:=0;
   FTableDescriptor.element:='anyfunc';
   FPredefinedConsoleInput:=TStringList.Create;
+  FExcludeExtensions:=TStringList.Create;
 end;
 
 destructor TWASIHost.Destroy;
 begin
+  FreeAndNil(FExcludeExtensions);
   FreeAndNil(FPredefinedConsoleInput);
   FreeAndNil(FEnv);
   inherited Destroy;
 end;
 
+function TWASIHost.CreateStandardExtension(aClass : TImportExtensionClass) : TImportExtension;
+
+begin
+  Result:=aClass.Create;
+  if Assigned(FOnExtensionCreated) then
+    FOnExtensionCreated(Self,Result);
+end;
+
+procedure TWASIHost.DeleteExtensions;
+var
+  I : Integer;
+begin
+  For I:=0 to Length(FExtensions)-1 do
+    FreeAndNil(FExtensions[i]);
+  SetLength(FExtensions,0);
+end;
+
+procedure TWASIHost.DoCreateStandardExtensions;
+var
+  lCount : Integer;
+  lClass : TImportExtensionClass;
+  lClasses : TImportExtensionClassArray;
+begin
+  DeleteExtensions;
+  lClasses:=TImportExtensionRegistry.Instance.GetExtensions;
+  SetLength(FExtensions,Length(lClasses));
+  lCount:=0;
+  for lClass in lClasses do
+    if (FExcludeExtensions.IndexOf(lClass.RegisterName)=-1) and
+       (FExcludeExtensions.IndexOf(lClass.ClassName)=-1) then
+      begin
+      FExtensions[lCount]:=CreateStandardExtension(lClass);
+      inc(lCount);
+      end;
+end;
+
+procedure TWASIHost.CreateStandardExtensions;
+begin
+  DoCreateStandardExtensions;
+  if Assigned(FOnAllExtensionsCreated) then
+    FOnAllExtensionsCreated(Self);
+end;
+
+function TWASIHost.FindExtension(const aExtension: string): TImportExtension;
+var
+  I : Integer;
+begin
+  I:=Length(FExtensions)-1;
+  While (I>=0) and not (SameText(aExtension,FExtensions[i].ClassName) or SameText(aExtension,FExtensions[i].RegisterName)) do
+    Dec(I);
+  if I<0 then
+    Result:=Nil
+  else
+    Result:=FExtensions[i];
+end;
+
+generic function TWASIHost.GetExtension<T>(const aExtension: string): T;
+var
+  Ext : TImportExtension;
+begin
+  Ext:=FindExtension(aExtension);
+  if Not Assigned(Ext) then
+    Raise EWasiError.CreateFmt('No extension "%s" found',[aExtension]);
+  if not (Ext is T) then
+    Raise EWasiError.CreateFmt('Class of extension "%s" (%s) is not a %',[aExtension,Ext.ClassName,T.ClassName]);
+  Result:=T(Ext);
+end;
+
 procedure TWASIHost.WriteOutput(const aOutput: String);
 begin
   if assigned(FOnConsoleWrite) then
@@ -831,6 +965,91 @@ begin
   inherited Destroy;
 end;
 
+class procedure TImportExtension.register;
+begin
+  TImportExtensionRegistry.Instance.RegisterExtension(Self);
+end;
+
+class function TImportExtension.RegisterName: string;
+begin
+  Result:=ClassName;
+end;
+
+{ TImportExtensionRegistry }
+
+procedure TImportExtensionRegistry.Grow;
+begin
+  SetLength(FExtensions,Length(FExtensions)+1);
+end;
+
+class constructor TImportExtensionRegistry.init;
+begin
+  Writeln('TImportExtensionRegistry.Instance init');
+  _instance:=TImportExtensionRegistry.Create;
+end;
+
+class destructor TImportExtensionRegistry.done;
+begin
+  Writeln('TImportExtensionRegistry.Instance done');
+//  FreeAndNil(_instance);
+end;
+
+constructor TImportExtensionRegistry.create;
+begin
+  FExtensionCount:=0;
+  Grow;
+end;
+
+destructor TImportExtensionRegistry.destroy;
+begin
+  inherited destroy;
+end;
+
+function TImportExtensionRegistry.IndexOf(const aExtension : String) : Integer;
+begin
+  Result:=FExtensionCount-1;
+  While (Result>=0) and not SameText(FExtensions[Result].RegisterName,aExtension) do
+    Dec(Result);
+end;
+
+function TImportExtensionRegistry.GetExtensions: TImportExtensionClassArray;
+begin
+  Result:=Copy(FExtensions,0,FExtensionCount);
+end;
+
+function TImportExtensionRegistry.Find(const aExtension: String): TImportExtensionClass;
+
+var
+  Idx: Integer;
+
+begin
+  Result:=Nil;
+  Idx:=IndexOf(aExtension);
+  if (Idx<>-1) then
+    Result:=FExtensions[Idx];
+end;
+
+procedure TImportExtensionRegistry.RegisterExtension(aExtension: TImportExtensionClass);
+var
+  Idx : Integer;
+begin
+  Idx:=IndexOf(aExtension.RegisterName);
+  if Idx<>-1 then
+    FExtensions[Idx]:=aExtension
+  else
+    begin
+    if FExtensionCount=Length(FExtensions) then
+      grow;
+    FExtensions[FExtensionCount]:=aExtension;
+    Inc(FExtensionCount);
+    end;
+end;
+
+procedure TImportExtensionRegistry.UnRegisterExtension(aExtension: TImportExtensionClass);
+begin
+
+end;
+
 procedure TPas2JSWASIEnvironment.AddImports(aObject: TJSObject);
 
 Var