1 // The license of this source is "Ruby License"
  2 /**
  3  * HotRuby
  4  * @class
  5  * @construtor
  6  */
  7 var HotRuby = function() {
  8 	/** 
  9 	 * Global Variables
 10 	 * @type Object 
 11 	 */
 12 	this.globalVars = {};
 13 	/** 
 14 	 * END blocks
 15 	 * @type Array 
 16 	 */
 17 	this.endBlocks = [];
 18 	/** 
 19 	 * Debug DOM
 20 	 * @type HTMLElement 
 21 	 */
 22 	this.debugDom = document.getElementById("debug");
 23 
 24 	if (this.debugDom == null) {
 25 		this.debugDom = document.body;
 26 	}
 27 };
 28 
 29 /**
 30  * StackFrame
 31  * @class
 32  * @construtor
 33  */
 34 HotRuby.StackFrame = function() {
 35 	/** 
 36 	 * Stack Pointer
 37 	 * @type Number 
 38 	 */
 39 	this.sp = 0;
 40 	/** 
 41 	 * Local Variables
 42 	 * @type Array 
 43 	 */
 44 	this.localVars = [];
 45 	/** 
 46 	 * Stack 
 47 	 * @type Array 
 48 	 */
 49 	this.stack = [];
 50 	/** 
 51 	 * Current class to define methods
 52 	 * @type Object 
 53 	 */
 54 	this.classObj = null;
 55 	/** 
 56 	 * Current method name
 57 	 * @type String 
 58 	 */
 59 	this.methodName = "";
 60 	/** 
 61 	 * Current line no
 62 	 * @type Number 
 63 	 */
 64 	this.lineNo = 0;
 65 	/** 
 66 	 * File name
 67 	 * @type String 
 68 	 */
 69 	this.fileName = "";
 70 	/** 
 71 	 * self
 72 	 * @type Object 
 73 	 */
 74 	this.self = null;
 75 	/** 
 76 	 * Parent StackFrame
 77 	 * @type HotRuby.StackFrame 
 78 	 */
 79 	this.parentStackFrame = null;
 80 	/** 
 81 	 * Is Proc(Block)
 82 	 * @type boolean 
 83 	 */
 84 	this.isProc = false;
 85 	/** 
 86 	 * Object Specific class
 87 	 * @type Object 
 88 	 */
 89 	this.cbaseObj = null;
 90 };
 91 
 92 HotRuby.prototype = {
 93 	/**
 94 	 * Run the script.
 95  	 * @param {Array} opcode
 96 	 */
 97 	run : function(opcode) {
 98 		try {
 99 			this.runOpcode(opcode, this.classes["<global>"], null, null, [], null, false, null);
100 		} catch(e) {
101 			alert(e);
102 		}
103 	},
104 	
105 	/**
106 	 * Run the opcode.
107 	 * @param {Array} opcode
108 	 * @param {Object} classObj
109 	 * @param {String} methodName
110 	 * @param {Object} self
111 	 * @param {Array} args
112 	 * @param {HotRuby.StackFrame} parentSF Parent StackFrame
113 	 * @param {boolean} isProc
114 	 * @param {Object} cbaseObj
115 	 * @private
116 	 */
117 	runOpcode : function(opcode, classObj, methodName, self, args, parentSF, isProc, cbaseObj) {
118 		if(args.length != opcode[4].arg_size)
119 			throw "wrong number of arguments (" + args.length + " for " + opcode[4].arg_size + ")";
120 		
121 		// Create Stack Frame
122 		var sf = new HotRuby.StackFrame();
123 		sf.localVars = new Array(opcode[4].local_size + 1);
124 		sf.stack = new Array(opcode[4].stack_max);
125 		sf.fileName = opcode[6];
126 		sf.classObj = classObj;
127 		sf.methodName = methodName;
128 		sf.self = self;
129 		sf.parentStackFrame = parentSF;
130 		sf.isProc = isProc;
131 		sf.cbaseObj = cbaseObj;
132 		
133 		// Copy args to localVars. Fill from last.
134 		for (var i = 0;i < args.length; i++) {
135 			sf.localVars[sf.localVars.length - 1 - i] = args[i];
136 		}
137 		
138 		// Run the mainLoop
139 		this.mainLoop(opcode[11], sf);
140 		
141 		// Copy the stack to the parent stack frame
142 		if (parentSF != null) {
143 			for (var i = 0;i < sf.sp; i++) {
144 				parentSF.stack[parentSF.sp++] = sf.stack[i];
145 			}
146 		} else {
147 			// Run END blocks
148 			if(this.endBlocks.length > 0) {
149 				this.run(this.endBlocks.pop());
150 			}
151 		}
152 	},
153 	
154 	/**
155 	 * Main loop for opcodes.
156 	 * @param {Array} opcode
157 	 * @param {HotRuby.StackFrame} sf
158 	 * @private
159 	 */
160 	mainLoop : function(opcode, sf) {
161 		// Create label to ip
162 		if(!("label2ip" in opcode)) {
163 			opcode.label2ip = {};
164 			for (var ip = 0;ip < opcode.length; ip++) {
165 				// If "cmd is a String then it is a jump label
166 				var cmd = opcode[ip];
167 				if (typeof(cmd) == "string") {
168 					opcode.label2ip[cmd] = ip;
169 					opcode[ip] = null;
170 				}
171 			}
172 		}
173 		
174 		for (var ip = 0;ip < opcode.length; ip++) {
175 			// Get the next command
176 			var cmd = opcode[ip];
177 			if (cmd == null)
178 				continue;
179 
180 			// If "cmd" is a Number then it is the line number.
181 			if (typeof(cmd) == "number") {
182 				sf.lineNo = cmd;
183 				continue;
184 			}
185 			// "cmd" must be an Array
186 			if (!(cmd instanceof Array))
187 				continue;
188 			
189 			switch (cmd[0]) {
190 				case "jump" :
191 					ip = opcode.label2ip[cmd[1]];
192 					break;
193 				case "branchif" :
194 					var val = sf.stack[--sf.sp];
195 					if(val != null && val != false) {
196 						ip = opcode.label2ip[cmd[1]];
197 					}
198 					break;
199 				case "branchunless" :
200 					var val = sf.stack[--sf.sp];
201 					if(val == null || val == false) {
202 						ip = opcode.label2ip[cmd[1]];
203 					}
204 					break;
205 				case "leave" :
206 					return;
207 				case "putnil" :
208 					sf.stack[sf.sp++] = null;
209 					break;
210 				case "putself" :
211 					sf.stack[sf.sp++] = sf.self;
212 					break;
213 				case "putobject" :
214 					var value = cmd[1];
215 					if(typeof(value) == "string") {
216 						if(value.match(/^(\d+)\.\.(\d+)$/)) {
217 							value = this.createRubyRange(
218 								parseInt(RegExp.$2), 
219 								parseInt(RegExp.$1), 
220 								false);
221 						}
222 					}
223 					sf.stack[sf.sp++] = value;
224 					break;
225 				case "putstring" :
226 					sf.stack[sf.sp++] = this.createRubyString(cmd[1]);
227 					break;
228 				case "concatstrings" :
229 					sf.stack[sf.sp++] = this.createRubyString(
230 						sf.stack.slice(sf.stack.length - cmd[1], sf.stack.length).join());
231 					break;
232 				case "newarray" :
233 					var value = this.createRubyArray(sf.stack.slice(sf.sp - cmd[1], sf.sp));
234 					sf.sp -= value.length;
235 					sf.stack[sf.sp++] = value;
236 					break;
237 				case "duparray" :
238 					sf.stack[sf.sp++] = this.createRubyArray(cmd[1]);
239 					break;
240 				case "expandarray" :
241 					var ary = sf.stack[--sf.sp];
242 					if(ary instanceof Array) {
243 						for(var i=0; i<cmd[1]; i++) {
244 							sf.stack[sf.sp++] = ary[i];						
245 						}
246 						if(cmd[2] && 1) {
247 							// TODO
248 						}
249 						if(cmd[2] && 2) {
250 							// TODO
251 						}
252 						if(cmd[2] && 4) {
253 							// TODO
254 						}
255 					} else {
256 						sf.stack[sf.sp++] = ary;
257 						for (var i = 0;i < cmd[1] - 1; i++) {
258 							sf.stack[sf.sp++] = null;
259 						}
260 					}
261 					break;
262 				case "newhash" :
263 					var hash = this.createRubyHash(sf.stack.slice(sf.sp - cmd[1], sf.sp));
264 					sf.sp -= cmd[1];
265 					sf.stack[sf.sp++] = hash;
266 					break;
267 				case "newrange" :
268 					var value = this.createRubyRange(sf.stack[--sf.sp], sf.stack[--sf.sp], cmd[1]);
269 					sf.stack[sf.sp++] = value;
270 					break;
271 				case "setlocal" :
272 					var localSF = sf;
273 					while (localSF.isProc) {
274 						localSF = localSF.parentStackFrame;
275 					}
276 					localSF.localVars[cmd[1]] = sf.stack[--sf.sp];
277 					break;
278 				case "getlocal" :
279 					var localSF = sf;
280 					while (localSF.isProc) {
281 						localSF = localSF.parentStackFrame;
282 					}
283 					sf.stack[sf.sp++] = localSF.localVars[cmd[1]];
284 					break;
285 				case "setglobal" :
286 					this.globalVars[cmd[1]] = sf.stack[--sf.sp];
287 					break;
288 				case "getglobal" :
289 					sf.stack[sf.sp++] = this.globalVars[cmd[1]];
290 					break;
291 				case "setconstant" :
292 					this.setConstant(sf, sf.stack[--sf.sp], cmd[1], sf.stack[--sf.sp]);
293 					break;
294 				case "getconstant" :
295 					var value = this.getConstant(sf, sf.stack[--sf.sp], cmd[1]);
296 					sf.stack[sf.sp++] = value;
297 					break;
298 				case "setinstancevariable" :
299 					sf.self.__instanceVars[cmd[1]] = sf.stack[--sf.sp];
300 					break;
301 				case "getinstancevariable" :
302 					sf.stack[sf.sp++] = sf.self.__instanceVars[cmd[1]];
303 					break;
304 				case "setclassvariable" :
305 					sf.classObj.__classVars[cmd[1]] = sf.stack[--sf.sp];
306 					break;
307 				case "getclassvariable" :
308 					var searchClass = sf.classObj;
309 					while (true) {
310 						if (cmd[1] in searchClass.__classVars) {
311 							sf.stack[sf.sp++] = searchClass.__classVars[cmd[1]];
312 							break;
313 						}
314 						searchClass = searchClass.__parentClass;
315 						if (searchClass == null) {
316 							throw "Cannot find class variable : " + cmd[1];
317 						}
318 					}
319 					break;
320 				case "getdynamic" :
321 					var lookupSF = sf;
322 					for (var i = 0;i < cmd[2]; i++) {
323 						lookupSF = lookupSF.parentStackFrame;
324 					}
325 					sf.stack[sf.sp++] = lookupSF.localVars[cmd[1]];
326 					break;
327 				case "setdynamic" :
328 					var lookupSF = sf;
329 					for (var i = 0;i < cmd[2]; i++) {
330 						lookupSF = lookupSF.parentStackFrame;
331 					}
332 					lookupSF.localVars[cmd[1]] = sf.stack[--sf.sp];
333 					break;
334 //				case "getspecial" :
335 //					break;
336 //				case "setspecial" :
337 //					break;
338 				case "pop" :
339 					sf.sp--;
340 					break;
341 				case "dup" :
342 					sf.stack[sf.sp] = sf.stack[sf.sp - 1];
343 					sf.sp++;
344 					break;
345 				case "dupn" :
346 					for (var i = 0;i < cmd[1]; i++) {
347 						sf.stack[sf.sp + i] = sf.stack[sf.sp + i - cmd[1]];
348 					}
349 					sf.sp += cmd[1];
350 					break;
351 				case "swap" :
352 					var tmp = sf.stack[sf.sp - 1];
353 					sf.stack[sf.sp - 1] = sf.stack[sf.sp - 2];
354 					sf.stack[sf.sp - 2] = tmp;
355 					break;
356 				case "topn" :
357 					sf.stack[sf.sp] = sf.stack[sf.sp - cmd[1]];
358 					sf.sp++;
359 					break;
360 				case "setn" :
361 					sf.stack[sf.sp - cmd[1]] = sf.stack[sf.sp - 1];
362 					break;
363 				case "emptstack" :
364 					sf.sp = 0;
365 					break;
366 				case "send" :
367 					var args = sf.stack.slice(sf.sp - cmd[2], sf.sp);
368 					sf.sp -= cmd[2];
369 					var recver = sf.stack[--sf.sp];
370 					if (recver == null)
371 						recver = sf.self;
372 					if(cmd[3] instanceof Array)
373 						cmd[3] = this.createRubyProc(cmd[3], sf);
374 					if(cmd[3] != null)
375 						args.push(cmd[3]);
376 					this.invokeMethod(recver, cmd[1], args, sf, cmd[4], false);
377 					break;
378 				case "invokesuper" :
379 					var args = sf.stack.slice(sf.sp - cmd[1], sf.sp);
380 					sf.sp -= cmd[1];
381 					// TODO When to use this autoPassAllArgs?
382 					var autoPassAllArgs = sf.stack[--sf.sp];
383 					if(cmd[2] instanceof Array)
384 						cmd[2] = this.createRubyProc(cmd[1], sf);
385 					if(cmd[2] != null)
386 						args.push(cmd[2]);
387 					this.invokeMethod(sf.self, sf.methodName, args, sf, cmd[3], true);
388 					break;
389 				case "definemethod" :
390 					var obj = sf.stack[--sf.sp];
391 					if(sf.cbaseObj != null)
392 						obj = sf.cbaseObj;
393 					if (obj == null) {
394 						sf.classObj[cmd[1]] = cmd[2];
395 					} else {
396 						if (!("__methods" in obj))
397 							obj.__methods = {};
398 						obj.__methods[cmd[1]] = cmd[2];
399 					}
400 					opcode[ip] = null;
401 					opcode[ip - 1] = null;
402 					break;
403 				case "defineclass" :
404 					var parentClass = sf.stack[--sf.sp];
405 					var isRedefine = (parentClass == false);
406 					if(parentClass == null)
407 						parentClass = this.classes.Object;
408 					var cbaseObj = sf.stack[--sf.sp];
409 					if(cmd[3] == 0) {
410 						// Search predefined class
411 						var newClass = this.getConstant(sf, sf.classObj, cmd[1]);
412 						if(newClass == null || isRedefine) {
413 							// Create class object
414 							var newClass = {
415 								__className : cmd[1],
416 								__parentClass : parentClass,
417 								__constantVars : {},
418 								__classVars : {}
419 							};
420 							this.classes[cmd[1]] = newClass;
421 							// Puts the className to CONSTANT
422 							this.setConstant(sf, sf.classObj, cmd[1], newClass);
423 						}
424 						// Run the class definition
425 						this.runOpcode(cmd[2], newClass, null, null, [], sf, false, null);
426 					} else if(cmd[3] == 1) {
427 						// Object-Specific Classes
428 						if(cbaseObj == null || typeof(cbaseObj) != "object")
429 							throw "Not supported Object-Specific Classes on Primitive Object"
430 						// Run the class definition
431 						this.runOpcode(cmd[2], cbaseObj.__className, null, null, [], sf, false, cbaseObj);
432 					} else 	if(cmd[3] == 2) {
433 						// TODO 
434 						throw "Not implemented";
435 					}
436 					break;
437 				case "postexe" :
438 					this.endBlocks.push(cmd[1]);
439 					break;
440 				case "nop" :
441 					break;
442 				case "reput" :
443 					break;
444 				default :
445 					throw "[mainLoop] Unknown opcode : " + cmd[0];
446 			}
447 		}
448 	},
449 	
450 	/**
451 	 * Invoke the method
452 	 * @param {Object} recver
453 	 * @param {String} methodName
454 	 * @param {Array} args
455 	 * @param {HotRuby.StackFrame} sf
456 	 * @param {Number} type VM_CALL_ARGS_SPLAT_BIT, ...
457 	 * @param {boolean} invokeSuper
458 	 */
459 	invokeMethod : function(recver, methodName, args, sf, type, invokeSuper) {
460 		var recverClassName = this.getClassName(recver);
461 		var invokeClassName = recverClassName;
462 		var invokeMethodName = methodName;
463 		var func = null;
464 		
465 		if (invokeSuper) {
466 			var searchClass = this.classes[recverClassName];
467 			while (func == null) {
468 				// Search Parent class
469 				if (!("__parentClass" in searchClass)) break;
470 				searchClass = searchClass.__parentClass;
471 				invokeClassName = searchClass.__className;
472 
473 				// Search method in class
474 				func = searchClass[methodName];
475 			}
476 		} else {
477 			// Search method in object
478 			if (recver != null && recver.__methods != null) {
479 				func = recver.__methods[methodName];
480 			}
481 			if (func == null) {
482 				var searchClass = this.classes[recverClassName];
483 				while (true) {
484 					// Search method in class
485 					func = searchClass[methodName];
486 					if (func != null) break;
487 					
488 					if (methodName == "new") {
489 						func = searchClass["initialize"];
490 						if (func != null) {
491 							invokeMethodName = "initialize";
492 							break;
493 						}
494 					}
495 	
496 					// Search Parent class
497 					if ("__parentClass" in searchClass) {
498 						searchClass = searchClass.__parentClass;
499 						if(searchClass == null) {
500 							func = null;
501 							break;
502 						}
503 						invokeClassName = searchClass.__className;
504 						continue;
505 					}
506 					break;
507 				}
508 			}
509 		}
510 		if (func == null) {
511 			if (invokeSuper) {
512 				sf.stack[sf.sp++] = null;
513 				return;
514 			}
515 			if (methodName != "new") {
516 				throw "[invokeMethod] Undefined function : " + methodName;
517 			}
518 		}
519 		
520 		if (methodName == "new") {
521 			// Create instance
522 			var newObj = {
523 				__className : recverClassName,
524 				__instanceVars : {}
525 			};
526 			sf.stack[sf.sp++] = newObj;
527 			if (func == null) return;
528 
529 			recver = newObj;
530 		}
531 
532 		// Splat array args
533 		if (type & HotRuby.VM_CALL_ARGS_SPLAT_BIT) {
534 			args = args.concat(args.pop());
535 		}
536 		
537 		// Exec method
538 		switch (typeof(func)) {
539 			case "function" :
540 				sf.stack[sf.sp++] = func.call(this, recver, args, sf);
541 				break;
542 			case "object" :
543 				this.runOpcode(func, this.classes[invokeClassName],
544 						invokeMethodName, recver, args, sf, false, sf.cbaseObj);
545 				break;
546 			default :
547 				throw "[invokeMethod] Unknown function type : " + typeof(func);
548 		}
549 		
550 		// Returned value of initialize() is unnecessally at new()
551 		if (methodName == "new") {
552 			sf.sp--;
553 		}
554 	},
555 	
556 	/**
557 	 * Set the Constant
558 	 * @param {HotRuby.StackFrame} sf
559 	 * @param {Object} classObj
560 	 * @param {String} constName
561 	 * @param constValue
562 	 * @private
563 	 */
564 	setConstant : function(sf, classObj, constName, constValue) {
565 		if (classObj == null) {
566 			classObj = sf.classObj;
567 		} else if (classObj == false) {
568 			// TODO
569 			throw "[setConstant] Not implemented";
570 		}
571 		// Const in <global> belongs to Object
572 		if(classObj.__className == "<global>")
573 			classObj = this.classes.Object;
574 		classObj.__constantVars[constName] = constValue;
575 	},
576 	
577 	/**
578 	 * Get the constant
579 	 * @param {HotRuby.StackFrame} sf
580 	 * @param {Object} classObj
581 	 * @param {String} constName
582 	 * @return constant value
583 	 * @private
584 	 */
585 	getConstant : function(sf, classObj, constName) {
586 		if (classObj == null) {
587 			var isFound = false;
588 			// Search outer(parentStackFrame)
589 			for (var checkSF = sf;!isFound; checkSF = checkSF.parentStackFrame) {
590 				if (checkSF.classObj.__className == "<global>") {
591 					break;
592 				}
593 				if (constName in checkSF.classObj.__constantVars) {
594 					classObj = checkSF.classObj;
595 					isFound = true;
596 				}
597 			}
598 			// Search parent class
599 			if (!isFound) {
600 				for (classObj = sf.classObj;classObj.__className != "<global>";) {
601 					if (constName in classObj.__constantVars) {
602 						isFound = true;
603 						break;
604 					}
605 					classObj = classObj.__parentClass;
606 				}
607 			}
608 			// Search in Object class
609 			if (!isFound) {
610 				classObj = this.classes.Object;
611 			}
612 		} else if (classObj == false) {
613 			// TODO
614 			throw "[setConstant] Not implemented";
615 		}
616 		if (classObj == null)
617 			throw "[getConstant] Cannot find constant : " + constName;
618 		// Const in <global> belongs to Object
619 		if (classObj.__className == "<global>")
620 			classObj = this.classes.Object;
621 		return classObj.__constantVars[constName];
622 	},
623 	
624 	/**
625 	 * Returns class name from object.
626 	 * @param obj
627 	 * @return {String}
628 	 */
629 	getClassName : function(obj) {
630 		if (obj == null)
631 			return "<global>";
632 		switch (typeof(obj)) {
633 			case "object" :
634 				return obj.__className;
635 			case "number" :
636 				return "Float";
637 			case "string" :
638 				return "String";
639 			case "boolean" :
640 				return obj ? "TrueClass" : "FalseClass";
641 			default :
642 				throw "[getClassName] unknown type : " + typeof(obj);
643 		}
644 	},
645 	
646 	/**
647 	 * JavaScript String -> Ruby String
648 	 * @param {String} str
649 	 * @return {String}
650 	 */
651 	createRubyString : function(str) {
652 		str.__className = "String";
653 		str.__parentClass = this.classes.Object;
654 		return str;
655 	},
656 	
657 	/**
658 	 * opcode -> Ruby Proc
659 	 * @param {Array} opcode
660 	 * @param {HotRuby.StackFrame} sf
661 	 * @return {Object} Proc
662 	 */
663 	createRubyProc : function(opcode, sf) {
664 		return {
665 			__opcode : opcode,
666 			__className : "Proc",
667 			__parentClass : this.classes.Object,
668 			__parentStackFrame : sf
669 		};
670 	},
671 	
672 	/**
673 	 * JavaScript Array -> Ruby Array
674 	 * @param {Array} ary
675 	 * @return {Array}
676 	 */
677 	createRubyArray : function(ary) {
678 		ary.__className = "Array";
679 		ary.__parentClass = this.classes.Object;
680 		return ary;
681 	},
682 	
683 	/**
684 	 * JavaScript Array -> Ruby Hash
685 	 * @param {Array} ary
686 	 * @return {Object}
687 	 */
688 	createRubyHash : function(ary) {
689 		var hash = {
690 			__className : "Hash",
691 			__parentClass : this.classes.Object,
692 			__instanceVars : {
693 				length : ary.length / 2
694 			}
695 		};
696 		for (var i = 0;i < ary.length; i += 2) {
697 			hash[ary[i]] = ary[i + 1];
698 		}
699 		return hash;
700 	},
701 	
702 	/**
703 	 * Creates Ruby Range
704 	 * @param {Number} last
705 	 * @param {Number} first
706 	 * @param {boolean} exclude_end
707 	 */
708 	createRubyRange : function(last, first, exclude_end) {
709 		return {
710 			__className : "Range",
711 			__parentClass : this.classes.Object,
712 			__instanceVars : {
713 				first : first,
714 				last : last,
715 				exclude_end : exclude_end
716 			}
717 		};
718 	},
719 	
720 	/**
721 	 * Print to debug dom.
722 	 * @param {String} str
723 	 */
724 	printDebug : function(str) {
725 		var div = document.createElement("div");
726 		var text = document.createTextNode(str);
727 		div.appendChild(text);
728 		this.debugDom.appendChild(div);
729 	},
730 
731 	/**
732 	 * Search <script type="text/ruby"></script> and run.
733 	 * @param {String} url Ruby compiler url
734 	 */
735 	runFromScriptTag : function(url) {
736 		var ary = document.getElementsByTagName("script");
737 		for(var i=0; i < ary.length; i++) {
738 			var hoge = ary[i].type;
739 			if(ary[i].type == "text/ruby") {
740 				this.compileAndRun(url, ary[i].text);
741 				break;
742 			}
743 		}
744 	},
745 	
746 	/**
747 	 * Send the source to server and run.
748 	 * @param {String} url Ruby compiler url
749 	 * @param {src} Ruby source
750 	 */
751 	compileAndRun : function(url, src) {
752 		Ext.lib.Ajax.request(
753 			"POST",
754 			url,
755 			{
756 				success: function(response) {
757 					if(response.responseText.length == 0) {
758 						alert("Compile failed");
759 					} else {
760 						this.run(eval("(" + response.responseText + ")"));
761 					}
762 				},
763 				failure: function(response) {
764 					alert("Compile failed");
765 				},
766 				scope: this
767 			},
768 			"src=" + encodeURIComponent(src)
769 		);
770 	}
771 };
772 
773 // Consts
774 /** @memberof HotRuby */
775 HotRuby.VM_CALL_ARGS_SPLAT_BIT = 2;
776 /** @memberof HotRuby */
777 HotRuby.VM_CALL_ARGS_BLOCKARG_BIT = 4;
778 /** @memberof HotRuby */
779 HotRuby.VM_CALL_FCALL_BIT = 8;
780 /** @memberof HotRuby */
781 HotRuby.VM_CALL_VCALL_BIT = 16;
782