mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-03 10:58:27 +02:00
870 lines
26 KiB
JavaScript
870 lines
26 KiB
JavaScript
var pas = {};
|
|
|
|
var rtl = {
|
|
|
|
quiet: false,
|
|
debug_load_units: false,
|
|
debug_rtti: false,
|
|
|
|
debug: function(){
|
|
if (rtl.quiet || !console || !console.log) return;
|
|
console.log(arguments);
|
|
},
|
|
|
|
error: function(s){
|
|
rtl.debug('Error: ',s);
|
|
throw s;
|
|
},
|
|
|
|
warn: function(s){
|
|
rtl.debug('Warn: ',s);
|
|
},
|
|
|
|
hasString: function(s){
|
|
return rtl.isString(s) && (s.length>0);
|
|
},
|
|
|
|
isArray: function(a) {
|
|
return Array.isArray(a);
|
|
},
|
|
|
|
isFunction: function(f){
|
|
return typeof(f)==="function";
|
|
},
|
|
|
|
isModule: function(m){
|
|
return rtl.isObject(m) && rtl.hasString(m.$name) && (pas[m.$name]===m);
|
|
},
|
|
|
|
isImplementation: function(m){
|
|
return rtl.isObject(m) && rtl.isModule(m.$module) && (m.$module.$impl===m);
|
|
},
|
|
|
|
isNumber: function(n){
|
|
return typeof(n)==="number";
|
|
},
|
|
|
|
isObject: function(o){
|
|
var s=typeof(o);
|
|
return (typeof(o)==="object") && (o!=null);
|
|
},
|
|
|
|
isString: function(s){
|
|
return typeof(s)==="string";
|
|
},
|
|
|
|
getNumber: function(n){
|
|
return typeof(n)==="number"?n:NaN;
|
|
},
|
|
|
|
getChar: function(c){
|
|
return ((typeof(c)==="string") && (c.length===1)) ? c : "";
|
|
},
|
|
|
|
getObject: function(o){
|
|
return ((typeof(o)==="object") || (typeof(o)==='function')) ? o : null;
|
|
},
|
|
|
|
isPasClass: function(type){
|
|
return (rtl.isObject(type) && type.hasOwnProperty('$classname') && rtl.isObject(type.$module));
|
|
},
|
|
|
|
isPasClassInstance: function(type){
|
|
return (rtl.isObject(type) && rtl.isPasClass(type.$class));
|
|
},
|
|
|
|
m_loading: 0,
|
|
m_loading_intf: 1,
|
|
m_intf_loaded: 2,
|
|
m_loading_impl: 3, // loading all used unit
|
|
m_initializing: 4, // running initialization
|
|
m_initialized: 5,
|
|
|
|
module: function(module_name, intfuseslist, intfcode, impluseslist, implcode){
|
|
if (rtl.debug_load_units) rtl.debug('rtl.module name="'+module_name+'" intfuses='+intfuseslist+' impluses='+impluseslist+' hasimplcode='+rtl.isFunction(implcode));
|
|
if (!rtl.hasString(module_name)) rtl.error('invalid module name "'+module_name+'"');
|
|
if (!rtl.isArray(intfuseslist)) rtl.error('invalid interface useslist of "'+module_name+'"');
|
|
if (!rtl.isFunction(intfcode)) rtl.error('invalid interface code of "'+module_name+'"');
|
|
if (!(impluseslist==undefined) && !rtl.isArray(impluseslist)) rtl.error('invalid implementation useslist of "'+module_name+'"');
|
|
if (!(implcode==undefined) && !rtl.isFunction(implcode)) rtl.error('invalid implementation code of "'+module_name+'"');
|
|
|
|
if (pas[module_name])
|
|
rtl.error('module "'+module_name+'" is already registered');
|
|
|
|
var module = pas[module_name] = {
|
|
$name: module_name,
|
|
$intfuseslist: intfuseslist,
|
|
$impluseslist: impluseslist,
|
|
$state: rtl.m_loading,
|
|
$intfcode: intfcode,
|
|
$implcode: implcode,
|
|
$impl: null,
|
|
$rtti: Object.create(rtl.tSectionRTTI),
|
|
};
|
|
module.$rtti.$module = module;
|
|
if (implcode) module.$impl = {
|
|
$module: module,
|
|
$rtti: module.$rtti,
|
|
};
|
|
},
|
|
|
|
exitcode: 0,
|
|
// Create needed polyfills for the rtl to run.
|
|
|
|
createPolyFills : function () {
|
|
if (!Math.trunc) {
|
|
Math.trunc = function(v) {
|
|
v = +v;
|
|
if (!isFinite(v)) return v;
|
|
return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0);
|
|
};
|
|
}
|
|
},
|
|
|
|
run: function(module_name){
|
|
|
|
function doRun(){
|
|
if (!rtl.hasString(module_name)) module_name='program';
|
|
if (rtl.debug_load_units) rtl.debug('rtl.run module="'+module_name+'"');
|
|
rtl.initRTTI();
|
|
var module = pas[module_name];
|
|
if (!module) rtl.error('rtl.run module "'+module_name+'" missing');
|
|
rtl.loadintf(module);
|
|
rtl.loadimpl(module);
|
|
if (module_name=='program'){
|
|
if (rtl.debug_load_units) rtl.debug('running $main');
|
|
var r = pas.program.$main();
|
|
if (rtl.isNumber(r)) rtl.exitcode = r;
|
|
}
|
|
}
|
|
|
|
rtl.createPolyFills();
|
|
|
|
if (rtl.showUncaughtExceptions) {
|
|
try{
|
|
doRun();
|
|
} catch(re) {
|
|
var errMsg = re.hasOwnProperty('$class') ? re.$class.$classname : '';
|
|
errMsg += ((errMsg) ? ': ' : '') + (re.hasOwnProperty('fMessage') ? re.fMessage : re);
|
|
alert('Uncaught Exception : '+errMsg);
|
|
rtl.exitCode = 216;
|
|
}
|
|
} else {
|
|
doRun();
|
|
}
|
|
return rtl.exitcode;
|
|
},
|
|
|
|
loadintf: function(module){
|
|
if (module.$state>rtl.m_loading_intf) return; // already finished
|
|
if (rtl.debug_load_units) rtl.debug('loadintf: "'+module.$name+'"');
|
|
if (module.$state===rtl.m_loading_intf)
|
|
rtl.error('unit cycle detected "'+module.$name+'"');
|
|
module.$state=rtl.m_loading_intf;
|
|
// load interfaces of interface useslist
|
|
rtl.loaduseslist(module,module.$intfuseslist,rtl.loadintf);
|
|
// run interface
|
|
if (rtl.debug_load_units) rtl.debug('loadintf: run intf of "'+module.$name+'"');
|
|
module.$intfcode(module.$intfuseslist);
|
|
// success
|
|
module.$state=rtl.m_intf_loaded;
|
|
// Note: units only used in implementations are not yet loaded (not even their interfaces)
|
|
},
|
|
|
|
loaduseslist: function(module,useslist,f){
|
|
if (useslist==undefined) return;
|
|
for (var i in useslist){
|
|
var unitname=useslist[i];
|
|
if (rtl.debug_load_units) rtl.debug('loaduseslist of "'+module.$name+'" uses="'+unitname+'"');
|
|
if (pas[unitname]==undefined)
|
|
rtl.error('module "'+module.$name+'" misses "'+unitname+'"');
|
|
f(pas[unitname]);
|
|
}
|
|
},
|
|
|
|
loadimpl: function(module){
|
|
if (module.$state>=rtl.m_loading_impl) return; // already processing
|
|
if (module.$state<rtl.m_intf_loaded) rtl.error('loadimpl: interface not loaded of "'+module.$name+'"');
|
|
if (rtl.debug_load_units) rtl.debug('loadimpl: load uses of "'+module.$name+'"');
|
|
module.$state=rtl.m_loading_impl;
|
|
// load interfaces of implementation useslist
|
|
rtl.loaduseslist(module,module.$impluseslist,rtl.loadintf);
|
|
// load implementation of interfaces useslist
|
|
rtl.loaduseslist(module,module.$intfuseslist,rtl.loadimpl);
|
|
// load implementation of implementation useslist
|
|
rtl.loaduseslist(module,module.$impluseslist,rtl.loadimpl);
|
|
// Note: At this point all interfaces used by this unit are loaded. If
|
|
// there are implementation uses cycles some used units might not yet be
|
|
// initialized. This is by design.
|
|
// run implementation
|
|
if (rtl.debug_load_units) rtl.debug('loadimpl: run impl of "'+module.$name+'"');
|
|
if (rtl.isFunction(module.$implcode)) module.$implcode(module.$impluseslist);
|
|
// run initialization
|
|
if (rtl.debug_load_units) rtl.debug('loadimpl: run init of "'+module.$name+'"');
|
|
module.$state=rtl.m_initializing;
|
|
if (rtl.isFunction(module.$init)) module.$init();
|
|
// unit initialized
|
|
module.$state=rtl.m_initialized;
|
|
},
|
|
|
|
createCallback: function(scope, fn){
|
|
var cb;
|
|
if (typeof(fn)==='string'){
|
|
cb = function(){
|
|
return scope[fn].apply(scope,arguments);
|
|
};
|
|
} else {
|
|
cb = function(){
|
|
return fn.apply(scope,arguments);
|
|
};
|
|
};
|
|
cb.scope = scope;
|
|
cb.fn = fn;
|
|
return cb;
|
|
},
|
|
|
|
cloneCallback: function(cb){
|
|
return rtl.createCallback(cb.scope,cb.fn);
|
|
},
|
|
|
|
eqCallback: function(a,b){
|
|
// can be a function or a function wrapper
|
|
if (a==b){
|
|
return true;
|
|
} else {
|
|
return (a!=null) && (b!=null) && (a.fn) && (a.scope===b.scope) && (a.fn==b.fn);
|
|
}
|
|
},
|
|
|
|
initClass: function(c,parent,name,initfn){
|
|
parent[name] = c;
|
|
c.$classname = name;
|
|
if ((parent.$module) && (parent.$module.$impl===parent)) parent=parent.$module;
|
|
c.$parent = parent;
|
|
c.$fullname = parent.$name+'.'+name;
|
|
if (rtl.isModule(parent)){
|
|
c.$module = parent;
|
|
c.$name = name;
|
|
} else {
|
|
c.$module = parent.$module;
|
|
c.$name = parent.name+'.'+name;
|
|
};
|
|
// rtti
|
|
if (rtl.debug_rtti) rtl.debug('initClass '+c.$fullname);
|
|
var t = c.$module.$rtti.$Class(c.$name,{ "class": c, module: parent });
|
|
c.$rtti = t;
|
|
if (rtl.isObject(c.$ancestor)) t.ancestor = c.$ancestor.$rtti;
|
|
if (!t.ancestor) t.ancestor = null;
|
|
// init members
|
|
initfn.call(c);
|
|
},
|
|
|
|
createClass: function(parent,name,ancestor,initfn){
|
|
// create a normal class,
|
|
// ancestor must be null or a normal class,
|
|
// the root ancestor can be an external class
|
|
var c = null;
|
|
if (ancestor != null){
|
|
c = Object.create(ancestor);
|
|
c.$ancestor = ancestor;
|
|
// Note:
|
|
// if root is an "object" then c.$ancestor === Object.getPrototypeOf(c)
|
|
// if root is a "function" then c.$ancestor === c.__proto__, Object.getPrototypeOf(c) returns the root
|
|
} else {
|
|
c = {};
|
|
c.$create = function(fnname,args){
|
|
if (args == undefined) args = [];
|
|
var o = Object.create(this);
|
|
o.$class = this; // Note: o.$class === Object.getPrototypeOf(o)
|
|
o.$init();
|
|
try{
|
|
o[fnname].apply(o,args);
|
|
o.AfterConstruction();
|
|
} catch($e){
|
|
o.$destroy;
|
|
throw $e;
|
|
}
|
|
return o;
|
|
};
|
|
c.$destroy = function(fnname){
|
|
this.BeforeDestruction();
|
|
this[fnname]();
|
|
this.$final;
|
|
};
|
|
};
|
|
rtl.initClass(c,parent,name,initfn);
|
|
},
|
|
|
|
createClassExt: function(parent,name,ancestor,newinstancefnname,initfn){
|
|
// Create a class using an external ancestor.
|
|
// If newinstancefnname is given, use that function to create the new object.
|
|
// If exist call BeforeDestruction and AfterConstruction.
|
|
var c = null;
|
|
c = Object.create(ancestor);
|
|
c.$create = function(fnname,args){
|
|
if (args == undefined) args = [];
|
|
var o = null;
|
|
if (newinstancefnname.length>0){
|
|
o = this[newinstancefnname](fnname,args);
|
|
} else {
|
|
o = Object.create(this);
|
|
}
|
|
o.$class = this; // Note: o.$class === Object.getPrototypeOf(o)
|
|
o.$init();
|
|
try{
|
|
o[fnname].apply(o,args);
|
|
if (o.AfterConstruction) o.AfterConstruction();
|
|
} catch($e){
|
|
o.$destroy;
|
|
throw $e;
|
|
}
|
|
return o;
|
|
};
|
|
c.$destroy = function(fnname){
|
|
if (this.BeforeDestruction) this.BeforeDestruction();
|
|
this[fnname]();
|
|
this.$final;
|
|
};
|
|
rtl.initClass(c,parent,name,initfn);
|
|
},
|
|
|
|
tObjectDestroy: "Destroy",
|
|
|
|
free: function(obj,name){
|
|
if (obj[name]==null) return;
|
|
obj[name].$destroy(rtl.tObjectDestroy);
|
|
obj[name]=null;
|
|
},
|
|
|
|
freeLoc: function(obj){
|
|
if (obj==null) return;
|
|
obj.$destroy(rtl.tObjectDestroy);
|
|
return null;
|
|
},
|
|
|
|
is: function(instance,type){
|
|
return type.isPrototypeOf(instance) || (instance===type);
|
|
},
|
|
|
|
isExt: function(instance,type,mode){
|
|
// mode===1 means instance must be a Pascal class instance
|
|
// mode===2 means instance must be a Pascal class
|
|
// Notes:
|
|
// isPrototypeOf and instanceof return false on equal
|
|
// isPrototypeOf does not work for Date.isPrototypeOf(new Date())
|
|
// so if isPrototypeOf is false test with instanceof
|
|
// instanceof needs a function on right side
|
|
if (instance == null) return false; // Note: ==null checks for undefined too
|
|
if ((typeof(type) !== 'object') && (typeof(type) !== 'function')) return false;
|
|
if (instance === type){
|
|
if (mode===1) return false;
|
|
if (mode===2) return rtl.isPasClass(instance);
|
|
return true;
|
|
}
|
|
if (type.isPrototypeOf && type.isPrototypeOf(instance)){
|
|
if (mode===1) return rtl.isPasClassInstance(instance);
|
|
if (mode===2) return rtl.isPasClass(instance);
|
|
return true;
|
|
}
|
|
if ((typeof type == 'function') && (instance instanceof type)) return true;
|
|
return false;
|
|
},
|
|
|
|
EInvalidCast: null,
|
|
|
|
raiseEInvalidCast: function(){
|
|
if (rtl.EInvalidCast){
|
|
if (rtl.EInvalidCast.Create){
|
|
throw rtl.EInvalidCast.$create("Create");
|
|
} else {
|
|
throw rtl.EInvalidCast.$create("create");
|
|
}
|
|
} else {
|
|
throw "invalid type cast";
|
|
}
|
|
},
|
|
|
|
as: function(instance,type){
|
|
if((instance === null) || rtl.is(instance,type)) return instance;
|
|
rtl.raiseEInvalidCast();
|
|
},
|
|
|
|
asExt: function(instance,type,mode){
|
|
if((instance === null) || rtl.isExt(instance,type,mode)) return instance;
|
|
rtl.raiseEInvalidCast();
|
|
},
|
|
|
|
checkMethodCall: function(obj,type){
|
|
if (rtl.isObject(obj) && rtl.is(obj,type)) return;
|
|
rtl.raiseEInvalidCast();
|
|
},
|
|
|
|
raiseRangeCheck: function(){
|
|
var m = pas.sysutils || pas.SysUtils;
|
|
if (m){
|
|
var t = m.ERangeError || m.erangeerror;
|
|
if (rtl.isPasClass(t)){
|
|
var f = 'Create';
|
|
if (rtl.isFunction(t[f])){
|
|
throw t.$create(f);
|
|
} else {
|
|
throw t.$create('create');
|
|
}
|
|
}
|
|
}
|
|
throw 'range error';
|
|
},
|
|
|
|
rc: function(i,minval,maxval){
|
|
// range check integer
|
|
if ((Math.floor(i)===i) && (i>=minval) && (i<=maxval)) return i;
|
|
rtl.raiseRangeCheck();
|
|
},
|
|
|
|
length: function(arr){
|
|
return (arr == null) ? 0 : arr.length;
|
|
},
|
|
|
|
arraySetLength: function(arr,defaultvalue,newlength){
|
|
// multi dim: (arr,defaultvalue,dim1,dim2,...)
|
|
if (arr == null) arr = [];
|
|
var p = arguments;
|
|
function setLength(a,argNo){
|
|
var oldlen = a.length;
|
|
var newlen = p[argNo];
|
|
if (oldlen!==newlength){
|
|
a.length = newlength;
|
|
if (argNo === p.length-1){
|
|
if (rtl.isArray(defaultvalue)){
|
|
for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
|
|
} else if (rtl.isFunction(defaultvalue)){
|
|
for (var i=oldlen; i<newlen; i++) a[i]=new defaultvalue(); // e.g. record
|
|
} else if (rtl.isObject(defaultvalue)) {
|
|
for (var i=oldlen; i<newlen; i++) a[i]={}; // e.g. set
|
|
} else {
|
|
for (var i=oldlen; i<newlen; i++) a[i]=defaultvalue;
|
|
}
|
|
} else {
|
|
for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
|
|
}
|
|
}
|
|
if (argNo < p.length-1){
|
|
// multi argNo
|
|
for (var i=0; i<newlen; i++) a[i]=setLength(a[i],argNo+1);
|
|
}
|
|
return a;
|
|
}
|
|
return setLength(arr,2);
|
|
},
|
|
|
|
arrayClone: function(type,src,srcpos,end,dst,dstpos){
|
|
// type: 0 for references, "refset" for calling refSet(), a function for new type()
|
|
// src must not be null
|
|
// This function does not range check.
|
|
if (rtl.isFunction(type)){
|
|
for (; srcpos<end; srcpos++) dst[dstpos++] = new type(src[srcpos]); // clone record
|
|
} else if(isString(type) && (type === 'refSet')) {
|
|
for (; srcpos<end; srcpos++) dst[dstpos++] = refSet(src[srcpos]); // ref set
|
|
} else {
|
|
for (; srcpos<end; srcpos++) dst[dstpos++] = src[srcpos]; // reference
|
|
};
|
|
},
|
|
|
|
arrayConcat: function(type){
|
|
// type: see rtl.arrayClone
|
|
var a = [];
|
|
var l = 0;
|
|
for (var i=1; i<arguments.length; i++) l+=arguments[i].length;
|
|
a.length = l;
|
|
l=0;
|
|
for (var i=1; i<arguments.length; i++){
|
|
var src = arguments[i];
|
|
if (src == null) continue;
|
|
rtl.arrayClone(type,src,0,src.length,a,l);
|
|
l+=src.length;
|
|
};
|
|
return a;
|
|
},
|
|
|
|
arrayCopy: function(type, srcarray, index, count){
|
|
// type: see rtl.arrayClone
|
|
// if count is missing, use srcarray.length
|
|
if (srcarray == null) return [];
|
|
if (index < 0) index = 0;
|
|
if (count === undefined) count=srcarray.length;
|
|
var end = index+count;
|
|
if (end>scrarray.length) end = scrarray.length;
|
|
if (index>=end) return [];
|
|
if (type===0){
|
|
return srcarray.slice(index,end);
|
|
} else {
|
|
var a = [];
|
|
a.length = end-index;
|
|
rtl.arrayClone(type,srcarray,index,end,a,0);
|
|
return a;
|
|
}
|
|
},
|
|
|
|
setCharAt: function(s,index,c){
|
|
return s.substr(0,index)+c+s.substr(index+1);
|
|
},
|
|
|
|
getResStr: function(mod,name){
|
|
var rs = mod.$resourcestrings[name];
|
|
return rs.current?rs.current:rs.org;
|
|
},
|
|
|
|
createSet: function(){
|
|
var s = {};
|
|
for (var i=0; i<arguments.length; i++){
|
|
if (arguments[i]!=null){
|
|
s[arguments[i]]=true;
|
|
} else {
|
|
var first=arguments[i+=1];
|
|
var last=arguments[i+=1];
|
|
for(var j=first; j<=last; j++) s[j]=true;
|
|
}
|
|
}
|
|
return s;
|
|
},
|
|
|
|
cloneSet: function(s){
|
|
var r = {};
|
|
for (var key in s) r[key]=true;
|
|
return r;
|
|
},
|
|
|
|
refSet: function(s){
|
|
s.$shared = true;
|
|
return s;
|
|
},
|
|
|
|
includeSet: function(s,enumvalue){
|
|
if (s.$shared) s = rtl.cloneSet(s);
|
|
s[enumvalue] = true;
|
|
return s;
|
|
},
|
|
|
|
excludeSet: function(s,enumvalue){
|
|
if (s.$shared) s = rtl.cloneSet(s);
|
|
delete s[enumvalue];
|
|
return s;
|
|
},
|
|
|
|
diffSet: function(s,t){
|
|
var r = {};
|
|
for (var key in s) if (!t[key]) r[key]=true;
|
|
delete r.$shared;
|
|
return r;
|
|
},
|
|
|
|
unionSet: function(s,t){
|
|
var r = {};
|
|
for (var key in s) r[key]=true;
|
|
for (var key in t) r[key]=true;
|
|
delete r.$shared;
|
|
return r;
|
|
},
|
|
|
|
intersectSet: function(s,t){
|
|
var r = {};
|
|
for (var key in s) if (t[key]) r[key]=true;
|
|
delete r.$shared;
|
|
return r;
|
|
},
|
|
|
|
symDiffSet: function(s,t){
|
|
var r = {};
|
|
for (var key in s) if (!t[key]) r[key]=true;
|
|
for (var key in t) if (!s[key]) r[key]=true;
|
|
delete r.$shared;
|
|
return r;
|
|
},
|
|
|
|
eqSet: function(s,t){
|
|
for (var key in s) if (!t[key] && (key!='$shared')) return false;
|
|
for (var key in t) if (!s[key] && (key!='$shared')) return false;
|
|
return true;
|
|
},
|
|
|
|
neSet: function(s,t){
|
|
return !rtl.eqSet(s,t);
|
|
},
|
|
|
|
leSet: function(s,t){
|
|
for (var key in s) if (!t[key] && (key!='$shared')) return false;
|
|
return true;
|
|
},
|
|
|
|
geSet: function(s,t){
|
|
for (var key in t) if (!s[key] && (key!='$shared')) return false;
|
|
return true;
|
|
},
|
|
|
|
strSetLength: function(s,newlen){
|
|
var oldlen = s.length;
|
|
if (oldlen > newlen){
|
|
return s.substring(0,newlen);
|
|
} else if (s.repeat){
|
|
// Note: repeat needs ECMAScript6!
|
|
return s+' '.repeat(newlen-oldlen);
|
|
} else {
|
|
while (oldlen<newlen){
|
|
s+=' ';
|
|
oldlen++;
|
|
};
|
|
return s;
|
|
}
|
|
},
|
|
|
|
spaceLeft: function(s,width){
|
|
var l=s.length;
|
|
if (l>=width) return s;
|
|
if (s.repeat){
|
|
// Note: repeat needs ECMAScript6!
|
|
return ' '.repeat(width-l) + s;
|
|
} else {
|
|
while (l<width){
|
|
s=' '+s;
|
|
l++;
|
|
};
|
|
};
|
|
},
|
|
|
|
floatToStr : function(d,w,p){
|
|
// input 1-3 arguments: double, width, precision
|
|
if (arguments.length>2){
|
|
return rtl.spaceLeft(d.toFixed(p),w);
|
|
} else {
|
|
// exponent width
|
|
var pad = "";
|
|
var ad = Math.abs(d);
|
|
if (ad<1.0e+10) {
|
|
pad='00';
|
|
} else if (ad<1.0e+100) {
|
|
pad='0';
|
|
}
|
|
if (arguments.length<2) {
|
|
w=9;
|
|
} else if (w<9) {
|
|
w=9;
|
|
}
|
|
var p = w-8;
|
|
var s=(d>0 ? " " : "" ) + d.toExponential(p);
|
|
s=s.replace(/e(.)/,'E$1'+pad);
|
|
return rtl.spaceLeft(s,w);
|
|
}
|
|
},
|
|
|
|
initRTTI: function(){
|
|
if (rtl.debug_rtti) rtl.debug('initRTTI');
|
|
|
|
// base types
|
|
rtl.tTypeInfo = { name: "tTypeInfo" };
|
|
function newBaseTI(name,kind,ancestor){
|
|
if (!ancestor) ancestor = rtl.tTypeInfo;
|
|
if (rtl.debug_rtti) rtl.debug('initRTTI.newBaseTI "'+name+'" '+kind+' ("'+ancestor.name+'")');
|
|
var t = Object.create(ancestor);
|
|
t.name = name;
|
|
t.kind = kind;
|
|
rtl[name] = t;
|
|
return t;
|
|
};
|
|
function newBaseInt(name,minvalue,maxvalue,ordtype){
|
|
var t = newBaseTI(name,1 /* tkInteger */,rtl.tTypeInfoInteger);
|
|
t.minvalue = minvalue;
|
|
t.maxvalue = maxvalue;
|
|
t.ordtype = ordtype;
|
|
return t;
|
|
};
|
|
newBaseTI("tTypeInfoInteger",1 /* tkInteger */);
|
|
newBaseInt("shortint",-0x80,0x7f,0);
|
|
newBaseInt("byte",0,0xff,1);
|
|
newBaseInt("smallint",-0x8000,0x7fff,2);
|
|
newBaseInt("word",0,0xffff,3);
|
|
newBaseInt("longint",-0x80000000,0x7fffffff,4);
|
|
newBaseInt("longword",0,0xffffffff,5);
|
|
newBaseInt("nativeint",-0x10000000000000,0xfffffffffffff,6);
|
|
newBaseInt("nativeuint",0,0xfffffffffffff,7);
|
|
newBaseTI("char",2 /* tkChar */);
|
|
newBaseTI("string",3 /* tkString */);
|
|
newBaseTI("tTypeInfoEnum",4 /* tkEnumeration */,rtl.tTypeInfoInteger);
|
|
newBaseTI("tTypeInfoSet",5 /* tkSet */);
|
|
newBaseTI("double",6 /* tkDouble */);
|
|
newBaseTI("boolean",7 /* tkBool */);
|
|
newBaseTI("tTypeInfoProcVar",8 /* tkProcVar */);
|
|
newBaseTI("tTypeInfoMethodVar",9 /* tkMethod */,rtl.tTypeInfoProcVar);
|
|
newBaseTI("tTypeInfoArray",10 /* tkArray */);
|
|
newBaseTI("tTypeInfoDynArray",11 /* tkDynArray */);
|
|
newBaseTI("tTypeInfoPointer",15 /* tkPointer */);
|
|
var t = newBaseTI("pointer",15 /* tkPointer */,rtl.tTypeInfoPointer);
|
|
t.reftype = null;
|
|
newBaseTI("jsvalue",16 /* tkJSValue */);
|
|
newBaseTI("tTypeInfoRefToProcVar",17 /* tkRefToProcVar */,rtl.tTypeInfoProcVar);
|
|
|
|
// member kinds
|
|
rtl.tTypeMember = {};
|
|
function newMember(name,kind){
|
|
var m = Object.create(rtl.tTypeMember);
|
|
m.name = name;
|
|
m.kind = kind;
|
|
rtl[name] = m;
|
|
};
|
|
newMember("tTypeMemberField",1); // tmkField
|
|
newMember("tTypeMemberMethod",2); // tmkMethod
|
|
newMember("tTypeMemberProperty",3); // tmkProperty
|
|
|
|
// base object for storing members: a simple object
|
|
rtl.tTypeMembers = {};
|
|
|
|
// tTypeInfoStruct - base object for tTypeInfoClass and tTypeInfoRecord
|
|
var tis = newBaseTI("tTypeInfoStruct",0);
|
|
tis.$addMember = function(name,ancestor,options){
|
|
if (rtl.debug_rtti){
|
|
if (!rtl.hasString(name) || (name.charAt()==='$')) throw 'invalid member "'+name+'", this="'+this.name+'"';
|
|
if (!rtl.is(ancestor,rtl.tTypeMember)) throw 'invalid ancestor "'+ancestor+':'+ancestor.name+'", "'+this.name+'.'+name+'"';
|
|
if ((options!=undefined) && (typeof(options)!='object')) throw 'invalid options "'+options+'", "'+this.name+'.'+name+'"';
|
|
};
|
|
var t = Object.create(ancestor);
|
|
t.name = name;
|
|
this.members[name] = t;
|
|
this.names.push(name);
|
|
if (rtl.isObject(options)){
|
|
for (var key in options) if (options.hasOwnProperty(key)) t[key] = options[key];
|
|
};
|
|
return t;
|
|
};
|
|
tis.addField = function(name,type,options){
|
|
var t = this.$addMember(name,rtl.tTypeMemberField,options);
|
|
if (rtl.debug_rtti){
|
|
if (!rtl.is(type,rtl.tTypeInfo)) throw 'invalid type "'+type+'", "'+this.name+'.'+name+'"';
|
|
};
|
|
t.typeinfo = type;
|
|
this.fields.push(name);
|
|
return t;
|
|
};
|
|
tis.addFields = function(){
|
|
var i=0;
|
|
while(i<arguments.length){
|
|
var name = arguments[i++];
|
|
var type = arguments[i++];
|
|
if ((i<arguments.length) && (typeof(arguments[i])==='object')){
|
|
this.addField(name,type,arguments[i++]);
|
|
} else {
|
|
this.addField(name,type);
|
|
};
|
|
};
|
|
};
|
|
tis.addMethod = function(name,methodkind,params,result,options){
|
|
var t = this.$addMember(name,rtl.tTypeMemberMethod,options);
|
|
t.methodkind = methodkind;
|
|
t.procsig = rtl.newTIProcSig(params);
|
|
t.procsig.resulttype = result?result:null;
|
|
this.methods.push(name);
|
|
return t;
|
|
};
|
|
tis.addProperty = function(name,flags,result,getter,setter,options){
|
|
var t = this.$addMember(name,rtl.tTypeMemberProperty,options);
|
|
t.flags = flags;
|
|
t.typeinfo = result;
|
|
t.getter = getter;
|
|
t.setter = setter;
|
|
// Note: in options: params, stored, defaultvalue
|
|
if (rtl.isArray(t.params)) t.params = rtl.newTIParams(t.params);
|
|
this.properties.push(name);
|
|
if (!rtl.isString(t.stored)) t.stored = "";
|
|
return t;
|
|
};
|
|
tis.getField = function(index){
|
|
return this.members[this.fields[index]];
|
|
};
|
|
tis.getMethod = function(index){
|
|
return this.members[this.methods[index]];
|
|
};
|
|
tis.getProperty = function(index){
|
|
return this.members[this.properties[index]];
|
|
};
|
|
|
|
newBaseTI("tTypeInfoRecord",12 /* tkRecord */,rtl.tTypeInfoStruct);
|
|
newBaseTI("tTypeInfoClass",13 /* tkClass */,rtl.tTypeInfoStruct);
|
|
newBaseTI("tTypeInfoClassRef",14 /* tkClassRef */);
|
|
},
|
|
|
|
tSectionRTTI: {
|
|
$module: null,
|
|
$inherited: function(name,ancestor,o){
|
|
if (rtl.debug_rtti){
|
|
rtl.debug('tSectionRTTI.newTI "'+(this.$module?this.$module.$name:"(no module)")
|
|
+'"."'+name+'" ('+ancestor.name+') '+(o?'init':'forward'));
|
|
};
|
|
var t = this[name];
|
|
if (t){
|
|
if (!t.$forward) throw 'duplicate type "'+name+'"';
|
|
if (!ancestor.isPrototypeOf(t)) throw 'typeinfo ancestor mismatch "'+name+'" ancestor="'+ancestor.name+'" t.name="'+t.name+'"';
|
|
} else {
|
|
t = Object.create(ancestor);
|
|
t.name = name;
|
|
t.module = this.module;
|
|
this[name] = t;
|
|
}
|
|
if (o){
|
|
delete t.$forward;
|
|
for (var key in o) if (o.hasOwnProperty(key)) t[key]=o[key];
|
|
} else {
|
|
t.$forward = true;
|
|
}
|
|
return t;
|
|
},
|
|
$Scope: function(name,ancestor,o){
|
|
var t=this.$inherited(name,ancestor,o);
|
|
t.members = {};
|
|
t.names = [];
|
|
t.fields = [];
|
|
t.methods = [];
|
|
t.properties = [];
|
|
return t;
|
|
},
|
|
$TI: function(name,kind,o){ var t=this.$inherited(name,rtl.tTypeInfo,o); t.kind = kind; return t; },
|
|
$Int: function(name,o){ return this.$inherited(name,rtl.tTypeInfoInteger,o); },
|
|
$Enum: function(name,o){ return this.$inherited(name,rtl.tTypeInfoEnum,o); },
|
|
$Set: function(name,o){ return this.$inherited(name,rtl.tTypeInfoSet,o); },
|
|
$StaticArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoArray,o); },
|
|
$DynArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoDynArray,o); },
|
|
$ProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoProcVar,o); },
|
|
$RefToProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoRefToProcVar,o); },
|
|
$MethodVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoMethodVar,o); },
|
|
$Record: function(name,o){ return this.$Scope(name,rtl.tTypeInfoRecord,o); },
|
|
$Class: function(name,o){ return this.$Scope(name,rtl.tTypeInfoClass,o); },
|
|
$ClassRef: function(name,o){ return this.$inherited(name,rtl.tTypeInfoClassRef,o); },
|
|
$Pointer: function(name,o){ return this.$inherited(name,rtl.tTypeInfoPointer,o); },
|
|
},
|
|
|
|
newTIParam: function(param){
|
|
// param is an array, 0=name, 1=type, 2=optional flags
|
|
var t = {
|
|
name: param[0],
|
|
typeinfo: param[1],
|
|
flags: (rtl.isNumber(param[2]) ? param[2] : 0),
|
|
};
|
|
return t;
|
|
},
|
|
|
|
newTIParams: function(list){
|
|
// list: optional array of [paramname,typeinfo,optional flags]
|
|
var params = [];
|
|
if (rtl.isArray(list)){
|
|
for (var i=0; i<list.length; i++) params.push(rtl.newTIParam(list[i]));
|
|
};
|
|
return params;
|
|
},
|
|
|
|
newTIProcSig: function(params,result,flags){
|
|
var s = {
|
|
params: rtl.newTIParams(params),
|
|
resulttype: result,
|
|
flags: flags
|
|
};
|
|
return s;
|
|
},
|
|
}
|