virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { if (p_start_mode == START_MODE_RESUME_YIELD) { return 0; //resuming yield } else { //yield Object *object = NULL; switch (call_mode) { case VisualScriptYieldSignal::CALL_MODE_SELF: { object = instance->get_owner_ptr(); } break; case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: { Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); if (!node) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Base object is not a Node!"; return 0; } Node *another = node->get_node(node_path); if (!another) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Path does not lead Node!"; return 0; } object = another; } break; case VisualScriptYieldSignal::CALL_MODE_INSTANCE: { object = *p_inputs[0]; if (!object) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Supplied instance input is null."; return 0; } } break; } Ref<VisualScriptFunctionState> state; state.instance(); state->connect_to_signal(object, signal, Array()); *p_working_mem = state; return STEP_YIELD_BIT; } }
//virtual int get_working_memory_size() const { return 0; } //execute by parsing the tree directly virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Variant::CallError &ce) { switch (p_node->type) { case VisualScriptExpression::ENode::TYPE_INPUT: { const VisualScriptExpression::InputNode *in = static_cast<const VisualScriptExpression::InputNode *>(p_node); r_ret = *p_inputs[in->index]; } break; case VisualScriptExpression::ENode::TYPE_CONSTANT: { const VisualScriptExpression::ConstantNode *c = static_cast<const VisualScriptExpression::ConstantNode *>(p_node); r_ret = c->value; } break; case VisualScriptExpression::ENode::TYPE_SELF: { r_ret = instance->get_owner_ptr(); } break; case VisualScriptExpression::ENode::TYPE_OPERATOR: { const VisualScriptExpression::OperatorNode *op = static_cast<const VisualScriptExpression::OperatorNode *>(p_node); Variant a; bool ret = _execute(p_inputs, op->nodes[0], a, r_error_str, ce); if (ret) return true; Variant b; if (op->nodes[1]) { ret = _execute(p_inputs, op->nodes[1], b, r_error_str, ce); if (ret) return true; } bool valid = true; Variant::evaluate(op->op, a, b, r_ret, valid); if (!valid) { r_error_str = "Invalid operands to operator " + Variant::get_operator_name(op->op) + ": " + Variant::get_type_name(a.get_type()) + " and " + Variant::get_type_name(b.get_type()) + "."; return true; } } break; case VisualScriptExpression::ENode::TYPE_INDEX: { const VisualScriptExpression::IndexNode *index = static_cast<const VisualScriptExpression::IndexNode *>(p_node); Variant base; bool ret = _execute(p_inputs, index->base, base, r_error_str, ce); if (ret) return true; Variant idx; ret = _execute(p_inputs, index->index, idx, r_error_str, ce); if (ret) return true; bool valid; r_ret = base.get(idx, &valid); if (!valid) { r_error_str = "Invalid index of type " + Variant::get_type_name(idx.get_type()) + " for base of type " + Variant::get_type_name(base.get_type()) + "."; return true; } } break; case VisualScriptExpression::ENode::TYPE_NAMED_INDEX: { const VisualScriptExpression::NamedIndexNode *index = static_cast<const VisualScriptExpression::NamedIndexNode *>(p_node); Variant base; bool ret = _execute(p_inputs, index->base, base, r_error_str, ce); if (ret) return true; bool valid; r_ret = base.get_named(index->name, &valid); if (!valid) { r_error_str = "Invalid index '" + String(index->name) + "' for base of type " + Variant::get_type_name(base.get_type()) + "."; return true; } } break; case VisualScriptExpression::ENode::TYPE_ARRAY: { const VisualScriptExpression::ArrayNode *array = static_cast<const VisualScriptExpression::ArrayNode *>(p_node); Array arr; arr.resize(array->array.size()); for (int i = 0; i < array->array.size(); i++) { Variant value; bool ret = _execute(p_inputs, array->array[i], value, r_error_str, ce); if (ret) return true; arr[i] = value; } r_ret = arr; } break; case VisualScriptExpression::ENode::TYPE_DICTIONARY: { const VisualScriptExpression::DictionaryNode *dictionary = static_cast<const VisualScriptExpression::DictionaryNode *>(p_node); Dictionary d; for (int i = 0; i < dictionary->dict.size(); i += 2) { Variant key; bool ret = _execute(p_inputs, dictionary->dict[i + 0], key, r_error_str, ce); if (ret) return true; Variant value; ret = _execute(p_inputs, dictionary->dict[i + 1], value, r_error_str, ce); if (ret) return true; d[key] = value; } r_ret = d; } break; case VisualScriptExpression::ENode::TYPE_CONSTRUCTOR: { const VisualScriptExpression::ConstructorNode *constructor = static_cast<const VisualScriptExpression::ConstructorNode *>(p_node); Vector<Variant> arr; Vector<const Variant *> argp; arr.resize(constructor->arguments.size()); argp.resize(constructor->arguments.size()); for (int i = 0; i < constructor->arguments.size(); i++) { Variant value; bool ret = _execute(p_inputs, constructor->arguments[i], value, r_error_str, ce); if (ret) return true; arr[i] = value; argp[i] = &arr[i]; } r_ret = Variant::construct(constructor->data_type, argp.ptr(), argp.size(), ce); if (ce.error != Variant::CallError::CALL_OK) { r_error_str = "Invalid arguments to construct '" + Variant::get_type_name(constructor->data_type) + "'."; return true; } } break; case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC: { const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode *>(p_node); Vector<Variant> arr; Vector<const Variant *> argp; arr.resize(bifunc->arguments.size()); argp.resize(bifunc->arguments.size()); for (int i = 0; i < bifunc->arguments.size(); i++) { Variant value; bool ret = _execute(p_inputs, bifunc->arguments[i], value, r_error_str, ce); if (ret) return true; arr[i] = value; argp[i] = &arr[i]; } VisualScriptBuiltinFunc::exec_func(bifunc->func, argp.ptr(), &r_ret, ce, r_error_str); if (ce.error != Variant::CallError::CALL_OK) { r_error_str = "Builtin Call Failed. " + r_error_str; return true; } } break; case VisualScriptExpression::ENode::TYPE_CALL: { const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode *>(p_node); Variant base; bool ret = _execute(p_inputs, call->base, base, r_error_str, ce); if (ret) return true; Vector<Variant> arr; Vector<const Variant *> argp; arr.resize(call->arguments.size()); argp.resize(call->arguments.size()); for (int i = 0; i < call->arguments.size(); i++) { Variant value; bool ret = _execute(p_inputs, call->arguments[i], value, r_error_str, ce); if (ret) return true; arr[i] = value; argp[i] = &arr[i]; } r_ret = base.call(call->method, argp.ptr(), argp.size(), ce); if (ce.error != Variant::CallError::CALL_OK) { r_error_str = "On call to '" + String(call->method) + "':"; return true; } } break; } return false; }