//------------------------------------------------------------------------- void ConstantExpression::unaryOperation( ConstantExpression& result, AST::UnaryExpression::Operator op ) const { if ( this->getType() == SCALAR_INVALID ) { if ( mErrorHandler ) { Error err( Error::ERR_INVALIDPARAMS, "uninitilized operand" ); mErrorHandler->handleError( &err ); } result.setValue( 0. ); return; } else if ( this->getType() == SCALAR_BOOL && op != AST::UnaryExpression::NOT ) { if ( mErrorHandler ) { Error err( Error::ERR_INVALIDPARAMS, "boolean operand in arithmetical operation" ); mErrorHandler->handleError( &err ); } result.setValue( 0. ); return; } else if ( this->getType() == SCALAR_BOOL && op == AST::UnaryExpression::NOT ) { result.setValue( !this->getBoolValue() ); } else if ( this->getType() == SCALAR_LONG ) { result.setValue( unaryOperation( this->getLongValue(), op ) ); } else { result.setValue( unaryOperation( this->getDoubleValue(), op ) ); } }
Variant& StackMachine::evaluate(const VariableStore& store, const FunctionRegistry& functions) { reset(); for(const auto& instruction : _instructions) { switch(instruction._opCode) { case NOP: { break; } case PUSH: { _valueStack.emplace(instruction._value); break; } case PUSHVAR: { if(instruction._value.getType() != INT) { CSVSQLDB_THROW(StackMachineException, "expected an INT as variable index"); } int64_t index = instruction._value.asInt(); _valueStack.emplace(store[static_cast<size_t>(index)]); break; } case ADD: case SUB: case DIV: case MOD: case MUL: case EQ: case NEQ: case IS: case ISNOT: case GT: case GE: case LT: case LE: case AND: case OR: case CONCAT: { const Variant lhs(getNextValue()); Variant& rhs(getTopValue()); rhs = binaryOperation(mapOpCodeToBinaryOperationType(instruction._opCode), lhs, rhs); break; } case NOT: { Variant& rhs(getTopValue()); rhs = unaryOperation(OP_NOT, BOOLEAN, rhs); break; } case PLUS: { // this is a nop, as the value will not change, so just leave it on the stack break; } case MINUS: { Variant& rhs = getTopValue(); rhs = unaryOperation(OP_MINUS, rhs.getType(), rhs); break; } case BETWEEN: { const Variant lhs = getNextValue(); const Variant from = getNextValue(); Variant& to = getTopValue(); Variant result(BOOLEAN); if(not(lhs.isNull() || from.isNull() || to.isNull())) { if(binaryOperation(OP_GE, to, from).asBool()) { result = binaryOperation(OP_GE, lhs, from); if(result.asBool()) { result = binaryOperation(OP_LE, lhs, to); } } else { result = binaryOperation(OP_GE, lhs, to); if(result.asBool()) { result = binaryOperation(OP_LE, lhs, from); } } } to = result; break; } case FUNC: { if(instruction._value.getType() != STRING) { CSVSQLDB_THROW(StackMachineException, "expected a string as variable name"); } std::string funcname = instruction._value.asString(); Function::Ptr func = functions.getFunction(funcname); if(!func) { CSVSQLDB_THROW(StackMachineException, "function '" << funcname << "' not found"); } Variants parameter; size_t count = func->getParameterTypes().size(); for(const auto& param : func->getParameterTypes()) { Variant v = getNextValue(); if(param != v.getType()) { try { v = unaryOperation(OP_CAST, param, v); } catch(const std::exception&) { CSVSQLDB_THROW(StackMachineException, "calling function '" << funcname << "' with wrong parameter"); } } parameter.emplace(parameter.end(), v); --count; } if(count) { CSVSQLDB_THROW(StackMachineException, "too much parameters for function '" << funcname << "'"); } _valueStack.emplace(func->call(parameter)); break; } case CAST: { Variant& rhs = getTopValue(); rhs = unaryOperation(OP_CAST, instruction._value.getType(), rhs); break; } case IN: { size_t count = static_cast<size_t>(instruction._value.asInt()); const Variant lhs = getNextValue(); bool found(false); for(size_t n = 0; n < count; ++n) { Variant result = binaryOperation(OP_EQ, lhs, getNextValue()); if(result.asBool()) { found = true; ++n; for(; n < count; ++n) { // remove rest of the values from stack _valueStack.pop(); } break; } } if(found) { _valueStack.emplace(Variant(true)); } else { _valueStack.emplace(Variant(false)); } break; } case LIKE: { if(!instruction._r) { CSVSQLDB_THROW(StackMachineException, "expected a regexp in LIKE expression"); } Variant lhs = getTopValue(); if(lhs.getType() != STRING) { lhs = unaryOperation(OP_CAST, STRING, lhs); CSVSQLDB_THROW(StackMachineException, "can only do like operations on strings"); } if(instruction._r->match(lhs.asString())) { _valueStack.emplace(Variant(true)); } else { _valueStack.emplace(Variant(false)); } break; } } } return _valueStack.top(); }