system.pas 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. {
  2. This file is part of the Pas2JS run time library.
  3. Copyright (c) 2018 by Mattias Gaertner
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit System;
  11. {$mode objfpc}
  12. {$modeswitch externalclass}
  13. interface
  14. {$IFDEF NodeJS}
  15. var
  16. LineEnding: string = #10;
  17. sLineBreak: string = #10;
  18. {$ELSE}
  19. const
  20. LineEnding = #10;
  21. sLineBreak = LineEnding;
  22. {$ENDIF}
  23. Var
  24. PathDelim : Char = '/';
  25. AllowDirectorySeparators : Set of Char = ['/'];
  26. AllowDriveSeparators : Set of Char = [':'];
  27. ExtensionSeparator : Char = '.';
  28. const
  29. MaxSmallint = 32767;
  30. MinSmallint = -32768;
  31. MaxShortInt = 127;
  32. MinShortInt = -128;
  33. MaxByte = $FF;
  34. MaxWord = $FFFF;
  35. MaxLongint = $7fffffff;
  36. MaxCardinal = LongWord($ffffffff);
  37. Maxint = MaxLongint;
  38. IsMultiThread = false;
  39. {*****************************************************************************
  40. Base types
  41. *****************************************************************************}
  42. type
  43. HRESULT = Longint; // For Delphi compatibility
  44. Int8 = ShortInt;
  45. UInt8 = Byte;
  46. Int16 = SmallInt;
  47. UInt16 = Word;
  48. Int32 = Longint;
  49. UInt32 = LongWord;
  50. Integer = LongInt;
  51. Cardinal = LongWord;
  52. DWord = LongWord;
  53. SizeInt = NativeInt;
  54. SizeUInt = NativeUInt;
  55. PtrInt = NativeInt;
  56. PtrUInt = NativeUInt;
  57. ValSInt = NativeInt;
  58. ValUInt = NativeUInt;
  59. CodePointer = Pointer;
  60. ValReal = Double;
  61. Real = type Double;
  62. Extended = type Double;
  63. TDateTime = type double;
  64. TTime = type TDateTime;
  65. TDate = type TDateTime;
  66. Int64 = type NativeInt unimplemented; // only 53 bits at runtime
  67. UInt64 = type NativeUInt unimplemented; // only 52 bits at runtime
  68. QWord = type NativeUInt unimplemented; // only 52 bits at runtime
  69. Single = type Double unimplemented;
  70. Comp = type NativeInt unimplemented;
  71. NativeLargeInt = NativeInt;
  72. NativeLargeUInt = NativeUInt;
  73. WideString = type String;
  74. UnicodeChar = char;
  75. TDynArrayIndex = NativeInt;
  76. TTextLineBreakStyle = (tlbsLF,tlbsCRLF,tlbsCR);
  77. TCompareOption = ({coLingIgnoreCase, coLingIgnoreDiacritic, }coIgnoreCase{,
  78. coIgnoreKanaType, coIgnoreNonSpace, coIgnoreSymbols, coIgnoreWidth,
  79. coLingCasing, coDigitAsNumbers, coStringSort});
  80. TCompareOptions = set of TCompareOption;
  81. generic TArray<T> = array of T;
  82. {*****************************************************************************
  83. TObject, TClass, IUnknown, IInterface, TInterfacedObject
  84. *****************************************************************************}
  85. type
  86. TGuid = record
  87. D1: DWord;
  88. D2: word;
  89. D3: word;
  90. D4: array[0..7] of byte;
  91. end;
  92. TGUIDString = type string;
  93. PMethod = ^TMethod;
  94. TMethod = record
  95. Code : CodePointer;
  96. Data : Pointer;
  97. end;
  98. TClass = class of TObject;
  99. { TObject }
  100. {$DispatchField Msg} // enable checking message methods for record field name "Msg"
  101. {$DispatchStrField MsgStr}
  102. TObject = class
  103. private
  104. class var FClassName: String; external name '$classname';
  105. class var FClassParent: TClass; external name '$ancestor';
  106. class var FUnitName: String; external name '$module.$name';
  107. public
  108. constructor Create;
  109. destructor Destroy; virtual;
  110. // Free is using compiler magic.
  111. // Reasons:
  112. // 1. In JS calling obj.Free when obj=nil would crash.
  113. // 2. In JS freeing memory requires to set all references to nil.
  114. // Therefore any obj.free call is replaced by the compiler with some rtl magic.
  115. procedure Free;
  116. class function ClassType: TClass; assembler;
  117. class property ClassName: String read FClassName;
  118. class function ClassNameIs(const Name: string): boolean;
  119. class property ClassParent: TClass read FClassParent;
  120. class function InheritsFrom(aClass: TClass): boolean; assembler;
  121. class property UnitName: String read FUnitName;
  122. Class function MethodName(aCode : Pointer) : String;
  123. Class function MethodAddress(aName : String) : Pointer;
  124. Class Function FieldAddress(aName : String) : Pointer;
  125. Class Function ClassInfo : Pointer;
  126. procedure AfterConstruction; virtual;
  127. procedure BeforeDestruction; virtual;
  128. // message handling routines
  129. procedure Dispatch(var aMessage); virtual;
  130. procedure DispatchStr(var aMessage); virtual;
  131. procedure DefaultHandler(var aMessage); virtual;
  132. procedure DefaultHandlerStr(var aMessage); virtual;
  133. function GetInterface(const iid: TGuid; out obj): boolean;
  134. function GetInterface(const iidstr: String; out obj): boolean; inline;
  135. function GetInterfaceByStr(const iidstr: String; out obj): boolean;
  136. function GetInterfaceWeak(const iid: TGuid; out obj): boolean; // equal to GetInterface but the interface returned is not referenced
  137. function Equals(Obj: TObject): boolean; virtual;
  138. function ToString: String; virtual;
  139. end;
  140. { TCustomAttribute - base class of all user defined attributes. }
  141. TCustomAttribute = class
  142. end;
  143. TCustomAttributeArray = array of TCustomAttribute;
  144. const
  145. { IInterface }
  146. S_OK = 0;
  147. S_FALSE = 1;
  148. E_NOINTERFACE = -2147467262; // FPC: longint($80004002)
  149. E_UNEXPECTED = -2147418113; // FPC: longint($8000FFFF)
  150. E_NOTIMPL = -2147467263; // FPC: longint($80004001)
  151. type
  152. {$Interfaces COM}
  153. IUnknown = interface
  154. ['{00000000-0000-0000-C000-000000000046}']
  155. function QueryInterface(const iid: TGuid; out obj): Integer;
  156. function _AddRef: Integer;
  157. function _Release: Integer;
  158. end;
  159. IInterface = IUnknown;
  160. {$M+}
  161. IInvokable = interface(IInterface)
  162. end;
  163. {$M-}
  164. { Enumerator support }
  165. IEnumerator = interface(IInterface)
  166. function GetCurrent: TObject;
  167. function MoveNext: Boolean;
  168. procedure Reset;
  169. property Current: TObject read GetCurrent;
  170. end;
  171. IEnumerable = interface(IInterface)
  172. function GetEnumerator: IEnumerator;
  173. end;
  174. { TInterfacedObject }
  175. TInterfacedObject = class(TObject,IUnknown)
  176. protected
  177. fRefCount: Integer;
  178. { implement methods of IUnknown }
  179. function QueryInterface(const iid: TGuid; out obj): Integer; virtual;
  180. function _AddRef: Integer; virtual;
  181. function _Release: Integer; virtual;
  182. public
  183. procedure BeforeDestruction; override;
  184. property RefCount: Integer read fRefCount;
  185. end;
  186. TInterfacedClass = class of TInterfacedObject;
  187. { TAggregatedObject - sub or satellite object using same interface as controller }
  188. TAggregatedObject = class(TObject)
  189. private
  190. fController: Pointer;
  191. function GetController: IUnknown;
  192. protected
  193. { implement methods of IUnknown }
  194. function QueryInterface(const iid: TGuid; out obj): Integer; virtual;
  195. function _AddRef: Integer; virtual;
  196. function _Release: Integer; virtual;
  197. public
  198. constructor Create(const aController: IUnknown); reintroduce;
  199. property Controller: IUnknown read GetController;
  200. end;
  201. { TContainedObject }
  202. TContainedObject = class(TAggregatedObject,IInterface)
  203. protected
  204. function QueryInterface(const iid: TGuid; out obj): Integer; override;
  205. end;
  206. const
  207. { for safe as operator support }
  208. IObjectInstance: TGuid = '{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}';
  209. function GUIDToString(const GUID: TGUID): string; external name 'rtl.guidrToStr';
  210. {*****************************************************************************
  211. RTTI support
  212. *****************************************************************************}
  213. type
  214. // if you change the following enumeration type in any way
  215. // you also have to change the rtl.js in an appropriate way !
  216. TTypeKind = (
  217. tkUnknown, // 0
  218. tkInteger, // 1
  219. tkChar, // 2 in Delphi/FPC tkWChar, tkUChar
  220. tkString, // 3 in Delphi/FPC tkSString, tkWString or tkUString
  221. tkEnumeration, // 4
  222. tkSet, // 5
  223. tkDouble, // 6
  224. tkBool, // 7
  225. tkProcVar, // 8 function or procedure
  226. tkMethod, // 9 proc var of object
  227. tkArray, // 10 static array
  228. tkDynArray, // 11
  229. tkRecord, // 12
  230. tkClass, // 13
  231. tkClassRef, // 14
  232. tkPointer, // 15
  233. tkJSValue, // 16
  234. tkRefToProcVar, // 17 variable of procedure type
  235. tkInterface, // 18
  236. //tkObject,
  237. //tkSString,tkLString,tkAString,tkWString,
  238. //tkVariant,
  239. //tkWChar,
  240. //tkInt64,
  241. //tkQWord,
  242. //tkInterfaceRaw,
  243. //tkUString,tkUChar,
  244. tkHelper, // 19
  245. //tkFile,
  246. tkExtClass // 20
  247. );
  248. TTypeKinds = set of TTypeKind;
  249. const
  250. tkFloat = tkDouble; // for compatibility with Delphi/FPC
  251. tkProcedure = tkProcVar; // for compatibility with Delphi
  252. tkAny = [Low(TTypeKind)..High(TTypeKind)];
  253. tkMethods = [tkMethod];
  254. tkProperties = tkAny-tkMethods-[tkUnknown];
  255. {*****************************************************************************
  256. Array of const support
  257. *****************************************************************************}
  258. const
  259. vtInteger = 0;
  260. vtBoolean = 1;
  261. //vtChar = 2; // Delphi/FPC: ansichar
  262. vtExtended = 3; // Note: double in pas2js, PExtended in Delphi/FPC
  263. //vtString = 4; // Delphi/FPC: PShortString
  264. vtPointer = 5;
  265. //vtPChar = 6;
  266. vtObject = 7;
  267. vtClass = 8;
  268. vtWideChar = 9;
  269. //vtPWideChar = 10;
  270. //vtAnsiString = 11;
  271. vtCurrency = 12; // Note: currency in pas2js, PCurrency in Delphi/FPC
  272. //vtVariant = 13;
  273. vtInterface = 14;
  274. //vtWideString = 15;
  275. //vtInt64 = 16;
  276. //vtQWord = 17;
  277. vtUnicodeString = 18;
  278. // only pas2js, not in Delphi/FPC:
  279. vtNativeInt = 19;
  280. vtJSValue = 20;
  281. type
  282. PVarRec = ^TVarRec;
  283. TVarRec = record
  284. VType: byte;
  285. VJSValue: JSValue;
  286. VInteger: LongInt external name 'VJSValue';
  287. VBoolean: Boolean external name 'VJSValue';
  288. VExtended: Double external name 'VJSValue';
  289. VPointer: Pointer external name 'VJSValue';
  290. VObject: TObject external name 'VJSValue';
  291. VClass: TClass external name 'VJSValue';
  292. VWideChar: WideChar external name 'VJSValue';
  293. VCurrency: Currency external name 'VJSValue';
  294. VInterface: Pointer external name 'VJSValue';
  295. VUnicodeString: UnicodeString external name 'VJSValue';
  296. VNativeInt: NativeInt external name 'VJSValue';
  297. end;
  298. TVarRecArray = array of TVarRec;
  299. function VarRecs: TVarRecArray; varargs;
  300. {*****************************************************************************
  301. Init / Exit / ExitProc
  302. *****************************************************************************}
  303. var
  304. ExitCode: Integer; external name 'rtl.exitcode';
  305. IsConsole: Boolean = {$IFDEF NodeJS}true{$ELSE}false{$ENDIF};
  306. FirstDotAtFileNameStartIsExtension : Boolean = False;
  307. type
  308. TOnParamCount = function: Longint;
  309. TOnParamStr = function(Index: Longint): String;
  310. var
  311. OnParamCount: TOnParamCount;
  312. OnParamStr: TOnParamStr;
  313. function ParamCount: Longint;
  314. function ParamStr(Index: Longint): String;
  315. {*****************************************************************************
  316. Math
  317. *****************************************************************************}
  318. const
  319. PI: Double; external name 'Math.PI';
  320. MathE: Double; external name 'Math.E'; // Euler's number
  321. MathLN10: Double; external name 'Math.LN10'; // ln(10)
  322. MathLN2: Double; external name 'Math.LN2'; // ln(2)
  323. MathLog10E: Double; external name 'Math.Log10E'; // log10(e)
  324. MathLog2E: Double; external name 'Math.LOG2E'; // log2(e)
  325. MathSQRT1_2: Double; external name 'Math.SQRT1_2'; // sqrt(0.5)
  326. MathSQRT2: Double; external name 'Math.SQRT2'; // sqrt(2)
  327. function Abs(const A: integer): integer; overload; external name 'Math.abs';
  328. function Abs(const A: NativeInt): integer; overload; external name 'Math.abs';
  329. function Abs(const A: Double): Double; overload; external name 'Math.abs';
  330. function ArcTan(const A: Double): Double; external name 'Math.atan';
  331. function ArcTan2(const A,B: Double): Double; external name 'Math.atan2';
  332. function Cos(const A: Double): Double; external name 'Math.cos';
  333. function Exp(const A: Double): Double; external name 'Math.exp';
  334. function Frac(const A: Double): Double; assembler;
  335. function Ln(const A: Double): Double; external name 'Math.log';
  336. function Odd(const A: Integer): Boolean; assembler;
  337. function Random(const Range: Integer): Integer; overload; assembler;
  338. function Random: Double; overload; external name 'Math.random';
  339. function Round(const A: Double): NativeInt; external name 'Math.round';
  340. function Sin(const A: Double): Double; external name 'Math.sin';
  341. function Sqr(const A: Integer): Integer; assembler; overload;
  342. function Sqr(const A: Double): Double; assembler; overload;
  343. function sqrt(const A: Double): Double; external name 'Math.sqrt';
  344. function Trunc(const A: Double): NativeInt;
  345. {*****************************************************************************
  346. String functions
  347. *****************************************************************************}
  348. const
  349. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
  350. function Int(const A: Double): double;
  351. function Copy(const S: string; Index, Size: Integer): String; assembler; overload;
  352. function Copy(const S: string; Index: Integer): String; assembler; overload;
  353. procedure Delete(var S: String; Index, Size: Integer); overload;
  354. function Pos(const Search, InString: String): Integer; assembler; overload;
  355. function Pos(const Search, InString: String; StartAt : Integer): Integer; assembler; overload;
  356. procedure Insert(const Insertion: String; var Target: String; Index: Integer); overload;
  357. function upcase(c : char) : char; assembler;
  358. function HexStr(Val: NativeInt; cnt: byte): string; external name 'rtl.hexStr'; overload;
  359. function binstr(val : NativeUInt; cnt : byte) : string;
  360. procedure val(const S: String; out NI : NativeInt; out Code: Integer); overload;
  361. procedure val(const S: String; out NI : NativeUInt; out Code: Integer); overload;
  362. procedure val(const S: String; out SI : ShortInt; out Code: Integer); overload;
  363. procedure val(const S: String; out B : Byte; out Code: Integer); overload;
  364. procedure val(const S: String; out SI : smallint; out Code: Integer); overload;
  365. procedure val(const S: String; out W : word; out Code : Integer); overload;
  366. procedure val(const S: String; out I : integer; out Code : Integer); overload;
  367. procedure val(const S: String; out C : Cardinal; out Code: Integer); overload;
  368. procedure val(const S: String; out d : double; out Code : Integer); overload;
  369. procedure val(const S: String; out b : boolean; out Code: Integer); overload;
  370. function StringOfChar(c: Char; l: NativeInt): String;
  371. {*****************************************************************************
  372. Other functions
  373. *****************************************************************************}
  374. procedure Write; varargs; // ToDo: should be compiler built-in function
  375. procedure Writeln; varargs; // ToDo: should be compiler built-in function
  376. Type
  377. TConsoleHandler = Procedure (S : JSValue; NewLine : Boolean);
  378. Function SetWriteCallBack(H : TConsoleHandler) : TConsoleHandler;
  379. function Assigned(const V: JSValue): boolean; assembler; overload;
  380. function StrictEqual(const A: JSValue; const B): boolean; assembler;
  381. function StrictInequal(const A: JSValue; const B): boolean; assembler;
  382. implementation
  383. type
  384. { TJSObj - simple access to JS Object }
  385. TJSObj = class external name 'Object'
  386. private
  387. function GetProperties(Name: String): JSValue; external name '[]';
  388. procedure SetProperties(Name: String; const AValue: JSValue); external name '[]';
  389. public
  390. //constructor new;
  391. //function hasOwnProperty(prop: String): boolean;
  392. property Properties[Name: String]: JSValue read GetProperties write SetProperties; default;
  393. end;
  394. TJSArray = class external name 'Array'
  395. public
  396. //length: nativeint;
  397. //constructor new; overload;
  398. function push(aElement : JSValue) : NativeInt; varargs;
  399. end;
  400. TJSArguments = class external name 'arguments'
  401. private
  402. FLength: NativeInt; external name 'length';
  403. function GetElements(Index: NativeInt): JSValue; external name '[]';
  404. public
  405. property Length: NativeInt read FLength;
  406. property Elements[Index: NativeInt]: JSValue read GetElements; default;
  407. end;
  408. var
  409. JSArguments: TJSArguments; external name 'arguments';
  410. function isNumber(const v: JSValue): boolean; external name 'rtl.isNumber';
  411. function isObject(const v: JSValue): boolean; external name 'rtl.isObject'; // true if not null and a JS Object
  412. function isString(const v: JSValue): boolean; external name 'rtl.isString';
  413. function isNaN(i: JSValue): boolean; external name 'isNaN'; // may result NaN
  414. // needed by ClassNameIs, the real SameText is in SysUtils
  415. function SameText(const s1, s2: String): Boolean; assembler;
  416. asm
  417. return s1.toLowerCase() == s2.toLowerCase();
  418. end;
  419. function VarRecs: TVarRecArray;
  420. var
  421. i: nativeint;
  422. v: PVarRec;
  423. begin
  424. Result:=nil;
  425. while i<JSArguments.Length do
  426. begin
  427. new(v);
  428. v^.VType:=byte(JSArguments[i]);
  429. inc(i);
  430. v^.VJSValue:=JSArguments[i];
  431. inc(i);
  432. TJSArray(Result).push(v^);
  433. end;
  434. end;
  435. function ParamCount: Longint;
  436. begin
  437. if Assigned(OnParamCount) then
  438. Result:=OnParamCount()
  439. else
  440. Result:=0;
  441. end;
  442. function ParamStr(Index: Longint): String;
  443. begin
  444. if Assigned(OnParamStr) then
  445. Result:=OnParamStr(Index)
  446. else if Index=0 then
  447. Result:='js'
  448. else
  449. Result:='';
  450. end;
  451. function Frac(const A: Double): Double; assembler;
  452. asm
  453. return A % 1;
  454. end;
  455. function Odd(const A: Integer): Boolean; assembler;
  456. asm
  457. return A&1 != 0;
  458. end;
  459. function Random(const Range: Integer): Integer; assembler;
  460. asm
  461. return Math.floor(Math.random()*Range);
  462. end;
  463. function Sqr(const A: Integer): Integer; assembler;
  464. asm
  465. return A*A;
  466. end;
  467. function Sqr(const A: Double): Double; assembler;
  468. asm
  469. return A*A;
  470. end;
  471. function Trunc(const A: Double): NativeInt; assembler;
  472. asm
  473. if (!Math.trunc) {
  474. Math.trunc = function(v) {
  475. v = +v;
  476. if (!isFinite(v)) return v;
  477. return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0);
  478. };
  479. }
  480. $mod.Trunc = Math.trunc;
  481. return Math.trunc(A);
  482. end;
  483. function Copy(const S: string; Index, Size: Integer): String; assembler;
  484. asm
  485. if (Index<1) Index = 1;
  486. return (Size>0) ? S.substring(Index-1,Index+Size-1) : "";
  487. end;
  488. function Copy(const S: string; Index: Integer): String; assembler;
  489. asm
  490. if (Index<1) Index = 1;
  491. return S.substr(Index-1);
  492. end;
  493. procedure Delete(var S: String; Index, Size: Integer);
  494. var
  495. h: String;
  496. begin
  497. if (Index<1) or (Index>length(S)) or (Size<=0) then exit;
  498. h:=S;
  499. S:=copy(h,1,Index-1)+copy(h,Index+Size);
  500. end;
  501. function Pos(const Search, InString: String): Integer; assembler;
  502. asm
  503. return InString.indexOf(Search)+1;
  504. end;
  505. function Pos(const Search, InString: String; StartAt : Integer): Integer; assembler; overload;
  506. asm
  507. return InString.indexOf(Search,StartAt-1)+1;
  508. end;
  509. procedure Insert(const Insertion: String; var Target: String; Index: Integer);
  510. var
  511. t: String;
  512. begin
  513. if Insertion='' then exit;
  514. t:=Target;
  515. if Index<1 then
  516. Target:=Insertion+t
  517. else if Index>length(t) then
  518. Target:=t+Insertion
  519. else
  520. Target:=copy(t,1,Index-1)+Insertion+copy(t,Index,length(t));
  521. end;
  522. var
  523. WriteBuf: String;
  524. WriteCallBack : TConsoleHandler;
  525. Function SetWriteCallBack(H : TConsoleHandler) : TConsoleHandler;
  526. begin
  527. Result:=WriteCallBack;
  528. WriteCallBack:=H;
  529. end;
  530. procedure Write;
  531. var
  532. i: Integer;
  533. begin
  534. for i:=0 to JSArguments.Length-1 do
  535. if Assigned(WriteCallBack) then
  536. WriteCallBack(JSArguments[i],False)
  537. else
  538. WriteBuf:=WriteBuf+String(JSArguments[i]);
  539. end;
  540. procedure Writeln;
  541. var
  542. i,l: Integer;
  543. s: String;
  544. begin
  545. L:=JSArguments.Length-1;
  546. if Assigned(WriteCallBack) then
  547. begin
  548. for i:=0 to L do
  549. WriteCallBack(JSArguments[i],I=L);
  550. end
  551. else
  552. begin
  553. s:=WriteBuf;
  554. for i:=0 to L do
  555. s:=s+String(JSArguments[i]);
  556. asm
  557. console.log(s);
  558. end;
  559. WriteBuf:='';
  560. end;
  561. end;
  562. function Int(const A: Double): double;
  563. begin
  564. // trunc contains fix for missing Math.trunc in IE
  565. Result:=Trunc(A);
  566. end;
  567. function Number(S: String): Double; external name 'Number';
  568. function valint(const S: String; MinVal, MaxVal: NativeInt; out Code: Integer): NativeInt;
  569. var
  570. x: double;
  571. begin
  572. if S='' then
  573. begin
  574. code:=1;
  575. exit;
  576. end;
  577. x:=Number(S);
  578. if isNaN(x) then
  579. case copy(s,1,1) of
  580. '$': x:=Number('0x'+copy(S,2));
  581. '&': x:=Number('0o'+copy(S,2));
  582. '%': x:=Number('0b'+copy(S,2));
  583. else
  584. Code:=1;
  585. exit;
  586. end;
  587. if isNaN(x) or (X<>Int(X)) then
  588. Code:=1
  589. else if (x<MinVal) or (x>MaxVal) then
  590. Code:=2
  591. else
  592. begin
  593. Result:=Trunc(x);
  594. Code:=0;
  595. end;
  596. end;
  597. procedure val(const S: String; out NI : NativeInt; out Code: Integer);
  598. begin
  599. NI:=valint(S,low(NI),high(NI),Code);
  600. end;
  601. procedure val(const S: String; out NI: NativeUInt; out Code: Integer);
  602. var
  603. x : double;
  604. begin
  605. if S='' then
  606. begin
  607. code:=1;
  608. exit;
  609. end;
  610. x:=Number(S);
  611. if isNaN(x) or (X<>Int(X)) or (X<0) then
  612. Code:=1
  613. else
  614. begin
  615. Code:=0;
  616. NI:=Trunc(x);
  617. end;
  618. end;
  619. procedure val(const S: String; out SI : ShortInt; out Code: Integer);
  620. begin
  621. SI:=valint(S,low(SI),high(SI),Code);
  622. end;
  623. procedure val(const S: String; out SI: smallint; out Code: Integer);
  624. begin
  625. SI:=valint(S,low(SI),high(SI),Code);
  626. end;
  627. procedure val(const S: String; out C: Cardinal; out Code: Integer);
  628. begin
  629. C:=valint(S,low(C),high(C),Code);
  630. end;
  631. procedure val(const S: String; out B: Byte; out Code: Integer);
  632. begin
  633. B:=valint(S,low(B),high(B),Code);
  634. end;
  635. procedure val(const S: String; out W: word; out Code: Integer);
  636. begin
  637. W:=valint(S,low(W),high(W),Code);
  638. end;
  639. procedure val(const S : String; out I : integer; out Code : Integer);
  640. begin
  641. I:=valint(S,low(I),high(I),Code);
  642. end;
  643. procedure val(const S : String; out d : double; out Code : Integer);
  644. Var
  645. x: double;
  646. begin
  647. if S='' then
  648. begin
  649. code:=1;
  650. exit;
  651. end;
  652. x:=Number(S);
  653. if isNaN(x) then
  654. Code:=1
  655. else
  656. begin
  657. Code:=0;
  658. d:=x;
  659. end;
  660. end;
  661. procedure val(const S: String; out b: boolean; out Code: Integer);
  662. begin
  663. if SameText(S,'true') then
  664. begin
  665. Code:=0;
  666. b:=true;
  667. end
  668. else if SameText(S,'false') then
  669. begin
  670. Code:=0;
  671. b:=false;
  672. end
  673. else
  674. Code:=1;
  675. end;
  676. function binstr(val : NativeUInt;cnt : byte) : string;
  677. var
  678. i : Integer;
  679. begin
  680. SetLength(Result,cnt);
  681. for i:=cnt downto 1 do
  682. begin
  683. Result[i]:=char(48+val and 1);
  684. val:=val shr 1;
  685. end;
  686. end;
  687. function upcase(c : char) : char; assembler;
  688. asm
  689. return c.toUpperCase();
  690. end;
  691. function StringOfChar(c: Char; l: NativeInt): String;
  692. var
  693. i: Integer;
  694. begin
  695. asm
  696. if ((l>0) && c.repeat) return c.repeat(l);
  697. end;
  698. Result:='';
  699. for i:=1 to l do Result:=Result+c;
  700. end;
  701. function Assigned(const V: JSValue): boolean; assembler;
  702. asm
  703. return (V!=undefined) && (V!=null) && (!rtl.isArray(V) || (V.length > 0));
  704. end;
  705. function StrictEqual(const A: JSValue; const B): boolean; assembler;
  706. asm
  707. return A === B;
  708. end;
  709. function StrictInequal(const A: JSValue; const B): boolean; assembler;
  710. asm
  711. return A !== B;
  712. end;
  713. { TContainedObject }
  714. function TContainedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  715. begin
  716. if GetInterface(iid,obj) then
  717. Result:=S_OK
  718. else
  719. Result:=Integer(E_NOINTERFACE);
  720. end;
  721. { TAggregatedObject }
  722. function TAggregatedObject.GetController: IUnknown;
  723. begin
  724. Result := IUnknown(fController);
  725. end;
  726. function TAggregatedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  727. begin
  728. Result := IUnknown(fController).QueryInterface(iid, obj);
  729. end;
  730. function TAggregatedObject._AddRef: Integer;
  731. begin
  732. Result := IUnknown(fController)._AddRef;
  733. end;
  734. function TAggregatedObject._Release: Integer;
  735. begin
  736. Result := IUnknown(fController)._Release;
  737. end;
  738. constructor TAggregatedObject.Create(const aController: IUnknown);
  739. begin
  740. inherited Create;
  741. { do not keep a counted reference to the controller! }
  742. fController := Pointer(aController);
  743. end;
  744. { TInterfacedObject }
  745. function TInterfacedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  746. begin
  747. if GetInterface(iid,obj) then
  748. Result:=S_OK
  749. else
  750. Result:=Integer(E_NOINTERFACE);
  751. end;
  752. function TInterfacedObject._AddRef: Integer;
  753. begin
  754. inc(fRefCount);
  755. Result:=fRefCount;
  756. end;
  757. function TInterfacedObject._Release: Integer;
  758. begin
  759. dec(fRefCount);
  760. Result:=fRefCount;
  761. if fRefCount=0 then
  762. Destroy;
  763. end;
  764. procedure TInterfacedObject.BeforeDestruction;
  765. begin
  766. if fRefCount<>0 then
  767. asm
  768. rtl.raiseE('EHeapMemoryError');
  769. end;
  770. end;
  771. { TObject }
  772. constructor TObject.Create;
  773. begin
  774. end;
  775. destructor TObject.Destroy;
  776. begin
  777. end;
  778. procedure TObject.Free;
  779. begin
  780. Destroy;
  781. end;
  782. class function TObject.ClassType: TClass; assembler;
  783. asm
  784. return this;
  785. end;
  786. class function TObject.ClassNameIs(const Name: string): boolean;
  787. begin
  788. Result:=SameText(Name,ClassName);
  789. end;
  790. class function TObject.InheritsFrom(aClass: TClass): boolean; assembler;
  791. asm
  792. return (aClass!=null) && ((this==aClass) || aClass.isPrototypeOf(this));
  793. end;
  794. Class function TObject.MethodName(aCode : Pointer) : String;
  795. begin
  796. Result:='';
  797. if aCode=Nil then
  798. exit;
  799. asm
  800. if (typeof(aCode)!=='function') return "";
  801. var i = 0;
  802. var TI = this.$rtti;
  803. if (rtl.isObject(aCode.scope)){
  804. // callback
  805. if (typeof aCode.fn === "string") return aCode.fn;
  806. aCode = aCode.fn;
  807. }
  808. // Not a callback, check rtti
  809. while ((Result === "") && (TI != null)) {
  810. i = 0;
  811. while ((Result === "") && (i < TI.methods.length)) {
  812. if (this[TI.getMethod(i).name] === aCode)
  813. Result=TI.getMethod(i).name;
  814. i += 1;
  815. };
  816. if (Result === "") TI = TI.ancestor;
  817. };
  818. // return Result;
  819. end;
  820. end;
  821. Class function TObject.MethodAddress(aName : String) : Pointer;
  822. // We must do this in asm, because the typinfo unit is not available.
  823. begin
  824. Result:=Nil;
  825. if AName='' then
  826. exit;
  827. asm
  828. var i = 0;
  829. var TI = this.$rtti;
  830. var N = "";
  831. var MN = "";
  832. N = aName.toLowerCase();
  833. while ((MN === "") && (TI != null)) {
  834. i = 0;
  835. while ((MN === "") && (i < TI.methods.length)) {
  836. if (TI.getMethod(i).name.toLowerCase() === N) MN = TI.getMethod(i).name;
  837. i += 1;
  838. };
  839. if (MN === "") TI = TI.ancestor;
  840. };
  841. if (MN !== "") Result = this[MN];
  842. // return Result;
  843. end;
  844. end;
  845. class function TObject.FieldAddress(aName: String): Pointer;
  846. begin
  847. Result:=Nil;
  848. if aName='' then exit;
  849. asm
  850. var aClass = this.$class;
  851. var ClassTI = null;
  852. var myName = aName.toLowerCase();
  853. var MemberTI = null;
  854. while (aClass !== null) {
  855. ClassTI = aClass.$rtti;
  856. for (var i = 0, $end2 = ClassTI.fields.length - 1; i <= $end2; i++) {
  857. MemberTI = ClassTI.getField(i);
  858. if (MemberTI.name.toLowerCase() === myName) {
  859. return MemberTI;
  860. };
  861. };
  862. aClass = aClass.$ancestor ? aClass.$ancestor : null;
  863. };
  864. end;
  865. end;
  866. Class Function TObject.ClassInfo : Pointer;
  867. begin
  868. // This works different from FPC/Delphi.
  869. // We get the actual type info.
  870. Result:=TypeInfo(Self);
  871. end;
  872. procedure TObject.AfterConstruction;
  873. begin
  874. end;
  875. procedure TObject.BeforeDestruction;
  876. begin
  877. end;
  878. procedure TObject.Dispatch(var aMessage);
  879. // aMessage is a record with an integer field 'Msg'
  880. var
  881. aClass: TClass;
  882. Msg: TJSObj absolute aMessage;
  883. Id: jsvalue;
  884. begin
  885. if not isObject(Msg) then exit;
  886. Id:=Msg['Msg'];
  887. if not isNumber(Id) then exit;
  888. aClass:=ClassType;
  889. while aClass<>nil do
  890. begin
  891. asm
  892. var Handlers = aClass.$msgint;
  893. if (rtl.isObject(Handlers) && Handlers.hasOwnProperty(Id)){
  894. this[Handlers[Id]](aMessage);
  895. return;
  896. }
  897. end;
  898. aClass:=aClass.ClassParent;
  899. end;
  900. DefaultHandler(aMessage);
  901. end;
  902. procedure TObject.DispatchStr(var aMessage);
  903. // aMessage is a record with a string field 'MsgStr'
  904. var
  905. aClass: TClass;
  906. Msg: TJSObj absolute aMessage;
  907. Id: jsvalue;
  908. begin
  909. if not isObject(Msg) then exit;
  910. Id:=Msg['MsgStr'];
  911. if not isString(Id) then exit;
  912. aClass:=ClassType;
  913. while (aClass<>Nil) do
  914. begin
  915. asm
  916. var Handlers = aClass.$msgstr;
  917. if (rtl.isObject(Handlers) && Handlers.hasOwnProperty(Id)){
  918. this[Handlers[Id]](aMessage);
  919. return;
  920. }
  921. end;
  922. aClass:=aClass.ClassParent;
  923. end;
  924. DefaultHandlerStr(aMessage);
  925. end;
  926. procedure TObject.DefaultHandler(var aMessage);
  927. begin
  928. if jsvalue(TMethod(aMessage)) then ;
  929. end;
  930. procedure TObject.DefaultHandlerStr(var aMessage);
  931. begin
  932. if jsvalue(TMethod(aMessage)) then ;
  933. end;
  934. function TObject.GetInterface(const iid: TGuid; out obj): boolean;
  935. begin
  936. asm
  937. var i = iid.$intf;
  938. if (i){
  939. // iid is the private TGuid of an interface
  940. i = rtl.getIntfG(this,i.$guid,2);
  941. if (i){
  942. obj.set(i);
  943. return true;
  944. }
  945. }
  946. end;
  947. Result := GetInterfaceByStr(GUIDToString(iid),obj);
  948. end;
  949. function TObject.GetInterface(const iidstr: String; out obj): boolean;
  950. begin
  951. Result := GetInterfaceByStr(iidstr,obj);
  952. end;
  953. function TObject.GetInterfaceByStr(const iidstr: String; out obj): boolean;
  954. begin
  955. Result:=false;
  956. if not TJSObj(IObjectInstance)['$str'] then
  957. TJSObj(IObjectInstance)['$str']:=GUIDToString(IObjectInstance);
  958. if iidstr = TJSObj(IObjectInstance)['$str'] then
  959. begin
  960. obj:=Self;
  961. exit(true);
  962. end;
  963. asm
  964. var i = rtl.getIntfG(this,iidstr,2);
  965. obj.set(i);
  966. Result=(i!==null);
  967. end;
  968. end;
  969. function TObject.GetInterfaceWeak(const iid: TGuid; out obj): boolean;
  970. begin
  971. Result:=GetInterface(iid,obj);
  972. asm
  973. if (Result){
  974. var o = obj.get();
  975. if (o.$kind==='com'){
  976. o._Release();
  977. }
  978. }
  979. end;
  980. end;
  981. function TObject.Equals(Obj: TObject): boolean;
  982. begin
  983. Result:=Obj=Self;
  984. end;
  985. function TObject.ToString: String;
  986. begin
  987. Result:=ClassName;
  988. end;
  989. initialization
  990. ExitCode:=0; // set it here, so that WPO does not remove it
  991. end.