| | 206 | function pushCallingUserdefFuncCode(userDefFunc, argc) { |
| | 207 | if(!userDefFuncs[userDefFunc.id]) { |
| | 208 | userDefFuncs[userDefFunc.id] = userDefFunc; |
| | 209 | } |
| | 210 | push('var args = [];'); |
| | 211 | push('var len = stack.length;'); |
| | 212 | var origArgsCount = 0; |
| | 213 | var argMax = userDefFunc.paramTypes.length; |
| | 214 | var recvArgMax = 0; // local を除いた仮引数の数 |
| | 215 | for(var i = 0; i < argMax; i ++) { |
| | 216 | if(userDefFunc.paramTypes[i] != MPType.LOCALVAR) recvArgMax ++; |
| | 217 | } |
| | 218 | if(recvArgMax < argc) { |
| | 219 | push('throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS);'); |
| | 220 | return; |
| | 221 | } |
| | 222 | for(var i = 0; i < argMax; i ++) { |
| | 223 | var mptype = userDefFunc.paramTypes[i]; |
| | 224 | push('var arg = stack[len - '+(argc-origArgsCount)+'];'); |
| | 225 | switch(mptype) { |
| | 226 | case MPType.DNUM: |
| | 227 | push('args['+i+'] = self.scanArg(arg, "n").toDoubleValue();'); |
| | 228 | break; |
| | 229 | case MPType.INUM: |
| | 230 | push('args['+i+'] = arg ? self.scanArg(arg, "n").toIntValue() : new IntValue(0);'); |
| | 231 | break; |
| | 232 | case MPType.LOCALVAR: |
| | 233 | push('args['+i+'] = new Variable;'); |
| | 234 | continue; |
| | 235 | case MPType.ARRAYVAR: |
| | 236 | push('args['+i+'] = self.scanArg(arg, "v").variable;'); |
| | 237 | break; |
| | 238 | case MPType.SINGLEVAR: |
| | 239 | push('args['+i+'] = self.scanArg(arg, "v");'); |
| | 240 | break; |
| | 241 | case MPType.LOCALSTRING: |
| | 242 | push('args['+i+'] = self.scanArg(arg, "s").toStrValue();'); |
| | 243 | break; |
| | 244 | case MPType.MODULEVAR: |
| | 245 | push('args['+i+'] = new ModVarData(self.scanArg(arg, "v").variable, arg.indices);'); |
| | 246 | break; |
| | 247 | case MPType.IMODULEVAR: |
| | 248 | push('args['+i+'] = arg;'); |
| | 249 | break; |
| | 250 | default: |
| | 251 | throw new Error('未対応のパラメータタイプ: '+mptype); |
| | 252 | } |
| | 253 | origArgsCount ++; |
| | 254 | } |
| | 255 | push('stack.length -= '+argc+';'); |
| | 256 | push('if(self.frameStack.length >= 256) {'); |
| | 257 | push(' throw new HSPError(ErrorCode.STACK_OVERFLOW);'); |
| | 258 | push('}'); |
| | 259 | push('self.frameStack.push(new Frame('+(pc + 1)+', userDefFuncs['+userDefFunc.id+'], args));'); |
| | 260 | push('self.pc = '+userDefFunc.label.pos+';'); |
| | 261 | } |
| 475 | | if(insn.opts[0]) { |
| 476 | | push('self.return_(stack.pop());'); |
| | 522 | var existReturnVal = insn.opts[0]; |
| | 523 | push('if(self.frameStack.length == 0) {'); |
| | 524 | push(' throw new HSPError(ErrorCode.RETURN_WITHOUT_GOSUB);'); |
| | 525 | push('}'); |
| | 526 | push('var frame = self.frameStack.pop();'); |
| | 527 | if(existReturnVal) { |
| | 528 | push('if(frame.userDefFunc && frame.userDefFunc.isCType) {'); |
| | 529 | push(' stack[stack.length - 1] = stack[stack.length - 1].toValue();'); |
| | 530 | push('} else {'); indent ++ |
| | 531 | push('var val = stack.pop();'); |
| | 532 | push('switch(val.getType()) {'); |
| | 533 | push('case '+VarType.STR+':'); |
| | 534 | push(' self.refstr.assign(0, val.toStrValue());'); |
| | 535 | push(' break;'); |
| | 536 | push('case '+VarType.DOUBLE+':'); |
| | 537 | push(' self.refdval.assign(0, val.toDoubleValue());'); |
| | 538 | push(' break;'); |
| | 539 | push('case '+VarType.INT+':'); |
| | 540 | push(' this.stat.assign(0, val.toIntValue());'); |
| | 541 | push(' break;'); |
| | 542 | push('default:'); |
| | 543 | push(' throw new HSPError(ErrorCode.TYPE_MISMATCH);'); |
| | 544 | push('}'); |
| | 545 | indent --; push('}'); |
| 671 | | callBuiltinFunc: function callBuiltinFunc(insn) { |
| 672 | | var type = insn.opts[0]; |
| 673 | | var subid = insn.opts[1]; |
| 674 | | var argc = insn.opts[2]; |
| 675 | | var func = BuiltinFuncs[type][subid]; |
| 676 | | if(!func) { |
| 677 | | var name = this.getBuiltinFuncName(insn); |
| 678 | | if(name) { |
| 679 | | throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION, name + ' はサポートされていません'); |
| 680 | | } else { |
| 681 | | throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION); |
| 682 | | } |
| 683 | | } |
| 684 | | var args = Utils.aryPopN(this.stack, argc); |
| 685 | | return func.apply(this, args); |
| 686 | | }, |
| 687 | | callUserDefFunc: function callUserDefFunc(userDefFunc, origArgs, callback) { |
| 688 | | var args = []; |
| 689 | | var origArgsCount = 0; |
| 690 | | for(var i = 0; i < userDefFunc.paramTypes.length; i ++) { |
| 691 | | var mptype = userDefFunc.paramTypes[i]; |
| 692 | | var arg = origArgs[origArgsCount]; |
| 693 | | switch(mptype) { |
| 694 | | case MPType.DNUM: |
| 695 | | this.scanArg(arg, 'n', false); |
| 696 | | args.push(arg.toDoubleValue()); |
| 697 | | origArgsCount ++; |
| 698 | | break; |
| 699 | | case MPType.INUM: |
| 700 | | this.scanArg(arg, 'n', true); |
| 701 | | args.push(arg ? arg.toIntValue() : new IntValue(0)); |
| 702 | | origArgsCount ++; |
| 703 | | break; |
| 704 | | case MPType.LOCALVAR: |
| 705 | | args.push(new Variable); |
| 706 | | break; |
| 707 | | case MPType.ARRAYVAR: |
| 708 | | this.scanArg(arg, 'v', false); |
| 709 | | args.push(arg.variable); |
| 710 | | origArgsCount ++; |
| 711 | | break; |
| 712 | | case MPType.SINGLEVAR: |
| 713 | | this.scanArg(arg, 'v', false); |
| 714 | | args.push(arg); |
| 715 | | origArgsCount ++; |
| 716 | | break; |
| 717 | | case MPType.LOCALSTRING: |
| 718 | | this.scanArg(arg, 's', false); |
| 719 | | args.push(arg.toStrValue()); |
| 720 | | origArgsCount ++; |
| 721 | | break; |
| 722 | | case MPType.MODULEVAR: |
| 723 | | case MPType.IMODULEVAR: |
| 724 | | case MPType.TMODULEVAR: |
| 725 | | this.scanArg(arg, 'v', false); |
| 726 | | args.push(new ModVarData(arg.variable, arg.indices)); |
| 727 | | origArgsCount ++; |
| 728 | | break; |
| 729 | | default: |
| 730 | | throw new HSPError(ErrorCode.INVALID_STRUCT_SOURCE); |
| 731 | | } |
| 732 | | } |
| 733 | | if(origArgsCount < origArgs.length) { |
| 734 | | throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS); |
| 735 | | } |
| 736 | | if(this.frameStack.length >= 256) { |
| 737 | | throw new HSPError(ErrorCode.STACK_OVERFLOW); |
| 738 | | } |
| 739 | | this.frameStack.push(new Frame(this.pc + 1, userDefFunc, args, callback)); |
| 740 | | this.pc = userDefFunc.label.pos - 1; |
| 741 | | }, |
| 742 | | return_: function return_(val) { |
| 743 | | if(this.frameStack.length == 0) { |
| 744 | | throw new HSPError(ErrorCode.RETURN_WITHOUT_GOSUB); |
| 745 | | } |
| 746 | | var frame = this.frameStack.pop(); |
| 747 | | if(frame.userDefFunc && frame.userDefFunc.isCType) { |
| 748 | | if(!val) throw new HSPError(ErrorCode.NORETVAL); |
| 749 | | this.stack.push(val.toValue()); |
| 750 | | } else if(val) { |
| 751 | | switch(val.getType()) { |
| 752 | | case VarType.STR: |
| 753 | | this.refstr.assign(0, val.toStrValue()); |
| 754 | | break; |
| 755 | | case VarType.DOUBLE: |
| 756 | | this.refdval.assign(0, val.toDoubleValue()); |
| 757 | | break; |
| 758 | | case VarType.INT: |
| 759 | | this.stat.assign(0, val.toIntValue()); |
| 760 | | break; |
| 761 | | default: |
| 762 | | throw new HSPError(ErrorCode.TYPE_MISMATCH); |
| 763 | | } |
| 764 | | } |
| 765 | | this.pc = frame.pc - 1; |
| 766 | | var runCallback = function() { |
| 767 | | if(frame.callback) { |
| 768 | | var fn = frame.callback(); |
| 769 | | while(fn) { |
| 770 | | fn = fn(); |
| 771 | | } |
| 772 | | } |
| 773 | | }; |
| 774 | | if(frame.userDefFunc) { |
| 775 | | this.deleteLocalVars(frame.userDefFunc.paramTypes, frame.args, runCallback); |
| 776 | | } else { |
| 777 | | runCallback(); |
| 778 | | } |
| 779 | | }, |
| 824 | | }, |
| 825 | | deleteStruct: function deleteStruct(agent, callback) { |
| 826 | | var fn = this.deleteStruct0(agent, callback); |
| 827 | | while(fn) { |
| 828 | | fn = fn(); |
| 829 | | } |
| 830 | | }, |
| 831 | | deleteAllStruct: function deleteAllStruct(variable, callback) { |
| 832 | | var fn = this.deleteAllStruct0(variable, callback); |
| 833 | | while(fn) { |
| 834 | | fn = fn(); |
| 835 | | } |
| 836 | | }, |
| 837 | | deleteStruct0: function deleteStruct0(agent, callback) { |
| 838 | | this.deleteStructRecursionLevel = 0; |
| 839 | | var struct = agent.toValue(); |
| 840 | | var self = this; |
| 841 | | if(struct.isUsing() != 1) { |
| 842 | | if(callback) return callback(); |
| 843 | | return null; |
| 844 | | } |
| 845 | | var myCallback = function() { |
| 846 | | var i = 0; |
| 847 | | return (function() { |
| 848 | | if(++self.deleteStructRecursionLevel >= 128) { |
| 849 | | self.deleteStructRecursionLevel = 0; |
| 850 | | return arguments.callee; |
| 851 | | } |
| 852 | | while(i < struct.members.length) { |
| 853 | | var member = struct.members[i]; |
| 854 | | i ++; |
| 855 | | if(member.getType() == VarType.STRUCT) { |
| 856 | | return self.deleteAllStruct0(member, arguments.callee); |
| 857 | | } |
| 858 | | } |
| 859 | | agent.assign(StructValue.EMPTY); |
| 860 | | if(callback) return callback(); |
| 861 | | return null; |
| 862 | | })(); |
| 863 | | } |
| 864 | | if(struct.module.destructor) { |
| 865 | | this.callUserDefFunc(struct.module.destructor, [agent], myCallback); |
| 866 | | return null; |
| 867 | | } else { |
| 868 | | return myCallback; |
| 869 | | } |
| 870 | | }, |
| 871 | | deleteAllStruct0: function deleteAllStruct0(variable, callback) { |
| 872 | | var i = 0; |
| 873 | | var self = this; |
| 874 | | return (function() { |
| 875 | | while(i < variable.getL0()) { |
| 876 | | var agent = new VariableAgent(variable, [i]); |
| 877 | | i ++; |
| 878 | | if(agent.isUsing() == 1) { |
| 879 | | return self.deleteStruct0(agent, arguments.callee); |
| 880 | | } |
| 881 | | } |
| 882 | | return callback(); |
| 883 | | })(); |
| 884 | | }, |
| 885 | | deleteLocalVars: function deleteLocalVars(paramTypes, args, callback) { |
| 886 | | var i = 0; |
| 887 | | var self = this; |
| 888 | | (function() { |
| 889 | | while(i < args.length) { |
| 890 | | var paramType = paramTypes[i]; |
| 891 | | var arg = args[i]; |
| 892 | | i ++; |
| 893 | | if(paramType == MPType.LOCALVAR && arg.getType() == VarType.STRUCT) { |
| 894 | | self.deleteAllStruct(arg, arguments.callee); |
| 895 | | return; |
| 896 | | } |
| 897 | | } |
| 898 | | callback(); |
| 899 | | return; |
| 900 | | })(); |