system.pas 28 KB

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