system.pas 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  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. UnicodeString = type String;
  74. WideString = type String;
  75. WideChar = char;
  76. UnicodeChar = char;
  77. TDynArrayIndex = NativeInt;
  78. TTextLineBreakStyle = (tlbsLF,tlbsCRLF,tlbsCR);
  79. TCompareOption = ({coLingIgnoreCase, coLingIgnoreDiacritic, }coIgnoreCase{,
  80. coIgnoreKanaType, coIgnoreNonSpace, coIgnoreSymbols, coIgnoreWidth,
  81. coLingCasing, coDigitAsNumbers, coStringSort});
  82. TCompareOptions = set of TCompareOption;
  83. {*****************************************************************************
  84. TObject, TClass, IUnknown, IInterface, TInterfacedObject
  85. *****************************************************************************}
  86. type
  87. TGuid = record
  88. D1: DWord;
  89. D2: word;
  90. D3: word;
  91. D4: array[0..7] of byte;
  92. end;
  93. TGUIDString = type string;
  94. PMethod = ^TMethod;
  95. TMethod = record
  96. Code : CodePointer;
  97. Data : Pointer;
  98. end;
  99. TClass = class of TObject;
  100. { TObject }
  101. {$DispatchField Msg} // enable checking message methods for record field name "Msg"
  102. {$DispatchStrField MsgStr}
  103. TObject = class
  104. private
  105. class var FClassName: String; external name '$classname';
  106. class var FClassParent: TClass; external name '$ancestor';
  107. class var FUnitName: String; external name '$module.$name';
  108. public
  109. constructor Create;
  110. destructor Destroy; virtual;
  111. // Free is using compiler magic.
  112. // Reasons:
  113. // 1. In JS calling obj.Free when obj=nil would crash.
  114. // 2. In JS freeing memory requires to set all references to nil.
  115. // Therefore any obj.free call is replaced by the compiler with some rtl magic.
  116. procedure Free;
  117. class function ClassType: TClass; assembler;
  118. class property ClassName: String read FClassName;
  119. class function ClassNameIs(const Name: string): boolean;
  120. class property ClassParent: TClass read FClassParent;
  121. class function InheritsFrom(aClass: TClass): boolean; assembler;
  122. class property UnitName: String read FUnitName;
  123. Class function MethodName(aCode : Pointer) : String;
  124. Class function MethodAddress(aName : String) : Pointer;
  125. Class Function FieldAddress(aName : String) : Pointer;
  126. Class Function ClassInfo : Pointer;
  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. x:=Number(S);
  574. if isNaN(x) then
  575. case copy(s,1,1) of
  576. '$': x:=Number('0x'+copy(S,2));
  577. '&': x:=Number('0o'+copy(S,2));
  578. '%': x:=Number('0b'+copy(S,2));
  579. else
  580. Code:=1;
  581. exit;
  582. end;
  583. if isNaN(x) or (X<>Int(X)) then
  584. Code:=1
  585. else if (x<MinVal) or (x>MaxVal) then
  586. Code:=2
  587. else
  588. begin
  589. Result:=Trunc(x);
  590. Code:=0;
  591. end;
  592. end;
  593. procedure val(const S: String; out NI : NativeInt; out Code: Integer);
  594. begin
  595. NI:=valint(S,low(NI),high(NI),Code);
  596. end;
  597. procedure val(const S: String; out NI: NativeUInt; out Code: Integer);
  598. var
  599. x : double;
  600. begin
  601. x:=Number(S);
  602. if isNaN(x) or (X<>Int(X)) or (X<0) then
  603. Code:=1
  604. else
  605. begin
  606. Code:=0;
  607. NI:=Trunc(x);
  608. end;
  609. end;
  610. procedure val(const S: String; out SI : ShortInt; out Code: Integer);
  611. begin
  612. SI:=valint(S,low(SI),high(SI),Code);
  613. end;
  614. procedure val(const S: String; out SI: smallint; out Code: Integer);
  615. begin
  616. SI:=valint(S,low(SI),high(SI),Code);
  617. end;
  618. procedure val(const S: String; out C: Cardinal; out Code: Integer);
  619. begin
  620. C:=valint(S,low(C),high(C),Code);
  621. end;
  622. procedure val(const S: String; out B: Byte; out Code: Integer);
  623. begin
  624. B:=valint(S,low(B),high(B),Code);
  625. end;
  626. procedure val(const S: String; out W: word; out Code: Integer);
  627. begin
  628. W:=valint(S,low(W),high(W),Code);
  629. end;
  630. procedure val(const S : String; out I : integer; out Code : Integer);
  631. begin
  632. I:=valint(S,low(I),high(I),Code);
  633. end;
  634. procedure val(const S : String; out d : double; out Code : Integer);
  635. Var
  636. x: double;
  637. begin
  638. x:=Number(S);
  639. if isNaN(x) then
  640. Code:=1
  641. else
  642. begin
  643. Code:=0;
  644. d:=x;
  645. end;
  646. end;
  647. procedure val(const S: String; out b: boolean; out Code: Integer);
  648. begin
  649. if SameText(S,'true') then
  650. begin
  651. Code:=0;
  652. b:=true;
  653. end
  654. else if SameText(S,'false') then
  655. begin
  656. Code:=0;
  657. b:=false;
  658. end
  659. else
  660. Code:=1;
  661. end;
  662. function binstr(val : NativeUInt;cnt : byte) : string;
  663. var
  664. i : Integer;
  665. begin
  666. SetLength(Result,cnt);
  667. for i:=cnt downto 1 do
  668. begin
  669. Result[i]:=char(48+val and 1);
  670. val:=val shr 1;
  671. end;
  672. end;
  673. function upcase(c : char) : char; assembler;
  674. asm
  675. return c.toUpperCase();
  676. end;
  677. function StringOfChar(c: Char; l: NativeInt): String;
  678. var
  679. i: Integer;
  680. begin
  681. asm
  682. if ((l>0) && c.repeat) return c.repeat(l);
  683. end;
  684. Result:='';
  685. for i:=1 to l do Result:=Result+c;
  686. end;
  687. function Assigned(const V: JSValue): boolean; assembler;
  688. asm
  689. return (V!=undefined) && (V!=null) && (!rtl.isArray(V) || (V.length > 0));
  690. end;
  691. function StrictEqual(const A: JSValue; const B): boolean; assembler;
  692. asm
  693. return A === B;
  694. end;
  695. function StrictInequal(const A: JSValue; const B): boolean; assembler;
  696. asm
  697. return A !== B;
  698. end;
  699. { TContainedObject }
  700. function TContainedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  701. begin
  702. if GetInterface(iid,obj) then
  703. Result:=S_OK
  704. else
  705. Result:=Integer(E_NOINTERFACE);
  706. end;
  707. { TAggregatedObject }
  708. function TAggregatedObject.GetController: IUnknown;
  709. begin
  710. Result := IUnknown(fController);
  711. end;
  712. function TAggregatedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  713. begin
  714. Result := IUnknown(fController).QueryInterface(iid, obj);
  715. end;
  716. function TAggregatedObject._AddRef: Integer;
  717. begin
  718. Result := IUnknown(fController)._AddRef;
  719. end;
  720. function TAggregatedObject._Release: Integer;
  721. begin
  722. Result := IUnknown(fController)._Release;
  723. end;
  724. constructor TAggregatedObject.Create(const aController: IUnknown);
  725. begin
  726. inherited Create;
  727. { do not keep a counted reference to the controller! }
  728. fController := Pointer(aController);
  729. end;
  730. { TInterfacedObject }
  731. function TInterfacedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  732. begin
  733. if GetInterface(iid,obj) then
  734. Result:=S_OK
  735. else
  736. Result:=Integer(E_NOINTERFACE);
  737. end;
  738. function TInterfacedObject._AddRef: Integer;
  739. begin
  740. inc(fRefCount);
  741. Result:=fRefCount;
  742. end;
  743. function TInterfacedObject._Release: Integer;
  744. begin
  745. dec(fRefCount);
  746. Result:=fRefCount;
  747. if fRefCount=0 then
  748. Destroy;
  749. end;
  750. procedure TInterfacedObject.BeforeDestruction;
  751. begin
  752. if fRefCount<>0 then
  753. asm
  754. rtl.raiseE('EHeapMemoryError');
  755. end;
  756. end;
  757. { TObject }
  758. constructor TObject.Create;
  759. begin
  760. end;
  761. destructor TObject.Destroy;
  762. begin
  763. end;
  764. procedure TObject.Free;
  765. begin
  766. Destroy;
  767. end;
  768. class function TObject.ClassType: TClass; assembler;
  769. asm
  770. return this;
  771. end;
  772. class function TObject.ClassNameIs(const Name: string): boolean;
  773. begin
  774. Result:=SameText(Name,ClassName);
  775. end;
  776. class function TObject.InheritsFrom(aClass: TClass): boolean; assembler;
  777. asm
  778. return (aClass!=null) && ((this==aClass) || aClass.isPrototypeOf(this));
  779. end;
  780. Class function TObject.MethodName(aCode : Pointer) : String;
  781. begin
  782. Result:='';
  783. if aCode=Nil then
  784. exit;
  785. asm
  786. if (typeof(aCode)!=='function') return "";
  787. var i = 0;
  788. var TI = this.$rtti;
  789. if (rtl.isObject(aCode.scope)){
  790. // callback
  791. if (typeof aCode.fn === "string") return aCode.fn;
  792. aCode = aCode.fn;
  793. }
  794. // Not a callback, check rtti
  795. while ((Result === "") && (TI != null)) {
  796. i = 0;
  797. while ((Result === "") && (i < TI.methods.length)) {
  798. if (this[TI.getMethod(i).name] === aCode)
  799. Result=TI.getMethod(i).name;
  800. i += 1;
  801. };
  802. if (Result === "") TI = TI.ancestor;
  803. };
  804. // return Result;
  805. end;
  806. end;
  807. Class function TObject.MethodAddress(aName : String) : Pointer;
  808. // We must do this in asm, because the typinfo unit is not available.
  809. begin
  810. Result:=Nil;
  811. if AName='' then
  812. exit;
  813. asm
  814. var i = 0;
  815. var TI = this.$rtti;
  816. var N = "";
  817. var MN = "";
  818. N = aName.toLowerCase();
  819. while ((MN === "") && (TI != null)) {
  820. i = 0;
  821. while ((MN === "") && (i < TI.methods.length)) {
  822. if (TI.getMethod(i).name.toLowerCase() === N) MN = TI.getMethod(i).name;
  823. i += 1;
  824. };
  825. if (MN === "") TI = TI.ancestor;
  826. };
  827. if (MN !== "") Result = this[MN];
  828. // return Result;
  829. end;
  830. end;
  831. class function TObject.FieldAddress(aName: String): Pointer;
  832. begin
  833. Result:=Nil;
  834. if aName='' then exit;
  835. asm
  836. var aClass = null;
  837. var i = 0;
  838. var ClassTI = null;
  839. var myName = aName.toLowerCase();
  840. var MemberTI = null;
  841. aClass = this.$class;
  842. while (aClass !== null) {
  843. ClassTI = aClass.$rtti;
  844. for (var $l1 = 0, $end2 = ClassTI.fields.length - 1; $l1 <= $end2; $l1++) {
  845. i = $l1;
  846. MemberTI = ClassTI.getField(i);
  847. if (MemberTI.name.toLowerCase() === myName) {
  848. return MemberTI;
  849. };
  850. };
  851. aClass = aClass.$ancestor ? aClass.$ancestor : null;
  852. };
  853. end;
  854. end;
  855. Class Function TObject.ClassInfo : Pointer;
  856. begin
  857. // This works different from FPC/Delphi.
  858. // We get the actual type info.
  859. Result:=TypeInfo(Self);
  860. end;
  861. procedure TObject.AfterConstruction;
  862. begin
  863. end;
  864. procedure TObject.BeforeDestruction;
  865. begin
  866. end;
  867. procedure TObject.Dispatch(var aMessage);
  868. // aMessage is a record with an integer field 'Msg'
  869. var
  870. aClass: TClass;
  871. Msg: TJSObj absolute aMessage;
  872. Id: jsvalue;
  873. begin
  874. if not isObject(Msg) then exit;
  875. Id:=Msg['Msg'];
  876. if not isNumber(Id) then exit;
  877. aClass:=ClassType;
  878. while aClass<>nil do
  879. begin
  880. asm
  881. var Handlers = aClass.$msgint;
  882. if (rtl.isObject(Handlers) && Handlers.hasOwnProperty(Id)){
  883. this[Handlers[Id]](aMessage);
  884. return;
  885. }
  886. end;
  887. aClass:=aClass.ClassParent;
  888. end;
  889. DefaultHandler(aMessage);
  890. end;
  891. procedure TObject.DispatchStr(var aMessage);
  892. // aMessage is a record with a string field 'MsgStr'
  893. var
  894. aClass: TClass;
  895. Msg: TJSObj absolute aMessage;
  896. Id: jsvalue;
  897. begin
  898. if not isObject(Msg) then exit;
  899. Id:=Msg['MsgStr'];
  900. if not isString(Id) then exit;
  901. aClass:=ClassType;
  902. while (aClass<>Nil) do
  903. begin
  904. asm
  905. var Handlers = aClass.$msgstr;
  906. if (rtl.isObject(Handlers) && Handlers.hasOwnProperty(Id)){
  907. this[Handlers[Id]](aMessage);
  908. return;
  909. }
  910. end;
  911. aClass:=aClass.ClassParent;
  912. end;
  913. DefaultHandlerStr(aMessage);
  914. end;
  915. procedure TObject.DefaultHandler(var aMessage);
  916. begin
  917. if jsvalue(TMethod(aMessage)) then ;
  918. end;
  919. procedure TObject.DefaultHandlerStr(var aMessage);
  920. begin
  921. if jsvalue(TMethod(aMessage)) then ;
  922. end;
  923. function TObject.GetInterface(const iid: TGuid; out obj): boolean;
  924. begin
  925. asm
  926. var i = iid.$intf;
  927. if (i){
  928. // iid is the private TGuid of an interface
  929. i = rtl.getIntfG(this,i.$guid,2);
  930. if (i){
  931. obj.set(i);
  932. return true;
  933. }
  934. }
  935. end;
  936. Result := GetInterfaceByStr(GUIDToString(iid),obj);
  937. end;
  938. function TObject.GetInterface(const iidstr: String; out obj): boolean;
  939. begin
  940. Result := GetInterfaceByStr(iidstr,obj);
  941. end;
  942. function TObject.GetInterfaceByStr(const iidstr: String; out obj): boolean;
  943. begin
  944. Result:=false;
  945. if not TJSObj(IObjectInstance)['$str'] then
  946. TJSObj(IObjectInstance)['$str']:=GUIDToString(IObjectInstance);
  947. if iidstr = TJSObj(IObjectInstance)['$str'] then
  948. begin
  949. obj:=Self;
  950. exit(true);
  951. end;
  952. asm
  953. var i = rtl.getIntfG(this,iidstr,2);
  954. obj.set(i);
  955. Result=(i!==null);
  956. end;
  957. end;
  958. function TObject.GetInterfaceWeak(const iid: TGuid; out obj): boolean;
  959. begin
  960. Result:=GetInterface(iid,obj);
  961. asm
  962. if (Result){
  963. var o = obj.get();
  964. if (o.$kind==='com'){
  965. o._Release();
  966. }
  967. }
  968. end;
  969. end;
  970. function TObject.Equals(Obj: TObject): boolean;
  971. begin
  972. Result:=Obj=Self;
  973. end;
  974. function TObject.ToString: String;
  975. begin
  976. Result:=ClassName;
  977. end;
  978. initialization
  979. ExitCode:=0; // set it here, so that WPO does not remove it
  980. end.