예제 #1
0
bool VariableRef::readFloat( float& out ) const
{
    VALIDATE();

    pushValue();
    out = (float)lua_tonumber(m_ownerContext->getPimpl()->L, -1);
    popValue();

    return true;
}
예제 #2
0
bool VariableRef::readUInt32( uint32& out ) const
{
    VALIDATE();

    pushValue();
    out = (uint32)lua_tonumber(m_ownerContext->getPimpl()->L, -1);
    popValue();

    return true;
}
예제 #3
0
    void LuaModule::popJsonFromArbStack(Json::Value &json, lua_State * state) {
        lua_pushnil(state);  /* first key */

        if (!lua_istable(state, -2)) {
            throw std::runtime_error("Not a table at the top of the stack");
        }

        while (lua_next(state, -2) != 0) {
            int keyType = lua_type(state, -2);
            int valType = lua_type(state, -1);
            /*std::cout <<
                      lua_typename(state, keyType) << " - " <<
                      lua_typename(state, valType) << std::endl;*/
            int keyInt = -100;
            std::string keyStr = "__INIT_FAILED__";

            if (keyType == LUA_TNUMBER) {
                keyInt = (int)lua_tointeger(state, -2) - 1;
            } else if (keyType == LUA_TSTRING) {
                keyStr = lua_tostring(state, -2);
            } else {
                throw std::runtime_error("Wrong key type");
            }

            if (valType == LUA_TTABLE) {
                if (keyType == LUA_TNUMBER) {
                    popJsonFromArbStack(json[keyInt], state);
                    lua_pop(state, 1);
                } else {
                    popJsonFromArbStack(json[keyStr], state);
                    lua_pop(state, 1);
                }
            } else {
                if (keyType == LUA_TNUMBER) {
                    popValue(json[keyInt], state);
                } else {
                    popValue(json[keyStr], state);
                }
            }
        }
    }
예제 #4
0
bool VariableRef::readBytes( size_t num, uint8* out_buf ) const
{
    VALIDATE();

    lua_State* L = m_ownerContext->getPimpl()->L;

    bool success = false;

    pushValue();
    if (lua_istable(L, -1) == 1)
    {
        success = true;

        lua_pushnil(L);

        for (size_t i = 0; i < num; ++i)
        {
            const int next_ret = lua_next(L, -2);
            if (next_ret == 0)
            {
                log_error("Not enough values in table (%d required, has %d)", num, i);
                success = false;
                break;
            }

            if (lua_isnumber(L, -1) == 0)
            {
                log_error("Non-number value in table when reading bytes");
                success = false;
                break;
            }

            // Checks for fractional parts, too high values etc...

            const uint8 val = (uint8)lua_tonumber(L, -1);
            out_buf[i] = val;

            lua_pop(L, 1);
        }

        lua_pop(L, 1);
    }
    popValue();

    return true;
}
예제 #5
0
bool VariableRef::readString( mkString& out ) const
{
    VALIDATE();

    bool success = false;

    pushValue();
    const char* ptr = lua_tolstring(m_ownerContext->getPimpl()->L, -1, NULL);
    if (ptr)
    {
        success = true;
        out = ptr;
    }
    popValue();

    return success;
}
예제 #6
0
void BytecodeInterpreter::interpret()
{
    while (bci() < bc()->length()) {
        bool jmp = false;
        Value first;
        Value second;

        switch (bc()->getInsn(bci())) {
        case BC_STOP:
            return;

        case BC_DLOAD0:
            pushValue(0.0);
            break;
        case BC_ILOAD0:
            pushValue<int64_t>(0);
            break;
        case BC_DLOAD1:
            pushValue(1.0);
            break;
        case BC_ILOAD1:
            pushValue<int64_t>(1);
            break;
        case BC_DLOADM1:
            pushValue(-1.0);
            break;
        case BC_ILOADM1:
            pushValue<int64_t>(-1);
            break;
        case BC_DLOAD:
            pushValue(bc()->getDouble(bci() + 1));
            break;
        case BC_ILOAD:
            pushValue(bc()->getInt64(bci() + 1));
            break;
        case BC_SLOAD:
            pushValue(m_code->constantById(bc()->getUInt16(bci() + 1)).c_str());
            break;

        case BC_CALLNATIVE:
            pushValue(callNativeFunction(bc()->getUInt16(bci() + 1)));
            break;
        case BC_CALL:
            m_locals.push(bc()->getUInt16(bci() + 1));
            pushFunc(bc()->getUInt16(bci() + 1));
            pushBci();
            jmp = true;
            break;
        case BC_RETURN:
            m_locals.pop();
            popFunc();
            popBci();
            //jmp = true;
            break;

#define LOAD_VAR_N(type, n) \
    pushValue(m_locals.load(1, n).type()); \
    break;
        case BC_LOADDVAR0:
            LOAD_VAR_N(doubleValue, 0)
        case BC_LOADDVAR1:
            LOAD_VAR_N(doubleValue, 1)
        case BC_LOADDVAR2:
            LOAD_VAR_N(doubleValue, 2)
        case BC_LOADDVAR3:
            LOAD_VAR_N(doubleValue, 3)
        case BC_LOADIVAR0:
            LOAD_VAR_N(intValue, 0)
        case BC_LOADIVAR1:
            LOAD_VAR_N(intValue, 1)
        case BC_LOADIVAR2:
            LOAD_VAR_N(intValue, 2)
        case BC_LOADIVAR3:
            LOAD_VAR_N(intValue, 3)
        case BC_LOADSVAR0:
            LOAD_VAR_N(stringValue, 0)
        case BC_LOADSVAR1:
            LOAD_VAR_N(stringValue, 1)
        case BC_LOADSVAR2:
            LOAD_VAR_N(stringValue, 2)
        case BC_LOADSVAR3:
            LOAD_VAR_N(stringValue, 3)
#undef LOAD_VAR_N

#define STORE_VAR_N(type, n) \
    pushValue(m_locals.load(1, n).type()); \
    break;
        case BC_STOREDVAR0:
            STORE_VAR_N(doubleValue, 0)
        case BC_STOREDVAR1:
            STORE_VAR_N(doubleValue, 1)
        case BC_STOREDVAR2:
            STORE_VAR_N(doubleValue, 2)
        case BC_STOREDVAR3:
            STORE_VAR_N(doubleValue, 3)
        case BC_STOREIVAR0:
            STORE_VAR_N(intValue, 0)
        case BC_STOREIVAR1:
            STORE_VAR_N(intValue, 1)
        case BC_STOREIVAR2:
            STORE_VAR_N(intValue, 2)
        case BC_STOREIVAR3:
            STORE_VAR_N(intValue, 3)
        case BC_STORESVAR0:
            STORE_VAR_N(stringValue, 0)
        case BC_STORESVAR1:
            STORE_VAR_N(stringValue, 1)
        case BC_STORESVAR2:
            STORE_VAR_N(stringValue, 2)
        case BC_STORESVAR3:
            STORE_VAR_N(stringValue, 3)
#undef STORE_VAR_N

#define LOAD_VAR(type) \
    pushValue(m_locals.load(1, bc()->getUInt16(bci() + 1)).type()); \
    break;
        case BC_LOADDVAR:
            LOAD_VAR(doubleValue)
        case BC_LOADIVAR:
            LOAD_VAR(intValue)
        case BC_LOADSVAR:
            LOAD_VAR(stringValue)
#undef LOAD_CTX_VAR

#define STORE_VAR(type) \
    m_locals.store(popValue().type(), 1, bc()->getUInt16(bci() + 1)); \
    break;
        case BC_STOREDVAR:
            STORE_VAR(doubleValue)
        case BC_STOREIVAR:
            STORE_VAR(intValue)
        case BC_STORESVAR:
            STORE_VAR(stringValue)
#undef STORE_VAR

#define LOAD_CTX_VAR(type) \
    pushValue(m_locals.load(bc()->getUInt16(bci() + 1), \
                            bc()->getUInt16(bci() + 3)).type()); \
    break;
        case BC_LOADCTXDVAR:
            LOAD_CTX_VAR(doubleValue)
        case BC_LOADCTXIVAR:
            LOAD_CTX_VAR(intValue)
        case BC_LOADCTXSVAR:
            LOAD_CTX_VAR(stringValue)
#undef LOAD_CTX_VAR

#define STORE_CTX_VAR(type) \
    m_locals.store(popValue().type(), \
                   bc()->getUInt16(bci() + 1), \
                   bc()->getUInt16(bci() + 3)); \
    break;
        case BC_STORECTXDVAR:
            STORE_CTX_VAR(doubleValue)
        case BC_STORECTXIVAR:
            STORE_CTX_VAR(intValue)
        case BC_STORECTXSVAR:
            STORE_CTX_VAR(stringValue)
#undef STORE_CTX_VAR

#define CMP_JMP(op) \
    first = popValue(); \
    second = popValue(); \
    if (first.intValue() op second.intValue()) { \
        bci() += bc()->getInt16(bci() + 1) + 1; \
        jmp = true; \
    } \
    break;
        case BC_IFICMPNE:
            CMP_JMP(!=)
        case BC_IFICMPE:
            CMP_JMP(==)
        case BC_IFICMPG:
            CMP_JMP(>)
        case BC_IFICMPGE:
            CMP_JMP(>=)
        case BC_IFICMPL:
            CMP_JMP(<)
        case BC_IFICMPLE:
            CMP_JMP(<=)
#undef CMP_JMP

        case BC_JA:
            bci() += bc()->getInt16(bci() + 1) + 1;
            jmp = true;
            break;

#define BINARY_OP(type, op) \
    first = popValue(); \
    second = popValue(); \
    pushValue(first.type() op second.type()); \
    break;
        case BC_DADD:
            BINARY_OP(doubleValue, +)
        case BC_IADD:
            BINARY_OP(intValue, +)
        case BC_DSUB:
            BINARY_OP(doubleValue, -)
        case BC_ISUB:
            BINARY_OP(intValue, -)
        case BC_DMUL:
            BINARY_OP(doubleValue, *)
        case BC_IMUL:
            BINARY_OP(intValue, *)
        case BC_DDIV:
            BINARY_OP(doubleValue, /)
        case BC_IDIV:
            BINARY_OP(intValue, /)
        case BC_IMOD:
            BINARY_OP(intValue, %)
        case BC_IAOR:
            BINARY_OP(intValue, |)
        case BC_IAAND:
            BINARY_OP(intValue, &)
        case BC_IAXOR:
            BINARY_OP(intValue, ^)
#undef BINARY_OP

#define CMP(type) \
    first = popValue(); \
    second = popValue(); \
    if (first.type() < second.type()) \
        pushValue<int64_t>(-1); \
    else if (first.type() == second.type()) \
        pushValue<int64_t>(0); \
    else \
        pushValue<int64_t>(1); \
    break;
        case BC_DCMP:
            CMP(doubleValue)
        case BC_ICMP:
            CMP(intValue)
#undef CMP

        case BC_DNEG:
            pushValue(-popValue().doubleValue());
            break;
        case BC_INEG:
            pushValue(-popValue().intValue());
            break;

        case BC_S2I:
            first = popValue();
            pushValue<int64_t>(first.stringValue() != 0);
            break;
        case BC_I2D:
            pushValue<double>(popValue().intValue());
            break;
        case BC_D2I:
            pushValue<int64_t>(popValue().doubleValue());
            break;
        case BC_SWAP:
            first = popValue();
            second = popValue();
            pushValue(first);
            pushValue(second);
            break;
        case BC_POP:
            popValue();
            break;

        case BC_IPRINT:
            writeValue(std::cout, popValue(), VT_INT);
            break;
        case BC_DPRINT:
            writeValue(std::cout, popValue(), VT_DOUBLE);
            break;
        case BC_SPRINT:
            writeValue(std::cout, popValue(), VT_STRING);
            break;
        case BC_DUMP:
            first = popValue();
            writeValue(std::cerr, first, first.type());
            break;

        case BC_BREAK:
        case BC_SLOAD0:
        default:
            throw BytecodeException("Unsupported bytecode");
        }

        moveBci(jmp);
    }

    throw BytecodeException("STOP bytecode is not found");
}
예제 #7
0
bool CVirtualMachine::execute()
{
  // Cache current function
  const SFunction &currentFunction = m_functions.at(m_currentFunctionIndex);

  // Default current instruction to implicit return
  SInstruction instruction;
  instruction.id = EInstruction::Ret;

  // Check for out of bounds instruction index
  if (currentFunction.instructionSize > m_currentInstructionIndex)
  {
    // Retrieve current instruction
    instruction = currentFunction.instructions.at(m_currentInstructionIndex);
  }

  // Debug
  // printRuntimeStack();
  std::cout << "Executing instruction " << toString(instruction) << std::endl;

  switch (instruction.id)
  {
  case EInstruction::Nop:
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Break:
    // Not implemented
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Exit:
    // Return false to signal end of script
    return false;
    break;

  case EInstruction::Movv:
    // Move variable to variable
    // Arg 0 is variable index of destination
    // Arg 1 is variable index of source
    m_runtimeStack[m_currentRuntimeStackBaseIndex +
                   *((uint32_t *)&instruction.args[0])] =
        m_runtimeStack.at(m_currentRuntimeStackBaseIndex +
                          *((uint32_t *)&instruction.args[1]));
    break;

  case EInstruction::Movi:
    // Move integer to variable
    // Arg 0 is variable index of destination
    // Arg 1 is source integer value
    m_runtimeStack[m_currentRuntimeStackBaseIndex +
                   *((uint32_t *)&instruction.args[0])] = instruction.args[1];
    break;

  case EInstruction::Movf:
    // Move float to variable
    // Arg 0 is variable index of destination
    // Arg 1 is source float value
    m_runtimeStack[m_currentRuntimeStackBaseIndex +
                   *((uint32_t *)&instruction.args[0])] =
        *((float *)&instruction.args[1]);
    break;

  case EInstruction::Movs:
    // Move string to variable
    // Arg 0 is variable index of destination
    // Arg 1 is source index of string
    m_runtimeStack[m_currentRuntimeStackBaseIndex +
                   *((uint32_t *)&instruction.args[0])] =
        m_strings.at(*((uint32_t *)&instruction.args[1]));
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Pushi:
    // Push signed 32 bit integer value to
    // Arg 0 is integer value
    pushValue(CValue(instruction.args[0]));
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Pushf:
    // Arg 0 is float value
    pushValue(CValue(*((float *)&instruction.args[0])));
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Pushv:
    // Arg 0 is variable index
    pushValue(m_runtimeStack.at(m_currentRuntimeStackBaseIndex +
                                *((uint32_t *)&instruction.args[0])));
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Pushs:
    // Arg 0 is string index
    pushValue(m_strings.at(*((uint32_t *)&instruction.args[0])));
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Pop:
    // Remove top element from runtime stack
    m_runtimeStack.pop_back();
    ++m_currentInstructionIndex;
    break;

  case EInstruction::Popv:
  {
    // Remove top of the stack and store it in variable
    // Arg 0 is variable index
    m_runtimeStack[m_currentRuntimeStackBaseIndex +
                   *((uint32_t *)&instruction.args[0])] = m_runtimeStack.back();
    m_runtimeStack.pop_back();
    ++m_currentInstructionIndex;
  }
  break;

  case EInstruction::Call:
  {
    // Push current function index, next instruction index and base stack index
    // for
    // return call.
    m_callStack.push(SFunctionFrame(m_currentFunctionIndex,
                                    m_currentInstructionIndex + 1,
                                    m_currentRuntimeStackBaseIndex));
    // Arg 0 is function index of the called function
    m_currentFunctionIndex = *((uint32_t *)&instruction.args[0]);
    // Reset instruction index
    m_currentInstructionIndex = 0;
    // Set new runtime stack base index for the called function
    uint32_t runtimeStackSize = static_cast<uint32_t>(m_runtimeStack.size());
    m_currentRuntimeStackBaseIndex = runtimeStackSize;
    // Modify by function parameter size
    const SFunction &newCurrentFunction =
        m_functions.at(m_currentFunctionIndex);
    m_currentRuntimeStackBaseIndex -= newCurrentFunction.parameterSize;
    // Resize runtime stack with local stack size of called function
    m_runtimeStack.resize(runtimeStackSize + newCurrentFunction.stackSize -
                          newCurrentFunction.parameterSize);
    break;
  }

  case EInstruction::Calle:
  {
    // Call external, arg 0 is extern function index
    const SExternFunction &externFunction =
        m_externFunctions.at(instruction.args[0]);

    // Check if function exists
    // TODO Check if arg count ok
    auto entry = m_externFunctionsMap.find(externFunction.name);
    if (entry == m_externFunctionsMap.end())
    {
      // Function does not exist
      std::cout << "The extern function '" << externFunction.name
                << "' does not exist." << std::endl;
      return false;
    }
    // Call if found
    entry->second->call(*this);
    ++m_currentInstructionIndex;
    break;
  }
  case EInstruction::Ret:
    // Return from script function
    if (m_callStack.empty())
    {
      // Empty stack indicates either error state or end of script
      return false;
    }
    // Resize runtime stack to remove local function variables.
    m_runtimeStack.resize(m_currentRuntimeStackBaseIndex);

    // Retrieve function index of previous function
    m_currentFunctionIndex = m_callStack.top().functionIndex;
    // Restore active function index
    m_currentInstructionIndex = m_callStack.top().instructionIndex;
    // Restore runtime stack base index for the active function
    m_currentRuntimeStackBaseIndex = m_callStack.top().runtimeStackBaseIndex;
    m_callStack.pop();
    break;

  case EInstruction::Retv:
  {
    // Returns variable from script function
    if (m_callStack.empty())
    {
      // Empty stack indicates either error state or end of script
      return false;
    }
    // Arg 0 is local variable index
    // Store return value at local stack position 0
    uint32_t varIndex = *((uint32_t *)&instruction.args[0]);
    if (varIndex != 0)
    {
      m_runtimeStack[m_currentRuntimeStackBaseIndex + 1] =
          m_runtimeStack.at(m_currentRuntimeStackBaseIndex + varIndex);
    }

    // Resize runtime stack to remove local function variables but the one
    // holding the return value.
    m_runtimeStack.resize(m_currentRuntimeStackBaseIndex + 1);

    // Retrieve function index of previous function
    m_currentFunctionIndex = m_callStack.top().functionIndex;
    // Restore active function index
    m_currentInstructionIndex = m_callStack.top().instructionIndex;
    // Restore runtime stack base index for the active function
    m_currentRuntimeStackBaseIndex = m_callStack.top().runtimeStackBaseIndex;
    m_callStack.pop();
    break;
  }

  case EInstruction::Reti:
  {
    // Returns variable from script function
    if (m_callStack.empty())
    {
      // Empty stack indicates either error state or end of script
      return false;
    }
    // Arg 0 is integer constant
    // Store return value at local stack position 0
    m_runtimeStack[m_currentRuntimeStackBaseIndex + 1] =
        *((int32_t *)&instruction.args[0]);

    // Resize runtime stack to remove local function variables but the one
    // holding the return value.
    m_runtimeStack.resize(m_currentRuntimeStackBaseIndex + 1);

    // Retrieve function index of previous function
    m_currentFunctionIndex = m_callStack.top().functionIndex;
    // Restore active function index
    m_currentInstructionIndex = m_callStack.top().instructionIndex;
    // Restore runtime stack base index for the active function
    m_currentRuntimeStackBaseIndex = m_callStack.top().runtimeStackBaseIndex;
    m_callStack.pop();
    break;
  }

  case EInstruction::Add:
  {
    CValue x;
    // 2 Values needed
    if (!popValue(x) || m_runtimeStack.empty())
    {
      return false;
    }
    m_runtimeStack.back() += x;
    ++m_currentInstructionIndex;
  }
  break;

  case EInstruction::Sub:
  {
    CValue x;
    // 2 Values needed
    if (!popValue(x) || m_runtimeStack.empty())
    {
      return false;
    }
    m_runtimeStack.back() -= x;
    ++m_currentInstructionIndex;
  }
  break;

  case EInstruction::Mul:
    // Not implemented
    return false;
    break;

  case EInstruction::Div:
    // Not implemented
    return false;
    break;
  case EInstruction::Inc:
    // Not implemented
    return false;
    break;
  case EInstruction::Dec:
    // Not implemented
    return false;
    break;

  case EInstruction::And:
    // Not implemented
    return false;
    break;
  case EInstruction::Or:
    // Not implemented
    return false;
    break;
  case EInstruction::Not:
    // Not implemented
    return false;
    break;
  case EInstruction::Xor:
    // Not implemented
    return false;
    break;

  case EInstruction::Jmp:
    // Not implemented
    return false;
    break;
  case EInstruction::Je:
  {
    // Compare top 2 values from stack, x == y
    CValue y;
    CValue x;
    if (!popValue(y) || !popValue(x))
    {
      // Not enough values on stack
      return false;
    }
    if (x == y)
    {
      // Arg 0 is target instruction index for jump
      uint32_t jumpIndex = *((uint32_t *)&instruction.args[0]);
      m_currentInstructionIndex = jumpIndex;
    }
    else
    {
      ++m_currentInstructionIndex;
    }
  }
  break;
  case EInstruction::Jne:
  {
    // Compare top 2 values from stack, x != y
    CValue y;
    CValue x;
    if (!popValue(y) || !popValue(x))
    {
      // Not enough values on stack
      return false;
    }
    if (x != y)
    {
      // Arg 0 is target instruction index for jump
      uint32_t jumpIndex = *((uint32_t *)&instruction.args[0]);
      m_currentInstructionIndex = jumpIndex;
    }
    else
    {
      ++m_currentInstructionIndex;
    }
  }
  break;
  case EInstruction::Jle:
  {
    // Compare top 2 values from stack, x <= y
    CValue y;
    CValue x;
    if (!popValue(y) || !popValue(x))
    {
      // Not enough values on stack
      return false;
    }
    if (x <= y)
    {
      // Arg 0 is target instruction index for jump
      uint32_t jumpIndex = *((uint32_t *)&instruction.args[0]);
      m_currentInstructionIndex = jumpIndex;
    }
    else
    {
      ++m_currentInstructionIndex;
    }
  }
  break;

  default:
    assert(false);
    return false;
  }

  return true;
}