Removed yield from cscript.

This commit is contained in:
Relintai 2022-07-13 00:38:23 +02:00
parent c4edec424d
commit c8579ef63f
11 changed files with 64 additions and 635 deletions

View File

@ -77,17 +77,6 @@ Object *CScriptNativeClass::instance() {
return ClassDB::instance(name);
}
void CScript::_clear_pending_func_states() {
CScriptLanguage::get_singleton()->lock.lock();
while (SelfList<CScriptFunctionState> *E = pending_func_states.first()) {
// Order matters since clearing the stack may already cause
// the CSCriptFunctionState to be destroyed and thus removed from the list.
pending_func_states.remove(E);
E->self()->_clear_stack();
}
CScriptLanguage::get_singleton()->lock.unlock();
}
CScriptInstance *CScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) {
/* STEP 1, CREATE */
@ -628,7 +617,6 @@ Error CScript::reload(bool p_keep_state) {
for (Map<StringName, Ref<CScript>>::Element *E = subclasses.front(); E; E = E->next()) {
_set_subclass_path(E->get(), path);
}
_clear_pending_func_states();
return OK;
}
@ -955,8 +943,6 @@ void CScript::_save_orphaned_subclasses() {
}
CScript::~CScript() {
_clear_pending_func_states();
for (Map<StringName, CScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
memdelete(E->get());
}
@ -1328,13 +1314,6 @@ CScriptInstance::CScriptInstance() {
CScriptInstance::~CScriptInstance() {
CScriptLanguage::singleton->lock.lock();
while (SelfList<CScriptFunctionState> *E = pending_func_states.first()) {
// Order matters since clearing the stack may already cause
// the CSCriptFunctionState to be destroyed and thus removed from the list.
pending_func_states.remove(E);
E->self()->_clear_stack();
}
if (script.is_valid() && owner) {
script->instances.erase(owner);
}
@ -1742,7 +1721,6 @@ void CScriptLanguage::get_reserved_words(List<String> *p_words) const {
"setget",
"signal",
"tool",
"yield",
// var
"const",
"enum",
@ -1930,10 +1908,6 @@ String CScriptWarning::get_message() const {
case NARROWING_CONVERSION: {
return "Narrowing conversion (float is converted to int and loses precision).";
} break;
case FUNCTION_MAY_YIELD: {
CHECK_SYMBOLS(1);
return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a CScriptFunctionState instead.";
} break;
case VARIABLE_CONFLICTS_FUNCTION: {
CHECK_SYMBOLS(1);
return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
@ -2025,7 +1999,6 @@ String CScriptWarning::get_name_from_code(Code p_code) {
"STANDALONE_EXPRESSION",
"VOID_ASSIGNMENT",
"NARROWING_CONVERSION",
"FUNCTION_MAY_YIELD",
"VARIABLE_CONFLICTS_FUNCTION",
"FUNCTION_CONFLICTS_VARIABLE",
"FUNCTION_CONFLICTS_CONSTANT",

View File

@ -109,9 +109,6 @@ class CScript : public Script {
String fully_qualified_name;
SelfList<CScript> script_list;
SelfList<CScriptFunctionState>::List pending_func_states;
void _clear_pending_func_states();
CScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
void _set_subclass_path(Ref<CScript> &p_sc, const String &p_path);
@ -258,8 +255,6 @@ class CScriptInstance : public ScriptInstance {
Vector<Variant> members;
bool base_ref;
SelfList<CScriptFunctionState>::List pending_func_states;
void _ml_call_reversed(CScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount);
public:
@ -311,7 +306,6 @@ struct CScriptWarning {
STANDALONE_EXPRESSION, // Expression not assigned to a variable
VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable
NARROWING_CONVERSION, // Float value into an integer slot, precision is lost
FUNCTION_MAY_YIELD, // Typed assign of function call that yields (it may return a function state)
VARIABLE_CONFLICTS_FUNCTION, // Variable has the same name of a function
FUNCTION_CONFLICTS_VARIABLE, // Function has the same name of a variable
FUNCTION_CONFLICTS_CONSTANT, // Function has the same name of a constant
@ -346,8 +340,6 @@ struct CScriptWarning {
#endif // DEBUG_ENABLED
class CScriptLanguage : public ScriptLanguage {
friend class CScriptFunctionState;
static CScriptLanguage *singleton;
Variant *_global_array;

View File

@ -676,32 +676,6 @@ int CScriptCompiler::_parse_expression(CodeGen &codegen, const CScriptParser::No
}
}
} break;
case CScriptParser::OperatorNode::OP_YIELD: {
ERR_FAIL_COND_V(on->arguments.size() && on->arguments.size() != 2, -1);
Vector<int> arguments;
int slevel = p_stack_level;
for (int i = 0; i < on->arguments.size(); i++) {
int ret = _parse_expression(codegen, on->arguments[i], slevel);
if (ret < 0) {
return ret;
}
if ((ret >> CScriptFunction::ADDR_BITS & CScriptFunction::ADDR_TYPE_STACK) == CScriptFunction::ADDR_TYPE_STACK) {
slevel++;
codegen.alloc_stack(slevel);
}
arguments.push_back(ret);
}
//push call bytecode
codegen.opcodes.push_back(arguments.size() == 0 ? CScriptFunction::OPCODE_YIELD : CScriptFunction::OPCODE_YIELD_SIGNAL); // basic type constructor
for (int i = 0; i < arguments.size(); i++) {
codegen.opcodes.push_back(arguments[i]); //arguments
}
codegen.opcodes.push_back(CScriptFunction::OPCODE_YIELD_RESUME);
//next will be where to place the result :)
} break;
//indexing operator
case CScriptParser::OperatorNode::OP_INDEX:

View File

@ -391,16 +391,6 @@ void CScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const
mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "Resource");
p_functions->push_back(mi);
}
{
MethodInfo mi;
mi.name = "yield";
mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
mi.arguments.push_back(PropertyInfo(Variant::STRING, "signal"));
mi.default_arguments.push_back(Variant());
mi.default_arguments.push_back(String());
mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "CScriptFunctionState");
p_functions->push_back(mi);
}
{
MethodInfo mi;
mi.name = "assert";
@ -2193,7 +2183,7 @@ static void _find_identifiers(const CScriptCompletionContext &p_context, bool p_
static const char *_keywords[] = {
"and", "in", "not", "or", "false", "PI", "TAU", "INF", "NAN", "self", "true", "as", "assert",
"breakpoint", "class", "extends", "is", "func", "preload", "setget", "signal", "tool", "yield",
"breakpoint", "class", "extends", "is", "func", "preload", "setget", "signal", "tool",
"const", "enum", "export", "onready", "static", "var", "break", "continue", "if", "elif",
"else", "for", "pass", "return", "match", "while",
nullptr
@ -2771,72 +2761,6 @@ Error CScriptLanguage::complete_code(const String &p_code, const String &p_path,
options.insert(option.display, option);
}
} break;
case CScriptParser::COMPLETION_YIELD: {
const CScriptParser::Node *node = parser.get_completion_node();
CScriptCompletionContext c = context;
c.line = node->line;
CScriptCompletionIdentifier type;
if (!_guess_expression_type(c, node, type)) {
break;
}
CScriptParser::DataType base_type = type.type;
while (base_type.has_type) {
switch (base_type.kind) {
case CScriptParser::DataType::CLASS: {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL);
option.insert_text = quote_style + option.display + quote_style;
options.insert(option.display, option);
}
base_type = base_type.class_type->base_type;
} break;
case CScriptParser::DataType::SCRIPT:
case CScriptParser::DataType::CSCRIPT: {
Ref<Script> scr = base_type.script_type;
if (scr.is_valid()) {
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
options.insert(option.display, option);
}
Ref<Script> base_script = scr->get_base_script();
if (base_script.is_valid()) {
base_type.script_type = base_script;
} else {
base_type.kind = CScriptParser::DataType::NATIVE;
base_type.native_type = scr->get_instance_base_type();
}
} else {
base_type.has_type = false;
}
} break;
case CScriptParser::DataType::NATIVE: {
base_type.has_type = false;
StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
class_name = String("_") + class_name;
if (!ClassDB::class_exists(class_name)) {
break;
}
}
List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
options.insert(option.display, option);
}
} break;
default: {
base_type.has_type = false;
}
}
}
} break;
case CScriptParser::COMPLETION_RESOURCE_PATH: {
if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options);

View File

@ -212,9 +212,6 @@ String CScriptFunction::_get_call_error(const Variant::CallError &p_err, const S
&&OPCODE_CALL_BUILT_IN, \
&&OPCODE_CALL_SELF, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_YIELD, \
&&OPCODE_YIELD_SIGNAL, \
&&OPCODE_YIELD_RESUME, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
@ -251,7 +248,7 @@ String CScriptFunction::_get_call_error(const Variant::CallError &p_err, const S
#define OPCODE_OUT break
#endif
Variant CScriptFunction::call(CScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state) {
Variant CScriptFunction::call(CScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err) {
OPCODES_TABLE;
if (!_code_ptr) {
@ -278,90 +275,75 @@ Variant CScriptFunction::call(CScriptInstance *p_instance, const Variant **p_arg
int ip = 0;
int line = _initial_line;
if (p_state) {
//use existing (supplied) state (yielded)
stack = (Variant *)p_state->stack.ptr();
call_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check
line = p_state->line;
ip = p_state->ip;
alloca_size = p_state->stack.size();
script = p_state->script;
p_instance = p_state->instance;
defarg = p_state->defarg;
self = p_state->self;
//stack[p_state->result_pos]=p_state->result; //assign stack with result
if (p_argcount != _argument_count) {
if (p_argcount > _argument_count) {
r_err.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_err.argument = _argument_count;
} else {
if (p_argcount != _argument_count) {
if (p_argcount > _argument_count) {
r_err.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_err.argument = _argument_count;
return Variant();
} else if (p_argcount < _argument_count - _default_arg_count) {
r_err.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_err.argument = _argument_count - _default_arg_count;
return Variant();
} else {
defarg = _argument_count - p_argcount;
}
return Variant();
} else if (p_argcount < _argument_count - _default_arg_count) {
r_err.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_err.argument = _argument_count - _default_arg_count;
return Variant();
} else {
defarg = _argument_count - p_argcount;
}
}
alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size;
alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size;
if (alloca_size) {
uint8_t *aptr = (uint8_t *)alloca(alloca_size);
if (alloca_size) {
uint8_t *aptr = (uint8_t *)alloca(alloca_size);
if (_stack_size) {
stack = (Variant *)aptr;
for (int i = 0; i < p_argcount; i++) {
if (!argument_types[i].has_type) {
memnew_placement(&stack[i], Variant(*p_args[i]));
if (_stack_size) {
stack = (Variant *)aptr;
for (int i = 0; i < p_argcount; i++) {
if (!argument_types[i].has_type) {
memnew_placement(&stack[i], Variant(*p_args[i]));
continue;
}
if (!argument_types[i].is_type(*p_args[i], true)) {
if (argument_types[i].is_type(Variant(), true)) {
memnew_placement(&stack[i], Variant);
continue;
}
if (!argument_types[i].is_type(*p_args[i], true)) {
if (argument_types[i].is_type(Variant(), true)) {
memnew_placement(&stack[i], Variant);
continue;
} else {
r_err.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_err.argument = i;
r_err.expected = argument_types[i].kind == CScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
return Variant();
}
}
if (argument_types[i].kind == CScriptDataType::BUILTIN) {
Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err);
memnew_placement(&stack[i], Variant(arg));
} else {
memnew_placement(&stack[i], Variant(*p_args[i]));
r_err.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_err.argument = i;
r_err.expected = argument_types[i].kind == CScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
return Variant();
}
}
for (int i = p_argcount; i < _stack_size; i++) {
memnew_placement(&stack[i], Variant);
if (argument_types[i].kind == CScriptDataType::BUILTIN) {
Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err);
memnew_placement(&stack[i], Variant(arg));
} else {
memnew_placement(&stack[i], Variant(*p_args[i]));
}
} else {
stack = nullptr;
}
if (_call_size) {
call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
call_args = nullptr;
for (int i = p_argcount; i < _stack_size; i++) {
memnew_placement(&stack[i], Variant);
}
} else {
stack = nullptr;
}
if (_call_size) {
call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
call_args = nullptr;
}
if (p_instance) {
self = p_instance->owner;
script = p_instance->script.ptr();
} else {
script = _script;
}
} else {
stack = nullptr;
call_args = nullptr;
}
if (p_instance) {
self = p_instance->owner;
script = p_instance->script.ptr();
} else {
script = _script;
}
#ifdef DEBUG_ENABLED
@ -415,7 +397,6 @@ Variant CScriptFunction::call(CScriptInstance *p_instance, const Variant **p_arg
profile.frame_call_count++;
}
bool exit_ok = false;
bool yielded = false;
#endif
#ifdef DEBUG_ENABLED
@ -1206,114 +1187,6 @@ Variant CScriptFunction::call(CScriptInstance *p_instance, const Variant **p_arg
}
DISPATCH_OPCODE;
OPCODE(OPCODE_YIELD)
OPCODE(OPCODE_YIELD_SIGNAL) {
int ipofs = 1;
if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
CHECK_SPACE(4);
ipofs += 2;
} else {
CHECK_SPACE(2);
}
Ref<CScriptFunctionState> gdfs = memnew(CScriptFunctionState);
gdfs->function = this;
gdfs->state.stack.resize(alloca_size);
//copy variant stack
for (int i = 0; i < _stack_size; i++) {
memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
}
gdfs->state.stack_size = _stack_size;
gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size;
gdfs->state.ip = ip + ipofs;
gdfs->state.line = line;
gdfs->state.script = _script;
CScriptLanguage::singleton->lock.lock();
_script->pending_func_states.add(&gdfs->scripts_list);
if (p_instance) {
gdfs->state.instance = p_instance;
p_instance->pending_func_states.add(&gdfs->instances_list);
} else {
gdfs->state.instance = nullptr;
}
CScriptLanguage::singleton->lock.unlock();
#ifdef DEBUG_ENABLED
gdfs->state.function_name = name;
gdfs->state.script_path = _script->get_path();
#endif
//gdfs->state.result_pos=ip+ipofs-1;
gdfs->state.defarg = defarg;
gdfs->function = this;
retvalue = gdfs;
if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
//do the oneshot connect
GET_VARIANT_PTR(argobj, 1);
GET_VARIANT_PTR(argname, 2);
#ifdef DEBUG_ENABLED
if (argobj->get_type() != Variant::OBJECT) {
err_text = "First argument of yield() not of type object.";
OPCODE_BREAK;
}
if (argname->get_type() != Variant::STRING) {
err_text = "Second argument of yield() not a string (for signal name).";
OPCODE_BREAK;
}
#endif
Object *obj = argobj->operator Object *();
String signal = argname->operator String();
if (argobj->is_invalid_object()) {
err_text = "First argument of yield() is a previously freed instance.";
OPCODE_BREAK;
}
#ifdef DEBUG_ENABLED
if (!obj) {
err_text = "First argument of yield() is null.";
OPCODE_BREAK;
}
if (signal.length() == 0) {
err_text = "Second argument of yield() is an empty string (for signal name).";
OPCODE_BREAK;
}
Error err = obj->connect(signal, gdfs.ptr(), "_signal_callback", varray(gdfs), Object::CONNECT_ONESHOT);
if (err != OK) {
err_text = "Error connecting to signal: " + signal + " during yield().";
OPCODE_BREAK;
}
#else
obj->connect(signal, gdfs.ptr(), "_signal_callback", varray(gdfs), Object::CONNECT_ONESHOT);
#endif
}
#ifdef DEBUG_ENABLED
exit_ok = true;
yielded = true;
#endif
OPCODE_BREAK;
}
OPCODE(OPCODE_YIELD_RESUME) {
CHECK_SPACE(2);
#ifdef DEBUG_ENABLED
if (!p_state) {
err_text = ("Invalid Resume (bug?)");
OPCODE_BREAK;
}
#endif
GET_VARIANT_PTR(result, 1);
*result = p_state->result;
ip += 2;
}
DISPATCH_OPCODE;
OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
int to = _code_ptr[ip + 1];
@ -1570,23 +1443,18 @@ Variant CScriptFunction::call(CScriptInstance *p_instance, const Variant **p_arg
// Will be true if never yielded as well
// When it's the last resume it will postpone the exit from stack,
// so the debugger knows which function triggered the resume of the next function (if any)
if (!p_state || yielded) {
if (ScriptDebugger::get_singleton()) {
CScriptLanguage::get_singleton()->exit_function();
}
#endif
if (_stack_size) {
//free stack
for (int i = 0; i < _stack_size; i++) {
stack[i].~Variant();
}
}
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton()) {
CScriptLanguage::get_singleton()->exit_function();
}
#endif
if (_stack_size) {
//free stack
for (int i = 0; i < _stack_size; i++) {
stack[i].~Variant();
}
}
return retvalue;
}
@ -1727,152 +1595,3 @@ CScriptFunction::~CScriptFunction() {
CScriptLanguage::get_singleton()->lock.unlock();
#endif
}
/////////////////////
Variant CScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
Variant arg;
r_error.error = Variant::CallError::CALL_OK;
if (p_argcount == 0) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 1;
return Variant();
} else if (p_argcount == 1) {
//noooneee
} else if (p_argcount == 2) {
arg = *p_args[0];
} else {
Array extra_args;
for (int i = 0; i < p_argcount - 1; i++) {
extra_args.push_back(*p_args[i]);
}
arg = extra_args;
}
Ref<CScriptFunctionState> self = *p_args[p_argcount - 1];
if (self.is_null()) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_argcount - 1;
r_error.expected = Variant::OBJECT;
return Variant();
}
return resume(arg);
}
bool CScriptFunctionState::is_valid(bool p_extended_check) const {
if (function == nullptr) {
return false;
}
if (p_extended_check) {
#ifndef NO_THREADS
MutexLock lock(CScriptLanguage::get_singleton()->lock);
#endif
// Script gone?
if (!scripts_list.in_list()) {
return false;
}
// Class instance gone? (if not static function)
if (state.instance && !instances_list.in_list()) {
return false;
}
}
return true;
}
Variant CScriptFunctionState::resume(const Variant &p_arg) {
ERR_FAIL_COND_V(!function, Variant());
{
#ifndef NO_THREADS
MutexLock lock(CScriptLanguage::singleton->lock);
#endif
if (!scripts_list.in_list()) {
#ifdef DEBUG_ENABLED
ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after yield, but script is gone. At script: " + state.script_path + ":" + itos(state.line));
#else
return Variant();
#endif
}
if (state.instance && !instances_list.in_list()) {
#ifdef DEBUG_ENABLED
ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after yield, but class instance is gone. At script: " + state.script_path + ":" + itos(state.line));
#else
return Variant();
#endif
}
// Do these now to avoid locking again after the call
scripts_list.remove_from_list();
instances_list.remove_from_list();
}
state.result = p_arg;
Variant::CallError err;
Variant ret = function->call(nullptr, nullptr, 0, err, &state);
bool completed = true;
// If the return value is a CScriptFunctionState reference,
// then the function did yield again after resuming.
if (ret.is_ref()) {
CScriptFunctionState *gdfs = Object::cast_to<CScriptFunctionState>(ret);
if (gdfs && gdfs->function == function) {
completed = false;
gdfs->first_state = first_state.is_valid() ? first_state : Ref<CScriptFunctionState>(this);
}
}
function = nullptr; //cleaned up;
state.result = Variant();
if (completed) {
if (first_state.is_valid()) {
first_state->emit_signal("completed", ret);
} else {
emit_signal("completed", ret);
}
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton()) {
CScriptLanguage::get_singleton()->exit_function();
}
#endif
}
return ret;
}
void CScriptFunctionState::_clear_stack() {
if (state.stack_size) {
Variant *stack = (Variant *)state.stack.ptr();
for (int i = 0; i < state.stack_size; i++) {
stack[i].~Variant();
}
state.stack_size = 0;
}
}
void CScriptFunctionState::_bind_methods() {
ClassDB::bind_method(D_METHOD("resume", "arg"), &CScriptFunctionState::resume, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &CScriptFunctionState::is_valid, DEFVAL(false));
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &CScriptFunctionState::_signal_callback, MethodInfo("_signal_callback"));
ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
}
CScriptFunctionState::CScriptFunctionState() :
scripts_list(this),
instances_list(this) {
function = nullptr;
}
CScriptFunctionState::~CScriptFunctionState() {
_clear_stack();
CScriptLanguage::singleton->lock.lock();
scripts_list.remove_from_list();
instances_list.remove_from_list();
CScriptLanguage::singleton->lock.unlock();
}

View File

@ -184,9 +184,6 @@ public:
OPCODE_CALL_BUILT_IN,
OPCODE_CALL_SELF,
OPCODE_CALL_SELF_BASE,
OPCODE_YIELD,
OPCODE_YIELD_SIGNAL,
OPCODE_YIELD_RESUME,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
@ -352,34 +349,10 @@ public:
return default_arguments[p_idx];
}
Variant call(CScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state = nullptr);
Variant call(CScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err);
CScriptFunction();
~CScriptFunction();
};
class CScriptFunctionState : public Reference {
GDCLASS(CScriptFunctionState, Reference);
friend class CScriptFunction;
CScriptFunction *function;
CScriptFunction::CallState state;
Variant _signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
Ref<CScriptFunctionState> first_state;
SelfList<CScriptFunctionState> scripts_list;
SelfList<CScriptFunctionState> instances_list;
protected:
static void _bind_methods();
public:
bool is_valid(bool p_extended_check = false) const;
Variant resume(const Variant &p_arg = Variant());
void _clear_stack();
CScriptFunctionState();
~CScriptFunctionState();
};
#endif // CSCRIPT_FUNCTION_H

View File

@ -518,79 +518,6 @@ CScriptParser::Node *CScriptParser::_parse_expression(Node *p_parent, bool p_sta
constant->datatype = _type_from_variant(constant->value);
expr = constant;
} else if (tokenizer->get_token() == CScriptTokenizer::TK_PR_YIELD) {
if (!current_function) {
_set_error("\"yield()\" can only be used inside function blocks.");
return nullptr;
}
current_function->has_yield = true;
tokenizer->advance();
if (tokenizer->get_token() != CScriptTokenizer::TK_PARENTHESIS_OPEN) {
_set_error("Expected \"(\" after \"yield\".");
return nullptr;
}
tokenizer->advance();
OperatorNode *yield = alloc_node<OperatorNode>();
yield->op = OperatorNode::OP_YIELD;
while (tokenizer->get_token() == CScriptTokenizer::TK_NEWLINE) {
tokenizer->advance();
}
if (tokenizer->get_token() == CScriptTokenizer::TK_PARENTHESIS_CLOSE) {
expr = yield;
tokenizer->advance();
} else {
parenthesis++;
Node *object = _parse_and_reduce_expression(p_parent, p_static);
if (!object) {
return nullptr;
}
yield->arguments.push_back(object);
if (tokenizer->get_token() != CScriptTokenizer::TK_COMMA) {
_set_error("Expected \",\" after the first argument of \"yield\".");
return nullptr;
}
tokenizer->advance();
if (tokenizer->get_token() == CScriptTokenizer::TK_CURSOR) {
completion_cursor = StringName();
completion_node = object;
completion_type = COMPLETION_YIELD;
completion_class = current_class;
completion_function = current_function;
completion_line = tokenizer->get_token_line();
completion_argument = 0;
completion_block = current_block;
completion_found = true;
tokenizer->advance();
}
Node *signal = _parse_and_reduce_expression(p_parent, p_static);
if (!signal) {
return nullptr;
}
yield->arguments.push_back(signal);
if (tokenizer->get_token() != CScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" after the second argument of \"yield\".");
return nullptr;
}
parenthesis--;
tokenizer->advance();
expr = yield;
}
} else if (tokenizer->get_token() == CScriptTokenizer::TK_SELF) {
if (p_static) {
_set_error("\"self\" isn't allowed in a static function or constant expression.");
@ -1874,9 +1801,6 @@ CScriptParser::Node *CScriptParser::_reduce_expression(Node *p_node, bool p_to_c
return op; //don't reduce yet
} else if (op->op == OperatorNode::OP_YIELD) {
return op;
} else if (op->op == OperatorNode::OP_INDEX) {
//can reduce indices into constant arrays or dictionaries
@ -6355,23 +6279,6 @@ CScriptParser::DataType CScriptParser::_reduce_node_type(Node *p_node) {
case OperatorNode::OP_PARENT_CALL: {
node_type = _reduce_function_call_type(op);
} break;
case OperatorNode::OP_YIELD: {
if (op->arguments.size() == 2) {
DataType base_type = _reduce_node_type(op->arguments[0]);
DataType signal_type = _reduce_node_type(op->arguments[1]);
// TODO: Check if signal exists when it's a constant
if (base_type.has_type && base_type.kind == DataType::BUILTIN && base_type.builtin_type != Variant::NIL && base_type.builtin_type != Variant::OBJECT) {
_set_error("The first argument of \"yield()\" must be an object.", op->line);
return DataType();
}
if (signal_type.has_type && (signal_type.kind != DataType::BUILTIN || signal_type.builtin_type != Variant::STRING)) {
_set_error("The second argument of \"yield()\" must be a string.", op->line);
return DataType();
}
}
// yield can return anything
node_type.has_type = false;
} break;
case OperatorNode::OP_IS:
case OperatorNode::OP_IS_BUILTIN: {
if (op->arguments.size() != 2) {
@ -7029,9 +6936,6 @@ CScriptParser::DataType CScriptParser::_reduce_function_call_type(const Operator
if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_types[i].kind == DataType::BUILTIN && par_types[i].builtin_type == Variant::REAL) {
_add_warning(CScriptWarning::NARROWING_CONVERSION, p_call->line, Variant::get_type_name(tn->vtype));
}
if (par_types[i].may_yield && p_call->arguments[i + 1]->type == Node::TYPE_OPERATOR) {
_add_warning(CScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i + 1])));
}
#endif // DEBUG_ENABLED
}
}
@ -7269,9 +7173,6 @@ CScriptParser::DataType CScriptParser::_reduce_function_call_type(const Operator
if (!par_type.has_type) {
_mark_line_as_unsafe(p_call->line);
if (par_type.may_yield && p_call->arguments[i]->type == Node::TYPE_OPERATOR) {
_add_warning(CScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i])));
}
} else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) {
// Supertypes are acceptable for dynamic compliance
if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) {
@ -8057,12 +7958,6 @@ void CScriptParser::_check_function_types(FunctionNode *p_function) {
return;
}
}
if (p_function->has_yield) {
// yield() will make the function return a CScriptFunctionState, so the type is ambiguous
p_function->return_type.has_type = false;
p_function->return_type.may_yield = true;
}
}
void CScriptParser::_check_class_blocks_types(ClassNode *p_class) {
@ -8171,9 +8066,6 @@ void CScriptParser::_check_block_types(BlockNode *p_block) {
}
}
}
if (lv->datatype.has_type && assign_type.may_yield && lv->assign->type == Node::TYPE_OPERATOR) {
_add_warning(CScriptWarning::FUNCTION_MAY_YIELD, lv->line, _find_function_name(static_cast<OperatorNode *>(lv->assign)));
}
for (int i = 0; i < current_class->variables.size(); i++) {
if (current_class->variables[i].identifier == lv->name) {
_add_warning(CScriptWarning::SHADOWED_VARIABLE, lv->line, lv->name, itos(current_class->variables[i].line));
@ -8311,9 +8203,6 @@ void CScriptParser::_check_block_types(BlockNode *p_block) {
}
}
}
if (lh_type.has_type && rh_type.may_yield && op->arguments[1]->type == Node::TYPE_OPERATOR) {
_add_warning(CScriptWarning::FUNCTION_MAY_YIELD, op->line, _find_function_name(static_cast<OperatorNode *>(op->arguments[1])));
}
#endif // DEBUG_ENABLED
bool type_match = lh_type.has_type && rh_type.has_type;
@ -8384,10 +8273,6 @@ void CScriptParser::_check_block_types(BlockNode *p_block) {
return;
}
} break;
case OperatorNode::OP_YIELD: {
_mark_line_as_safe(op->line);
_reduce_node_type(op);
} break;
default: {
_mark_line_as_safe(op->line);
_reduce_node_type(op); // Test for safety anyway

View File

@ -57,7 +57,6 @@ public:
bool is_constant;
bool is_meta_type; // Whether the value can be used as a type
bool infer_type;
bool may_yield; // For function calls
Variant::Type builtin_type;
StringName native_type;
@ -99,7 +98,6 @@ public:
is_constant(false),
is_meta_type(false),
infer_type(false),
may_yield(false),
builtin_type(Variant::NIL),
class_type(nullptr) {}
};
@ -203,7 +201,6 @@ public:
struct FunctionNode : public Node {
bool _static;
bool has_yield;
bool has_unreachable_code;
StringName name;
DataType return_type;
@ -228,7 +225,6 @@ public:
FunctionNode() {
type = TYPE_FUNCTION;
_static = false;
has_yield = false;
has_unreachable_code = false;
}
};
@ -343,7 +339,6 @@ public:
//call/constructor operator
OP_CALL,
OP_PARENT_CALL,
OP_YIELD,
OP_IS,
OP_IS_BUILTIN,
//indexing operator
@ -510,7 +505,6 @@ public:
COMPLETION_RESOURCE_PATH,
COMPLETION_INDEX,
COMPLETION_VIRTUAL_FUNC,
COMPLETION_YIELD,
COMPLETION_ASSIGN,
COMPLETION_TYPE_HINT,
COMPLETION_TYPE_HINT_INDEX,

View File

@ -103,7 +103,6 @@ const char *CScriptTokenizer::token_names[TK_MAX] = {
"enum",
"preload",
"assert",
"yield",
"signal",
"breakpoint",
"'['",
@ -200,7 +199,6 @@ static const _kws _keyword_list[] = {
{ CScriptTokenizer::TK_PR_VOID, "void" },
{ CScriptTokenizer::TK_PR_PRELOAD, "preload" },
{ CScriptTokenizer::TK_PR_ASSERT, "assert" },
{ CScriptTokenizer::TK_PR_YIELD, "yield" },
{ CScriptTokenizer::TK_PR_SIGNAL, "signal" },
{ CScriptTokenizer::TK_PR_BREAKPOINT, "breakpoint" },
{ CScriptTokenizer::TK_PR_CONST, "const" },
@ -259,7 +257,6 @@ bool CScriptTokenizer::is_token_literal(int p_offset, bool variable_safe) const
case TK_PR_FUNCTION:
case TK_PR_EXTENDS:
case TK_PR_ASSERT:
case TK_PR_YIELD:
case TK_PR_VAR:
case TK_CF_IF:

View File

@ -108,7 +108,6 @@ public:
TK_PR_ENUM,
TK_PR_PRELOAD,
TK_PR_ASSERT,
TK_PR_YIELD,
TK_PR_SIGNAL,
TK_PR_BREAKPOINT,
TK_BRACKET_OPEN,

View File

@ -138,7 +138,6 @@ static void _editor_init() {
void register_cscript_types() {
ClassDB::register_class<CScript>();
ClassDB::register_virtual_class<CScriptFunctionState>();
script_language_cscript = memnew(CScriptLanguage);
ScriptServer::register_language(script_language_cscript);