예제 #1
0
static bool _guess_expression_type(GDCompletionContext& context,const GDParser::Node* p_node,int p_line,GDCompletionIdentifier &r_type) {


	if (p_node->type==GDParser::Node::TYPE_CONSTANT) {

		const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node);

		r_type=_get_type_from_variant(cn->value);

		return true;
	} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {

		r_type.type=Variant::DICTIONARY;


		//what the heck, fill it anyway
		const GDParser::DictionaryNode *an = static_cast<const GDParser::DictionaryNode *>(p_node);
		Dictionary d;
		for(int i=0;i<an->elements.size();i++) {
			GDCompletionIdentifier k;
			if (_guess_expression_type(context,an->elements[i].key,p_line,k) && k.value.get_type()!=Variant::NIL) {
				GDCompletionIdentifier v;
				if (_guess_expression_type(context,an->elements[i].value,p_line,v)) {
					d[k.value]=v.value;
				}

			}
		}
		r_type.value=d;
		return true;
	} else if (p_node->type==GDParser::Node::TYPE_ARRAY) {

		r_type.type=Variant::ARRAY;
		//what the heck, fill it anyway
		const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode *>(p_node);
		Array arr;
		arr.resize(an->elements.size());
		for(int i=0;i<an->elements.size();i++) {
			GDCompletionIdentifier ci;
			if (_guess_expression_type(context,an->elements[i],p_line,ci)) {
				arr[i]=ci.value;
			}
		}
		r_type.value=arr;
		return true;

	} else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {

		MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function);
		r_type=_get_type_from_pinfo(mi.return_val);

		return true;
	} else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) {

		return _guess_identifier_type(context,p_line-1,static_cast<const GDParser::IdentifierNode *>(p_node)->name,r_type);
	} else if (p_node->type==GDParser::Node::TYPE_SELF) {
		//eeh...

		r_type=_get_native_class(context);
		return r_type.type!=Variant::NIL;

	} else if (p_node->type==GDParser::Node::TYPE_OPERATOR) {


		const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node);
		if (op->op==GDParser::OperatorNode::OP_CALL) {
			if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {

				const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode *>(op->arguments[0]);
				r_type.type=tn->vtype;
				return true;
			} else if (op->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {


				const GDParser::BuiltInFunctionNode *bin = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]);
				return _guess_expression_type(context,bin,p_line,r_type);

			} else if (op->arguments.size()>1 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {


				GDCompletionIdentifier base;
				if (!_guess_expression_type(context,op->arguments[0],p_line,base))
					return false;

				StringName id = static_cast<const GDParser::IdentifierNode *>(op->arguments[1])->name;

				if (base.type==Variant::OBJECT) {

					if (id.operator String()=="new" && base.value.get_type()==Variant::OBJECT) {
						Object *obj = base.value;
						if (obj && obj->cast_to<GDNativeClass>()) {
							GDNativeClass *gdnc = obj->cast_to<GDNativeClass>();
							r_type.type=Variant::OBJECT;
							r_type.value=Variant();
							r_type.obj_type=gdnc->get_name();
							return true;
						}
					}

					if (ObjectTypeDB::has_method(base.obj_type,id)) {

#ifdef TOOLS_ENABLED
						MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id);
						PropertyInfo pi = mb->get_argument_info(-1);

						//try calling the function if constant and all args are constant, should not crash..
						Object *baseptr = base.value;

						if (baseptr && mb->is_const() && pi.type==Variant::OBJECT) {
							bool all_valid=true;
							Vector<Variant> args;
							for(int i=2;i<op->arguments.size();i++) {
								GDCompletionIdentifier arg;

								if (_guess_expression_type(context,op->arguments[i],p_line,arg)) {
									if (arg.value.get_type()!=Variant::NIL && arg.value.get_type()!=Variant::OBJECT) { // calling with object seems dangerous, i don' t know
										args.push_back(arg.value);
									} else {
										all_valid=false;
										break;
									}
								} else {
									all_valid=false;
								}
							}
							if (all_valid) {
								Vector<const Variant*> argptr;
								for(int i=0;i<args.size();i++) {
									argptr.push_back(&args[i]);
								}

								Variant::CallError ce;
								Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);


								if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {

									if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {

										r_type=_get_type_from_variant(ret);
										return true;
									}
								}

							}
						}

						r_type.type=pi.type;
						if (pi.hint==PROPERTY_HINT_RESOURCE_TYPE) {
							r_type.obj_type=pi.hint_string;
						}



						return true;
#else
						return false;
#endif
					} else {
						return false;
					}
				} else {
					//method for some variant..
					Variant::CallError ce;
					Variant v = Variant::construct(base.type,NULL,0,ce);
					List<MethodInfo> mi;
					v.get_method_list(&mi);
					for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {

						if (!E->get().name.begins_with("_") && E->get().name==id.operator String()) {


							MethodInfo mi = E->get();
							r_type.type=mi.return_val.type;
							if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) {
								r_type.obj_type=mi.return_val.hint_string;
							}
							return true;
						}
					}

				}


			}
		} else if (op->op==GDParser::OperatorNode::OP_INDEX || op->op==GDParser::OperatorNode::OP_INDEX_NAMED) {

			GDCompletionIdentifier p1;
			GDCompletionIdentifier p2;



			if (op->op==GDParser::OperatorNode::OP_INDEX_NAMED) {

				if (op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
					String id = static_cast<const GDParser::IdentifierNode*>(op->arguments[1])->name;
					p2.type=Variant::STRING;
					p2.value=id;
				}

			} else {
				if (op->arguments[1]) {
					if (!_guess_expression_type(context,op->arguments[1],p_line,p2)) {

						return false;
					}
				}
			}

			if (op->arguments[0]->type==GDParser::Node::TYPE_ARRAY) {

				const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode *>(op->arguments[0]);
				if (p2.value.is_num()) {
					int index = p2.value;
					if (index<0 || index>=an->elements.size())
						return false;
					return _guess_expression_type(context,an->elements[index],p_line,r_type);
				}

			} else if (op->arguments[0]->type==GDParser::Node::TYPE_DICTIONARY) {

				const GDParser::DictionaryNode *dn = static_cast<const GDParser::DictionaryNode *>(op->arguments[0]);

				if (p2.value.get_type()==Variant::NIL)
					return false;

				for(int i=0;i<dn->elements.size();i++) {

					GDCompletionIdentifier k;

					if (!_guess_expression_type(context,dn->elements[i].key,p_line,k)) {

						return false;
					}

					if (k.value.get_type()==Variant::NIL)
						return false;

					if (k.value==p2.value) {

						return _guess_expression_type(context,dn->elements[i].value,p_line,r_type);
					}
				}

			} else {

				if (op->arguments[0]) {
					if (!_guess_expression_type(context,op->arguments[0],p_line,p1)) {

						return false;
					}

				}

				if (p1.value.get_type()==Variant::OBJECT) {
					//??
				} else if (p1.value.get_type()!=Variant::NIL) {

					bool valid;
					Variant ret = p1.value.get(p2.value,&valid);
					if (valid) {
						r_type=_get_type_from_variant(ret);
						return true;
					}

				} else {
					if (p1.type!=Variant::NIL) {
						Variant::CallError ce;
						Variant base = Variant::construct(p1.type,NULL,0,ce);
						bool valid;
						Variant ret = base.get(p2.value,&valid);
						if (valid) {
							r_type=_get_type_from_variant(ret);
							return true;
						}
					}
				}
			}

		} else {


			Variant::Operator vop = Variant::OP_MAX;
			switch(op->op) {
				case GDParser::OperatorNode::OP_ADD: vop=Variant::OP_ADD; break;
				case GDParser::OperatorNode::OP_SUB: vop=Variant::OP_SUBSTRACT; break;
				case GDParser::OperatorNode::OP_MUL: vop=Variant::OP_MULTIPLY; break;
				case GDParser::OperatorNode::OP_DIV: vop=Variant::OP_DIVIDE; break;
				case GDParser::OperatorNode::OP_MOD: vop=Variant::OP_MODULE; break;
				case GDParser::OperatorNode::OP_SHIFT_LEFT: vop=Variant::OP_SHIFT_LEFT; break;
				case GDParser::OperatorNode::OP_SHIFT_RIGHT: vop=Variant::OP_SHIFT_RIGHT; break;
				case GDParser::OperatorNode::OP_BIT_AND: vop=Variant::OP_BIT_AND; break;
				case GDParser::OperatorNode::OP_BIT_OR: vop=Variant::OP_BIT_OR; break;
				case GDParser::OperatorNode::OP_BIT_XOR: vop=Variant::OP_BIT_XOR; break;
				default:{}

			}



			if (vop==Variant::OP_MAX)
				return false;



			GDCompletionIdentifier p1;
			GDCompletionIdentifier p2;

			if (op->arguments[0]) {
				if (!_guess_expression_type(context,op->arguments[0],p_line,p1)) {

					return false;
				}

			}

			if (op->arguments.size()>1) {
				if (!_guess_expression_type(context,op->arguments[1],p_line,p2)) {

					return false;
				}
			}

			Variant::CallError ce;
			bool v1_use_value = p1.value.get_type()!=Variant::NIL && p1.value.get_type()!=Variant::OBJECT;
			Variant v1 = (v1_use_value)?p1.value:Variant::construct(p1.type,NULL,0,ce);
			bool v2_use_value = p2.value.get_type()!=Variant::NIL && p2.value.get_type()!=Variant::OBJECT;
			Variant v2 = (v2_use_value)?p2.value:Variant::construct(p2.type,NULL,0,ce);
			// avoid potential invalid ops
			if ((vop==Variant::OP_DIVIDE || vop==Variant::OP_MODULE) && v2.get_type()==Variant::INT) {
				v2=1;
				v2_use_value=false;
			}
			if (vop==Variant::OP_DIVIDE && v2.get_type()==Variant::REAL) {
				v2=1.0;
				v2_use_value=false;
			}

			Variant r;
			bool valid;
			Variant::evaluate(vop,v1,v2,r,valid);
			if (!valid)
				return false;
			r_type.type=r.get_type();
			if (v1_use_value && v2_use_value)
				r_type.value=r;

			return true;

		}

	}

	return false;
}