From 1da241c09cdd2e73286733fd00d39d8ba87cf9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Van=20Canneyt?= Date: Thu, 25 Apr 2024 11:26:24 +0200 Subject: [PATCH] * Add wasm-job for webassembly --- packages/fpmake_add.inc | 2 +- packages/fpmake_proc.inc | 8 + packages/wasm-job/fpmake.pp | 35 + packages/wasm-job/namespaced/Wasm.Job.Js.pas | 3 + .../wasm-job/namespaced/Wasm.Job.Shared.pas | 3 + packages/wasm-job/src/job.js.pas | 3324 +++++++++++++++++ packages/wasm-job/src/job.shared.pas | 120 + 7 files changed, 3494 insertions(+), 1 deletion(-) create mode 100644 packages/wasm-job/fpmake.pp create mode 100644 packages/wasm-job/namespaced/Wasm.Job.Js.pas create mode 100644 packages/wasm-job/namespaced/Wasm.Job.Shared.pas create mode 100644 packages/wasm-job/src/job.js.pas create mode 100644 packages/wasm-job/src/job.shared.pas diff --git a/packages/fpmake_add.inc b/packages/fpmake_add.inc index ace11cda80..7a3bca605e 100644 --- a/packages/fpmake_add.inc +++ b/packages/fpmake_add.inc @@ -156,4 +156,4 @@ add_fcl_css(ADirectory+IncludeTrailingPathDelimiter('fcl-css')); add_gstreamer(ADirectory+IncludeTrailingPathDelimiter('gstreamer')); add_testinsight(ADirectory+IncludeTrailingPathDelimiter('testinsight')); - + add_wasm_job(ADirectory+IncludeTrailingPathDelimiter('wasm-job')); diff --git a/packages/fpmake_proc.inc b/packages/fpmake_proc.inc index 81fcf0fa46..52c100956b 100644 --- a/packages/fpmake_proc.inc +++ b/packages/fpmake_proc.inc @@ -876,7 +876,15 @@ begin {$include gstreamer/fpmake.pp} end; +procedure add_wasm_job(const ADirectory: string); +begin + with Installer do +{$include wasm-job/fpmake.pp} +end; + {$include testinsight/fpmake.pp} {$include ide/fpmake.pp} {$include gitlab/fpmake.pp} + + diff --git a/packages/wasm-job/fpmake.pp b/packages/wasm-job/fpmake.pp new file mode 100644 index 0000000000..fd2170cb33 --- /dev/null +++ b/packages/wasm-job/fpmake.pp @@ -0,0 +1,35 @@ +{$ifndef ALLPACKAGES} +{$mode objfpc}{$H+} +program fpmake; + +uses {$ifdef unix}cthreads,{$endif} fpmkunit; + +Var + P : TPackage; + T : TTarget; +begin + With Installer do + begin +{$endif ALLPACKAGES} + + P:=AddPackage('wasm-job'); + P.Dependencies.Add('rtl-objpas'); + P.ShortName:='wasmjob'; + P.Description := 'Javascript Object Bindings units for webassembly.'; +{$ifdef ALLPACKAGES} + P.Directory:=ADirectory; +{$endif ALLPACKAGES} + P.Version:='3.3.1'; + P.SourcePath.Add('src'); + P.OSes := [wasi]; + P.CPUs:=[wasm32]; + T:=P.Targets.AddUnit('job.shared.pas'); + T:=P.Targets.AddUnit('job.js.pas'); + T.Dependencies.AddUnit('job.shared'); + P.NamespaceMap:='namespaces.lst'; + +{$ifndef ALLPACKAGES} + Run; + end; +end. +{$endif ALLPACKAGES} diff --git a/packages/wasm-job/namespaced/Wasm.Job.Js.pas b/packages/wasm-job/namespaced/Wasm.Job.Js.pas new file mode 100644 index 0000000000..0d16973fe3 --- /dev/null +++ b/packages/wasm-job/namespaced/Wasm.Job.Js.pas @@ -0,0 +1,3 @@ +{$DEFINE FPC_DOTTEDUNITS} +unit Wasm.Job.Js; +{$i job.js.pas} diff --git a/packages/wasm-job/namespaced/Wasm.Job.Shared.pas b/packages/wasm-job/namespaced/Wasm.Job.Shared.pas new file mode 100644 index 0000000000..6c3b115980 --- /dev/null +++ b/packages/wasm-job/namespaced/Wasm.Job.Shared.pas @@ -0,0 +1,3 @@ +{$DEFINE FPC_DOTTEDUNITS} +unit Wasm.Job.Shared; +{$i job.shared.pas} diff --git a/packages/wasm-job/src/job.js.pas b/packages/wasm-job/src/job.js.pas new file mode 100644 index 0000000000..1bb47ca20b --- /dev/null +++ b/packages/wasm-job/src/job.js.pas @@ -0,0 +1,3324 @@ +{ + JOB - JS Object Bridge for Webassembly + + Webassembly unit giving access to the browser DOM. + + see https://wiki.freepascal.org/WebAssembly/DOM +} +{$IFNDEF FPC_DOTTEDUNITS} +unit JOB.Js; +{$ENDIF} + +{$mode ObjFPC} +{$H+} +{$ModeSwitch advancedrecords} + +{$define VerboseJOB} + +interface + +uses + {$IFDEF FPC_DOTTEDUNITS} + System.SysUtils, System.Types, System.Math, System.Classes, System.Variants, Wasm.Job.Shared; + {$ELSE} + SysUtils, Types, Math, Classes, Variants, JOB.Shared; + {$ENDIF} + +const + MinSafeIntDouble = -$1fffffffffffff; // -9007199254740991 54 bits (52 plus signed bit plus implicit highest bit) + MaxSafeIntDouble = $1fffffffffffff; // 9007199254740991 + +Type +// TDOMHighResTimeStamp = Int64; + + PJOBObjectID = ^TJOBObjectID; + + EJSObject = class(Exception); + EJSInvoke = class(EJSObject) + public + ObjectID: TJOBObjectID; + FuncName: string; + end; + EJSArgParse = class(EJSObject); + + TJOB_JSValueKind = ( + jjvkUndefined, + jjvkBoolean, + jjvkDouble, + jjvkString, + jjvkObject, + jjvkMethod, + jjvkDictionary, + jjvkArrayOfJSValue, + jjvkArrayOfDouble + ); + TJOB_JSValueKinds = set of TJOB_JSValueKind; + +const + JOB_JSValueKindNames: array[TJOB_JSValueKind] of string = ( + 'Undefined', + 'Boolean', + 'Double', + 'String', + 'Object', + 'Method', + 'Dictionary', + 'ArrayOfJSValue', + 'ArrayOfDouble' + ); + + JOB_Undefined = Pointer(1); + +type + TUnicodeStringDynArray = array of UnicodeString; + + { TJOB_JSValue } + + TJOB_JSValue = class + public + Kind: TJOB_JSValueKind; + constructor Create(aKind: TJOB_JSValueKind); + function AsString: string; virtual; + end; + TJOB_JSValueClass = class of TJOB_JSValue; + TJOB_JSValueArray = array of TJOB_JSValue; + + { TJOB_Boolean } + + TJOB_Boolean = class(TJOB_JSValue) + public + Value: Boolean; + constructor Create(aValue: Boolean); + function AsString: string; override; + end; + + { TJOB_Double } + + TJOB_Double = class(TJOB_JSValue) + public + Value: Double; + constructor Create(const aValue: Double); + function AsString: string; override; + end; + + { TJOB_String } + + TJOB_String = class(TJOB_JSValue) + public + Value: UnicodeString; + constructor Create(const aValue: UnicodeString); + function AsString: string; override; + end; + + IJSObject = interface; + + { TJOB_Object } + + TJOB_Object = class(TJOB_JSValue) + public + Value: IJSObject; + constructor Create(aValue: IJSObject); + function AsString: string; override; + end; + + TJOBInvokeType = ( + jiCall, // call function + jiGet, // read property + jiGetTypeOf, // read property and do typeof + jiSet, // write property + jiNew // new operator + ); + TJOBInvokeTypes = set of TJOBInvokeType; + + TJSObject = class; + TJSArray = class; + TJSObjectClass = class of TJSObject; + + { TJOBCallbackHelper - parse callback arguments and create result } + + TJOBCallbackHelper = record + p: PByte; + Index: integer; + Count: integer; + procedure Init(Args: PByte); + function GetType: byte; // see JOBArg* constants, keeps p + procedure Skip; + function GetBoolean: boolean; + function GetDouble: double; + function GetString: UnicodeString; + function GetObject(aResultClass: TJSObjectClass): TJSObject; + function GetValue: TJOB_JSValue; + function GetVariant: Variant; + function GetLongInt: longint; + function GetMaxInt: int64; + function GetArray : TJSArray; + + function AllocUndefined: PByte; + function AllocBool(b: boolean): PByte; + function AllocLongint(i: longint): PByte; + function AllocDouble(const d: double): PByte; + function AllocString(const s: UnicodeString): PByte; + function AllocNil: PByte; + function AllocIntf(const Intf: IJSObject): PByte; + function AllocObject(Obj: TJSObject): PByte; + function AllocObjId(ObjId: TJOBObjectID): PByte; + function AllocJSValue(const Value: TJOB_JSValue): PByte; + function AllocVariant(const Value: Variant): PByte; + end; + + TJOBCallback = function(const aMethod: TMethod; var H: TJOBCallbackHelper): PByte; + + { TJOB_Method } + + TJOB_Method = class(TJOB_JSValue) + public + Value: TMethod; + Invoke: TJOBCallback; + constructor Create(const aMethod: TMethod; const AnInvoke: TJOBCallback); + function AsString: string; override; + end; + + TJOB_Pair = record + Name: UnicodeString; + Value: TJOB_JSValue; + end; + TJOB_PairArray = array of TJOB_Pair; + + { TJOB_Dictionary } + + TJOB_Dictionary = class(TJOB_JSValue) + public + Values: TJOB_PairArray; + procedure Add(const aName: UnicodeString; const aValue: TJOB_JSValue); + constructor Create(const Pairs: array of const); + destructor Destroy; override; + procedure Clear; + end; + + TJOB_ArrayBase = class(TJOB_JSValue) + end; + + { TJOB_ArrayOfJSValue } + + TJOB_ArrayOfJSValue = class(TJOB_ArrayBase) + public + Values: TJOB_JSValueArray; + procedure Add(const aValue: TJOB_JSValue); + constructor Create(const TheValues: array of const); + destructor Destroy; override; + procedure Clear; + end; + + { TJOB_ArrayOfDouble } + + TJOB_ArrayOfDouble = class(TJOB_ArrayBase) + public + Values: TDoubleDynArray; + constructor Create(const TheValues: TDoubleDynArray); + end; + + IJSArray = interface; + + { IJSObject } + + IJSObject = interface + ['{BE5CDE03-D471-4AB3-8F27-A5EA637416F7}'] + function GetJSObjectID: TJOBObjectID; + function GetJSObjectCastSrc: IJSObject; + function GetPascalClassName: string; + function GetProperties(const PropName: String): Variant; virtual; + procedure SetProperties(const PropName: String; const AValue: Variant); virtual; + // call a function + procedure InvokeJSNoResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall); virtual; + function InvokeJSBooleanResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Boolean; virtual; + function InvokeJSDoubleResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Double; virtual; + function InvokeJSUnicodeStringResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): UnicodeString; virtual; + function InvokeJSObjectResult(const aName: string; Const Args: Array of const; aResultClass: TJSObjectClass; Invoke: TJOBInvokeType = jiCall): TJSObject; virtual; + function InvokeJSValueResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): TJOB_JSValue; virtual; + function InvokeJSVariantResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Variant; virtual; + function InvokeJSUtf8StringResult(const aName: string; Const args: Array of const; Invoke: TJOBInvokeType = jiCall): String; virtual; + function InvokeJSLongIntResult(const aName: string; Const args: Array of const; Invoke: TJOBInvokeType = jiCall): LongInt; virtual; + function InvokeJSTypeOf(const aName: string; Const Args: Array of const): TJOBResult; virtual; + function InvokeJSUnicodeStringArrayResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): TUnicodeStringDynArray; virtual; + // read a property + function ReadJSPropertyBoolean(const aName: string): boolean; virtual; + function ReadJSPropertyDouble(const aName: string): double; virtual; + function ReadJSPropertyUnicodeString(const aName: string): UnicodeString; virtual; + function ReadJSPropertyObject(const aName: string; aResultClass: TJSObjectClass): TJSObject; virtual; + function ReadJSPropertyUtf8String(const aName: string): string; virtual; + function ReadJSPropertyLongInt(const aName: string): LongInt; virtual; + function ReadJSPropertyInt64(const aName: string): Int64; virtual; + function ReadJSPropertyValue(const aName: string): TJOB_JSValue; virtual; + function ReadJSPropertyVariant(const aName: string): Variant; virtual; + function ReadJSPropertyMethod(const aName: string): TMethod; virtual; + // write a property + procedure WriteJSPropertyBoolean(const aName: string; Value: Boolean); virtual; + procedure WriteJSPropertyDouble(const aName: string; Value: Double); virtual; + procedure WriteJSPropertyUnicodeString(const aName: string; const Value: UnicodeString); virtual; + procedure WriteJSPropertyUtf8String(const aName: string; const Value: String); virtual; + procedure WriteJSPropertyObject(const aName: string; Value: IJSObject); virtual; + procedure WriteJSPropertyLongInt(const aName: string; Value: LongInt); virtual; + procedure WriteJSPropertyInt64(const aName: string; Value: Int64); virtual; + procedure WriteJSPropertyValue(const aName: string; Value: TJOB_JSValue); virtual; + procedure WriteJSPropertyVariant(const aName: string; const Value: Variant); virtual; + procedure WriteJSPropertyMethod(const aName: string; const Value: TMethod); virtual; + // create a new object using the new-operator + function NewJSObject(Const Args: Array of const; aResultClass: TJSObjectClass): TJSObject; virtual; + // JS members + function getOwnPropertyNames(const Obj: IJSObject): TUnicodeStringDynArray; + function getPrototypeOf(const Obj: IJSObject): IJSObject; + function hasOwnProperty(const PropName: String): boolean; virtual; + function isPrototypeOf(const Obj: IJSObject): boolean; virtual; + function propertyIsEnumerable(const PropName: String): boolean; virtual; + function toLocaleString: UnicodeString; virtual; overload; + function toString: String; override; overload; + function toUString: UnicodeString; virtual; overload; + function valueOf: Variant; virtual; overload; + property Properties[const PropName: String]: Variant read GetProperties write SetProperties; default; + end; + + { TJSObject } + + TJSObject = class(TInterfacedObject,IJSObject) + private + FJOBObjectID: TJOBObjectID; + FJOBCastSrc: IJSObject; + FJOBObjectIDOwner: boolean; + protected + type + TJOBInvokeNoResultFunc = function( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte + ): TJOBResult; + TJOBInvokeOneResultFunc = function( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultP: PByte + ): TJOBResult; + function GetJSObjectID: TJOBObjectID; + function GetJSObjectCastSrc: IJSObject; + function GetPascalClassName: string; + function GetProperties(const PropName: String): Variant; virtual; + procedure SetProperties(const PropName: String; const AValue: Variant); virtual; + function FetchString(Len: NativeInt): UnicodeString; + function InvokeJSNoResultFunc(const aName: string; Const Args: Array of const; + const InvokeFunc: TJOBInvokeNoResultFunc; Invoke: TJOBInvokeType): TJOBResult; + function InvokeJSOneResult(const aName: string; Const Args: Array of const; + const InvokeFunc: TJOBInvokeOneResultFunc; ResultP: PByte; Invoke: TJOBInvokeType): TJOBResult; + procedure InvokeJS_Raise(const aName, Msg: string); virtual; + procedure InvokeJS_RaiseResultMismatch(const aName: string; Expected, Actual: TJOBResult); virtual; + procedure InvokeJS_RaiseResultMismatchStr(const aName: string; const Expected, Actual: string); virtual; + function CreateInvokeJSArgs(const Args: array of const): PByte; virtual; + public + constructor JOBCast(const Intf: IJSObject); overload; + constructor JOBCreateFromID(aID: TJOBObjectID); virtual; // use this only for the owner (it will release it on free) + constructor JOBCreateGlobal(const aID: UnicodeString); virtual; + class function Cast(const Intf: IJSObject): IJSObject; overload; + destructor Destroy; override; + property JOBObjectID: TJOBObjectID read FJOBObjectID; + property JOBObjectIDOwner: boolean read FJOBObjectIDOwner write FJOBObjectIDOwner; + property JOBCastSrc: IJSObject read FJOBCastSrc; // nil means it is the original, otherwise it is a typecast + // call a function + procedure InvokeJSNoResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall); virtual; + function InvokeJSBooleanResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Boolean; virtual; + function InvokeJSDoubleResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Double; virtual; + function InvokeJSUnicodeStringResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): UnicodeString; virtual; + function InvokeJSObjectResult(const aName: string; Const Args: Array of const; aResultClass: TJSObjectClass; Invoke: TJOBInvokeType = jiCall): TJSObject; virtual; + function InvokeJSValueResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): TJOB_JSValue; virtual; + function InvokeJSVariantResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Variant; virtual; + function InvokeJSUtf8StringResult(const aName: string; Const args: Array of const; Invoke: TJOBInvokeType = jiCall): String; virtual; + function InvokeJSLongIntResult(const aName: string; Const args: Array of const; Invoke: TJOBInvokeType = jiCall): LongInt; virtual; + function InvokeJSMaxIntResult(const aName: string; Const args: Array of const; Invoke: TJOBInvokeType = jiCall): int64; virtual; + function InvokeJSTypeOf(const aName: string; Const Args: Array of const): TJOBResult; virtual; + function InvokeJSUnicodeStringArrayResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): TUnicodeStringDynArray; virtual; + // read a property + function ReadJSPropertyBoolean(const aName: string): boolean; virtual; + function ReadJSPropertyDouble(const aName: string): double; virtual; + function ReadJSPropertyUnicodeString(const aName: string): UnicodeString; virtual; + function ReadJSPropertyObject(const aName: string; aResultClass: TJSObjectClass): TJSObject; virtual; + function ReadJSPropertyUtf8String(const aName: string): string; virtual; + function ReadJSPropertyLongInt(const aName: string): LongInt; virtual; + function ReadJSPropertyInt64(const aName: string): Int64; virtual; + function ReadJSPropertyValue(const aName: string): TJOB_JSValue; virtual; + function ReadJSPropertyVariant(const aName: string): Variant; virtual; + function ReadJSPropertyMethod(const aName: string): TMethod; virtual; + // write a property + procedure WriteJSPropertyBoolean(const aName: string; Value: Boolean); virtual; + procedure WriteJSPropertyDouble(const aName: string; Value: Double); virtual; + procedure WriteJSPropertyUnicodeString(const aName: string; const Value: UnicodeString); virtual; + procedure WriteJSPropertyUtf8String(const aName: string; const Value: String); virtual; + procedure WriteJSPropertyObject(const aName: string; Value: IJSObject); virtual; + procedure WriteJSPropertyLongInt(const aName: string; Value: LongInt); virtual; + procedure WriteJSPropertyInt64(const aName: string; Value: Int64); virtual; + procedure WriteJSPropertyValue(const aName: string; Value: TJOB_JSValue); virtual; + procedure WriteJSPropertyVariant(const aName: string; const Value: Variant); virtual; + procedure WriteJSPropertyMethod(const aName: string; const Value: TMethod); virtual; + // create a new object using the new-operator + function NewJSObject(Const Args: Array of const; aResultClass: TJSObjectClass): TJSObject; virtual; + // JS members + function getOwnPropertyNames(const Obj: IJSObject): TUnicodeStringDynArray; + function getPrototypeOf(const Obj: IJSObject): IJSObject; + function hasOwnProperty(const PropName: String): boolean; virtual; + function isPrototypeOf(const Obj: IJSObject): boolean; virtual; + function propertyIsEnumerable(const PropName: String): boolean; virtual; + function toLocaleString: UnicodeString; virtual; overload; + function toString: String; override; overload; + function toUString: UnicodeString; virtual; overload; + function valueOf: Variant; virtual; overload; + property Properties[const PropName: String]: Variant read GetProperties write SetProperties; default; + end; + + { IJSSet } + + IJSSet = interface(IJSObject) + ['{1D276953-95E2-4B07-8D4E-BE70D1CEF356}'] + end; + + { TJSSet } + + TJSSet = class(TJSObject,IJSSet) + public + class function Cast(const Intf: IJSObject): IJSSet; overload; + end; + + { IJSMap } + + IJSMap = interface(IJSObject) + ['{D31F19A1-388E-4612-BC71-9392ECA90DA3}'] + end; + + { TJSMap } + + TJSMap = class(TJSObject,IJSMap) + public + class function Cast(const Intf: IJSObject): IJSMap; overload; + end; + + { IJSFunction } + + IJSFunction = interface(IJSObject) + ['{8BD36F12-F6F7-4F8B-91FB-43D8626A72FE}'] + function _GetLength: NativeInt; + function _GetName: UnicodeString; + function _GetPrototyp: IJSFunction; + procedure _SetName(const AValue: UnicodeString); + property name: UnicodeString read _GetName write _SetName; + property prototyp: IJSFunction read _GetPrototyp; + property length: NativeInt read _GetLength; + //function apply(thisArg: TJSObject; const ArgArray: TJSValueDynArray): JSValue; varargs; + //function bind(thisArg: TJSObject): JSValue; varargs; + //function call(thisArg: TJSObject): JSValue; varargs; + end; + + { TJSFunction } + + TJSFunction = class(TJSObject,IJSFunction) + public + function _GetLength: NativeInt; + function _GetName: UnicodeString; + function _GetPrototyp: IJSFunction; + procedure _SetName(const AValue: UnicodeString); + property name: UnicodeString read _GetName write _SetName; + property prototyp: IJSFunction read _GetPrototyp; + property length: NativeInt read _GetLength; + class function Cast(const Intf: IJSObject): IJSFunction; overload; + end; + + { IJSDate } + + IJSDate = interface(IJSObject) + ['{F12818EA-542E-488C-A3C5-279E05639E9E}'] + function Create(aYear: NativeInt; aMonth: NativeInt; aDayOfMonth: NativeInt = 1; + TheHours: NativeInt = 0; TheMinutes: NativeInt = 0; TheSeconds: NativeInt = 0; + TheMilliseconds: NativeInt = 0): IJSDate; + function toLocaleDateString: UnicodeString; overload; // date in locale timezone, no time + end; + + { TJSDate } + + TJSDate = class(TJSObject,IJSDate) + public + class function Cast(const Intf: IJSObject): IJSDate; overload; + function Create(aYear: NativeInt; aMonth: NativeInt; aDayOfMonth: NativeInt = 1; + TheHours: NativeInt = 0; TheMinutes: NativeInt = 0; TheSeconds: NativeInt = 0; + TheMilliseconds: NativeInt = 0): IJSDate; + function toLocaleDateString: UnicodeString; overload; // date in locale timezone, no time + end; + + { IJSRegExp } + + IJSRegExp = interface(IJSObject) + ['{3E9E4F54-10DA-45BF-ABED-7ED2C255617E}'] + function exec(const aString: UnicodeString): IJSArray; + function _GetGlobal: Boolean; + function _GetIgnoreCase: Boolean; + function _GetLastIndex: NativeInt; + function _GetMultiLine: Boolean; + function _GetSource: UnicodeString; + function _GetUnicode: boolean; + procedure _SetGlobal(const AValue: Boolean); + procedure _SetIgnoreCase(const AValue: Boolean); + procedure _SetlastIndex(const AValue: NativeInt); + procedure _SetMultiline(const AValue: Boolean); + procedure _SetSource(const AValue: UnicodeString); + procedure _SetUnicode(const AValue: boolean); + function test(const aString: UnicodeString): boolean; + property lastIndex: NativeInt read _GetLastIndex write _SetlastIndex; + property global: Boolean read _GetGlobal write _SetGlobal; + property ignoreCase: Boolean read _GetIgnoreCase write _SetIgnoreCase; + property multiline: Boolean Read _GetMultiLine write _SetMultiline; + property source: UnicodeString Read _GetSource write _SetSource; + property unicode: boolean Read _GetUnicode write _SetUnicode; + end; + + { TJSRegExp } + + TJSRegExp = class(TJSObject,IJSRegExp) + public + function exec(const aString: UnicodeString): IJSArray; + function _GetGlobal: Boolean; + function _GetIgnoreCase: Boolean; + function _GetLastIndex: NativeInt; + function _GetMultiLine: Boolean; + function _GetSource: UnicodeString; + function _GetUnicode: boolean; + procedure _SetGlobal(const AValue: Boolean); + procedure _SetIgnoreCase(const AValue: Boolean); + procedure _SetlastIndex(const AValue: NativeInt); + procedure _SetMultiline(const AValue: Boolean); + procedure _SetSource(const AValue: UnicodeString); + procedure _SetUnicode(const AValue: boolean); + function test(const aString: UnicodeString): boolean; + property lastIndex: NativeInt read _GetLastIndex write _SetlastIndex; + property global: Boolean read _GetGlobal write _SetGlobal; + property ignoreCase: Boolean read _GetIgnoreCase write _SetIgnoreCase; + property multiline: Boolean Read _GetMultiLine write _SetMultiline; + property source: UnicodeString Read _GetSource write _SetSource; + property unicode: boolean Read _GetUnicode write _SetUnicode; + class function Cast(const Intf: IJSObject): IJSRegExp; overload; + end; + + { IJSString } + + IJSString = interface(IJSObject) + ['{4C3B1B1C-4C0D-42A2-81BE-36CC78DCF9AE}'] + end; + + { TJSString } + + TJSString = class(TJSObject,IJSString) + public + class function Cast(const Intf: IJSObject): IJSString; overload; + end; + + IJSIterator = interface (IJSObject) ['{21E331BA-7B57-42DD-8DCE-B26FEA85C639}'] + end; + + TJSIterator = class(TJSObject,IJSIterator) + end; + + { IJSArray } + + IJSArray = interface(IJSObject) + ['{21E331BA-7B57-42DD-8DCE-B26FEA85C693}'] + function _GetElements(Index: NativeInt): TJOB_JSValue; + function _GetLength: NativeInt; + procedure _SetElements(Index: NativeInt; const AValue: TJOB_JSValue); + procedure _SetLength(const AValue: NativeInt); + function isArray(a: TJOB_JSValue): Boolean; overload; + function concat(el: TJOB_JSValue): IJSArray; overload; {varargs;} + //function copyWithin(aTarget: NativeInt): TJSArray;overload; // not in IE + //function copyWithin(aTarget, aStart: NativeInt): TJSArray;overload; // not in IE + //function copyWithin(aTarget, aStart, aEnd: NativeInt): TJSArray;overload; // not in IE + //function entries: TJSIterator; + //Function every(const aCallback: TJSArrayCallBack): boolean;overload; + //Function every(const aCallback: TJSArrayEvent; aThis: TObject): boolean;overload; + //Function filter(const aCallBack: TJSArrayCallBack): TJSArray; overload; + //Function filter(const aCallBack: TJSArrayEvent; aThis: TObject): TJSArray;overload; + Function fill(aValue: TJOB_JSValue): IJSArray; overload; + Function fill(aValue: TJOB_JSValue; aStartIndex: NativeInt): IJSArray; overload; + Function fill(aValue: TJOB_JSValue; aStartIndex,aEndIndex: NativeInt): IJSArray; overload; + //Function find(const aCallBack: TJSArrayCallBack): TJOB_JSValue; overload; + //Function find(const aCallBack: TJSArrayEvent; aThis: TObject): TJOB_JSValue; overload; + //Function findIndex(const aCallBack: TJSArrayCallBack): NativeInt; overload; + //Function findIndex(const aCallBack: TJSArrayEvent; aThis: TObject): NativeInt; overload; + //procedure forEach(const aCallBack: TJSArrayEventProc); overload; + //procedure forEach(const aCallBack: TJSArrayEvent); overload; + //procedure forEach(const aCallBack: TJSArrayEvent; aThis: TObject); overload; + function includes(aElement: TJOB_JSValue): Boolean; overload; + function includes(aElement: TJOB_JSValue; FromIndex: NativeInt): Boolean; overload; + function indexOf(aElement: TJOB_JSValue): NativeInt; overload; + function indexOf(aElement: TJOB_JSValue; FromIndex: NativeInt): NativeInt; overload; + function join: UnicodeString; overload; + function join (const aSeparator: UnicodeString): UnicodeString; overload; + //function keys: TJSIterator; + function lastIndexOf(aElement: TJOB_JSValue): NativeInt; overload; + function lastIndexOf(aElement: TJOB_JSValue; FromIndex: NativeInt): NativeInt; overload; + //Function map(const aCallBack: TJSArrayMapCallBack): TJSArray; overload; + //Function map(const aCallBack: TJSArrayMapEvent; aThis: TObject): TJSArray; overload; + function pop: TJOB_JSValue; + function push(aElement: TJOB_JSValue): NativeInt; overload; {varargs;} + //function reduce(const aCallBack: TJSArrayReduceCallBack): TJOB_JSValue; overload; + //function reduce(const aCallBack: TJSArrayReduceCallBack; initialValue: TJOB_JSValue): TJOB_JSValue; overload; + //function reduceRight(const aCallBack: TJSArrayReduceCallBack): TJOB_JSValue; overload; + //function reduceRight(const aCallBack: TJSArrayReduceCallBack; initialValue: TJOB_JSValue): TJOB_JSValue; overload; + Function reverse: IJSArray; + Function shift: TJOB_JSValue; + Function slice: IJSArray; overload; + function slice(aBegin: NativeInt): IJSArray; overload; + function slice(aBegin,aEnd: NativeInt): IJSArray; overload; + //Function some(const aCallback: TJSArrayCallBack): boolean; overload; + //Function some(const aCallback: TJSArrayEvent; aThis: TObject): boolean; overload; + //Function sort(const aCallback: TJSArrayCompareCallBack): IJSArray; overload; + Function sort(): IJSArray; overload; + function splice(aStart: NativeInt): IJSArray; overload; + function splice(aStart,aDeleteCount: NativeInt): IJSArray; {varargs;} overload; + function toLocaleString(const locales: UnicodeString): UnicodeString; overload; + //function toLocaleString(locales: string; const Options: TLocaleCompareOptions): String; overload; + function unshift: NativeInt; {varargs;} + //function values: TJSIterator; + Property Length: NativeInt Read _GetLength Write _SetLength; + property Elements[Index: NativeInt]: TJOB_JSValue read _GetElements write _SetElements; default; + end; + + { TJSArray } + + TJSArray = class(TJSObject,IJSArray) + private + function _GetElements(Index: NativeInt): TJOB_JSValue; + function _GetLength: NativeInt; + procedure _SetElements(Index: NativeInt; const AValue: TJOB_JSValue); + procedure _SetLength(const AValue: NativeInt); + public + function isArray(a: TJOB_JSValue): Boolean; overload; + function concat(el: TJOB_JSValue): IJSArray; overload; {varargs;} + //function copyWithin(aTarget: NativeInt): IJSArray;overload; // not in IE + //function copyWithin(aTarget, aStart: NativeInt): IJSArray;overload; // not in IE + //function copyWithin(aTarget, aStart, aEnd: NativeInt): IJSArray;overload; // not in IE + //function entries: TJSIterator; + //Function every(const aCallback: TJSArrayCallBack): boolean;overload; + //Function every(const aCallback: TJSArrayEvent; aThis: TObject): boolean;overload; + //Function filter(const aCallBack: TJSArrayCallBack): IJSArray; overload; + //Function filter(const aCallBack: TJSArrayEvent; aThis: TObject): IJSArray;overload; + Function fill(aValue: TJOB_JSValue): IJSArray; overload; + Function fill(aValue: TJOB_JSValue; aStartIndex: NativeInt): IJSArray; overload; + Function fill(aValue: TJOB_JSValue; aStartIndex,aEndIndex: NativeInt): IJSArray; overload; + //Function find(const aCallBack: TJSArrayCallBack): TJOB_JSValue; overload; + //Function find(const aCallBack: TJSArrayEvent; aThis: TObject): TJOB_JSValue; overload; + //Function findIndex(const aCallBack: TJSArrayCallBack): NativeInt; overload; + //Function findIndex(const aCallBack: TJSArrayEvent; aThis: TObject): NativeInt; overload; + //procedure forEach(const aCallBack: TJSArrayEventProc); overload; + //procedure forEach(const aCallBack: TJSArrayEvent); overload; + //procedure forEach(const aCallBack: TJSArrayEvent; aThis: TObject); overload; + function includes(aElement: TJOB_JSValue): Boolean; overload; + function includes(aElement: TJOB_JSValue; FromIndex: NativeInt): Boolean; overload; + function indexOf(aElement: TJOB_JSValue): NativeInt; overload; + function indexOf(aElement: TJOB_JSValue; FromIndex: NativeInt): NativeInt; overload; + function join: UnicodeString; overload; + function join (const aSeparator: UnicodeString): UnicodeString; overload; + //function keys: TJSIterator; + function lastIndexOf(aElement: TJOB_JSValue): NativeInt; overload; + function lastIndexOf(aElement: TJOB_JSValue; FromIndex: NativeInt): NativeInt; overload; + //Function map(const aCallBack: TJSArrayMapCallBack): IJSArray; overload; + //Function map(const aCallBack: TJSArrayMapEvent; aThis: TObject): IJSArray; overload; + function pop: TJOB_JSValue; + function push(aElement: TJOB_JSValue): NativeInt; overload; {varargs;} + //function reduce(const aCallBack: TJSArrayReduceCallBack): TJOB_JSValue; overload; + //function reduce(const aCallBack: TJSArrayReduceCallBack; initialValue: TJOB_JSValue): TJOB_JSValue; overload; + //function reduceRight(const aCallBack: TJSArrayReduceCallBack): TJOB_JSValue; overload; + //function reduceRight(const aCallBack: TJSArrayReduceCallBack; initialValue: TJOB_JSValue): TJOB_JSValue; overload; + Function reverse: IJSArray; + Function shift: TJOB_JSValue; + Function slice: IJSArray; overload; + function slice(aBegin: NativeInt): IJSArray; overload; + function slice(aBegin,aEnd: NativeInt): IJSArray; overload; + //Function some(const aCallback: TJSArrayCallBack): boolean; overload; + //Function some(const aCallback: TJSArrayEvent; aThis: TObject): boolean; overload; + //Function sort(const aCallback: TJSArrayCompareCallBack): IJSArray; overload; + Function sort(): IJSArray; overload; + function splice(aStart: NativeInt): IJSArray; overload; + function splice(aStart,aDeleteCount: NativeInt): IJSArray; {varargs;} overload; + function toLocaleString(const locales: UnicodeString): UnicodeString; overload; + //function toLocaleString(locales: string; const Options: TLocaleCompareOptions): String; overload; + function unshift: NativeInt; {varargs;} + //function values: TJSIterator; + Property Length: NativeInt Read _GetLength Write _SetLength; + property Elements[Index: NativeInt]: TJOB_JSValue read _GetElements write _SetElements; default; + class function Cast(const Intf: IJSObject): IJSArray; overload; + end; + + { IJSArrayBuffer } + + IJSArrayBuffer = interface(IJSObject) + ['{A1612EED-4F05-46C0-90BE-ACD511B15E89}'] + end; + + + { TJSArrayBuffer } + + TJSArrayBuffer = class(TJSObject,IJSArrayBuffer) + public + class function Cast(const Intf: IJSObject): IJSArrayBuffer; overload; + end; + + { IJSArrayBufferView } + + IJSArrayBufferView = interface(IJSObject) + ['{A1612EED-4F05-46C0-90BE-ACD511B1598E}'] + end; + + { TJSArrayBufferView } + + TJSArrayBufferView = class(TJSObject,IJSArrayBufferView) + public + class function Cast(const Intf: IJSObject): IJSArrayBufferView; overload; + end; + + + { IJSTypedArray } + + IJSTypedArray = interface(IJSObject) + ['{6A76602B-9555-4136-A7B7-2E683265EA82}'] + end; + + { TJSTypedArray } + + TJSTypedArray = class(TJSObject,IJSTypedArray) + public + class function Cast(const Intf: IJSObject): IJSTypedArray; overload; + end; + + { IJSInt8Array } + + IJSInt8Array = interface(IJSTypedArray) + ['{72D65C5E-E18E-4294-8709-D7A63BF12958}'] + end; + + { TJSInt8Array } + + TJSInt8Array = class(TJSTypedArray,IJSInt8Array) + public + class function Cast(const Intf: IJSObject): IJSInt8Array; overload; + end; + + { IJSUint8Array } + + IJSUint8Array = interface(IJSTypedArray) + ['{99EC7B3A-30E5-425F-933C-C169B2F4193C}'] + end; + + { TJSUint8Array } + + TJSUint8Array = class(TJSTypedArray,IJSUint8Array) + public + class function Cast(const Intf: IJSObject): IJSUint8Array; overload; + end; + + { IJSUint8ClampedArray } + + IJSUint8ClampedArray = interface(IJSTypedArray) + ['{A1508D6E-8629-4416-875E-9F669ECDC47F}'] + end; + + { TJSUint8ClampedArray } + + TJSUint8ClampedArray = class(TJSTypedArray,IJSUint8ClampedArray) + public + class function Cast(const Intf: IJSObject): IJSUint8ClampedArray; overload; + end; + + { IJSInt16Array } + + IJSInt16Array = interface(IJSTypedArray) + ['{B5FA7A13-D8CA-44E4-ADAE-F10FFFAE46B4}'] + end; + + { TJSInt16Array } + + TJSInt16Array = class(TJSTypedArray,IJSInt16Array) + public + class function Cast(const Intf: IJSObject): IJSInt16Array; overload; + end; + + { IJSUint16Array } + + IJSUint16Array = interface(IJSTypedArray) + ['{6023E2BC-C464-4288-A8DA-4A5D0B2B915E}'] + end; + + { TJSUint16Array } + + TJSUint16Array = class(TJSTypedArray,IJSUint16Array) + public + class function Cast(const Intf: IJSObject): IJSUint16Array; overload; + end; + + { IJSInt32Array } + + IJSInt32Array = interface(IJSTypedArray) + ['{16F1A6FB-2F26-4A64-8A2B-D883DE2F58C4}'] + end; + + { TJSInt32Array } + + TJSInt32Array = class(TJSTypedArray,IJSInt32Array) + public + class function Cast(const Intf: IJSObject): IJSInt32Array; overload; + end; + + { IJSUint32Array } + + IJSUint32Array = interface(IJSTypedArray) + ['{C637B2FA-CED6-4EC7-8D97-C56824EAF8B3}'] + end; + + { TJSUint32Array } + + TJSUint32Array = class(TJSTypedArray,IJSUint32Array) + public + class function Cast(const Intf: IJSObject): IJSUint32Array; overload; + end; + + { IJSFloat32Array } + + IJSFloat32Array = interface(IJSTypedArray) + ['{B5CE57F6-CA7C-4168-AEA3-32EF13DA52D6}'] + end; + + { TJSFloat32Array } + + TJSFloat32Array = class(TJSTypedArray,IJSFloat32Array) + public + class function Cast(const Intf: IJSObject): IJSFloat32Array; overload; + end; + + { IJSFloat64Array } + + IJSFloat64Array = interface(IJSTypedArray) + ['{A7876DC5-9549-4FDA-BE35-A641CE9D9F0B}'] + end; + + { TJSFloat64Array } + + TJSFloat64Array = class(TJSTypedArray,IJSFloat64Array) + public + class function Cast(const Intf: IJSObject): IJSFloat64Array; overload; + end; + + { IJSBufferSource } + + IJSBufferSource = interface(IJSObject) + ['{7F2A68EE-2FA6-445C-BFC1-2C9E4D45FFBF}'] + end; + + { TJSBufferSource } + + TJSBufferSource = class(TJSObject,IJSBufferSource) + public + class function Cast(const Intf: IJSObject): IJSBufferSource; overload; + end; + + { IJSDataView } + + IJSDataView = interface(IJSObject) + ['{42F14387-FAD2-46BA-8CB4-057445095CEE}'] + end; + + { TJSDataView } + + TJSDataView = class(TJSObject,IJSDataView) + public + class function Cast(const Intf: IJSObject): IJSDataView; overload; + end; + + { IJSJSON } + + IJSJSON = interface(IJSObject) + ['{73535059-91DD-4A22-91A6-D8072008C5F3}'] + function parse(const aJSON: UnicodeString): TJOB_JSValue; overload; + // Use this only when you are sure you will get an object, no checking is done. + function parseObject(const aJSON: UnicodeString): IJSObject; overload; + function stringify(aValue: TJOB_JSValue): UnicodeString; overload; + function stringify(aValue,aReplacer: TJOB_JSValue): UnicodeString; overload; + function stringify(aValue,aReplacer: TJOB_JSValue; space: NativeInt): UnicodeString; overload; + function stringify(aValue,aReplacer: TJOB_JSValue; const space: UnicodeString): UnicodeString; overload; + end; + + { TJSJSON } + + TJSJSON = class(TJSObject,IJSJSON) + public + function parse(const aJSON: UnicodeString): TJOB_JSValue; overload; + // Use this only when you are sure you will get an object, no checking is done. + function parseObject(const aJSON: UnicodeString): IJSObject; overload; + function stringify(aValue: TJOB_JSValue): UnicodeString; overload; + function stringify(aValue,aReplacer: TJOB_JSValue): UnicodeString; overload; + function stringify(aValue,aReplacer: TJOB_JSValue; space: NativeInt): UnicodeString; overload; + function stringify(aValue,aReplacer: TJOB_JSValue; const space: UnicodeString): UnicodeString; overload; + class function Cast(const Intf: IJSObject): IJSJSON; overload; + end; + + { IJSError } + + IJSError = interface(IJSObject) + ['{80532C4D-CAD2-4C70-A4EA-01B29BB8C2C8}'] + end; + + { TJSError } + + TJSError = class(TJSObject,IJSError) + public + class function Cast(const Intf: IJSObject): IJSError; overload; + end; + + TJSPromiseResolver = function(const aValue: Variant): Variant of object; + TJSPromiseExecutor = procedure(const OnResolve, OnReject: TJSPromiseResolver) of object; + TJSPromiseFinallyHandler = procedure of object; + + { IJSPromise } + + IJSPromise = interface(IJSObject) + ['{2BFE673B-B5D4-4F31-96CD-5E1A60EFBE26}'] + function all(const arg: Variant): IJSPromise; overload; + function allSettled(const arg: Variant): IJSPromise; overload; + function race(const arg: Variant): IJSPromise; overload; + function reject(const reason: Variant): IJSPromise; overload; + function resolve(const value: Variant): IJSPromise; overload; + function resolve: IJSPromise; overload; + function _then(const OnAccepted: TJSPromiseResolver): IJSPromise; overload; + function _then(const OnAccepted, OnRejected: TJSPromiseResolver) : IJSPromise; overload; + function catch(const OnRejected: TJSPromiseResolver): IJSPromise; overload; + function _finally(const Handler: TJSPromiseFinallyHandler): IJSPromise; overload; + end; + + { TJSPromise } + + TJSPromise = class(TJSObject,IJSPromise) + public + //class function Create(const Executor: TJSPromiseExecutor): IJSPromise; overload; + function all(const arg: Variant): IJSPromise; overload; + function allSettled(const arg: Variant): IJSPromise; overload; + function race(const arg: Variant): IJSPromise; overload; + function reject(const reason: Variant): IJSPromise; overload; + function resolve(const value: Variant): IJSPromise; overload; + function resolve: IJSPromise; overload; + function _then(const OnAccepted: TJSPromiseResolver): IJSPromise; overload; + function _then(const OnAccepted, OnRejected: TJSPromiseResolver) : IJSPromise; overload; + function catch(const OnRejected: TJSPromiseResolver): IJSPromise; overload; + function _finally(const Handler: TJSPromiseFinallyHandler): IJSPromise; overload; + class function Cast(const Intf: IJSObject): IJSPromise; overload; + end; + + { IJSTextDecoder } + + IJSTextDecoder = interface(IJSObject) + ['{EB42F04D-B92D-42AC-96F8-58DEC2F7F8D0}'] + end; + + { TJSTextDecoder } + + TJSTextDecoder = class(TJSObject,IJSTextDecoder) + public + class function Cast(const Intf: IJSObject): IJSTextDecoder; overload; + end; + + { IJSTextEncoder } + + IJSTextEncoder = interface(IJSObject) + ['{C2964DC1-E9AE-4321-99BD-EB788A7F2D9E}'] + end; + + { TJSTextEncoder } + + TJSTextEncoder = class(TJSObject,IJSTextEncoder) + public + class function Cast(const Intf: IJSObject): IJSTextEncoder; overload; + end; + +var + JSObject: IJSObject; // singleton of JS 'Object' + JSDate: IJSDate; // singleton of JS 'Date' + +// imported functions from browser +function __job_invoke_noresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte +): TJOBResult; external JOBExportName name JOBFn_InvokeNoResult; + +function __job_invoke_boolresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultByteBoolP: PByte +): TJOBResult; external JOBExportName name JOBFn_InvokeBooleanResult; + +function __job_invoke_doubleresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultDoubleP: PByte +): TJOBResult; external JOBExportName name JOBFn_InvokeDoubleResult; + +function __job_invoke_stringresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultLenP: PByte // nativeint +): TJOBResult; external JOBExportName name JOBFn_InvokeStringResult; + +function __job_getstringresult( + ResultP: PByte +): TJOBResult; external JOBExportName name JOBFn_GetStringResult; + +function __job_releasestringresult( +): TJOBResult; external JOBExportName name JOBFn_ReleaseStringResult; + +function __job_invoke_objectresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultObjIDP: PByte // nativeint +): TJOBResult; external JOBExportName name JOBFn_InvokeObjectResult; + +function __job_release_object( + ObjID: TJOBObjectID +): TJOBResult; external JOBExportName name JOBFn_ReleaseObject; + +function __job_invoke_jsvalueresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultP: PByte // various +): TJOBResult; external JOBExportName name JOBFn_InvokeJSValueResult; + +function __job_invoke_arraystringresult( + ObjID: TJOBObjectID; + NameP: PChar; + NameLen: longint; + Invoke: longint; + ArgP: PByte; + ResultLenP: PByte // nativeint +): TJOBResult; external JOBExportName name JOBFn_InvokeArrayStringResult; + +function __job_get_global( + NameP: PWideChar; + NameLen: longint + ): TJOBObjectID; external JOBExportName name JOBFn_GetGlobal; + +function JOBCallback(const Func: TJOBCallback; Data, Code: Pointer; Args: PByte): PByte; +function VarRecToJSValue(const V: TVarRec): TJOB_JSValue; + +implementation + +const + InvokeGetToInt: array[TJOBInvokeType] of integer = ( + JOBInvokeCall, + JOBInvokeGet, + JOBInvokeGetTypeOf, + JOBInvokeSet, + JOBInvokeNew + ); + +{$IFDEF VerboseJOB} +function GetVarRecName(vt: word): string; +begin + case vt of + vtInteger: Result:='vtInteger'; + vtBoolean: Result:='vtBoolean'; + vtChar: Result:='vtChar'; + {$ifndef FPUNONE} + vtExtended: Result:='vtExtended'; + {$endif} + vtString: Result:='vtString'; + vtPointer: Result:='vtPointer'; + vtPChar: Result:='vtPChar'; + vtObject: Result:='vtObject'; + vtClass: Result:='vtClass'; + vtWideChar: Result:='vtWideChar'; + vtPWideChar: Result:='vtPWideChar'; + vtAnsiString: Result:='vtAnsiString'; + vtCurrency: Result:='vtCurrency'; + vtVariant: Result:='vtVariant'; + vtInterface: Result:='vtInterface'; + vtWideString: Result:='vtWideString'; + vtInt64: Result:='vtInt64'; + vtQWord: Result:='vtQWord'; + vtUnicodeString: Result:='vtUnicodeString'; + else + Result:='vt?'; + end; +end; +{$ENDIF} + +function __job_callback(w: NativeInt): boolean; +begin + writeln('__job_callback w=',w); + Result:=true; +end; + +function JOBCallback(const Func: TJOBCallback; Data, Code: Pointer; Args: PByte + ): PByte; +var + m: TMethod; + h: TJOBCallbackHelper; +begin + Result:=nil; + try + //writeln('JOBCallback'); + m.Data:=Data; + m.Code:=Code; + h.Init(Args); + Result:=Func(m,h); + finally + if Args<>nil then + FreeMem(Args); + end; +end; + +function VarRecToJSValue(const V: TVarRec): TJOB_JSValue; +var + p: Pointer; + CurLen: SizeInt; + S: String; + Obj: TObject; + Intf: IJSObject; +begin + case V.VType of + vtInteger: + Result:=TJOB_Double.Create(V.VInteger); + vtBoolean: + Result:=TJOB_Boolean.Create(V.VBoolean); + vtChar: + Result:=TJOB_String.Create(UnicodeString(V.VChar)); + {$ifndef FPUNONE} + vtExtended: + Result:=TJOB_Double.Create(V.VExtended^); + {$endif} + vtString: + Result:=TJOB_String.Create(UTF8Decode(V.VString^)); + vtPointer: + begin + p:=V.VPointer; + if p=nil then + Result:=TJOB_Object.Create(nil) + else if p=JOB_Undefined then + Result:=TJOB_JSValue.Create(jjvkUndefined) + else + raise EJSArgParse.Create('VarRecToJSValue pointer not supported'); + end; + vtPChar: + begin + CurLen:=strlen(V.VPChar); + SetString(S,V.VPChar,CurLen); + Result:=TJOB_String.Create(UTF8Decode(S)); + end; + vtObject: + begin + Obj:=V.VObject; + if Obj=nil then + Result:=TJOB_Object.Create(nil) + else if Obj is TJOB_JSValue then + Result:=TJOB_JSValue(Obj) + else if Obj is TJSObject then + Result:=TJOB_Object.Create(TJSObject(Obj) as IJSObject) + else + raise EJSArgParse.Create('VarRecToJSValue object '+Obj.ClassName+' not supported'); + end; + vtClass: + raise EJSArgParse.Create('VarRecToJSValue class not supported'); + vtWideChar: + Result:=TJOB_String.Create(V.VWideChar); + vtPWideChar: + raise EJSArgParse.Create('VarRecToJSValue vtPWideChar not supported'); + vtAnsiString: + Result:=TJOB_String.Create(UTF8Decode(PAnsiString(V.VAnsiString)^)); + vtCurrency: + Result:=TJOB_Double.Create(V.VCurrency^); + vtVariant: + raise EJSArgParse.Create('VarRecToJSValue vtVariant not supported'); + vtInterface: + begin + Intf:=IJSObject(V.VInterface); + Result:=TJOB_Object.Create(Intf); + end; + vtWideString: + raise EJSArgParse.Create('VarRecToJSValue vtWideString not supported'); + vtInt64: + Result:=TJOB_Double.Create(V.VInt64^); + vtQWord: + Result:=TJOB_Double.Create(V.VQWord^); + vtUnicodeString: + Result:=TJOB_String.Create(PUnicodeString(V.VUnicodeString)^); + else + raise EJSArgParse.Create('VarRecToJSValue unsupported VType '+IntToStr(V.VType)); + end; +end; + +function JOBCallTJSPromiseResolver(const aMethod: TMethod; var H: TJOBCallbackHelper): PByte; +var + aValue: Variant; +begin + aValue:=H.GetVariant; + Result:=H.AllocVariant(TJSPromiseResolver(aMethod)(aValue)); +end; + +function JOBCallTJSPromiseFinallyHandler(const aMethod: TMethod; var H: TJOBCallbackHelper): PByte; +begin + Result:=H.AllocUndefined; + TJSPromiseFinallyHandler(aMethod)(); +end; + +{ TJSTextEncoder } + +class function TJSTextEncoder.Cast(const Intf: IJSObject): IJSTextEncoder; +begin + Result:=TJSTextEncoder.Cast(Intf); +end; + +{ TJSTextDecoder } + +class function TJSTextDecoder.Cast(const Intf: IJSObject): IJSTextDecoder; +begin + Result:=TJSTextDecoder.Cast(Intf); +end; + +{ TJSPromise } + +function TJSPromise.all(const arg: Variant): IJSPromise; +begin + Result:=InvokeJSObjectResult('all',[arg],TJSPromise) as IJSPromise; +end; + +function TJSPromise.allSettled(const arg: Variant): IJSPromise; +begin + Result:=InvokeJSObjectResult('allSettled',[arg],TJSPromise) as IJSPromise; +end; + +function TJSPromise.race(const arg: Variant): IJSPromise; +begin + Result:=InvokeJSObjectResult('race',[arg],TJSPromise) as IJSPromise; +end; + +function TJSPromise.reject(const reason: Variant): IJSPromise; +begin + Result:=InvokeJSObjectResult('reject',[reason],TJSPromise) as IJSPromise; +end; + +function TJSPromise.resolve(const value: Variant): IJSPromise; +begin + Result:=InvokeJSObjectResult('resolve',[value],TJSPromise) as IJSPromise; +end; + +function TJSPromise.resolve: IJSPromise; +begin + Result:=InvokeJSObjectResult('resolve',[],TJSPromise) as IJSPromise; +end; + +function TJSPromise._then(const OnAccepted: TJSPromiseResolver): IJSPromise; +var + m: TJOB_Method; +begin + m:=TJOB_Method.Create(TMethod(onAccepted),@JOBCallTJSPromiseResolver); + try + Result:=InvokeJSObjectResult('then',[m],TJSPromise) as IJSPromise; + finally + m.Free; + end; +end; + +function TJSPromise._then(const OnAccepted, OnRejected: TJSPromiseResolver + ): IJSPromise; +var + ma, mr: TJOB_Method; +begin + ma:=TJOB_Method.Create(TMethod(OnAccepted),@JOBCallTJSPromiseResolver); + mr:=TJOB_Method.Create(TMethod(OnRejected),@JOBCallTJSPromiseResolver); + try + Result:=InvokeJSObjectResult('then',[ma,mr],TJSPromise) as IJSPromise; + finally + mr.Free; + ma.Free; + end; +end; + +function TJSPromise.catch(const OnRejected: TJSPromiseResolver): IJSPromise; +var + m: TJOB_Method; +begin + m:=TJOB_Method.Create(TMethod(OnRejected),@JOBCallTJSPromiseResolver); + try + Result:=InvokeJSObjectResult('catch',[m],TJSPromise) as IJSPromise; + finally + m.Free; + end; +end; + +function TJSPromise._finally(const Handler: TJSPromiseFinallyHandler + ): IJSPromise; +var + m: TJOB_Method; +begin + m:=TJOB_Method.Create(TMethod(Handler),@JOBCallTJSPromiseFinallyHandler); + try + Result:=InvokeJSObjectResult('finally',[m],TJSPromise) as IJSPromise; + finally + m.Free; + end; +end; + +class function TJSPromise.Cast(const Intf: IJSObject): IJSPromise; +begin + Result:=TJSPromise.Cast(Intf); +end; + +{ TJSError } + +class function TJSError.Cast(const Intf: IJSObject): IJSError; +begin + Result:=TJSError.Cast(Intf); +end; + +{ TJSJSON } + +function TJSJSON.parse(const aJSON: UnicodeString): TJOB_JSValue; +begin + Result:=InvokeJSValueResult('parse',[aJSON]); +end; + +function TJSJSON.parseObject(const aJSON: UnicodeString): IJSObject; +begin + Result:=InvokeJSObjectResult('parse',[aJSON],TJSObject) as IJSObject; +end; + +function TJSJSON.stringify(aValue: TJOB_JSValue): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('stringify',[aValue]); +end; + +function TJSJSON.stringify(aValue, aReplacer: TJOB_JSValue): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('stringify',[aValue,aReplacer]); +end; + +function TJSJSON.stringify(aValue, aReplacer: TJOB_JSValue; space: NativeInt + ): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('stringify',[aValue,aReplacer,space]); +end; + +function TJSJSON.stringify(aValue, aReplacer: TJOB_JSValue; + const space: UnicodeString): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('stringify',[aValue,aReplacer,space]); +end; + +class function TJSJSON.Cast(const Intf: IJSObject): IJSJSON; +begin + Result:=TJSJSON.Cast(Intf); +end; + +{ TJSDataView } + +class function TJSDataView.Cast(const Intf: IJSObject): IJSDataView; +begin + Result:=TJSDataView.Cast(Intf); +end; + +{ TJSBufferSource } + +class function TJSBufferSource.Cast(const Intf: IJSObject): IJSBufferSource; +begin + Result:=TJSBufferSource.Cast(Intf); +end; + +{ TJSFloat64Array } + +class function TJSFloat64Array.Cast(const Intf: IJSObject): IJSFloat64Array; +begin + Result:=TJSFloat64Array.Cast(Intf); +end; + +{ TJSFloat32Array } + +class function TJSFloat32Array.Cast(const Intf: IJSObject): IJSFloat32Array; +begin + Result:=TJSFloat32Array.Cast(Intf); +end; + +{ TJSUint32Array } + +class function TJSUint32Array.Cast(const Intf: IJSObject): IJSUint32Array; +begin + Result:=TJSUint32Array.Cast(Intf); +end; + +{ TJSInt32Array } + +class function TJSInt32Array.Cast(const Intf: IJSObject): IJSInt32Array; +begin + Result:=TJSInt32Array.Cast(Intf); +end; + +{ TJSUint16Array } + +class function TJSUint16Array.Cast(const Intf: IJSObject): IJSUint16Array; +begin + Result:=TJSUint16Array.Cast(Intf); +end; + +{ TJSInt16Array } + +class function TJSInt16Array.Cast(const Intf: IJSObject): IJSInt16Array; +begin + Result:=TJSInt16Array.Cast(Intf); +end; + +{ TJSUint8ClampedArray } + +class function TJSUint8ClampedArray.Cast(const Intf: IJSObject + ): IJSUint8ClampedArray; +begin + Result:=TJSUint8ClampedArray.Cast(Intf); +end; + +{ TJSUInt8Array } + +class function TJSUint8Array.Cast(const Intf: IJSObject): IJSUint8Array; +begin + Result:=TJSUInt8Array.Cast(Intf); +end; + +{ TJSInt8Array } + +class function TJSInt8Array.Cast(const Intf: IJSObject): IJSInt8Array; +begin + Result:=TJSInt8Array.Cast(Intf); +end; + +{ TJSTypedArray } + +class function TJSTypedArray.Cast(const Intf: IJSObject): IJSTypedArray; +begin + Result:=TJSTypedArray.Cast(Intf); +end; + +{ TJSArrayBuffer } + +class function TJSArrayBuffer.Cast(const Intf: IJSObject): IJSArrayBuffer; +begin + Result:=TJSArrayBuffer.Cast(Intf); +end; + +{ TJSArrayBufferView } + +class function TJSArrayBufferView.Cast(const Intf: IJSObject): IJSArrayBufferView; +begin + Result:=TJSArrayBufferView.JOBCast(Intf); +end; + + + + +{ TJSArray } + +function TJSArray._GetElements(Index: NativeInt): TJOB_JSValue; +begin + Result:=InvokeJSValueResult(IntToStr(Index),[],jiGet); +end; + +function TJSArray._GetLength: NativeInt; +begin + Result:=ReadJSPropertyLongInt('length'); +end; + +procedure TJSArray._SetElements(Index: NativeInt; const AValue: TJOB_JSValue); +begin + InvokeJSNoResult(IntToStr(Index),[AValue],jiSet); +end; + +procedure TJSArray._SetLength(const AValue: NativeInt); +begin + WriteJSPropertyLongInt('length',AValue); +end; + +function TJSArray.isArray(a: TJOB_JSValue): Boolean; +begin + Result:=InvokeJSBooleanResult('isArray',[a]); +end; + +function TJSArray.concat(el: TJOB_JSValue): IJSArray; +begin + Result:=InvokeJSObjectResult('isArray',[el],TJSArray) as IJSArray; +end; + +function TJSArray.fill(aValue: TJOB_JSValue): IJSArray; +begin + Result:=InvokeJSObjectResult('fill',[aValue],TJSArray) as IJSArray; +end; + +function TJSArray.fill(aValue: TJOB_JSValue; aStartIndex: NativeInt): IJSArray; +begin + Result:=InvokeJSObjectResult('fill',[aValue,aStartIndex],TJSArray) as IJSArray; +end; + +function TJSArray.fill(aValue: TJOB_JSValue; aStartIndex, aEndIndex: NativeInt + ): IJSArray; +begin + Result:=InvokeJSObjectResult('fill',[aValue,aStartIndex,aEndIndex],TJSArray) as IJSArray; +end; + +function TJSArray.includes(aElement: TJOB_JSValue): Boolean; +begin + Result:=InvokeJSBooleanResult('includes',[aElement]); +end; + +function TJSArray.includes(aElement: TJOB_JSValue; FromIndex: NativeInt + ): Boolean; +begin + Result:=InvokeJSBooleanResult('includes',[aElement,FromIndex]); +end; + +function TJSArray.indexOf(aElement: TJOB_JSValue): NativeInt; +begin + Result:=InvokeJSMaxIntResult('indexOf',[aElement]); +end; + +function TJSArray.indexOf(aElement: TJOB_JSValue; FromIndex: NativeInt + ): NativeInt; +begin + Result:=InvokeJSMaxIntResult('indexOf',[aElement,FromIndex]); +end; + +function TJSArray.join: UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('join',[]); +end; + +function TJSArray.join(const aSeparator: UnicodeString): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('join',[aSeparator]); +end; + +function TJSArray.lastIndexOf(aElement: TJOB_JSValue): NativeInt; +begin + Result:=InvokeJSMaxIntResult('lastIndexOf',[aElement]); +end; + +function TJSArray.lastIndexOf(aElement: TJOB_JSValue; FromIndex: NativeInt + ): NativeInt; +begin + Result:=InvokeJSMaxIntResult('lastIndexOf',[aElement,FromIndex]); +end; + +function TJSArray.pop: TJOB_JSValue; +begin + Result:=InvokeJSValueResult('pop',[]); +end; + +function TJSArray.push(aElement: TJOB_JSValue): NativeInt; +begin + Result:=InvokeJSMaxIntResult('push',[aElement]); +end; + +function TJSArray.reverse: IJSArray; +begin + Result:=InvokeJSObjectResult('reverse',[],TJSArray) as IJSArray; +end; + +function TJSArray.shift: TJOB_JSValue; +begin + Result:=InvokeJSValueResult('shift',[]); +end; + +function TJSArray.slice: IJSArray; +begin + Result:=InvokeJSObjectResult('slice',[],TJSArray) as IJSArray; +end; + +function TJSArray.slice(aBegin: NativeInt): IJSArray; +begin + Result:=InvokeJSObjectResult('slice',[aBegin],TJSArray) as IJSArray; +end; + +function TJSArray.slice(aBegin, aEnd: NativeInt): IJSArray; +begin + Result:=InvokeJSObjectResult('slice',[aBegin,aEnd],TJSArray) as IJSArray; +end; + +function TJSArray.sort(): IJSArray; +begin + Result:=InvokeJSObjectResult('sort',[],TJSArray) as IJSArray; +end; + +function TJSArray.splice(aStart: NativeInt): IJSArray; +begin + Result:=InvokeJSObjectResult('splice',[aStart],TJSArray) as IJSArray; +end; + +function TJSArray.splice(aStart, aDeleteCount: NativeInt): IJSArray; +begin + Result:=InvokeJSObjectResult('splice',[aStart,aDeleteCount],TJSArray) as IJSArray; +end; + +function TJSArray.toLocaleString(const locales: UnicodeString): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('toLocaleString',[locales]); +end; + +function TJSArray.unshift: NativeInt; +begin + Result:=InvokeJSMaxIntResult('unshift',[]); +end; + +class function TJSArray.Cast(const Intf: IJSObject): IJSArray; +begin + Result:=TJSArray.Cast(Intf); +end; + +{ TJSString } + +class function TJSString.Cast(const Intf: IJSObject): IJSString; +begin + Result:=TJSString.Cast(Intf); +end; + +{ TJSRegExp } + +function TJSRegExp.exec(const aString: UnicodeString): IJSArray; +begin + Result:=InvokeJSObjectResult('exec',[aString],TJSArray) as IJSArray; +end; + +function TJSRegExp._GetGlobal: Boolean; +begin + Result:=ReadJSPropertyBoolean('global'); +end; + +function TJSRegExp._GetIgnoreCase: Boolean; +begin + Result:=ReadJSPropertyBoolean('ignoreCase'); +end; + +function TJSRegExp._GetLastIndex: NativeInt; +begin + Result:=ReadJSPropertyLongInt('lastIndex'); +end; + +function TJSRegExp._GetMultiLine: Boolean; +begin + Result:=ReadJSPropertyBoolean('multiline'); +end; + +function TJSRegExp._GetSource: UnicodeString; +begin + Result:=ReadJSPropertyUnicodeString('source'); +end; + +function TJSRegExp._GetUnicode: boolean; +begin + Result:=ReadJSPropertyBoolean('unicode'); +end; + +procedure TJSRegExp._SetGlobal(const AValue: Boolean); +begin + WriteJSPropertyBoolean('global',AValue); +end; + +procedure TJSRegExp._SetIgnoreCase(const AValue: Boolean); +begin + WriteJSPropertyBoolean('ignoreCase',AValue); +end; + +procedure TJSRegExp._SetlastIndex(const AValue: NativeInt); +begin + WriteJSPropertyLongInt('lastIndex',AValue); +end; + +procedure TJSRegExp._SetMultiline(const AValue: Boolean); +begin + WriteJSPropertyBoolean('multiline',AValue); +end; + +procedure TJSRegExp._SetSource(const AValue: UnicodeString); +begin + WriteJSPropertyUnicodeString('source',AValue); +end; + +procedure TJSRegExp._SetUnicode(const AValue: boolean); +begin + WriteJSPropertyBoolean('unicode',AValue); +end; + +function TJSRegExp.test(const aString: UnicodeString): boolean; +begin + Result:=InvokeJSBooleanResult('test',[aString]); +end; + +class function TJSRegExp.Cast(const Intf: IJSObject): IJSRegExp; +begin + Result:=TJSRegExp.Cast(Intf); +end; + +{ TJSFunction } + +function TJSFunction._GetLength: NativeInt; +begin + Result:=ReadJSPropertyLongInt('length'); +end; + +function TJSFunction._GetName: UnicodeString; +begin + Result:=ReadJSPropertyUnicodeString('name'); +end; + +function TJSFunction._GetPrototyp: IJSFunction; +begin + Result:=ReadJSPropertyObject('prototyp',TJSFunction) as IJSFunction; +end; + +procedure TJSFunction._SetName(const AValue: UnicodeString); +begin + WriteJSPropertyUnicodeString('length',AValue); +end; + +class function TJSFunction.Cast(const Intf: IJSObject): IJSFunction; +begin + Result:=TJSFunction.Cast(Intf); +end; + +{ TJSMap } + +class function TJSMap.Cast(const Intf: IJSObject): IJSMap; +begin + Result:=TJSMap.Cast(Intf); +end; + +{ TJSSet } + +class function TJSSet.Cast(const Intf: IJSObject): IJSSet; +begin + Result:=TJSSet.Cast(Intf); +end; + +{ TJOBCallbackHelper } + +procedure TJOBCallbackHelper.Init(Args: PByte); +begin + p:=Args; + Index:=0; + if p<>nil then + begin + Count:=p^; + inc(p); + end else + Count:=0; +end; + +function TJOBCallbackHelper.GetType: byte; +begin + if Index=Count then + Result:=JOBArgUndefined + else + Result:=p^; +end; + +procedure TJOBCallbackHelper.Skip; +var + Len: LongWord; +begin + if Index=Count then exit; + case p^ of + JOBArgUndefined, + JOBArgTrue, + JOBArgFalse, + JOBArgNil: inc(p); + JOBArgDouble: inc(p,9); + JOBArgUnicodeString: + begin + inc(p); + Len:=PLongWord(p)^; + inc(p,4+2*Len); + end + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetBoolean: boolean; +begin + Result:=false; + if Index=Count then + exit; + case p^ of + JOBArgUndefined: ; + JOBArgTrue: Result:=true; + JOBArgFalse: ; + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(p); + inc(Index); +end; + +function TJOBCallbackHelper.GetDouble: double; +begin + Result:=NaN; + if Index=Count then + exit; + case p^ of + JOBArgUndefined: + inc(p); + JOBArgDouble: + begin + inc(p); + Result:=PDouble(p)^; + inc(p,8); + end + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetString: UnicodeString; +var + Len: LongWord; +begin + Result:=''; + if Index=Count then + exit; + case p^ of + JOBArgUndefined: + inc(p); + JOBArgUnicodeString: + begin + inc(p); + Len:=PLongWord(p)^; + inc(p,4); + if Len>0 then + begin + SetLength(Result,Len); + Move(p^,Result[1],2*Len); + inc(p,2*Len); + end; + end + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetObject(aResultClass: TJSObjectClass): TJSObject; +var + ObjId: LongWord; +begin + //writeln('TJOBCallbackHelper.GetObject ',Index,' Count=',Count); + Result:=nil; + if Index=Count then + exit; + //writeln('TJOBCallbackHelper.GetObject type=',p^); + case p^ of + JOBArgUndefined, + JOBArgNil: + inc(p); + JOBArgObject: + begin + inc(p); + ObjId:=PLongWord(p)^; + inc(p,4); + Result:=aResultClass.JOBCreateFromID(ObjId); + Result.JOBObjectIDOwner:=false; // owned by caller (JS code in browser) + end + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetArray: TJSArray; +var + ObjId: LongWord; +begin + //writeln('TJOBCallbackHelper.GetObject ',Index,' Count=',Count); + Result:=nil; + if Index=Count then + exit; + //writeln('TJOBCallbackHelper.GetObject type=',p^); + case p^ of + JOBArgUndefined, + JOBArgNil: + inc(p); + JOBArgObject: + begin + inc(p); + ObjId:=PLongWord(p)^; + inc(p,4); + Result:=TJSArray.JOBCreateFromID(ObjId); + Result.JOBObjectIDOwner:=false; // owned by caller (JS code in browser) + end + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetValue: TJOB_JSValue; +var + ObjId, Len: LongWord; + Obj: TJSObject; + S: UnicodeString; +begin + Result:=nil; + if (Index=Count) or (p^=JOBArgUndefined) then + begin + Result:=TJOB_JSValue.Create(jjvkUndefined); + exit; + end; + case p^ of + JOBArgTrue: + begin + Result:=TJOB_Boolean.Create(true); + inc(p); + end; + JOBArgFalse: + begin + Result:=TJOB_Boolean.Create(false); + inc(p); + end; + JOBArgDouble: + begin + inc(p); + Result:=TJOB_Double.Create(PDouble(p)^); + inc(p,8); + end; + JOBArgUnicodeString: + begin + inc(p); + Len:=PLongWord(p)^; + inc(p,4); + S:=''; + if Len>0 then + begin + SetLength(S,Len); + Move(p^,S[1],2*Len); + inc(p,2*Len); + end; + Result:=TJOB_String.Create(S); + end; + JOBArgNil: + begin + Result:=TJOB_Object.Create(nil); + inc(p); + end; + JOBArgObject: + begin + inc(p); + ObjId:=PLongWord(p)^; + inc(p,4); + Obj:=TJSObject.JOBCreateFromID(ObjId); + Result:=TJOB_Object.Create(Obj); + end; + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetVariant: Variant; +var + ObjId, Len: LongWord; + Obj: TJSObject; + S: UnicodeString; +begin + if Index=Count then + begin + Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Variants.Unassigned; + exit; + end; + case p^ of + JOBArgUndefined: + begin + Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Variants.Unassigned; + inc(p); + end; + JOBArgTrue: + begin + Result:=true; + inc(p); + end; + JOBArgFalse: + begin + Result:=false; + inc(p); + end; + JOBArgDouble: + begin + inc(p); + Result:=PDouble(p)^; + inc(p,8); + end; + JOBArgUnicodeString: + begin + inc(p); + Len:=PLongWord(p)^; + inc(p,4); + S:=''; + if Len>0 then + begin + SetLength(S,Len); + Move(p^,S[1],2*Len); + inc(p,2*Len); + end; + Result:=S; + end; + JOBArgNil: + begin + Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Variants.Null; + inc(p); + end; + JOBArgObject: + begin + inc(p); + ObjId:=PLongWord(p)^; + inc(p,4); + Obj:=TJSObject.JOBCreateFromID(ObjId); + Obj.JOBObjectIDOwner:=false; + Result:=Obj as IJSObject; + end; + else + raise EJSArgParse.Create(JOBArgNames[p^]); + end; + inc(Index); +end; + +function TJOBCallbackHelper.GetLongInt: longint; +var + d: Double; +begin + d:=GetDouble; + if (Frac(d)<>0) or (dhigh(longint)) then + raise EJSArgParse.Create('expected longint, but got double') + else + Result:=Trunc(d); +end; + +function TJOBCallbackHelper.GetMaxInt: int64; +var + d: Double; +begin + d:=GetDouble; + if (Frac(d)<>0) or (dhigh(int64)) then + raise EJSArgParse.Create('expected int64, but got double') + else + Result:=Trunc(d); +end; + +function TJOBCallbackHelper.AllocUndefined: PByte; +begin + GetMem(Result,1); + Result^:=JOBArgUndefined; +end; + +function TJOBCallbackHelper.AllocBool(b: boolean): PByte; +begin + GetMem(Result,1); + if b then + Result^:=JOBArgTrue + else + Result^:=JOBArgFalse; +end; + +function TJOBCallbackHelper.AllocLongint(i: longint): PByte; +begin + GetMem(Result,5); + Result^:=JOBArgLongint; + PLongint(Result+1)^:=i; +end; + +function TJOBCallbackHelper.AllocDouble(const d: double): PByte; +begin + GetMem(Result,9); + Result^:=JOBArgDouble; + PDouble(Result+1)^:=d; +end; + +function TJOBCallbackHelper.AllocString(const s: UnicodeString): PByte; +var + l: SizeInt; +begin + l:=length(s); + GetMem(Result,5+2*l); + Result^:=JOBArgUnicodeString; + PLongWord(Result+1)^:=l; + if l>0 then + Move(s[1],Result[5],2*l); +end; + +function TJOBCallbackHelper.AllocNil: PByte; +begin + GetMem(Result,1); + Result^:=JOBArgNil; +end; + +function TJOBCallbackHelper.AllocIntf(const Intf: IJSObject): PByte; +begin + if Intf=nil then + Result:=AllocNil + else + Result:=AllocObjId(Intf.GetJSObjectID); +end; + +function TJOBCallbackHelper.AllocObject(Obj: TJSObject): PByte; +begin + if Obj=nil then + Result:=AllocNil + else + Result:=AllocObjId(Obj.JOBObjectID); +end; + +function TJOBCallbackHelper.AllocObjId(ObjId: TJOBObjectID): PByte; +begin + //writeln('TJOBCallbackHelper.AllocObjId ObjID=',ObjId); + GetMem(Result,1+SizeOf(TJOBObjectID)); + Result^:=JOBArgObject; + PJOBObjectID(Result+1)^:=ObjId; +end; + +function TJOBCallbackHelper.AllocJSValue(const Value: TJOB_JSValue): PByte; +begin + if Value=nil then + exit(AllocUndefined); + case Value.Kind of + jjvkUndefined: Result:=AllocUndefined; + jjvkBoolean: Result:=AllocBool(TJOB_Boolean(Value).Value); + jjvkDouble: Result:=AllocDouble(TJOB_Double(Value).Value); + jjvkString: Result:=AllocString(TJOB_String(Value).Value); + jjvkObject: Result:=AllocIntf(TJOB_Object(Value).Value); + else + raise EJSArgParse.Create('AllocJSValue unsupported: '+JOB_JSValueKindNames[Value.Kind]); + end; +end; + +function TJOBCallbackHelper.AllocVariant(const Value: Variant): PByte; +var + t: tvartype; + Intf: IJSObject; +begin + t:=VarType(Value); + case t of + varEmpty: + Result:=AllocUndefined; + varNull: + Result:=AllocNil; + varSmallInt,varInteger,varByte,varWord,varShortInt: + Result:=AllocLongint(Value); + varLongWord,varCurrency,varInt64,varQWord,varSingle,varDouble,varDate: + Result:=AllocDouble(Value); + varOleStr,varString: + Result:=AllocString(Value); + varBoolean: + Result:=AllocBool(Value); + varUnknown: + begin + if tvardata(Value).vunknown=nil then + Result:=AllocNil + else if VarSupports(Value,IJSObject,Intf) then + Result:=AllocIntf(Intf) + else + raise EJSInvoke.Create('TJOBCallbackHelper.AllocVariant: [20220822103744] unsupported variant: '+IntToStr(t)); + end + else + raise EJSInvoke.Create('TJOBCallbackHelper.AllocVariant: [20220822103751] unsupported variant: '+IntToStr(t)); + end; +end; + +{ TJOB_JSValue } + +constructor TJOB_JSValue.Create(aKind: TJOB_JSValueKind); +begin + Kind:=aKind; +end; + +function TJOB_JSValue.AsString: string; +begin + if Kind=jjvkUndefined then + Result:='undefined' + else begin + Result:=''; + str(Kind,Result); + end; +end; + +{ TJOB_Boolean } + +constructor TJOB_Boolean.Create(aValue: Boolean); +begin + Kind:=jjvkBoolean; + Value:=aValue; +end; + +function TJOB_Boolean.AsString: string; +begin + str(Value,Result); +end; + +{ TJOB_Double } + +constructor TJOB_Double.Create(const aValue: Double); +begin + Kind:=jjvkDouble; + Value:=aValue; +end; + +function TJOB_Double.AsString: string; +begin + str(Value,Result); +end; + +{ TJOB_String } + +constructor TJOB_String.Create(const aValue: UnicodeString); +begin + Kind:=jjvkString; + Value:=aValue; +end; + +function TJOB_String.AsString: string; +begin + Result:=AnsiQuotedStr(String(Value),'"'); +end; + +{ TJOB_Object } + +constructor TJOB_Object.Create(aValue: IJSObject); +begin + Kind:=jjvkObject; + Value:=aValue; +end; + +function TJOB_Object.AsString: string; +begin + if Value=nil then + Result:='nil' + else + Result:='['+IntToStr(Value.GetJSObjectID)+']:'+Value.GetPascalClassName; +end; + +{ TJOB_Method } + +constructor TJOB_Method.Create(const aMethod: TMethod; + const AnInvoke: TJOBCallback); +begin + Kind:=jjvkMethod; + Value:=aMethod; + Invoke:=AnInvoke; +end; + +function TJOB_Method.AsString: string; +begin + Result:='Callback'; +end; + +{ TJOB_Dictionary } + +procedure TJOB_Dictionary.Add(const aName: UnicodeString; + const aValue: TJOB_JSValue); +var + p: TJOB_Pair; +begin + p.Name:=aName; + p.Value:=aValue; + Insert(p,Values,length(Values)); +end; + +constructor TJOB_Dictionary.Create(const Pairs: array of const); +var + i: Integer; + l, CurLen: SizeInt; + CurName: UnicodeString; +begin + inherited Create(jjvkDictionary); + l:=length(Pairs); + SetLength(Values,l div 2); + for i:=0 to length(Values)-1 do + Values[i].Value:=nil; + i:=0; + while inil then + FreeMem(InvokeArgs); + end; + end; +end; + +function TJSObject.InvokeJSOneResult(const aName: string; + const Args: array of const; const InvokeFunc: TJOBInvokeOneResultFunc; + ResultP: PByte; Invoke: TJOBInvokeType): TJOBResult; +var + InvokeArgs: PByte; +begin + if length(Args)=0 then + Result:=InvokeFunc(JOBObjectID,PChar(aName),length(aName),InvokeGetToInt[Invoke],nil,ResultP) + else begin + InvokeArgs:=CreateInvokeJSArgs(Args); + try + Result:=InvokeFunc(JOBObjectID,PChar(aName),length(aName),InvokeGetToInt[Invoke],InvokeArgs,ResultP); + finally + if InvokeArgs<>nil then + FreeMem(InvokeArgs); + end; + end; +end; + +procedure TJSObject.InvokeJS_Raise(const aName, Msg: string); +var + E: EJSInvoke; +begin + E:=EJSInvoke.Create(Msg); + E.ObjectID:=JOBObjectID; + E.FuncName:=aName; + raise E; +end; + +procedure TJSObject.InvokeJS_RaiseResultMismatch(const aName: string; + Expected, Actual: TJOBResult); +begin + case Actual of + JOBResult_UnknownObjId: InvokeJS_Raise(aName,'unknown object id '+IntToStr(JOBObjectID)); + JOBResult_NotAFunction: InvokeJS_Raise(aName,'object '+IntToStr(JOBObjectID)+' does not have a function "'+aName+'"'); + else + InvokeJS_RaiseResultMismatchStr(aName,JOBResult_Names[Expected],JOBResult_Names[Actual]); + end; +end; + +procedure TJSObject.InvokeJS_RaiseResultMismatchStr(const aName: string; + const Expected, Actual: string); +begin + InvokeJS_Raise(aName,'expected '+Expected+', but got '+Actual+' from object '+IntToStr(JOBObjectID)+' function "'+aName+'"'); +end; + +function TJSObject.CreateInvokeJSArgs(const Args: array of const): PByte; + + procedure RaiseNotSupported(const Msg: string); + begin + raise EJSInvoke.Create('Invoke js: type not supported '+Msg); + end; + + procedure RaiseRange; + begin + raise ERangeError.Create('Invoke js: number out of bounds'); + end; + +var + p: PByte; + Len: NativeInt; + + function SizeOfTJOB_JSValue(JSValue: TJOB_JSValue): integer; + var + Dict: TJOB_PairArray; + i: Integer; + Arr: TJOB_JSValueArray; + begin + case JSValue.Kind of + jjvkUndefined: Result:=1; + jjvkBoolean: Result:=1; + jjvkDouble: Result:=9; + jjvkString: Result:=1+SizeOf(NativeInt)+SizeOf(PByte); + jjvkObject: + if TJOB_Object(JSValue).Value=nil then + Result:=1 + else + Result:=1+SizeOf(TJOBObjectID); + jjvkMethod: Result:=1+3*SizeOf(PByte); + jjvkDictionary: + begin + Result:=1+SizeOf(NativeInt); + Dict:=TJOB_Dictionary(JSValue).Values; + for i:=0 to length(Dict)-1 do + begin + inc(Result,1+SizeOf(NativeInt)+SizeOf(PByte)); + inc(Result,SizeOfTJOB_JSValue(Dict[i].Value)); + end; + end; + jjvkArrayOfJSValue: + begin + Result:=1+SizeOf(NativeInt); + Arr:=TJOB_ArrayOfJSValue(JSValue).Values; + for i:=0 to length(Arr)-1 do + inc(Result,SizeOfTJOB_JSValue(Dict[i].Value)); + end; + jjvkArrayOfDouble: + Result:=1+SizeOf(NativeInt)+SizeOf(PByte); + else + RaiseNotSupported('20220630135718'){%H-}; + end; + end; + + procedure Grow(Need: NativeInt); + begin + inc(Need,p-Result); + if Need<=Len then exit; + Len:=Len*2; + if Len255 then + raise EJSInvoke.Create('Invoke js: too many args'); + + Len:=1+length(Args); + Result:=GetMem(Len); + ok:=false; + try + p:=Result; + + p^:=length(Args); + inc(p); + for i:=0 to high(Args) do + begin + case Args[i].VType of + vtInteger: + AddLongInt(Args[i].VInteger); + vtBoolean: + AddBoolean(Args[i].VBoolean); + vtExtended: + AddDouble(double(Args[i].VExtended^)); + vtChar: + AddChar(ord(Args[i].VChar)); + vtWideChar: + AddChar(ord(Args[i].VWideChar)); + vtString: + begin + // shortstring + h:=PByte(Args[i].VString); + AddUTF8String(h+1,h^); + end; + vtPointer: + begin + h:=Args[i].VPointer; + if h=nil then + Prep(1,JOBArgNil) + else if h=JOB_Undefined then + Prep(1,JOBArgUndefined) + else begin + Prep(1+SizeOf(Pointer),JOBArgPointer); + PPointer(p)^:=h; + inc(p,sizeof(Pointer)); + end; + end; + vtPChar: + begin + h:=PByte(Args[i].VPChar); + AddUTF8String(h,strlen(PChar(h))); + end; + vtObject: + begin + Obj:=Args[i].VObject; + if Obj=nil then + Prep(1,JOBArgNil) + else if Obj is TJSObject then + AddObjectID(TJSObject(Obj).JOBObjectID) + else if Obj is TJOB_JSValue then + begin + JSValue:=TJOB_JSValue(Obj); + Add_TJOB_JSValue(JSValue); + end else + RaiseNotSupported(Obj.ClassName); + end; + vtClass: ; + vtPWideChar: + begin + h:=PByte(Args[i].VPWideChar); + AddUnicodeString(h,strlen(PWideChar(h))); + end; + vtAnsiString: + begin + h:=Args[i].VAnsiString; + s:=AnsiString(h); + AddUTF8String(h,length(s)); + end; + vtCurrency: + AddDouble(double(Args[i].VCurrency^)); + vtVariant: + AddVariant(i); + vtInterface: + begin + h:=Args[i].VInterface; + AddIJSObject(IJSObject(h)); + end; + vtWideString: + begin + h:=Args[i].VWideString; + ws:=WideString(h); + AddUnicodeString(h,length(ws)); + end; + vtInt64: + begin + i64:=Args[i].VInt64^; + if (i64>=low(longint)) and (i64<=high(longint)) then + AddLongInt(i64) + else + AddDouble(i64); + end; + vtUnicodeString: + begin + h:=Args[i].VUnicodeString; + us:=UnicodeString(h); + AddUnicodeString(h,length(us)); + end; + vtQWord: + begin + qw:=Args[i].VQWord^; + if (qw<=high(longint)) then + AddLongInt(qw) + else + AddDouble(qw); + end; + else + RaiseNotSupported(IntToStr(Args[i].VType)); + end; + end; + Len:=p-Result; + ReAllocMem(Result,Len); + ok:=true; + finally + if not ok then + FreeMemAndNil(Result); + end; + + {$IFDEF VerboseInvokeJSArgs} + s:='TJSObject.CreateInvokeJSArgs ArgCnt='+IntToStr(length(Args)); + for i:=0 to high(Args) do + s:=s+' '+GetVarRecName(Args[i].VType); + s:=s+' Len='+IntToStr(Len); + s:=s+' Bytes='; + for i:=0 to Len-1 do + s:=s+HexStr(Result[i],2); + writeln(s); + {$ENDIF} +end; + +constructor TJSObject.JOBCast(const Intf: IJSObject); +begin + FJOBObjectID:=Intf.GetJSObjectID; + FJOBCastSrc:=Intf.GetJSObjectCastSrc; + if FJOBCastSrc=nil then + FJOBCastSrc:=Intf; +end; + +constructor TJSObject.JOBCreateFromID(aID: TJOBObjectID); +begin + FJOBObjectID:=aID; + FJOBObjectIDOwner:=true; +end; + +constructor TJSObject.JOBCreateGlobal(const aID: UnicodeString); +begin + FJOBObjectID:=__job_get_global(PWideChar(aID),length(aID)); + if FJOBObjectID=0 then + raise EJSObject.Create('JS object "'+String(aID)+'" is not registered'); + FJOBObjectIDOwner:=true; +end; + +class function TJSObject.Cast(const Intf: IJSObject): IJSObject; +begin + Result:=JOBCast(Intf); +end; + +destructor TJSObject.Destroy; +begin + if FJOBCastSrc<>nil then + FJOBCastSrc:=nil + else if (JOBObjectID>=0) and JOBObjectIDOwner then + __job_release_object(JOBObjectID); + FJOBObjectID:=0; + inherited Destroy; +end; + +procedure TJSObject.InvokeJSNoResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType); +var + aError: TJOBResult; +begin + aError:=InvokeJSNoResultFunc(aName,Args,@__job_invoke_noresult,Invoke); + if aError<>JOBResult_Success then + InvokeJS_RaiseResultMismatch(aName,JOBResult_Success,aError); +end; + +function TJSObject.InvokeJSBooleanResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType): Boolean; +var + aError: TJOBResult; + b: bytebool; +begin + b:=false; + aError:=InvokeJSOneResult(aName,Args,@__job_invoke_boolresult,@b,Invoke); + if aError=JOBResult_Boolean then + else if aError=JOBResult_Undefined then + b:=false + else + InvokeJS_RaiseResultMismatch(aName,JOBResult_Boolean,aError); + Result:=b; +end; + +function TJSObject.InvokeJSDoubleResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType): Double; +var + aError: TJOBResult; +begin + Result:=NaN; + aError:=InvokeJSOneResult(aName,Args,@__job_invoke_doubleresult,@Result,Invoke); + if aError=JOBResult_Double then + else if aError=JOBResult_Undefined then + Result:=NaN + else + InvokeJS_RaiseResultMismatch(aName,JOBResult_Double,aError); +end; + +function TJSObject.InvokeJSUnicodeStringResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType): UnicodeString; +var + ResultLen: NativeInt; + aError: TJOBResult; +begin + ResultLen:=0; + aError:=InvokeJSOneResult(aName,Args,@__job_invoke_stringresult,@ResultLen,Invoke); + if aError=JOBResult_String then + Result:=FetchString(ResultLen) + else begin + Result:=''; + if aError<>JOBResult_Undefined then + InvokeJS_RaiseResultMismatch(aName,JOBResult_String,aError); + end; + //writeln('TJSObject.InvokeJSUnicodeStringResult Result="',Result,'"'); +end; + +function TJSObject.InvokeJSObjectResult(const aName: string; + const Args: array of const; aResultClass: TJSObjectClass; + Invoke: TJOBInvokeType): TJSObject; +var + aError: TJOBResult; + NewObjId: TJOBObjectID; +begin + Result:=nil; + NewObjId:=-1; + aError:=InvokeJSOneResult(aName,Args,@__job_invoke_objectresult,@NewObjId,Invoke); + if (aError=JOBResult_Null) or (aError=JOBResult_Undefined) then + exit; + if aError<>JOBResult_Object then + InvokeJS_RaiseResultMismatch(aName,JOBResult_Object,aError); + + Result:=aResultClass.JOBCreateFromID(NewObjId); +end; + +function TJSObject.InvokeJSValueResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType): TJOB_JSValue; +var + Buf: array[0..7] of byte; + p: PByte; + aError: TJOBResult; + Obj: TJSObject; +begin + Result:=nil; + FillByte(Buf[0],length(Buf),0); + p:=@Buf[0]; + aError:=InvokeJSOneResult(aName,Args,@__job_invoke_jsvalueresult,p,Invoke); + case aError of + JOBResult_Undefined: + Result:=TJOB_JSValue.Create(jjvkUndefined); + JOBResult_Null: + Result:=TJOB_Object.Create(nil); + JOBResult_Boolean: + Result:=TJOB_Boolean.Create(p^<>0); + JOBResult_Double: + Result:=TJOB_Double.Create(PDouble(p)^); + JOBResult_String: + Result:=TJOB_String.Create(FetchString(PNativeInt(p)^)); + JOBResult_Function, + JOBResult_Object: + begin + Obj:=TJSObject.JOBCreateFromID(PJOBObjectID(p)^); + Result:=TJOB_Object.Create(Obj); + end; + else + InvokeJS_RaiseResultMismatchStr(aName,'jsvalue',JOBResult_Names[aError]); + end; +end; + +function TJSObject.InvokeJSVariantResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType): Variant; +var + Buf: array[0..7] of byte; + p: PByte; + r: TJOBResult; + Obj: TJSObject; +begin + FillByte(Buf[0],length(Buf),0); + p:=@Buf[0]; + r:=InvokeJSOneResult(aName,Args,@__job_invoke_jsvalueresult,p,Invoke); + case r of + JOBResult_Undefined: + Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Variants.Unassigned; + JOBResult_Null: + Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Variants.Null; + JOBResult_Boolean: + Result:=p^<>0; + JOBResult_Double: + Result:=PDouble(p)^; + JOBResult_String: + Result:=FetchString(PNativeInt(p)^); + JOBResult_Function, + JOBResult_Object: + begin + Obj:=TJSObject.JOBCreateFromID(PJOBObjectID(p)^); + Result:=Obj as IJSObject; + end; + else + VarClear(Result); + InvokeJS_RaiseResultMismatchStr(aName,'jsvalue',JOBResult_Names[r]); + end; +end; + +function TJSObject.InvokeJSUtf8StringResult(const aName: string; + const args: array of const; Invoke: TJOBInvokeType): String; +begin + Result:=UTF8Encode(InvokeJSUnicodeStringResult(aName,Args,Invoke)); +end; + +function TJSObject.InvokeJSLongIntResult(const aName: string; + const args: array of const; Invoke: TJOBInvokeType): LongInt; +var + d: Double; +begin + d:=InvokeJSDoubleResult(aName,Args,Invoke); + if (Frac(d)<>0) or (dhigh(longint)) then + InvokeJS_RaiseResultMismatchStr(aName,'longint','double') + else + Result:=Trunc(d); +end; + +function TJSObject.InvokeJSMaxIntResult(const aName: string; + const args: array of const; Invoke: TJOBInvokeType): int64; +var + d: Double; +begin + d:=InvokeJSDoubleResult(aName,Args,Invoke); + if (Frac(d)<>0) or (dhigh(int64)) then + InvokeJS_RaiseResultMismatchStr(aName,'int64','double') + else + Result:=Trunc(d); +end; + +function TJSObject.InvokeJSTypeOf(const aName: string; + const Args: array of const): TJOBResult; +begin + Result:=InvokeJSNoResultFunc(aName,Args,@__job_invoke_noresult,jiGetTypeOf); +end; + +function TJSObject.InvokeJSUnicodeStringArrayResult(const aName: string; + const Args: array of const; Invoke: TJOBInvokeType): TUnicodeStringDynArray; +var + ResultP: NativeInt; + aError: TJOBResult; +begin + ResultP:=0; + aError:=InvokeJSOneResult(aName,Args,@__job_invoke_arraystringresult,@ResultP,Invoke); + if aError=JOBResult_ArrayOfString then + Result:=TUnicodeStringDynArray(ResultP) + else begin + Result:=[]; + if aError<>JOBResult_Undefined then + InvokeJS_RaiseResultMismatch(aName,JOBResult_ArrayOfString,aError); + end; +end; + +function TJSObject.ReadJSPropertyBoolean(const aName: string): boolean; +begin + Result:=InvokeJSBooleanResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyDouble(const aName: string): double; +begin + Result:=InvokeJSDoubleResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyUnicodeString(const aName: string + ): UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyObject(const aName: string; + aResultClass: TJSObjectClass): TJSObject; +begin + Result:=InvokeJSObjectResult(aName,[],aResultClass,jiGet); +end; + +function TJSObject.ReadJSPropertyUtf8String(const aName: string): string; +begin + Result:=InvokeJSUtf8StringResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyLongInt(const aName: string): LongInt; +begin + Result:=InvokeJSLongIntResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyInt64(const aName: string): Int64; +begin + Result:=Trunc(InvokeJSDoubleResult(aName,[],jiGet)); +end; + +function TJSObject.ReadJSPropertyValue(const aName: string): TJOB_JSValue; +begin + Result:=InvokeJSValueResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyVariant(const aName: string): Variant; +begin + Result:=InvokeJSVariantResult(aName,[],jiGet); +end; + +function TJSObject.ReadJSPropertyMethod(const aName: string): TMethod; +begin +// Result:=InvokeJSVariantResult(aName,[],jiGet); +end; + +procedure TJSObject.WriteJSPropertyBoolean(const aName: string; Value: Boolean); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyDouble(const aName: string; Value: Double); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyUnicodeString(const aName: string; + const Value: UnicodeString); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyUtf8String(const aName: string; + const Value: String); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyObject(const aName: string; Value: IJSObject + ); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyLongInt(const aName: string; Value: LongInt); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyInt64(const aName: string; Value: Int64); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyValue(const aName: string; + Value: TJOB_JSValue); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyVariant(const aName: string; + const Value: Variant); +begin + InvokeJSNoResult(aName,[Value],jiSet); +end; + +procedure TJSObject.WriteJSPropertyMethod(const aName: string; + const Value: TMethod); +begin + // TODO InvokeJSNoResult(aName,[Value],jiSet); +end; + +function TJSObject.NewJSObject(const Args: array of const; + aResultClass: TJSObjectClass): TJSObject; +begin + Result:=InvokeJSObjectResult('',Args,aResultClass,jiNew); +end; + +function TJSObject.getOwnPropertyNames(const Obj: IJSObject + ): TUnicodeStringDynArray; +begin + Result:=JSObject.InvokeJSUnicodeStringArrayResult('getOwnPropertyNames',[Obj]); +end; + +function TJSObject.getPrototypeOf(const Obj: IJSObject): IJSObject; +begin + Result:=JSObject.InvokeJSObjectResult('getPrototypeOf',[Obj],TJSObject) as IJSObject; +end; + +function TJSObject.hasOwnProperty(const PropName: String): boolean; +begin + Result:=InvokeJSBooleanResult('hasOwnProperty',[PropName]); +end; + +function TJSObject.isPrototypeOf(const Obj: IJSObject): boolean; +begin + Result:=InvokeJSBooleanResult('isPrototypeOf',[Obj]); +end; + +function TJSObject.propertyIsEnumerable(const PropName: String): boolean; +begin + Result:=InvokeJSBooleanResult('propertyIsEnumerable',[PropName]); +end; + +function TJSObject.toLocaleString: UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('toLocaleString',[]); +end; + +function TJSObject.toString: String; +begin + Result:=InvokeJSUtf8StringResult('toString',[]); +end; + +function TJSObject.toUString: UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('toString',[]); +end; + +function TJSObject.valueOf: Variant; +begin + Result:=InvokeJSVariantResult('valueOf',[]); +end; + +{ TJSDate } + +class function TJSDate.Cast(const Intf: IJSObject): IJSDate; +begin + Result:=TJSDate.JOBCast(Intf); +end; + +function TJSDate.Create(aYear: NativeInt; aMonth: NativeInt; + aDayOfMonth: NativeInt; TheHours: NativeInt; TheMinutes: NativeInt; + TheSeconds: NativeInt; TheMilliseconds: NativeInt): IJSDate; +begin + Result:=JSDate.NewJSObject([aYear,aMonth,aDayOfMonth,TheHours,TheMinutes,TheSeconds,TheMilliseconds],TJSDate) as IJSDate; +end; + +function TJSDate.toLocaleDateString: UnicodeString; +begin + Result:=InvokeJSUnicodeStringResult('toLocaleDateString',[]); +end; + +initialization + JSObject:=TJSObject.JOBCreateGlobal('Object') as IJSObject; + JSDate:=TJSDate.JOBCreateGlobal('Date') as IJSDate; + +end. + diff --git a/packages/wasm-job/src/job.shared.pas b/packages/wasm-job/src/job.shared.pas new file mode 100644 index 0000000000..4895215b0d --- /dev/null +++ b/packages/wasm-job/src/job.shared.pas @@ -0,0 +1,120 @@ +{ + JOB - JS Object Bridge for Webassembly + + These types and constants are shared between pas2js and webassembly. +} +{$IFNDEF FPC_DOTTEDUNITS} +unit JOB.Shared; +{$ENDIF} + +interface + +type + TJOBObjectID = NativeInt; + TJOBObjectIDArray = array of TJOBObjectID; + +// invoke results +type + TJOBResult = longint; +const + JOBResult_None = 0; + JOBResult_Success = 1; + JOBResult_UnknownObjId = 2; + JOBResult_NotAFunction = 3; + JOBResult_WrongArgs = 4; + JOBResult_Undefined = 5; + JOBResult_Null = 6; + JOBResult_Boolean = 7; + JOBResult_Double = 8; + JOBResult_String = 9; + JOBResult_Function = 10; + JOBResult_Object = 11; + JOBResult_BigInt = 12; + JOBResult_Symbol = 13; + JOBResult_ArrayOfString = 14; + + JOBResultLast = 14; + + JOBResult_Names: array[0..JOBResultLast] of string = ( + 'None', + 'Success', + 'UnknownObjId', + 'NotAFunction', + 'WrongArgs', + 'Undefined', + 'Null', + 'Boolean', + 'Double', + 'String', + 'Function', + 'Object', + 'BigInt', + 'Symbol', + 'ArrayOfString' + ); + + JOBExportName = 'job'; + JOBFn_GetGlobal = 'get_registered'; + JOBFn_InvokeNoResult = 'invoke_noresult'; + JOBFn_InvokeBooleanResult = 'invoke_boolresult'; + JOBFn_InvokeDoubleResult = 'invoke_doubleresult'; + JOBFn_InvokeStringResult = 'invoke_stringresult'; + JOBFn_GetStringResult = 'get_stringresult'; + JOBFn_InvokeArrayStringResult = 'invoke_arraystringresult'; + JOBFn_ReleaseStringResult = 'release_stringresult'; + JOBFn_InvokeObjectResult = 'invoke_objectresult'; + JOBFn_ReleaseObject = 'release_object'; + JOBFn_InvokeJSValueResult = 'invoke_jsvalueresult'; + JOBFn_CallbackHandler = 'JOBCallback'; + + JOBArgUndefined = 0; + JOBArgLongint = 1; + JOBArgDouble = 2; + JOBArgTrue = 3; + JOBArgFalse = 4; + JOBArgChar = 5; // followed by a word + JOBArgString = 6; // followed by length and UTF-16 data + JOBArgUnicodeString = 7; // followed by length and pointer + JOBArgNil = 8; + JOBArgPointer = 9; + JOBArgObject = 10; // followed by ObjectID + JOBArgMethod = 11; // followed by Callback, Data, Code + JOBArgDictionary = 12; // followed by count and pairs + JOBArgArrayOfJSValue = 13; // followed by count and values + JOBArgArrayOfDouble = 14; // followed by count and pointer + + JOBArgNames: array[0..14] of string = ( + 'Undefined', + 'Longint', + 'Double', + 'True', + 'False', + 'Char', + 'UTF8String', + 'UnicodeString', + 'Nil', + 'Pointer', + 'Object', + 'Method', + 'Dictionary', + 'ArrayOfJSValue', + 'ArrayOfDouble' + ); + + JOBInvokeCall = 0; // call function + JOBInvokeGet = 1; // read property + JOBInvokeGetTypeOf = 2; // read property and typeof + JOBInvokeSet = 3; // set property + JOBInvokeNew = 4; // new operator + + JOBInvokeNames: array[0..4] of string = ( + 'Call', + 'Get', + 'GetTypeOf', + 'Set', + 'New' + ); + +implementation + +end.