xtool/contrib/mORMot/SyNode/SyNodePluginIntf.pas

203 lines
5.4 KiB
ObjectPascal

unit SyNodePluginIntf;
interface
{$I Synopse.inc} // define HASINLINE CPU32 CPU64 OWNNORMTOUPPER
{$I SyNode.inc} //define WITHASSERT
uses
SynCommons,
SpiderMonkey;
type
{$ifdef USERECORDWITHMETHODS}TSMPluginRec = record
{$else}TSMPluginRec = object{$endif}
cx: PJSContext;
Exp: PJSRootedObject;
Req: PJSRootedObject;
Module: PJSRootedObject;
filename: PWideChar;
dirname: PWideChar;
constructor Create(aCx: PJSContext; aExports_: PJSRootedObject; aRequire: PJSRootedObject; aModule: PJSRootedObject; _filename: PWideChar; _dirname: PWideChar);
function require(aFileName: string): PJSObject;
end;
TCustomSMPlugin = class
protected
fCx: PJSContext;
procedure UnInit; virtual;
procedure Init(const rec: TSMPluginRec); virtual;
public
constructor Create(aCx: PJSContext; aExports_: PJSRootedObject; aRequire: PJSRootedObject; aModule: PJSRootedObject; _filename: PWideChar; _dirname: PWideChar);
destructor Destroy; override;
end;
TThreadRec = record
threadID: TThreadID;
plugin: TCustomSMPlugin;
end;
TCustomSMPluginType = class of TCustomSMPlugin;
type
TNsmFunction = function(cx: PJSContext; argc: uintN; vals: PjsvalVector; thisObj, calleeObj: PJSObject): jsval; cdecl;
const
ptVoid = 0;
ptInt = 1;
ptStr = 2;
ptObj = 3;
ptBuffer = 100;
ptAny = 500;
type
PNSMCallInfo = ^TNSMCallInfo;
TNSMCallInfo = record
func: TNsmFunction;
argc: Integer;
argt: PInt64Array;
end;
TNSMCallInfoArray = array of TNSMCallInfo;
/// Helper to call a native function depending on JS function arguments.
// As a side effect will verify JS function arguments types. Can be used e.g. as:
// ! const
// ! overload1Args: array [0..0] of uintN = ( ptInt );
// ! overload2Args: array [0..1] of uintN = ( ptInt, SyNodePluginIntf.ptStr );
// ! overloads: array [0..1] of TNSMCallInfo = (
// ! (func: @SLReadLn_impl; argc: Length(overload1Args); argt: @overload1Args),
// ! (func: @SLReadLn_impl; argc: Length(overload2Args); argt: @overload2Args));
// ! begin
// ! Result := nsmCallFunc(cx, argc, vp, @overloads, Length(overloads));
// ! end;
function nsmCallFunc(cx: PJSContext; argc: uintN; var vp: JSArgRec; const overloads: TNSMCallInfoArray; overloadsCount: Integer = 1; isConstructor: Boolean = false): Boolean; cdecl;
const
StaticROAttrs = JSPROP_ENUMERATE or JSPROP_READONLY or JSPROP_PERMANENT;
implementation
uses
SysUtils;
function isParamCorrect(paramType: uintN; val: jsval): Boolean;
begin
case paramType of
ptVoid: result := val.isVoid;
ptInt: result := val.isInteger;
ptStr: result := val.isString;
ptObj: result := val.isObject;
ptBuffer: result := val.isObject and (val.asObject.IsArrayBufferObject or val.asObject.IsArrayBufferViewObject);
ptAny: result := True;
else result := false;
end;
end;
function nsmCallFunc(cx: PJSContext; argc: uintN; var vp: JSArgRec; const overloads: TNSMCallInfoArray; overloadsCount: Integer = 1; isConstructor: Boolean = false): Boolean; cdecl;
var
thisObj, calleeObj: PJSObject;
vals: PjsvalVector;
i,j: Integer;
overloadCase: PNSMCallInfo;
IsCalled, IsCorrect: Boolean;
begin
Result := False;
try
if isConstructor xor vp.IsConstructing then
raise ESMException.Create('JS_IS_CONSTRUCTING');
thisObj := vp.thisObject[cx];
calleeObj := vp.calleObject;
vals := vp.argv;
IsCalled := false;
for i := 0 to overloadsCount - 1 do begin
overloadCase := @overloads[i];
if (overloadCase <> nil) then begin
if argc = overloadCase.argc then begin
IsCorrect := true;
for j := 0 to overloadCase.argc - 1 do begin
IsCorrect := isParamCorrect(overloadCase.argt[j], vals[j]);
if not IsCorrect then Break;
end;
if IsCorrect then begin
vp.rval := overloadCase.func(cx, argc, vals, thisObj, calleeObj);
IsCalled := True;
Break;
end;
end;
end;
end;
if not IsCalled then
raise ESMException.CreateUTF8('There is no overloaded function "%" with such a list of arguments', [calleeObj.GetFunctionId().ToSynUnicode(cx)]);
Result := True;
except
on E: Exception do
begin
JSError(cx, E);
end;
end;
end;
{ TCustomSMPlugin }
destructor TCustomSMPlugin.Destroy;
begin
fCx.BeginRequest;
try
UnInit;
finally
fCx.EndRequest;
end;
inherited;
end;
procedure TCustomSMPlugin.Init(const rec: TSMPluginRec);
begin
end;
procedure TCustomSMPlugin.UnInit;
begin
end;
constructor TCustomSMPlugin.Create(aCx: PJSContext; aExports_, aRequire,
aModule: PJSRootedObject; _filename, _dirname: PWideChar);
var
rec: TSMPluginRec;
begin
fCx := aCx;
rec.Create(aCx, aExports_, aRequire, aModule, _filename, _dirname);
fCx.BeginRequest;
try
Init(rec);
finally
fCx.EndRequest;
end;
end;
constructor TSMPluginRec.Create(aCx: PJSContext; aExports_: PJSRootedObject; aRequire: PJSRootedObject; aModule: PJSRootedObject; _filename: PWideChar; _dirname: PWideChar);
begin
cx := aCx;
Exp := aExports_;
Req := aRequire;
Module := aModule;
filename := _filename;
dirname := _dirname;
end;
function TSMPluginRec.require(aFileName: string): PJSObject;
var
arg, rval: jsval;
begin
arg := cx.NewJSString(aFileName).ToJSVal;
if not Module.ptr.CallFunction(cx, req.ptr, 1, @arg, rval) then
raise ESMException.Create('Error require '+aFileName);
Result := rval.asObject;
end;
end.