rtl.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. var pas = {};
  2. var rtl = {
  3. quiet: false,
  4. debug_load_units: false,
  5. debug_rtti: false,
  6. debug: function(){
  7. if (rtl.quiet || !console || !console.log) return;
  8. console.log(arguments);
  9. },
  10. error: function(s){
  11. rtl.debug('Error: ',s);
  12. throw s;
  13. },
  14. warn: function(s){
  15. rtl.debug('Warn: ',s);
  16. },
  17. hasString: function(s){
  18. return rtl.isString(s) && (s.length>0);
  19. },
  20. isArray: function(a) {
  21. return Array.isArray(a);
  22. },
  23. isFunction: function(f){
  24. return typeof(f)==="function";
  25. },
  26. isModule: function(m){
  27. return rtl.isObject(m) && rtl.hasString(m.$name) && (pas[m.$name]===m);
  28. },
  29. isImplementation: function(m){
  30. return rtl.isObject(m) && rtl.isModule(m.$module) && (m.$module.$impl===m);
  31. },
  32. isNumber: function(n){
  33. return typeof(n)==="number";
  34. },
  35. isObject: function(o){
  36. var s=typeof(o);
  37. return (typeof(o)==="object") && (o!=null);
  38. },
  39. isString: function(s){
  40. return typeof(s)==="string";
  41. },
  42. getNumber: function(n){
  43. return typeof(n)==="number"?n:NaN;
  44. },
  45. getChar: function(c){
  46. return ((typeof(c)==="string") && (c.length===1)) ? c : "";
  47. },
  48. getObject: function(o){
  49. return ((typeof(o)==="object") || (typeof(o)==='function')) ? o : null;
  50. },
  51. isPasClass: function(type){
  52. return (rtl.isObject(type) && type.hasOwnProperty('$classname') && rtl.isObject(type.$module));
  53. },
  54. isPasClassInstance: function(type){
  55. return (rtl.isObject(type) && rtl.isPasClass(type.$class));
  56. },
  57. m_loading: 0,
  58. m_loading_intf: 1,
  59. m_intf_loaded: 2,
  60. m_loading_impl: 3, // loading all used unit
  61. m_initializing: 4, // running initialization
  62. m_initialized: 5,
  63. module: function(module_name, intfuseslist, intfcode, impluseslist, implcode){
  64. if (rtl.debug_load_units) rtl.debug('rtl.module name="'+module_name+'" intfuses='+intfuseslist+' impluses='+impluseslist+' hasimplcode='+rtl.isFunction(implcode));
  65. if (!rtl.hasString(module_name)) rtl.error('invalid module name "'+module_name+'"');
  66. if (!rtl.isArray(intfuseslist)) rtl.error('invalid interface useslist of "'+module_name+'"');
  67. if (!rtl.isFunction(intfcode)) rtl.error('invalid interface code of "'+module_name+'"');
  68. if (!(impluseslist==undefined) && !rtl.isArray(impluseslist)) rtl.error('invalid implementation useslist of "'+module_name+'"');
  69. if (!(implcode==undefined) && !rtl.isFunction(implcode)) rtl.error('invalid implementation code of "'+module_name+'"');
  70. if (pas[module_name])
  71. rtl.error('module "'+module_name+'" is already registered');
  72. var module = pas[module_name] = {
  73. $name: module_name,
  74. $intfuseslist: intfuseslist,
  75. $impluseslist: impluseslist,
  76. $state: rtl.m_loading,
  77. $intfcode: intfcode,
  78. $implcode: implcode,
  79. $impl: null,
  80. $rtti: Object.create(rtl.tSectionRTTI),
  81. };
  82. module.$rtti.$module = module;
  83. if (implcode) module.$impl = {
  84. $module: module,
  85. $rtti: module.$rtti,
  86. };
  87. },
  88. exitcode: 0,
  89. run: function(module_name){
  90. function doRun(){
  91. if (!rtl.hasString(module_name)) module_name='program';
  92. if (rtl.debug_load_units) rtl.debug('rtl.run module="'+module_name+'"');
  93. rtl.initRTTI();
  94. var module = pas[module_name];
  95. if (!module) rtl.error('rtl.run module "'+module_name+'" missing');
  96. rtl.loadintf(module);
  97. rtl.loadimpl(module);
  98. if (module_name=='program'){
  99. if (rtl.debug_load_units) rtl.debug('running $main');
  100. var r = pas.program.$main();
  101. if (rtl.isNumber(r)) rtl.exitcode = r;
  102. }
  103. }
  104. if (rtl.showUncaughtExceptions) {
  105. try{
  106. doRun();
  107. } catch(re) {
  108. var errMsg = re.hasOwnProperty('$class') ? re.$class.$classname : '';
  109. errMsg += ((errMsg) ? ': ' : '') + (re.hasOwnProperty('fMessage') ? re.fMessage : re);
  110. alert('Uncaught Exception : '+errMsg);
  111. rtl.exitCode = 216;
  112. }
  113. } else {
  114. doRun();
  115. }
  116. return rtl.exitcode;
  117. },
  118. loadintf: function(module){
  119. if (module.$state>rtl.m_loading_intf) return; // already finished
  120. if (rtl.debug_load_units) rtl.debug('loadintf: "'+module.$name+'"');
  121. if (module.$state===rtl.m_loading_intf)
  122. rtl.error('unit cycle detected "'+module.$name+'"');
  123. module.$state=rtl.m_loading_intf;
  124. // load interfaces of interface useslist
  125. rtl.loaduseslist(module,module.$intfuseslist,rtl.loadintf);
  126. // run interface
  127. if (rtl.debug_load_units) rtl.debug('loadintf: run intf of "'+module.$name+'"');
  128. module.$intfcode(module.$intfuseslist);
  129. // success
  130. module.$state=rtl.m_intf_loaded;
  131. // Note: units only used in implementations are not yet loaded (not even their interfaces)
  132. },
  133. loaduseslist: function(module,useslist,f){
  134. if (useslist==undefined) return;
  135. for (var i in useslist){
  136. var unitname=useslist[i];
  137. if (rtl.debug_load_units) rtl.debug('loaduseslist of "'+module.$name+'" uses="'+unitname+'"');
  138. if (pas[unitname]==undefined)
  139. rtl.error('module "'+module.$name+'" misses "'+unitname+'"');
  140. f(pas[unitname]);
  141. }
  142. },
  143. loadimpl: function(module){
  144. if (module.$state>=rtl.m_loading_impl) return; // already processing
  145. if (module.$state<rtl.m_intf_loaded) rtl.error('loadimpl: interface not loaded of "'+module.$name+'"');
  146. if (rtl.debug_load_units) rtl.debug('loadimpl: load uses of "'+module.$name+'"');
  147. module.$state=rtl.m_loading_impl;
  148. // load interfaces of implementation useslist
  149. rtl.loaduseslist(module,module.$impluseslist,rtl.loadintf);
  150. // load implementation of interfaces useslist
  151. rtl.loaduseslist(module,module.$intfuseslist,rtl.loadimpl);
  152. // load implementation of implementation useslist
  153. rtl.loaduseslist(module,module.$impluseslist,rtl.loadimpl);
  154. // Note: At this point all interfaces used by this unit are loaded. If
  155. // there are implementation uses cycles some used units might not yet be
  156. // initialized. This is by design.
  157. // run implementation
  158. if (rtl.debug_load_units) rtl.debug('loadimpl: run impl of "'+module.$name+'"');
  159. if (rtl.isFunction(module.$implcode)) module.$implcode(module.$impluseslist);
  160. // run initialization
  161. if (rtl.debug_load_units) rtl.debug('loadimpl: run init of "'+module.$name+'"');
  162. module.$state=rtl.m_initializing;
  163. if (rtl.isFunction(module.$init)) module.$init();
  164. // unit initialized
  165. module.$state=rtl.m_initialized;
  166. },
  167. createCallback: function(scope, fn){
  168. var cb;
  169. if (typeof(fn)==='string'){
  170. cb = function(){
  171. return scope[fn].apply(scope,arguments);
  172. };
  173. } else {
  174. cb = function(){
  175. return fn.apply(scope,arguments);
  176. };
  177. };
  178. cb.scope = scope;
  179. cb.fn = fn;
  180. return cb;
  181. },
  182. cloneCallback: function(cb){
  183. return rtl.createCallback(cb.scope,cb.fn);
  184. },
  185. eqCallback: function(a,b){
  186. // can be a function or a function wrapper
  187. if (a==b){
  188. return true;
  189. } else {
  190. return (a!=null) && (b!=null) && (a.fn) && (a.scope===b.scope) && (a.fn==b.fn);
  191. }
  192. },
  193. initClass: function(c,parent,name,initfn){
  194. parent[name] = c;
  195. c.$classname = name;
  196. if ((parent.$module) && (parent.$module.$impl===parent)) parent=parent.$module;
  197. c.$parent = parent;
  198. c.$fullname = parent.$name+'.'+name;
  199. if (rtl.isModule(parent)){
  200. c.$module = parent;
  201. c.$name = name;
  202. } else {
  203. c.$module = parent.$module;
  204. c.$name = parent.name+'.'+name;
  205. };
  206. // rtti
  207. if (rtl.debug_rtti) rtl.debug('initClass '+c.$fullname);
  208. var t = c.$module.$rtti.$Class(c.$name,{ "class": c, module: parent });
  209. c.$rtti = t;
  210. if (rtl.isObject(c.$ancestor)) t.ancestor = c.$ancestor.$rtti;
  211. if (!t.ancestor) t.ancestor = null;
  212. // init members
  213. initfn.call(c);
  214. },
  215. createClass: function(parent,name,ancestor,initfn){
  216. // create a normal class,
  217. // ancestor must be null or a normal class,
  218. // the root ancestor can be an external class
  219. var c = null;
  220. if (ancestor != null){
  221. c = Object.create(ancestor);
  222. c.$ancestor = ancestor;
  223. // Note:
  224. // if root is an "object" then c.$ancestor === Object.getPrototypeOf(c)
  225. // if root is a "function" then c.$ancestor === c.__proto__, Object.getPrototypeOf(c) returns the root
  226. } else {
  227. c = {};
  228. c.$create = function(fnname,args){
  229. if (args == undefined) args = [];
  230. var o = Object.create(this);
  231. o.$class = this; // Note: o.$class === Object.getPrototypeOf(o)
  232. o.$init();
  233. try{
  234. o[fnname].apply(o,args);
  235. o.AfterConstruction();
  236. } catch($e){
  237. o.$destroy;
  238. throw $e;
  239. }
  240. return o;
  241. };
  242. c.$destroy = function(fnname){
  243. this.BeforeDestruction();
  244. this[fnname]();
  245. this.$final;
  246. };
  247. };
  248. rtl.initClass(c,parent,name,initfn);
  249. },
  250. createClassExt: function(parent,name,ancestor,newinstancefnname,initfn){
  251. // Create a class using an external ancestor.
  252. // If newinstancefnname is given, use that function to create the new object.
  253. // If exist call BeforeDestruction and AfterConstruction.
  254. var c = null;
  255. c = Object.create(ancestor);
  256. c.$create = function(fnname,args){
  257. if (args == undefined) args = [];
  258. var o = null;
  259. if (newinstancefnname.length>0){
  260. o = this[newinstancefnname](fnname,args);
  261. } else {
  262. o = Object.create(this);
  263. }
  264. o.$class = this; // Note: o.$class === Object.getPrototypeOf(o)
  265. o.$init();
  266. try{
  267. o[fnname].apply(o,args);
  268. if (o.AfterConstruction) o.AfterConstruction();
  269. } catch($e){
  270. o.$destroy;
  271. throw $e;
  272. }
  273. return o;
  274. };
  275. c.$destroy = function(fnname){
  276. if (this.BeforeDestruction) this.BeforeDestruction();
  277. this[fnname]();
  278. this.$final;
  279. };
  280. rtl.initClass(c,parent,name,initfn);
  281. },
  282. tObjectDestroy: "Destroy",
  283. free: function(obj,name){
  284. if (obj[name]==null) return;
  285. obj[name].$destroy(rtl.tObjectDestroy);
  286. obj[name]=null;
  287. },
  288. freeLoc: function(obj){
  289. if (obj==null) return;
  290. obj.$destroy(rtl.tObjectDestroy);
  291. return null;
  292. },
  293. is: function(instance,type){
  294. return type.isPrototypeOf(instance) || (instance===type);
  295. },
  296. isExt: function(instance,type,mode){
  297. // mode===1 means instance must be a Pascal class instance
  298. // mode===2 means instance must be a Pascal class
  299. // Notes:
  300. // isPrototypeOf and instanceof return false on equal
  301. // isPrototypeOf does not work for Date.isPrototypeOf(new Date())
  302. // so if isPrototypeOf is false test with instanceof
  303. // instanceof needs a function on right side
  304. if (instance == null) return false; // Note: ==null checks for undefined too
  305. if ((typeof(type) !== 'object') && (typeof(type) !== 'function')) return false;
  306. if (instance === type){
  307. if (mode===1) return false;
  308. if (mode===2) return rtl.isPasClass(instance);
  309. return true;
  310. }
  311. if (type.isPrototypeOf && type.isPrototypeOf(instance)){
  312. if (mode===1) return rtl.isPasClassInstance(instance);
  313. if (mode===2) return rtl.isPasClass(instance);
  314. return true;
  315. }
  316. if ((typeof type == 'function') && (instance instanceof type)) return true;
  317. return false;
  318. },
  319. EInvalidCast: null,
  320. raiseEInvalidCast: function(){
  321. if (rtl.EInvalidCast){
  322. if (rtl.EInvalidCast.Create){
  323. throw rtl.EInvalidCast.$create("Create");
  324. } else {
  325. throw rtl.EInvalidCast.$create("create");
  326. }
  327. } else {
  328. throw "invalid type cast";
  329. }
  330. },
  331. as: function(instance,type){
  332. if((instance === null) || rtl.is(instance,type)) return instance;
  333. rtl.raiseEInvalidCast();
  334. },
  335. asExt: function(instance,type,mode){
  336. if((instance === null) || rtl.isExt(instance,type,mode)) return instance;
  337. rtl.raiseEInvalidCast();
  338. },
  339. checkMethodCall: function(obj,type){
  340. if (rtl.isObject(obj) && rtl.is(obj,type)) return;
  341. rtl.raiseEInvalidCast();
  342. },
  343. raiseRangeCheck: function(){
  344. var m = pas.sysutils || pas.SysUtils;
  345. if (m){
  346. var t = m.ERangeError || m.erangeerror;
  347. if (rtl.isPasClass(t)){
  348. var f = 'Create';
  349. if (rtl.isFunction(t[f])){
  350. throw t.$create(f);
  351. } else {
  352. throw t.$create('create');
  353. }
  354. }
  355. }
  356. throw 'range error';
  357. },
  358. rc: function(i,minval,maxval){
  359. // range check integer
  360. if ((Math.floor(i)===i) && (i>=minval) && (i<=maxval)) return i;
  361. rtl.raiseRangeCheck();
  362. },
  363. length: function(arr){
  364. return (arr == null) ? 0 : arr.length;
  365. },
  366. arraySetLength: function(arr,defaultvalue,newlength){
  367. // multi dim: (arr,defaultvalue,dim1,dim2,...)
  368. if (arr == null) arr = [];
  369. var p = arguments;
  370. function setLength(a,argNo){
  371. var oldlen = a.length;
  372. var newlen = p[argNo];
  373. if (oldlen!==newlength){
  374. a.length = newlength;
  375. if (argNo === p.length-1){
  376. if (rtl.isArray(defaultvalue)){
  377. for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
  378. } else if (rtl.isFunction(defaultvalue)){
  379. for (var i=oldlen; i<newlen; i++) a[i]=new defaultvalue(); // e.g. record
  380. } else if (rtl.isObject(defaultvalue)) {
  381. for (var i=oldlen; i<newlen; i++) a[i]={}; // e.g. set
  382. } else {
  383. for (var i=oldlen; i<newlen; i++) a[i]=defaultvalue;
  384. }
  385. } else {
  386. for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
  387. }
  388. }
  389. if (argNo < p.length-1){
  390. // multi argNo
  391. for (var i=0; i<newlen; i++) a[i]=setLength(a[i],argNo+1);
  392. }
  393. return a;
  394. }
  395. return setLength(arr,2);
  396. },
  397. arrayClone: function(type,src,srcpos,end,dst,dstpos){
  398. // type: 0 for references, "refset" for calling refSet(), a function for new type()
  399. // src must not be null
  400. // This function does not range check.
  401. if (rtl.isFunction(type)){
  402. for (; srcpos<end; srcpos++) dst[dstpos++] = new type(src[srcpos]); // clone record
  403. } else if(isString(type) && (type === 'refSet')) {
  404. for (; srcpos<end; srcpos++) dst[dstpos++] = refSet(src[srcpos]); // ref set
  405. } else {
  406. for (; srcpos<end; srcpos++) dst[dstpos++] = src[srcpos]; // reference
  407. };
  408. },
  409. arrayConcat: function(type){
  410. // type: see rtl.arrayClone
  411. var a = [];
  412. var l = 0;
  413. for (var i=1; i<arguments.length; i++) l+=arguments[i].length;
  414. a.length = l;
  415. l=0;
  416. for (var i=1; i<arguments.length; i++){
  417. var src = arguments[i];
  418. if (src == null) continue;
  419. rtl.arrayClone(type,src,0,src.length,a,l);
  420. l+=src.length;
  421. };
  422. return a;
  423. },
  424. arrayCopy: function(type, srcarray, index, count){
  425. // type: see rtl.arrayClone
  426. // if count is missing, use srcarray.length
  427. if (srcarray == null) return [];
  428. if (index < 0) index = 0;
  429. if (count === undefined) count=srcarray.length;
  430. var end = index+count;
  431. if (end>scrarray.length) end = scrarray.length;
  432. if (index>=end) return [];
  433. if (type===0){
  434. return srcarray.slice(index,end);
  435. } else {
  436. var a = [];
  437. a.length = end-index;
  438. rtl.arrayClone(type,srcarray,index,end,a,0);
  439. return a;
  440. }
  441. },
  442. setCharAt: function(s,index,c){
  443. return s.substr(0,index)+c+s.substr(index+1);
  444. },
  445. getResStr: function(mod,name){
  446. var rs = mod.$resourcestrings[name];
  447. return rs.current?rs.current:rs.org;
  448. },
  449. createSet: function(){
  450. var s = {};
  451. for (var i=0; i<arguments.length; i++){
  452. if (arguments[i]!=null){
  453. s[arguments[i]]=true;
  454. } else {
  455. var first=arguments[i+=1];
  456. var last=arguments[i+=1];
  457. for(var j=first; j<=last; j++) s[j]=true;
  458. }
  459. }
  460. return s;
  461. },
  462. cloneSet: function(s){
  463. var r = {};
  464. for (var key in s) r[key]=true;
  465. return r;
  466. },
  467. refSet: function(s){
  468. s.$shared = true;
  469. return s;
  470. },
  471. includeSet: function(s,enumvalue){
  472. if (s.$shared) s = rtl.cloneSet(s);
  473. s[enumvalue] = true;
  474. return s;
  475. },
  476. excludeSet: function(s,enumvalue){
  477. if (s.$shared) s = rtl.cloneSet(s);
  478. delete s[enumvalue];
  479. return s;
  480. },
  481. diffSet: function(s,t){
  482. var r = {};
  483. for (var key in s) if (!t[key]) r[key]=true;
  484. delete r.$shared;
  485. return r;
  486. },
  487. unionSet: function(s,t){
  488. var r = {};
  489. for (var key in s) r[key]=true;
  490. for (var key in t) r[key]=true;
  491. delete r.$shared;
  492. return r;
  493. },
  494. intersectSet: function(s,t){
  495. var r = {};
  496. for (var key in s) if (t[key]) r[key]=true;
  497. delete r.$shared;
  498. return r;
  499. },
  500. symDiffSet: function(s,t){
  501. var r = {};
  502. for (var key in s) if (!t[key]) r[key]=true;
  503. for (var key in t) if (!s[key]) r[key]=true;
  504. delete r.$shared;
  505. return r;
  506. },
  507. eqSet: function(s,t){
  508. for (var key in s) if (!t[key] && (key!='$shared')) return false;
  509. for (var key in t) if (!s[key] && (key!='$shared')) return false;
  510. return true;
  511. },
  512. neSet: function(s,t){
  513. return !rtl.eqSet(s,t);
  514. },
  515. leSet: function(s,t){
  516. for (var key in s) if (!t[key] && (key!='$shared')) return false;
  517. return true;
  518. },
  519. geSet: function(s,t){
  520. for (var key in t) if (!s[key] && (key!='$shared')) return false;
  521. return true;
  522. },
  523. strSetLength: function(s,newlen){
  524. var oldlen = s.length;
  525. if (oldlen > newlen){
  526. return s.substring(0,newlen);
  527. } else if (s.repeat){
  528. // Note: repeat needs ECMAScript6!
  529. return s+' '.repeat(newlen-oldlen);
  530. } else {
  531. while (oldlen<newlen){
  532. s+=' ';
  533. oldlen++;
  534. };
  535. return s;
  536. }
  537. },
  538. spaceLeft: function(s,width){
  539. var l=s.length;
  540. if (l>=width) return s;
  541. if (s.repeat){
  542. // Note: repeat needs ECMAScript6!
  543. return ' '.repeat(width-l) + s;
  544. } else {
  545. while (l<width){
  546. s=' '+s;
  547. l++;
  548. };
  549. };
  550. },
  551. floatToStr : function(d,w,p){
  552. // input 1-3 arguments: double, width, precision
  553. if (arguments.length>2){
  554. return rtl.spaceLeft(d.toFixed(p),w);
  555. } else {
  556. // exponent width
  557. var pad = "";
  558. var ad = Math.abs(d);
  559. if (ad<1.0e+10) {
  560. pad='00';
  561. } else if (ad<1.0e+100) {
  562. pad='0';
  563. }
  564. if (arguments.length<2) {
  565. w=9;
  566. } else if (w<9) {
  567. w=9;
  568. }
  569. var p = w-8;
  570. var s=(d>0 ? " " : "" ) + d.toExponential(p);
  571. s=s.replace(/e(.)/,'E$1'+pad);
  572. return rtl.spaceLeft(s,w);
  573. }
  574. },
  575. initRTTI: function(){
  576. if (rtl.debug_rtti) rtl.debug('initRTTI');
  577. // base types
  578. rtl.tTypeInfo = { name: "tTypeInfo" };
  579. function newBaseTI(name,kind,ancestor){
  580. if (!ancestor) ancestor = rtl.tTypeInfo;
  581. if (rtl.debug_rtti) rtl.debug('initRTTI.newBaseTI "'+name+'" '+kind+' ("'+ancestor.name+'")');
  582. var t = Object.create(ancestor);
  583. t.name = name;
  584. t.kind = kind;
  585. rtl[name] = t;
  586. return t;
  587. };
  588. function newBaseInt(name,minvalue,maxvalue,ordtype){
  589. var t = newBaseTI(name,1 /* tkInteger */,rtl.tTypeInfoInteger);
  590. t.minvalue = minvalue;
  591. t.maxvalue = maxvalue;
  592. t.ordtype = ordtype;
  593. return t;
  594. };
  595. newBaseTI("tTypeInfoInteger",1 /* tkInteger */);
  596. newBaseInt("shortint",-0x80,0x7f,0);
  597. newBaseInt("byte",0,0xff,1);
  598. newBaseInt("smallint",-0x8000,0x7fff,2);
  599. newBaseInt("word",0,0xffff,3);
  600. newBaseInt("longint",-0x80000000,0x7fffffff,4);
  601. newBaseInt("longword",0,0xffffffff,5);
  602. newBaseInt("nativeint",-0x10000000000000,0xfffffffffffff,6);
  603. newBaseInt("nativeuint",0,0xfffffffffffff,7);
  604. newBaseTI("char",2 /* tkChar */);
  605. newBaseTI("string",3 /* tkString */);
  606. newBaseTI("tTypeInfoEnum",4 /* tkEnumeration */,rtl.tTypeInfoInteger);
  607. newBaseTI("tTypeInfoSet",5 /* tkSet */);
  608. newBaseTI("double",6 /* tkDouble */);
  609. newBaseTI("boolean",7 /* tkBool */);
  610. newBaseTI("tTypeInfoProcVar",8 /* tkProcVar */);
  611. newBaseTI("tTypeInfoMethodVar",9 /* tkMethod */,rtl.tTypeInfoProcVar);
  612. newBaseTI("tTypeInfoArray",10 /* tkArray */);
  613. newBaseTI("tTypeInfoDynArray",11 /* tkDynArray */);
  614. newBaseTI("tTypeInfoPointer",15 /* tkPointer */);
  615. var t = newBaseTI("pointer",15 /* tkPointer */,rtl.tTypeInfoPointer);
  616. t.reftype = null;
  617. newBaseTI("jsvalue",16 /* tkJSValue */);
  618. newBaseTI("tTypeInfoRefToProcVar",17 /* tkRefToProcVar */,rtl.tTypeInfoProcVar);
  619. // member kinds
  620. rtl.tTypeMember = {};
  621. function newMember(name,kind){
  622. var m = Object.create(rtl.tTypeMember);
  623. m.name = name;
  624. m.kind = kind;
  625. rtl[name] = m;
  626. };
  627. newMember("tTypeMemberField",1); // tmkField
  628. newMember("tTypeMemberMethod",2); // tmkMethod
  629. newMember("tTypeMemberProperty",3); // tmkProperty
  630. // base object for storing members: a simple object
  631. rtl.tTypeMembers = {};
  632. // tTypeInfoStruct - base object for tTypeInfoClass and tTypeInfoRecord
  633. var tis = newBaseTI("tTypeInfoStruct",0);
  634. tis.$addMember = function(name,ancestor,options){
  635. if (rtl.debug_rtti){
  636. if (!rtl.hasString(name) || (name.charAt()==='$')) throw 'invalid member "'+name+'", this="'+this.name+'"';
  637. if (!rtl.is(ancestor,rtl.tTypeMember)) throw 'invalid ancestor "'+ancestor+':'+ancestor.name+'", "'+this.name+'.'+name+'"';
  638. if ((options!=undefined) && (typeof(options)!='object')) throw 'invalid options "'+options+'", "'+this.name+'.'+name+'"';
  639. };
  640. var t = Object.create(ancestor);
  641. t.name = name;
  642. this.members[name] = t;
  643. this.names.push(name);
  644. if (rtl.isObject(options)){
  645. for (var key in options) if (options.hasOwnProperty(key)) t[key] = options[key];
  646. };
  647. return t;
  648. };
  649. tis.addField = function(name,type,options){
  650. var t = this.$addMember(name,rtl.tTypeMemberField,options);
  651. if (rtl.debug_rtti){
  652. if (!rtl.is(type,rtl.tTypeInfo)) throw 'invalid type "'+type+'", "'+this.name+'.'+name+'"';
  653. };
  654. t.typeinfo = type;
  655. this.fields.push(name);
  656. return t;
  657. };
  658. tis.addFields = function(){
  659. var i=0;
  660. while(i<arguments.length){
  661. var name = arguments[i++];
  662. var type = arguments[i++];
  663. if ((i<arguments.length) && (typeof(arguments[i])==='object')){
  664. this.addField(name,type,arguments[i++]);
  665. } else {
  666. this.addField(name,type);
  667. };
  668. };
  669. };
  670. tis.addMethod = function(name,methodkind,params,result,options){
  671. var t = this.$addMember(name,rtl.tTypeMemberMethod,options);
  672. t.methodkind = methodkind;
  673. t.procsig = rtl.newTIProcSig(params);
  674. t.procsig.resulttype = result?result:null;
  675. this.methods.push(name);
  676. return t;
  677. };
  678. tis.addProperty = function(name,flags,result,getter,setter,options){
  679. var t = this.$addMember(name,rtl.tTypeMemberProperty,options);
  680. t.flags = flags;
  681. t.typeinfo = result;
  682. t.getter = getter;
  683. t.setter = setter;
  684. // Note: in options: params, stored, defaultvalue
  685. if (rtl.isArray(t.params)) t.params = rtl.newTIParams(t.params);
  686. this.properties.push(name);
  687. if (!rtl.isString(t.stored)) t.stored = "";
  688. return t;
  689. };
  690. tis.getField = function(index){
  691. return this.members[this.fields[index]];
  692. };
  693. tis.getMethod = function(index){
  694. return this.members[this.methods[index]];
  695. };
  696. tis.getProperty = function(index){
  697. return this.members[this.properties[index]];
  698. };
  699. newBaseTI("tTypeInfoRecord",12 /* tkRecord */,rtl.tTypeInfoStruct);
  700. newBaseTI("tTypeInfoClass",13 /* tkClass */,rtl.tTypeInfoStruct);
  701. newBaseTI("tTypeInfoClassRef",14 /* tkClassRef */);
  702. },
  703. tSectionRTTI: {
  704. $module: null,
  705. $inherited: function(name,ancestor,o){
  706. if (rtl.debug_rtti){
  707. rtl.debug('tSectionRTTI.newTI "'+(this.$module?this.$module.$name:"(no module)")
  708. +'"."'+name+'" ('+ancestor.name+') '+(o?'init':'forward'));
  709. };
  710. var t = this[name];
  711. if (t){
  712. if (!t.$forward) throw 'duplicate type "'+name+'"';
  713. if (!ancestor.isPrototypeOf(t)) throw 'typeinfo ancestor mismatch "'+name+'" ancestor="'+ancestor.name+'" t.name="'+t.name+'"';
  714. } else {
  715. t = Object.create(ancestor);
  716. t.name = name;
  717. t.module = this.module;
  718. this[name] = t;
  719. }
  720. if (o){
  721. delete t.$forward;
  722. for (var key in o) if (o.hasOwnProperty(key)) t[key]=o[key];
  723. } else {
  724. t.$forward = true;
  725. }
  726. return t;
  727. },
  728. $Scope: function(name,ancestor,o){
  729. var t=this.$inherited(name,ancestor,o);
  730. t.members = {};
  731. t.names = [];
  732. t.fields = [];
  733. t.methods = [];
  734. t.properties = [];
  735. return t;
  736. },
  737. $TI: function(name,kind,o){ var t=this.$inherited(name,rtl.tTypeInfo,o); t.kind = kind; return t; },
  738. $Int: function(name,o){ return this.$inherited(name,rtl.tTypeInfoInteger,o); },
  739. $Enum: function(name,o){ return this.$inherited(name,rtl.tTypeInfoEnum,o); },
  740. $Set: function(name,o){ return this.$inherited(name,rtl.tTypeInfoSet,o); },
  741. $StaticArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoArray,o); },
  742. $DynArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoDynArray,o); },
  743. $ProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoProcVar,o); },
  744. $RefToProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoRefToProcVar,o); },
  745. $MethodVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoMethodVar,o); },
  746. $Record: function(name,o){ return this.$Scope(name,rtl.tTypeInfoRecord,o); },
  747. $Class: function(name,o){ return this.$Scope(name,rtl.tTypeInfoClass,o); },
  748. $ClassRef: function(name,o){ return this.$inherited(name,rtl.tTypeInfoClassRef,o); },
  749. $Pointer: function(name,o){ return this.$inherited(name,rtl.tTypeInfoPointer,o); },
  750. },
  751. newTIParam: function(param){
  752. // param is an array, 0=name, 1=type, 2=optional flags
  753. var t = {
  754. name: param[0],
  755. typeinfo: param[1],
  756. flags: (rtl.isNumber(param[2]) ? param[2] : 0),
  757. };
  758. return t;
  759. },
  760. newTIParams: function(list){
  761. // list: optional array of [paramname,typeinfo,optional flags]
  762. var params = [];
  763. if (rtl.isArray(list)){
  764. for (var i=0; i<list.length; i++) params.push(rtl.newTIParam(list[i]));
  765. };
  766. return params;
  767. },
  768. newTIProcSig: function(params,result,flags){
  769. var s = {
  770. params: rtl.newTIParams(params),
  771. resulttype: result,
  772. flags: flags
  773. };
  774. return s;
  775. },
  776. }