395 default: |
394 default: |
396 throw "Not able to convert type " + |
395 throw "Not able to convert type " + |
397 typeof(value)+" from Javascript to Lua"; |
396 typeof(value)+" from Javascript to Lua"; |
398 } |
397 } |
399 }, |
398 }, |
400 call: function (lfFunction, args) |
399 call: function (func, args) |
401 { |
400 { |
402 if(typeof(lfFunction) == "function") |
401 var f = func.precall(); |
403 { |
402 if(typeof(f) == "function") |
404 return lfFunction.apply(this, args); |
403 { |
|
404 return f.apply(this, args); |
405 } |
405 } |
406 else |
406 else |
407 { |
407 { |
408 var frame = {f:lfFunction,pc:0,entry:true}; |
408 var frame = {f:f,pc:0,entry:true}; |
409 if(args) |
409 if(args) |
410 frame.reg = args.slice(0); |
410 frame.reg = args.slice(0); |
411 else |
411 else |
412 frame.reg = []; |
412 frame.reg = []; |
413 this.callstack.push(frame); |
413 this.callstack.push(frame); |
414 for(var i=frame.reg.length;i<lfFunction.maxStackSize;i++) |
414 for(var i=frame.reg.length;i<f.maxStackSize;i++) |
415 frame.reg[i] = this.LValue(null); |
415 frame.reg[i] = this.LValue(null); |
416 return this.run(frame); |
416 return this.run(frame); |
417 } |
417 } |
418 }, |
418 }, |
419 run: function(frame) |
419 run: function(frame) |
512 args[i] = new LValue(this, "nil", null); |
512 args[i] = new LValue(this, "nil", null); |
513 // Patch frame for new function |
513 // Patch frame for new function |
514 frame.f = f; frame.pc = 0; frame.reg = args; |
514 frame.f = f; frame.pc = 0; frame.reg = args; |
515 break; |
515 break; |
516 case OP_CALL: |
516 case OP_CALL: |
517 var f = frame.reg[INS_A(instruction)].precall(); // return JS or LValue |
517 var f = frame.reg[INS_A(instruction)].precall(); // return JS or LFunction |
518 var A = INS_A(instruction), B = INS_B(instruction), C = INS_C(instruction); |
518 var A = INS_A(instruction), B = INS_B(instruction), C = INS_C(instruction); |
519 var undefined; |
519 var undefined; |
520 var args; |
520 var args; |
521 if(B != 1) |
521 if(B != 1) |
522 args = frame.reg.slice(A+1, B==0?undefined:(A+B)); |
522 args = frame.reg.slice(A+1, B==0?undefined:(A+B)); |
525 if(B != 0) |
525 if(B != 0) |
526 frame.reg.length = A+B; |
526 frame.reg.length = A+B; |
527 if(typeof(f) == "function") |
527 if(typeof(f) == "function") |
528 { |
528 { |
529 // JS native function |
529 // JS native function |
530 var ret = this.call(f, args); |
530 var ret = this.call(frame.reg[INS_A(instruction)], args); |
531 // Insert ret to reg starting at R(A), with C-1 limit |
531 // Insert ret to reg starting at R(A), with C-1 limit |
532 var nresults = ret.length; |
532 var nresults = ret.length; |
533 var nexpected; |
533 var nexpected; |
534 if(C == 0) |
534 if(C == 0) |
535 { |
535 { |
626 } |
626 } |
627 break; |
627 break; |
628 case OP_TFORLOOP: |
628 case OP_TFORLOOP: |
629 var A = INS_A(instruction); |
629 var A = INS_A(instruction); |
630 var C = INS_C(instruction); |
630 var C = INS_C(instruction); |
631 var f = frame.reg[A].precall(); // Iterator function |
631 var RA = frame.reg[A]; // Iterator function |
632 var rets = this.call(f, [frame.reg[A+1], frame.reg[A+2]]); |
632 var rets = this.call(RA, [frame.reg[A+1], frame.reg[A+2]]); |
633 frame.reg.length = A+3; |
633 frame.reg.length = A+3; |
634 for(var i = 0; i<C; i++) |
634 for(var i = 0; i<C; i++) |
635 frame.reg[A+3+i] = rets[i]; |
635 frame.reg[A+3+i] = rets[i]; |
636 if(frame.reg[A+3].type != "nil") |
636 if(frame.reg[A+3].type != "nil") |
637 frame.reg[A+2] = frame.reg[A+3]; |
637 frame.reg[A+2] = frame.reg[A+3]; |
756 else |
756 else |
757 t = env; // Import directly into env |
757 t = env; // Import directly into env |
758 |
758 |
759 for(var k in lib) |
759 for(var k in lib) |
760 t.setIndex(this.LValue(k), this.LValue(lib[k])); |
760 t.setIndex(this.LValue(k), this.LValue(lib[k])); |
|
761 }, |
|
762 loadstring: function (chunk, env) |
|
763 { |
|
764 var c = new LBinaryChunk(this, chunk); |
|
765 var f = new LFunction(this, c, env); |
|
766 return new LValue(this, "function", f); |
761 } |
767 } |
762 }; |
768 }; |
763 |
769 |
764 try{ |
770 try{ |
765 var testvm = new LVM(); |
771 var testvm = new LVM(); |
766 |
772 |
767 var fs=require("fs"); |
773 var fs=require("fs"); |
768 var sys=require("sys"); |
774 var sys=require("sys"); |
769 var c = new LBinaryChunk(testvm, fs.readFileSync("luac.out", "binary")); |
|
770 |
775 |
771 var _G = testvm.LValue([]); |
776 var _G = testvm.LValue([]); |
772 |
777 |
773 // Standard library |
778 // Standard library |
774 |
779 |
889 testvm.LValue(function (t, k) { sys.puts("Access of nil global: "+k); }) |
894 testvm.LValue(function (t, k) { sys.puts("Access of nil global: "+k); }) |
890 ); |
895 ); |
891 _G.setMetatable(mt); |
896 _G.setMetatable(mt); |
892 |
897 |
893 |
898 |
894 var f = new LFunction(testvm, c, _G); |
899 var f = testvm.loadstring(fs.readFileSync("luac.out", "binary"), _G); |
895 |
900 |
896 var ret = testvm.call(f); |
901 var ret = testvm.call(f); |
897 if(ret) |
902 if(ret) |
898 sys.puts("Returned: "+sys.inspect(ret)); |
903 sys.puts("Returned: "+sys.inspect(ret)); |
899 } |
904 } |