“use strict”;
/* jshint undef: true, unused: true */ /* global _ */
var instruct_instruct_instruct = function (funcs) {
this.funcs = _.merge(instruct_instruct_instruct.base, funcs); this.stack = null; return this;
};
// === Scope (function () {
var I = instruct_instruct_instruct; var jquery_proxy = $('body'); function log() { if (window.console) console['log'].apply(console, arguments); } function is_numeric(val) { return _.isNumber(val) && !_.isNaN(val); } function concat() { var args = _.toArray(arguments); var base = _.first(args); var arrs = _.rest(args); _.each(arrs, function (v) { _.each(v, function (val) { base.push(val); }); }); return base; } function inspect(o) { return '(' + typeof(o) + ') "' + o + '"' ; } instruct_instruct_instruct.base = { 'add to stack': function (iii) { concat(iii.stack, iii.shift('all')); }, '$': function (iii) { var args = iii.shift('all'); if (_.isEmpty(args)) return $(iii.pop('string')); else return $.apply($, args); }, 'array': function (iii) { return iii.shift('all'); }, "or": function (iii) { var left = iii.pop('boolean'); if (left) return true; return iii.shift('boolean'); }, 'and': function (iii) { var left = iii.pop('boolean'); if (left) return left === iii.shift('boolean'); else return false; }, 'if true': function (iii) { var left = iii.pop('boolean'); if (!left) return left; iii.shift('all'); return left; }, 'if false': function (iii) { var left = iii.pop('boolean'); if (left) return left; iii.shift('all'); return left; }, 'less or equal': function (iii) { var left = iii.pop('number'); var right = iii.shift('number'); return left <= right; }, 'bigger or equal': function (iii) { var left = iii.pop('number'); var right = iii.shift('number'); return left >= right; }, 'bigger': function (iii) { return iii.pop('number') > iii.shift('number'); }, 'less': function (iii) { return iii.pop('number') < iii.shift('number'); }, 'equal': function (iii) { var left = iii.pop(); var right = iii.shift(); var l_type = typeof(left); var r_type = typeof(right); if (l_type !== r_type) throw new Error("Type mis-match: " + inspect(left) + ' !== ' + inspect(right)); return left === right; } }; I.prototype.spawn = function () { var funcs = _.clone(this.funcs); return new instruct_instruct_instruct(funcs); }; // function I.prototype.run = function (raw_code) { var self = this; var left = []; var code = _.clone(raw_code); var o = null; var last_o = null; var func_name = null; var result = null; var jquery = null; var env = { stack: left, run_args : function () { if (!_.isUndefined(this.raw_args)) this.args = self.spawn().run(this.raw_args).stack; this.raw_args = undefined; return this.args; }, pop: function (type) { var val; var is_empty = _.isEmpty(left); if (is_empty) { if (type) throw new Error("Left Stack underflow while popping for " + type + '.'); else throw new Error("Left Stack underflow while popping."); } val = left.pop(); switch (type) { case 'number': if (!is_numeric(val)) throw new Error("Left Stack popped value is not a number: " + inspect(val)); break; case 'string': if (!_.isString(val)) throw new Error("Left Stack popped value is not a string: " + inspect(val)); break; case 'boolean': if (!_.isBoolean(val)) throw new Error("Left Stack popped value is not a boolean: " + inspect(val)); break; default: if (type !== undefined) throw new Error("Unknown type for .pop(): " + inspect(type)); } // === switch return val; }, shift: function (type) { this.run_args(); if (type === 'all') { var vals = this.args; this.args = []; return vals; } if (_.isEmpty(this.args)) { if (type) throw new Error("Argument Stack underflow while shifting for " + type + "."); else throw new Error("Argument Stack underflow."); } var val = this.args.shift(); switch (type) { case 'number': if (!is_numeric(val)) throw new Error("Argument Stack shifted value is not a number: " + inspect(val)); break; case 'string': if (!_.isString(val)) throw new Error("Argument Stack shifted value is not a string: " + inspect(val)); break; case 'boolean': if (!_.isBoolean(val)) throw new Error("Argument Stack shifted value is not a boolean: " + inspect(val)); break; default: if (type !== undefined) throw new Error("Unknown type for .shift(): " + inspect(type)); } // === switch return val; } }; while (!_.isEmpty(code)) { o = code.shift(); if (_.isString(o) || is_numeric(o) || _.isBoolean(o)) { left.push(o); } else if (_.isArray(o)) { if (!_.isString(last_o)) { throw new Error('Invalid data type for function name: ' + inspect(last_o)); } env.raw_args = o; func_name = left.pop(); if (!this.funcs[func_name]) { if (!jquery_proxy[func_name]) throw new Error("Func not found: " + func_name); jquery = _.last(left)[func_name] ? left.pop() : $(env.pop('string')); result = jquery[func_name].apply(jquery, env.shift('all')); } else { result = this.funcs[func_name](env); } if (result !== undefined) left.unshift( result ); } else { throw new Error("Invalid data type: " + inspect(o)); } last_o = o; } // === while i < size return { code: raw_code, stack: left }; }; // function run
})(); // === scope