2
0

system.pas 30 KB

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