/** All methods and properties available to ruby/js sources at runtime. These are kept in their own namespace to keep the opal namespace clean. */ Op.runtime = {}; // for minimizng var Rt = Op.runtime; Rt.opal = Op; /** Opal platform - this is overriden in gem context and nodejs context. These are the default values used in the browser, `opal-browser'. */ Op.platform = { platform: "opal", engine: "opal-browser", version: "1.9.2", argv: [] }; /** Core runtime classes, objects and literals. */ var cBasicObject, cObject, cModule, cClass, mKernel, cNilClass, cTrueClass, cFalseClass, cArray, cRegexp, cMatch, top_self, Qnil, Qfalse, Qtrue, cDir; /** Core object type flags. Added as local variables, and onto runtime. */ var T_CLASS = Rt.T_CLASS = 1, T_MODULE = Rt.T_MODULE = 2, T_OBJECT = Rt.T_OBJECT = 4, T_BOOLEAN = Rt.T_BOOLEAN = 8, T_STRING = Rt.T_STRING = 16, T_ARRAY = Rt.T_ARRAY = 32, T_NUMBER = Rt.T_NUMBER = 64, T_PROC = Rt.T_PROC = 128, T_SYMBOL = Rt.T_SYMBOL = 256, T_HASH = Rt.T_HASH = 512, T_RANGE = Rt.T_RANGE = 1024, T_ICLASS = Rt.T_ICLASS = 2056, FL_SINGLETON = Rt.FL_SINGLETON = 4112; /** Method visibility modes */ var FL_PUBLIC = 0, FL_PRIVATE = 1; /** Define classes. This is the public API for defining classes, shift classes and modules. @param {RubyObject} base @param {RClass} super_class @param {String} id @param {Function} body @param {Number} flag */ Rt.dc = function(base, super_class, id, body, flag) { var klass; switch (flag) { case 0: if (base.$flags & T_OBJECT) { base = class_real(base.$klass); } if (super_class == Qnil) { super_class = cObject; } klass = define_class_under(base, id, super_class); break; case 1: klass = singleton_class(base); break; case 2: if (base.$flags & T_OBJECT) { base = class_real(base.$klass); } klass = define_module_under(base, id); break; default: raise(eException, "define_class got a unknown flag " + flag); } // when reopening a class always set it back to public klass.$mode = FL_PUBLIC; var res = body(klass); return res; }; /** Regexp object. This holds the results of last regexp match. X for regeXp. */ Rt.X = null; /** Undefine methods */ Rt.um = function(kls) { var args = [].slice.call(arguments, 1); for (var i = 0, ii = args.length; i < ii; i++) { (function(mid) { var func = function() { raise(eNoMethodError, "undefined method `" + mid + "' for " + this.m$inspect()); }; kls.allocator.prototype['m$' + mid] = func; if (kls.$bridge_prototype) { kls.$bridge_prototype['m$' + mid] = func; } })(args[i].m$to_s()); } return Qnil; }; /** Method missing support - used in debug mode (opt in). */ Rt.mm = function(method_ids) { var prototype = cBasicObject.$m_tbl; for (var i = 0, ii = method_ids.length; i < ii; i++) { var mid = method_ids[i]; if (!prototype[mid]) { var imp = (function(mid, method_id) { return function(self) { var args = [].slice.call(arguments, 0); args.unshift(intern(method_id)); args.unshift(self); return self.$m.method_missing.apply(null, args); }; })(mid, method_ids[i]); imp.$rbMM = true; prototype[mid] = prototype['$' + mid] = imp; } } }; /** Define methods. Public method for defining a method on the given base. @param {Object} klass The base to define method on @param {String} name Ruby mid @param {Function} public_body The method implementation @param {Number} arity Method arity @return {Qnil} */ Rt.dm = function(klass, name, public_body, arity) { if (klass.$flags & T_OBJECT) { klass = klass.$klass; } var mode = klass.$mode; var private_body = public_body; if (mode == FL_PRIVATE) { public_body = function() { raise(eNoMethodError, "private method `" + name + "' called for " + this.$m$inspect()); }; public_body.$arity = -1; } if (!private_body.$rbName) { private_body.$rbName = name; private_body.$rbArity = arity; } // FIXME: add to private/public methods // klass.$methods.push(intern(name)); define_raw_method(klass, name, private_body, public_body); return Qnil; }; /** Define singleton method. @param {Object} base The base to define method on @param {String} method_id Method id @param {Function} body Method implementation @param {Number} arity Method arity @return {Qnil} */ Rt.ds = function(base, method_id, body, arity) { return Rt.dm(singleton_class(base), method_id, body); }; /** Call a super method. callee is the function that actually called super(). We use this to find the right place in the tree to find the method that actually called super. This is actually done in super_find. */ Rt.S = function(callee, self, args) { var mid = callee.$rbName; var func = super_find(self.$klass, callee, mid); if (!func) { raise(eNoMethodError, "super: no super class method `" + mid + "`" + " for " + self.m$inspect()); } var args_to_send = [self].concat(args); return func.apply(self, args_to_send); }; /** Actually find super impl to call. Returns null if cannot find it. */ function super_find(klass, callee, mid) { var cur_method; while (klass) { if (klass.$m_tbl[mid]) { if (klass.$m_tbl[mid] == callee) { cur_method = klass.$m_tbl[mid]; break; } } klass = klass.$super; } if (!(klass && cur_method)) { return null; } klass = klass.$super; while (klass) { if (klass.$m_tbl[mid]) { return klass.$m_tbl[mid]; } klass = klass.$super; } return null; }; /** Exception classes. Some of these are used by runtime so they are here for convenience. */ var eException, eStandardError, eLocalJumpError, eNameError, eNoMethodError, eArgError, eScriptError, eLoadError, eRuntimeError, eTypeError, eIndexError, eKeyError, eRangeError; var eExceptionInstance; /** Standard jump exceptions to save re-creating them everytime they are needed */ var eReturnInstance, eBreakInstance, eNextInstance; /** Ruby break statement with the given value. When no break value is needed, nil should be passed here. An undefined/null value is not valid and will cause an internal error. @param {RubyObject} value The break value. */ Rt.B = function(value) { eBreakInstance.$value = value; raise_exc(eBreakInstance); }; /** Ruby return, with the given value. The func is the reference function which represents the method that this statement must return from. */ Rt.R = function(value, func) { eReturnInstance.$value = value; eReturnInstance.$func = func; throw eReturnInstance; }; /** Get the given constant name from the given base */ Rt.cg = function(base, id) { if (base.$flags & T_OBJECT) { base = class_real(base.$klass); } return const_get(base, id); }; /** Set constant from runtime */ Rt.cs = function(base, id, val) { if (base.$flags & T_OBJECT) { base = class_real(base.$klass); } return const_set(base, id, val); }; /** Get global by id */ Rt.gg = function(id) { return gvar_get(id); }; /** Set global by id */ Rt.gs = function(id, value) { return gvar_set(id, value); }; function regexp_match_getter(id) { var matched = Rt.X; if (matched) { if (matched.$md) { return matched.$md; } else { var res = new cMatch.allocator(); res.$data = matched; matched.$md = res; return res; } } else { return Qnil; } }