int VisualScriptBuiltinFunc::get_input_value_port_count() const {

	return get_func_argument_count(func);
}
Example #2
0
Expression::ENode *Expression::_parse_expression() {

	Vector<ExpressionNode> expression;

	while (true) {
		//keep appending stuff to expression
		ENode *expr = NULL;

		Token tk;
		_get_token(tk);
		if (error_set)
			return NULL;

		switch (tk.type) {
			case TK_CURLY_BRACKET_OPEN: {
				//a dictionary
				DictionaryNode *dn = alloc_node<DictionaryNode>();

				while (true) {

					int cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_CURLY_BRACKET_CLOSE) {
						break;
					}
					str_ofs = cofs; //revert
					//parse an expression
					ENode *subexpr = _parse_expression();
					if (!subexpr)
						return NULL;
					dn->dict.push_back(subexpr);

					_get_token(tk);
					if (tk.type != TK_COLON) {
						_set_error("Expected ':'");
						return NULL;
					}

					subexpr = _parse_expression();
					if (!subexpr)
						return NULL;

					dn->dict.push_back(subexpr);

					cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_COMMA) {
						//all good
					} else if (tk.type == TK_CURLY_BRACKET_CLOSE) {
						str_ofs = cofs;
					} else {
						_set_error("Expected ',' or '}'");
					}
				}

				expr = dn;
			} break;
			case TK_BRACKET_OPEN: {
				//an array

				ArrayNode *an = alloc_node<ArrayNode>();

				while (true) {

					int cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_BRACKET_CLOSE) {
						break;
					}
					str_ofs = cofs; //revert
					//parse an expression
					ENode *subexpr = _parse_expression();
					if (!subexpr)
						return NULL;
					an->array.push_back(subexpr);

					cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_COMMA) {
						//all good
					} else if (tk.type == TK_BRACKET_CLOSE) {
						str_ofs = cofs;
					} else {
						_set_error("Expected ',' or ']'");
					}
				}

				expr = an;
			} break;
			case TK_PARENTHESIS_OPEN: {
				//a suexpression
				ENode *e = _parse_expression();
				if (error_set)
					return NULL;
				_get_token(tk);
				if (tk.type != TK_PARENTHESIS_CLOSE) {
					_set_error("Expected ')'");
					return NULL;
				}

				expr = e;

			} break;
			case TK_IDENTIFIER: {

				String identifier = tk.value;

				int cofs = str_ofs;
				_get_token(tk);
				if (tk.type == TK_PARENTHESIS_OPEN) {
					//function call
					CallNode *func_call = alloc_node<CallNode>();
					func_call->method = identifier;
					SelfNode *self_node = alloc_node<SelfNode>();
					func_call->base = self_node;

					while (true) {

						int cofs2 = str_ofs;
						_get_token(tk);
						if (tk.type == TK_PARENTHESIS_CLOSE) {
							break;
						}
						str_ofs = cofs2; //revert
						//parse an expression
						ENode *subexpr = _parse_expression();
						if (!subexpr)
							return NULL;

						func_call->arguments.push_back(subexpr);

						cofs2 = str_ofs;
						_get_token(tk);
						if (tk.type == TK_COMMA) {
							//all good
						} else if (tk.type == TK_PARENTHESIS_CLOSE) {
							str_ofs = cofs2;
						} else {
							_set_error("Expected ',' or ')'");
						}
					}

					expr = func_call;
				} else {
					//named indexing
					str_ofs = cofs;

					int input_index = -1;
					for (int i = 0; i < input_names.size(); i++) {
						if (input_names[i] == identifier) {
							input_index = i;
							break;
						}
					}

					if (input_index != -1) {
						InputNode *input = alloc_node<InputNode>();
						input->index = input_index;
						expr = input;
					} else {

						NamedIndexNode *index = alloc_node<NamedIndexNode>();
						SelfNode *self_node = alloc_node<SelfNode>();
						index->base = self_node;
						index->name = identifier;
						expr = index;
					}
				}
			} break;
			case TK_INPUT: {

				InputNode *input = alloc_node<InputNode>();
				input->index = tk.value;
				expr = input;
			} break;
			case TK_SELF: {

				SelfNode *self = alloc_node<SelfNode>();
				expr = self;
			} break;
			case TK_CONSTANT: {
				ConstantNode *constant = alloc_node<ConstantNode>();
				constant->value = tk.value;
				expr = constant;
			} break;
			case TK_BASIC_TYPE: {
				//constructor..

				Variant::Type bt = Variant::Type(int(tk.value));
				_get_token(tk);
				if (tk.type != TK_PARENTHESIS_OPEN) {
					_set_error("Expected '('");
					return NULL;
				}

				ConstructorNode *constructor = alloc_node<ConstructorNode>();
				constructor->data_type = bt;

				while (true) {

					int cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_PARENTHESIS_CLOSE) {
						break;
					}
					str_ofs = cofs; //revert
					//parse an expression
					ENode *subexpr = _parse_expression();
					if (!subexpr)
						return NULL;

					constructor->arguments.push_back(subexpr);

					cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_COMMA) {
						//all good
					} else if (tk.type == TK_PARENTHESIS_CLOSE) {
						str_ofs = cofs;
					} else {
						_set_error("Expected ',' or ')'");
					}
				}

				expr = constructor;

			} break;
			case TK_BUILTIN_FUNC: {
				//builtin function

				_get_token(tk);
				if (tk.type != TK_PARENTHESIS_OPEN) {
					_set_error("Expected '('");
					return NULL;
				}

				BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
				bifunc->func = BuiltinFunc(int(tk.value));

				while (true) {

					int cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_PARENTHESIS_CLOSE) {
						break;
					}
					str_ofs = cofs; //revert
					//parse an expression
					ENode *subexpr = _parse_expression();
					if (!subexpr)
						return NULL;

					bifunc->arguments.push_back(subexpr);

					cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_COMMA) {
						//all good
					} else if (tk.type == TK_PARENTHESIS_CLOSE) {
						str_ofs = cofs;
					} else {
						_set_error("Expected ',' or ')'");
					}
				}

				int expected_args = get_func_argument_count(bifunc->func);
				if (bifunc->arguments.size() != expected_args) {
					_set_error("Builtin func '" + get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments.");
				}

				expr = bifunc;

			} break;
			case TK_OP_SUB: {

				ExpressionNode e;
				e.is_op = true;
				e.op = Variant::OP_NEGATE;
				expression.push_back(e);
				continue;
			} break;
			case TK_OP_NOT: {

				ExpressionNode e;
				e.is_op = true;
				e.op = Variant::OP_NOT;
				expression.push_back(e);
				continue;
			} break;

			default: {
				_set_error("Expected expression.");
				return NULL;
			} break;
		}

		//before going to operators, must check indexing!

		while (true) {
			int cofs2 = str_ofs;
			_get_token(tk);
			if (error_set)
				return NULL;

			bool done = false;

			switch (tk.type) {
				case TK_BRACKET_OPEN: {
					//value indexing

					IndexNode *index = alloc_node<IndexNode>();
					index->base = expr;

					ENode *what = _parse_expression();
					if (!what)
						return NULL;

					index->index = what;

					_get_token(tk);
					if (tk.type != TK_BRACKET_CLOSE) {
						_set_error("Expected ']' at end of index.");
						return NULL;
					}
					expr = index;

				} break;
				case TK_PERIOD: {
					//named indexing or function call
					_get_token(tk);
					if (tk.type != TK_IDENTIFIER) {
						_set_error("Expected identifier after '.'");
						return NULL;
					}

					StringName identifier = tk.value;

					int cofs = str_ofs;
					_get_token(tk);
					if (tk.type == TK_PARENTHESIS_OPEN) {
						//function call
						CallNode *func_call = alloc_node<CallNode>();
						func_call->method = identifier;
						func_call->base = expr;

						while (true) {

							int cofs3 = str_ofs;
							_get_token(tk);
							if (tk.type == TK_PARENTHESIS_CLOSE) {
								break;
							}
							str_ofs = cofs3; //revert
							//parse an expression
							ENode *subexpr = _parse_expression();
							if (!subexpr)
								return NULL;

							func_call->arguments.push_back(subexpr);

							cofs3 = str_ofs;
							_get_token(tk);
							if (tk.type == TK_COMMA) {
								//all good
							} else if (tk.type == TK_PARENTHESIS_CLOSE) {
								str_ofs = cofs3;
							} else {
								_set_error("Expected ',' or ')'");
							}
						}

						expr = func_call;
					} else {
						//named indexing
						str_ofs = cofs;

						NamedIndexNode *index = alloc_node<NamedIndexNode>();
						index->base = expr;
						index->name = identifier;
						expr = index;
					}

				} break;
				default: {
					str_ofs = cofs2;
					done = true;
				} break;
			}

			if (done)
				break;
		}

		//push expression
		{
			ExpressionNode e;
			e.is_op = false;
			e.node = expr;
			expression.push_back(e);
		}

		//ok finally look for an operator

		int cofs = str_ofs;
		_get_token(tk);
		if (error_set)
			return NULL;

		Variant::Operator op = Variant::OP_MAX;

		switch (tk.type) {
			case TK_OP_IN: op = Variant::OP_IN; break;
			case TK_OP_EQUAL: op = Variant::OP_EQUAL; break;
			case TK_OP_NOT_EQUAL: op = Variant::OP_NOT_EQUAL; break;
			case TK_OP_LESS: op = Variant::OP_LESS; break;
			case TK_OP_LESS_EQUAL: op = Variant::OP_LESS_EQUAL; break;
			case TK_OP_GREATER: op = Variant::OP_GREATER; break;
			case TK_OP_GREATER_EQUAL: op = Variant::OP_GREATER_EQUAL; break;
			case TK_OP_AND: op = Variant::OP_AND; break;
			case TK_OP_OR: op = Variant::OP_OR; break;
			case TK_OP_NOT: op = Variant::OP_NOT; break;
			case TK_OP_ADD: op = Variant::OP_ADD; break;
			case TK_OP_SUB: op = Variant::OP_SUBTRACT; break;
			case TK_OP_MUL: op = Variant::OP_MULTIPLY; break;
			case TK_OP_DIV: op = Variant::OP_DIVIDE; break;
			case TK_OP_MOD: op = Variant::OP_MODULE; break;
			case TK_OP_SHIFT_LEFT: op = Variant::OP_SHIFT_LEFT; break;
			case TK_OP_SHIFT_RIGHT: op = Variant::OP_SHIFT_RIGHT; break;
			case TK_OP_BIT_AND: op = Variant::OP_BIT_AND; break;
			case TK_OP_BIT_OR: op = Variant::OP_BIT_OR; break;
			case TK_OP_BIT_XOR: op = Variant::OP_BIT_XOR; break;
			case TK_OP_BIT_INVERT: op = Variant::OP_BIT_NEGATE; break;
			default: {};
		}

		if (op == Variant::OP_MAX) { //stop appending stuff
			str_ofs = cofs;
			break;
		}

		//push operator and go on
		{
			ExpressionNode e;
			e.is_op = true;
			e.op = op;
			expression.push_back(e);
		}
	}

	/* Reduce the set set of expressions and place them in an operator tree, respecting precedence */

	while (expression.size() > 1) {

		int next_op = -1;
		int min_priority = 0xFFFFF;
		bool is_unary = false;

		for (int i = 0; i < expression.size(); i++) {

			if (!expression[i].is_op) {

				continue;
			}

			int priority;

			bool unary = false;

			switch (expression[i].op) {

				case Variant::OP_BIT_NEGATE:
					priority = 0;
					unary = true;
					break;
				case Variant::OP_NEGATE:
					priority = 1;
					unary = true;
					break;

				case Variant::OP_MULTIPLY: priority = 2; break;
				case Variant::OP_DIVIDE: priority = 2; break;
				case Variant::OP_MODULE: priority = 2; break;

				case Variant::OP_ADD: priority = 3; break;
				case Variant::OP_SUBTRACT: priority = 3; break;

				case Variant::OP_SHIFT_LEFT: priority = 4; break;
				case Variant::OP_SHIFT_RIGHT: priority = 4; break;

				case Variant::OP_BIT_AND: priority = 5; break;
				case Variant::OP_BIT_XOR: priority = 6; break;
				case Variant::OP_BIT_OR: priority = 7; break;

				case Variant::OP_LESS: priority = 8; break;
				case Variant::OP_LESS_EQUAL: priority = 8; break;
				case Variant::OP_GREATER: priority = 8; break;
				case Variant::OP_GREATER_EQUAL: priority = 8; break;

				case Variant::OP_EQUAL: priority = 8; break;
				case Variant::OP_NOT_EQUAL: priority = 8; break;

				case Variant::OP_IN: priority = 10; break;

				case Variant::OP_NOT:
					priority = 11;
					unary = true;
					break;
				case Variant::OP_AND: priority = 12; break;
				case Variant::OP_OR: priority = 13; break;

				default: {
					_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
					return NULL;
				}
			}

			if (priority < min_priority) {
				// < is used for left to right (default)
				// <= is used for right to left

				next_op = i;
				min_priority = priority;
				is_unary = unary;
			}
		}

		if (next_op == -1) {

			_set_error("Yet another parser bug....");
			ERR_FAIL_COND_V(next_op == -1, NULL);
		}

		// OK! create operator..
		if (is_unary) {

			int expr_pos = next_op;
			while (expression[expr_pos].is_op) {

				expr_pos++;
				if (expr_pos == expression.size()) {
					//can happen..
					_set_error("Unexpected end of expression...");
					return NULL;
				}
			}

			//consecutively do unary opeators
			for (int i = expr_pos - 1; i >= next_op; i--) {

				OperatorNode *op = alloc_node<OperatorNode>();
				op->op = expression[i].op;
				op->nodes[0] = expression[i + 1].node;
				op->nodes[1] = NULL;
				expression.write[i].is_op = false;
				expression.write[i].node = op;
				expression.remove(i + 1);
			}

		} else {

			if (next_op < 1 || next_op >= (expression.size() - 1)) {
				_set_error("Parser bug...");
				ERR_FAIL_V(NULL);
			}

			OperatorNode *op = alloc_node<OperatorNode>();
			op->op = expression[next_op].op;

			if (expression[next_op - 1].is_op) {

				_set_error("Parser bug...");
				ERR_FAIL_V(NULL);
			}

			if (expression[next_op + 1].is_op) {
				// this is not invalid and can really appear
				// but it becomes invalid anyway because no binary op
				// can be followed by a unary op in a valid combination,
				// due to how precedence works, unaries will always disappear first

				_set_error("Unexpected two consecutive operators.");
				return NULL;
			}

			op->nodes[0] = expression[next_op - 1].node; //expression goes as left
			op->nodes[1] = expression[next_op + 1].node; //next expression goes as right

			//replace all 3 nodes by this operator and make it an expression
			expression.write[next_op - 1].node = op;
			expression.remove(next_op);
			expression.remove(next_op);
		}
	}

	return expression[0].node;
}