diff --git a/src/script/context.cpp b/src/script/context.cpp index 5a8880cc..1bd3e860 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -44,12 +44,15 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { try { // Instruction pointer const Instruction* instr = &script.instructions[0]; - const Instruction* end = &*script.instructions.end(); + const Instruction* end = instr + script.instructions.size(); // Loop until we are done while (instr < end) { // Evaluate the current instruction Instruction i = *instr++; + // If a scope is created, destroy it at end of block. + scoped_ptr scope; + switch (i.instr) { case I_NOP: break; // Push a constant @@ -59,7 +62,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { } // Jump case I_JUMP: { - instr = &script.instructions[i.data]; + instr = &script.instructions[0] + i.data; break; } // Conditional jump @@ -67,7 +70,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { bool condition = *stack.back(); stack.pop_back(); if (!condition) { - instr = &script.instructions[i.data]; + instr = &script.instructions[0] + i.data; } break; } @@ -98,7 +101,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { stack.push_back(val); } else { stack.erase(stack.end() - 2); // remove iterator - instr = &script.instructions[i.data]; + instr = &script.instructions[0] + i.data; } break; } @@ -112,7 +115,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { stack.push_back(key); } else { stack.erase(stack.end() - 2); // remove iterator - instr = &script.instructions[i.data]; + instr = &script.instructions[0] + i.data; } break; } @@ -123,9 +126,8 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { } // Function call - case I_CALL: { - // new scope - LocalScope local_scope(*this); + case I_CALL: scope.reset(new LocalScope(*this)); //new scope + case I_TAILCALL: { // prepare arguments for (unsigned int j = 0 ; j < i.data ; ++j) { setVariable((Variable)instr[i.data - j - 1].data, stack.back()); @@ -203,6 +205,12 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { instrQuaternary(i.instr4, a, b, c, d); break; } + // Pop off stack + case I_POP: { + stack.pop_back(); + break; + } + // Duplicate stack case I_DUP: { stack.push_back(stack.at(stack.size() - i.data - 1)); @@ -419,9 +427,6 @@ class ScriptCompose : public ScriptValue { void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& b) { switch (i) { - case I_POP: - // a = a; - break; case I_MEMBER: a = a->getMember(*b); break; diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index ef92fc5b..852a01a8 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -169,7 +169,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) delete j; } - if (instr >= &*script.instructions.end()) break; // end of script + if (instr >= &script.instructions[0] + script.instructions.size()) break; // end of script // Analyze the current instruction Instruction i = *instr++; @@ -182,11 +182,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) } // Jump case I_JUMP: { - if (&script.instructions[i.data] >= instr) { + if ( &script.instructions[0] + i.data >= instr) { // forward jump // create jump record Jump* jump = new Jump; - jump->target = &script.instructions[i.data]; + jump->target = &script.instructions[0] + i.data; jump->stack_top.assign(stack.begin() + stack_size, stack.end()); getBindings(scope, jump->bindings); jumps.push(jump); @@ -313,10 +313,6 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) } // Simple instruction: binary case I_BINARY: { - if (i.instr2 == I_POP) { - stack.pop_back(); - continue; - } ScriptValueP b = stack.back(); stack.pop_back(); ScriptValueP& a = stack.back(); switch (i.instr2) { @@ -356,6 +352,10 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) stack.push_back(stack.at(stack.size() - i.data - 1)); break; } + // Pop value off stack + case I_POP: { + stack.pop_back(); + } } } diff --git a/src/script/parser.cpp b/src/script/parser.cpp index a59824e8..f699ae90 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -534,10 +534,10 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) { expectToken(input, _("do")); // do if (with_key) { script.addInstruction(I_SET_VAR, key); // set key_name - script.addInstruction(I_BINARY, I_POP); // pop + script.addInstruction(I_POP); // pop } script.addInstruction(I_SET_VAR, var); // set name - script.addInstruction(I_BINARY, I_POP); // pop + script.addInstruction(I_POP); // pop parseOper(input, script, PREC_SET, I_BINARY, I_ADD); // EEE; add script.addInstruction(I_JUMP, lblStart); // jump lbl_start script.comeFrom(lblStart); // lbl_end: @@ -650,7 +650,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc // allow ; at end of expression without errors break; } - script.addInstruction(I_BINARY, I_POP); // discard result of first expression + script.addInstruction(I_POP); // discard result of first expression parseOper(input, script, PREC_SET); } else if (minPrec <= PREC_SET && token==_(":=")) { // We made a mistake, the part before the := should be a variable name, @@ -761,7 +761,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc // newline functions as ; // only if we don't match another token! input.putBack(); - script.addInstruction(I_BINARY, I_POP); + script.addInstruction(I_POP); parseOper(input, script, PREC_SET); } else { input.putBack(); diff --git a/src/script/script.cpp b/src/script/script.cpp index de423b43..4c6ef639 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -99,7 +99,11 @@ ScriptValueP Script::dependencies(Context& ctx, const Dependency& dep) const { static const unsigned int INVALID_ADDRESS = 0x03FFFFFF; unsigned int Script::addInstruction(InstructionType t) { - assert( t == I_JUMP || t == I_JUMP_IF_NOT || t == I_LOOP || t == I_LOOP_WITH_KEY); + assert( t == I_JUMP + || t == I_JUMP_IF_NOT + || t == I_LOOP + || t == I_LOOP_WITH_KEY + || t == I_POP); Instruction i = {t, {INVALID_ADDRESS}}; instructions.push_back(i); return getLabel() - 1; @@ -179,7 +183,6 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { break; case I_BINARY: ret += _("binary\t"); switch (i.instr2) { - case I_POP: ret += _("pop"); break; case I_ITERATOR_R: ret += _("iterator_r"); break; case I_MEMBER: ret += _("member"); break; case I_ADD: ret += _("+"); break; @@ -210,6 +213,8 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { } break; case I_DUP: ret += _("dup"); break; + case I_POP: ret += _("pop"); break; + case I_TAILCALL: ret += _("tailcall"); break; } // arg switch (i.instr) { diff --git a/src/script/script.hpp b/src/script/script.hpp index 3aa137fd..437ab1b3 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -43,6 +43,8 @@ enum InstructionType , I_TERNARY = 14 ///< arg = 3ary instr : pop 3 values, apply a function, push the result , I_QUATERNARY = 15 ///< arg = 4ary instr : pop 4 values, apply a function, push the result , I_DUP = 16 ///< arg = int : duplicate the k-from-top element of the stack +, I_POP = 17 ///< arg = * : pop the top value off the stack. +, I_TAILCALL = 18 ///< arg = int, n*var : perform a tail call - like I_CALL, except faster }; /// Types of unary instructions (taking one argument from the stack) @@ -54,8 +56,7 @@ enum UnaryInstructionType /// Types of binary instructions (taking two arguments from the stack) enum BinaryInstructionType -{ I_POP ///< Pop the top value of the stack -, I_ITERATOR_R ///< Make an iterator for a range (two integers) +{ I_ITERATOR_R ///< Make an iterator for a range (two integers) , I_MEMBER ///< Member of an object // Arithmatic , I_ADD ///< add