fpc/utils/pas2js/dist/rtl.js
michael 7702ebb261 * Patch from Mattias Gaertner; SetCharAt
git-svn-id: trunk@35429 -
2017-02-12 15:17:12 +00:00

292 lines
8.0 KiB
JavaScript

/*
This file is part of the Free Pascal pas2js tool.
Copyright (c) 2017 Mattias Gaertner
Basic RTL for pas2js programs.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
var pas = {};
var rtl = {
quiet: false,
debug_load_units: true,
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,
debug: function(){
if (!window.console || rtl.quiet) return;
console.log(arguments);
},
error: function(s){
rtl.debug('Error: ',s);
throw s;
},
warn: function(s){
rtl.debug('Warn: ',s);
},
isArray: function isArray(a) {
return a instanceof Array;
},
isNumber: function isNumber(n){
return typeof(n)=="number";
},
isInteger: function isInteger(A){
return Math.floor(A)===A;
},
isBoolean: function isBoolean(b){
return typeof(b)=="boolean";
},
isString: function isString(s){
return typeof(s)=="string";
},
isObject: function isObject(o){
return typeof(o)=="object";
},
isFunction: function isFunction(f){
return typeof(f)=="function";
},
isNull: function isNull(o){
return (o==null && typeof(o)=='object') || o==undefined;
},
hasString: function(s){
return rtl.isString(s) && (s.length>0);
},
module: function(module_name, intfuseslist, code, impluseslist){
if (rtl.debug_load_units) rtl.debug('rtl.module name="'+module_name+'" intfuses='+intfuseslist+' impluses='+impluseslist);
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(code)) rtl.error('invalid module code of "'+module_name+'"');
if ((impluseslist!=undefined) && !rtl.isArray(impluseslist)) rtl.error('invalid implementation useslist of "'+module_name+'"');
if (pas[module_name])
rtl.error('module "'+module_name+'" already registered');
var module = pas[module_name] = {
$name: module_name,
$intfuseslist: intfuseslist,
$impluseslist: impluseslist,
$state: rtl.m_loading,
$code: code
};
},
run: function(module_name){
if (module_name==undefined) module_name='program';
var module = pas[module_name];
rtl.loadintf(module);
rtl.loadimpl(module);
if (module_name=='program'){
rtl.debug('running $main');
pas.program.$main();
}
return pas.System.ExitCode;
},
loadintf: function(module){
if (module.state>rtl.m_loading_intf) return; // already finished
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
rtl.debug('loadintf: run intf of '+module.$name);
module.$code(module.$intfuseslist,module);
// 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];
//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_loading_intf) rtl.loadintf(module);
rtl.debug('loadimpl: '+module.$name+' load uses');
module.$state=rtl.m_loading_impl;
// 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 initialization
rtl.debug('loadimpl: '+module.$name+' run init');
module.$state=rtl.m_initializing;
if (rtl.isFunction(module.$init))
module.$init();
// unit initialized
module.$state=rtl.m_initialized;
},
createCallback: function(scope, fn){
var wrapper = function(){
return fn.apply(scope,arguments);
};
wrapper.fn = fn;
return wrapper;
},
createClass: function(owner,name,ancestor,initfn){
var c = null;
if (ancestor != null){
c = Object.create(ancestor);
c.$ancestor = ancestor; // c.$ancestor == Object.getPrototypeOf(c)
} else {
c = {};
c.$create = function(fnname,args){
var o = Object.create(this);
o.$class = this; // Note: o.$class == Object.getPrototypeOf(o)
if (args == undefined) args = [];
o[fnname].apply(o,args);
o.$init();
o.AfterConstruction();
return o;
};
c.$destroy = function(fnname){
this.BeforeDestruction();
this[fnname].apply(obj,[]);
};
};
c.$classname = name;
c.$name = owner.$name+'.'+name;
c.$unitname = rtl.isString(owner.$unitname) ? owner.$unitname : owner.$name;
owner[name] = c;
initfn.call(c);
},
as: function(instance,typ){
if(typ.isPrototypeOf(instance)) return instance;
throw pas.System.EInvalidCast.$create("create");
},
setArrayLength: function(arr,newlength,defaultvalue){
if (newlength == 0) return null;
if (arr == null) arr = [];
var oldlen = arr.length;
if (oldlen==newlength) return;
arr.length = newlength;
if (rtl.isArray(defaultvalue)){
for (var i=oldlen; i<newlength; i++) arr[i]=[]; // new array
} else {
for (var i=oldlen; i<newlength; i++) arr[i]=defaultvalue;
}
return arr;
},
setStringLength: function(s,newlength){
s.length = newlength;
},
length: function(a){
return (a!=null) ? a.length : 0;
},
setCharAt: function(s,index,c){
return s.substr(0,index)+c+s.substr(index+1);
},
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) if (s.hasOwnProperty(key)) r[key]=true;
return r;
},
diffSet: function(s,t){
var r = {};
for (var key in s) if (s.hasOwnProperty(key) && !t[key]) r[key]=true;
return r;
},
unionSet: function(s,t){
var r = {};
for (var key in s) if (s.hasOwnProperty(key)) r[key]=true;
for (var key in t) if (t.hasOwnProperty(key)) r[key]=true;
return r;
},
intersectSet: function(s,t){
var r = {};
for (var key in s) if (s.hasOwnProperty(key) && t[key]) r[key]=true;
return r;
},
symDiffSet: function(s,t){
var r = {};
for (var key in s) if (s.hasOwnProperty(key) && !t[key]) r[key]=true;
for (var key in t) if (t.hasOwnProperty(key) && !s[key]) r[key]=true;
return r;
},
eqSet: function(s,t){
for (var key in s) if (s.hasOwnProperty(key) && !t[key]) return false;
for (var key in t) if (t.hasOwnProperty(key) && !s[key]) return false;
return true;
},
neSet: function(s,t){
return !rtl.eqSet(s,t);
},
leSet: function(s,t){
for (var key in s) if (s.hasOwnProperty(key) && !t[key]) return false;
return true;
},
geSet: function(s,t){
for (var key in t) if (t.hasOwnProperty(key) && !s[key]) return false;
return true;
},
}