void CfgEmitter::selectFunctionCallees(const Function::Ptr &function) { // Use an iteration rather than a traversal because we want to consider all vertices that belong to the function, including // those not reachable from the entry vertex. BOOST_FOREACH (const ControlFlowGraph::VertexNode &vertex, graph_.vertices()) { if (vertexOrganization(vertex).isSelected() && owningFunction(vertex) == function) { BOOST_FOREACH (const ControlFlowGraph::EdgeNode &edge, vertex.outEdges()) { if (isInterFunctionEdge(edge)) { if (!edgeOrganization(edge).isSelected()) { edgeOrganization(edge).select(); edgeOrganization(edge).label(edgeLabel(edge)); edgeOrganization(edge).attributes(edgeAttributes(edge)); } Organization &tgt = vertexOrganization(edge.target()); if (!tgt.isSelected()) { tgt.select(); Function::Ptr callee = owningFunction(edge.target()); if (callee && edge.target()->value().type() == V_BASIC_BLOCK && edge.target()->value().address() == callee->address()) { // target is the entry block of a function tgt.label(functionLabel(callee)); tgt.attributes(functionAttributes(callee)); } else { // target is some block that isn't a function entry tgt.label(vertexLabel(edge.target())); tgt.attributes(vertexAttributes(edge.target())); } } } } } }
void CCodeGenerator::operator()(Construct* expr) { // Look up the function by name in the current context. String::Ptr id = env_->name("@init"); Class::Ptr clazz = expr->type()->clazz(); Function::Ptr func = clazz->function(id); std::vector<Operand> args; for (Expression::Ptr a = expr->arguments(); a; a = a->next()) { args.push_back(emit(a)); } return_ = alloc_temp(clazz->type()); out_ << func->label() << "("; Formal::Ptr formal = func->formals(); Expression::Ptr arg = expr->arguments(); for (int i = 0; i < args.size(); i++) { if(!formal->is_self() && !formal->type()->equals(arg->type())) { // Cast to the appropriate C-type, since C doesn't know anything // about subtypes, etc.. out_ << "("; operator()(formal->type()); out_ << ")"; } out_ << args[i]; if (i < args.size() - 1) { out_ << ", "; } formal = formal->next(); arg = arg->next(); } out_ << ");\n"; }
SAWYER_EXPORT std::string Grammar::evalFunction(TokenStream &tokens, ErrorLocation &eloc) const { ASSERT_require(tokens.isa(TOK_FUNCTION)); std::string funcName = tokens.lexeme(); ASSERT_require(funcName.size() >= 2 && '@' == funcName[0]); funcName = funcName.substr(1); tokens.consume(); // Get the function declaration const Function::Ptr func = functions_.getOrDefault(funcName); if (!func) throw SyntaxError("function \"" + funcName + "\" is not declared"); // Parse the actual arguments std::vector<std::string> actuals; while (tokens.isa(TOK_LEFT)) { tokens.consume(); if (func->isMacro()) { actuals.push_back(readArgument(tokens, eloc, CONSUME)); } else { actuals.push_back(evalArgument(tokens, eloc, CONSUME)); } } func->validateArgs(actuals, tokens); ErrorLocation::Trap t(eloc, tokens, "in function \"" + funcName + "\""); std::string retval = func->eval(*this, actuals); t.passed(); return retval; }
bool operator()(const ControlFlowGraph &cfg, const ControlFlowGraph::ConstEdgeIterator &callEdge, size_t depth) { if (depth > partitioner.stackDeltaInterproceduralLimit()) return false; ASSERT_require(callEdge != cfg.edges().end()); ASSERT_require(callEdge->target()->value().type() == V_BASIC_BLOCK); Function::Ptr function = callEdge->target()->value().function(); return function && !function->stackDelta().getOptional().orDefault(); }
static Value FunctionCall(const std::vector<Value>& args) { if (args.size() < 1) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for call()")); ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Function::Ptr self = static_cast<Function::Ptr>(vframe->Self); REQUIRE_NOT_NULL(self); std::vector<Value> uargs(args.begin() + 1, args.end()); return self->InvokeThis(args[0], uargs); }
static Value FunctionCallV(const Value& thisArg, const Array::Ptr& args) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Function::Ptr self = static_cast<Function::Ptr>(vframe->Self); REQUIRE_NOT_NULL(self); std::vector<Value> uargs; { ObjectLock olock(args); uargs = std::vector<Value>(args->Begin(), args->End()); } return self->InvokeThis(thisArg, uargs); }
static void InvokeAttributeHandlerHelper(const Function::Ptr& callback, const Object::Ptr& object, const Value& cookie) { std::vector<Value> arguments; arguments.push_back(object); callback->Invoke(arguments); }
static bool ArraySortCmp(const Function::Ptr& cmp, const Value& a, const Value& b) { std::vector<Value> args; args.push_back(a); args.push_back(b); return cmp->Invoke(args); }
static inline Value FunctionCall(ScriptFrame& frame, const Value& self, const Function::Ptr& func, const std::vector<Value>& arguments) { ScriptFrame vframe; if (!self.IsEmpty()) vframe.Self = self; return func->Invoke(arguments); }
ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { Value self, vfunc; String index; if (m_FName->GetReference(frame, false, &self, &index)) vfunc = VMOps::GetField(self, index, frame.Sandboxed, m_DebugInfo); else { ExpressionResult vfuncres = m_FName->Evaluate(frame); CHECK_RESULT(vfuncres); vfunc = vfuncres.GetValue(); } if (vfunc.IsObjectType<Type>()) { std::vector<Value> arguments; for (Expression *arg : m_Args) { ExpressionResult argres = arg->Evaluate(frame); CHECK_RESULT(argres); arguments.push_back(argres.GetValue()); } return VMOps::ConstructorCall(vfunc, arguments, m_DebugInfo); } if (!vfunc.IsObjectType<Function>()) BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo)); Function::Ptr func = vfunc; if (!func->IsSideEffectFree() && frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo)); std::vector<Value> arguments; for (Expression *arg : m_Args) { ExpressionResult argres = arg->Evaluate(frame); CHECK_RESULT(argres); arguments.push_back(argres.GetValue()); } return VMOps::FunctionCall(frame, self, func, arguments); }
static Array::Ptr ArrayMap(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast<Array::Ptr>(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Map function must be side-effect free.")); Array::Ptr result = new Array(); ObjectLock olock(self); for (const Value& item : self) { std::vector<Value> args; args.push_back(item); result->Add(function->Invoke(args)); } return result; }
static Array::Ptr ArraySort(const std::vector<Value>& args) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast<Array::Ptr>(vframe->Self); Array::Ptr arr = self->ShallowClone(); if (args.empty()) { ObjectLock olock(arr); std::sort(arr->Begin(), arr->End()); } else { Function::Ptr function = args[0]; if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Sort function must be side-effect free.")); ObjectLock olock(arr); std::sort(arr->Begin(), arr->End(), boost::bind(ArraySortCmp, args[0], _1, _2)); } return arr; }
static Value ArrayReduce(const Function::Ptr& function) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast<Array::Ptr>(vframe->Self); if (vframe->Sandboxed && !function->IsSideEffectFree()) BOOST_THROW_EXCEPTION(ScriptError("Reduce function must be side-effect free.")); if (self->GetLength() == 0) return Empty; Value result = self->Get(0); ObjectLock olock(self); for (size_t i = 1; i < self->GetLength(); i++) { std::vector<Value> args; args.push_back(result); args.push_back(self->Get(i)); result = function->Invoke(args); } return result; }
TEST(GTestFunction, TestInstanceOf) { Function::Ptr add = GTestFunctionAdd::create(); ASSERT_TRUE(add->instanceof(Type<GTestFunctionAdd>::id())); ASSERT_TRUE(add->instanceof(Type<Function>::id())); ASSERT_TRUE(add->instanceof(Type<Mutable>::id())); ASSERT_TRUE(add->instanceof(Type<Object>::id())); ASSERT_FALSE(add->instanceof(Type<Immutable>::id())); }
void CodeExpander::functor(Class* clazz) { // Generate the @call method for the functor, which contains a switch on // the type of the arugment passed to @call method. Function::Ptr func = clazz->function(env_->name("@call")); Location loc = clazz->location(); String::Ptr fn = func->formals()->next()->name(); IdentifierRef::Ptr guard(new IdentifierRef(loc, env_->name(""), fn)); Expression::Ptr stmt; for (Feature::Ptr feat = clazz->features(); feat; feat = feat->next()) { if (Function* func = dynamic_cast<Function*>(feat.pointer())) { String* nm = func->name(); if (nm->string().find("@case") == 0) { // This is a functor case, so generate a branch for it. Each // branch looks like this: self.@case_Type(obj) Type::Ptr type = func->formals()->next()->type(); Expression::Ptr arg0(new IdentifierRef(loc, env_->name(""), env_->name("__self"))); Expression::Ptr arg1(new Cast(loc, type, new IdentifierRef(loc, env_->name(""), fn))); arg0->type(func->formals()->type()); arg1->type(func->formals()->next()->type()); Expression::Ptr arg; arg = append(arg.pointer(), arg0.pointer()); arg = append(arg.pointer(), arg1.pointer()); IdentifierRef::Ptr id(new IdentifierRef(loc, env_->name(""), nm)); Call::Ptr expr(new Call(loc, id, arg)); expr->function(func); Is::Ptr is(new Is(loc, guard, type)); stmt = new Conditional(loc, is, expr, stmt); } } } Block::Ptr block = new Block(loc, env_->string(""), stmt); func->block(block); func->is_checked(false); semant_->operator()(func); }
static void InvokeAttributeHandlerHelper(const Function::Ptr& callback, const Object::Ptr& object, const Value& cookie) { callback->Invoke({ object }); }
TEST(GTestFunction, TestCall) { Function::Ptr add = GTestFunctionAdd::create(); Function::Ptr addx2 = GTestFunctionAddx2::create(); ASSERT_TRUE(add->call().instanceof(Type<Error>::id())); ASSERT_TRUE(add->call(1).equals(1)); ASSERT_TRUE(add->call(1, 2).equals(3)); ASSERT_TRUE(add->call(1, 2, 3).equals(6)); ASSERT_TRUE(add->call(1, 2, 3, 4).equals(10)); ASSERT_TRUE(add->call(1, 2, 3, 4, 5).equals(15)); ASSERT_TRUE(add->call(1, 2, 3, 4, 5, 6).equals(21)); ASSERT_TRUE(add->call(1, 2, 3, 4, 5, 6, 7).equals(28)); ASSERT_TRUE(add->call(1, 2, 3, 4, 5, 6, 7, 8).equals(36)); ASSERT_TRUE(add->call(1, 2, 3, 4, 5, 6, 7, 8, 9).equals(45)); ASSERT_TRUE(addx2->call(1, 2, 3, 4, 5, 6, 7, 8, 9).equals(90)); }
void Context::prepare(Function::Ptr function) { throwOnError(_context->Prepare(function->function())); }
bool sortFunctionsByAddress(const Function::Ptr &a, const Function::Ptr &b) { ASSERT_not_null(a); ASSERT_not_null(b); return a->address() < b->address(); }
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(); }