Error Expression::parse(const String &p_expression, const Vector<String> &p_input_names) { if (nodes) { memdelete(nodes); nodes = NULL; root = NULL; } error_str = String(); error_set = false; str_ofs = 0; input_names = p_input_names; expression = p_expression; root = _parse_expression(); if (error_set) { root = NULL; if (nodes) { memdelete(nodes); } nodes = NULL; return ERR_INVALID_PARAMETER; } return OK; }
bool VisualScriptExpression::_compile_expression() { if (!expression_dirty) return error_set; if (nodes) { memdelete(nodes); nodes = NULL; root = NULL; } error_str = String(); error_set = false; str_ofs = 0; root = _parse_expression(); if (error_set) { root = NULL; if (nodes) { memdelete(nodes); } nodes = NULL; return true; } expression_dirty = false; return false; }
bool GDCompiler::_create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) { ERR_FAIL_COND_V(on->arguments.size()!=2,false); int src_address_a = _parse_expression(codegen,on->arguments[0],p_stack_level); if (src_address_a<0) return false; if (src_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) p_stack_level++; //uses stack for return, increase stack int src_address_b = _parse_expression(codegen,on->arguments[1],p_stack_level); if (src_address_b<0) return false; codegen.opcodes.push_back(GDFunction::OPCODE_OPERATOR); // perform operator codegen.opcodes.push_back(op); //which operator codegen.opcodes.push_back(src_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) return true; }
int GDCompiler::_parse_assign_right_expression(CodeGen& codegen,const GDParser::OperatorNode *p_expression, int p_stack_level) { Variant::Operator var_op=Variant::OP_MAX; switch(p_expression->op) { case GDParser::OperatorNode::OP_ASSIGN_ADD: var_op=Variant::OP_ADD; break; case GDParser::OperatorNode::OP_ASSIGN_SUB: var_op=Variant::OP_SUBSTRACT; break; case GDParser::OperatorNode::OP_ASSIGN_MUL: var_op=Variant::OP_MULTIPLY; break; case GDParser::OperatorNode::OP_ASSIGN_DIV: var_op=Variant::OP_DIVIDE; break; case GDParser::OperatorNode::OP_ASSIGN_MOD: var_op=Variant::OP_MODULE; break; case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: var_op=Variant::OP_SHIFT_LEFT; break; case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: var_op=Variant::OP_SHIFT_RIGHT; break; case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: var_op=Variant::OP_BIT_AND; break; case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: var_op=Variant::OP_BIT_OR; break; case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: var_op=Variant::OP_BIT_XOR; break; case GDParser::OperatorNode::OP_ASSIGN: { //none } break; default: { ERR_FAIL_V(-1); } } if (var_op==Variant::OP_MAX) { return _parse_expression(codegen,p_expression->arguments[1],p_stack_level); } if (!_create_binary_operator(codegen,p_expression,var_op,p_stack_level)) return -1; int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; }
VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() { Vector<Expression> 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 *expr = _parse_expression(); if (!expr) return NULL; dn->dict.push_back(expr); _get_token(tk); if (tk.type != TK_COLON) { _set_error("Expected ':'"); return NULL; } expr = _parse_expression(); if (!expr) return NULL; dn->dict.push_back(expr); 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 *expr = _parse_expression(); if (!expr) return NULL; an->array.push_back(expr); 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 what = tk.value; int index = -1; for (int i = 0; i < inputs.size(); i++) { if (what == inputs[i].name) { index = i; break; } } if (index != -1) { InputNode *input = alloc_node<InputNode>(); input->index = index; expr = input; } else { _set_error("Invalid input identifier '" + what + "'. For script variables, use self (locals are for inputs)." + what); return NULL; } } 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 *expr = _parse_expression(); if (!expr) return NULL; constructor->arguments.push_back(expr); 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 = VisualScriptBuiltinFunc::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 *expr = _parse_expression(); if (!expr) return NULL; bifunc->arguments.push_back(expr); 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 = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func); if (bifunc->arguments.size() != expected_args) { _set_error("Builtin func '" + VisualScriptBuiltinFunc::get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments."); } expr = bifunc; } break; case TK_OP_SUB: { Expression e; e.is_op = true; e.op = Variant::OP_NEGATE; expression.push_back(e); continue; } break; case TK_OP_NOT: { Expression 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 cofs = str_ofs; _get_token(tk); if (tk.type == TK_PARENTHESIS_CLOSE) { break; } str_ofs = cofs; //revert //parse an expression ENode *expr = _parse_expression(); if (!expr) return NULL; func_call->arguments.push_back(expr); 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 = 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 { Expression 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 { Expression 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[i].is_op = false; expression[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[next_op - 1].node = op; expression.remove(next_op); expression.remove(next_op); } } return expression[0].node; }
Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_block,int p_stack_level,int p_break_addr,int p_continue_addr) { codegen.push_stack_identifiers(); int new_identifiers=0; codegen.current_line=p_block->line; for(int i=0;i<p_block->statements.size();i++) { const GDParser::Node *s = p_block->statements[i]; switch(s->type) { case GDParser::Node::TYPE_NEWLINE: { const GDParser::NewLineNode *nl = static_cast<const GDParser::NewLineNode*>(s); codegen.opcodes.push_back(GDFunction::OPCODE_LINE); codegen.opcodes.push_back(nl->line); codegen.current_line=nl->line; } break; case GDParser::Node::TYPE_CONTROL_FLOW: { // try subblocks const GDParser::ControlFlowNode *cf = static_cast<const GDParser::ControlFlowNode*>(s); switch(cf->cf_type) { case GDParser::ControlFlowNode::CF_IF: { #ifdef DEBUG_ENABLED codegen.opcodes.push_back(GDFunction::OPCODE_LINE); codegen.opcodes.push_back(cf->line); codegen.current_line=cf->line; #endif int ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false); if (ret<0) return ERR_PARSE_ERROR; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(ret); int else_addr=codegen.opcodes.size(); codegen.opcodes.push_back(0); //temporary Error err = _parse_block(codegen,cf->body,p_stack_level,p_break_addr,p_continue_addr); if (err) return err; if (cf->body_else) { codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); int end_addr=codegen.opcodes.size(); codegen.opcodes.push_back(0); codegen.opcodes[else_addr]=codegen.opcodes.size(); Error err = _parse_block(codegen,cf->body_else,p_stack_level,p_break_addr,p_continue_addr); if (err) return err; codegen.opcodes[end_addr]=codegen.opcodes.size(); } else { //end without else codegen.opcodes[else_addr]=codegen.opcodes.size(); } } break; case GDParser::ControlFlowNode::CF_FOR: { int slevel=p_stack_level; int iter_stack_pos=slevel; int iterator_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); int counter_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); int container_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.alloc_stack(slevel); codegen.push_stack_identifiers(); codegen.add_stack_identifier(static_cast<const GDParser::IdentifierNode*>(cf->arguments[0])->name,iter_stack_pos); int ret = _parse_expression(codegen,cf->arguments[1],slevel,false); if (ret<0) return ERR_COMPILATION_FAILED; //assign container codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); codegen.opcodes.push_back(container_pos); codegen.opcodes.push_back(ret); //begin loop codegen.opcodes.push_back(GDFunction::OPCODE_ITERATE_BEGIN); codegen.opcodes.push_back(counter_pos); codegen.opcodes.push_back(container_pos); codegen.opcodes.push_back(codegen.opcodes.size()+4); codegen.opcodes.push_back(iterator_pos); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); //skip code for next codegen.opcodes.push_back(codegen.opcodes.size()+8); //break loop int break_pos=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); //skip code for next codegen.opcodes.push_back(0); //skip code for next //next loop int continue_pos=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_ITERATE); codegen.opcodes.push_back(counter_pos); codegen.opcodes.push_back(container_pos); codegen.opcodes.push_back(break_pos); codegen.opcodes.push_back(iterator_pos); Error err = _parse_block(codegen,cf->body,slevel,break_pos,continue_pos); if (err) return err; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(continue_pos); codegen.opcodes[break_pos+1]=codegen.opcodes.size(); codegen.pop_stack_identifiers(); } break; case GDParser::ControlFlowNode::CF_WHILE: { codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size()+3); int break_addr=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(0); int continue_addr=codegen.opcodes.size(); int ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false); if (ret<0) return ERR_PARSE_ERROR; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(ret); codegen.opcodes.push_back(break_addr); Error err = _parse_block(codegen,cf->body,p_stack_level,break_addr,continue_addr); if (err) return err; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(continue_addr); codegen.opcodes[break_addr+1]=codegen.opcodes.size(); } break; case GDParser::ControlFlowNode::CF_SWITCH: { } break; case GDParser::ControlFlowNode::CF_BREAK: { if (p_break_addr<0) { _set_error("'break'' not within loop",cf); return ERR_COMPILATION_FAILED; } codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(p_break_addr); } break; case GDParser::ControlFlowNode::CF_CONTINUE: { if (p_continue_addr<0) { _set_error("'continue' not within loop",cf); return ERR_COMPILATION_FAILED; } codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(p_continue_addr); } break; case GDParser::ControlFlowNode::CF_RETURN: { int ret; if (cf->arguments.size()) { ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false); if (ret<0) return ERR_PARSE_ERROR; } else { ret=GDFunction::ADDR_TYPE_NIL << GDFunction::ADDR_BITS; } codegen.opcodes.push_back(GDFunction::OPCODE_RETURN); codegen.opcodes.push_back(ret); } break; } } break; case GDParser::Node::TYPE_ASSERT: { // try subblocks const GDParser::AssertNode *as = static_cast<const GDParser::AssertNode*>(s); int ret = _parse_expression(codegen,as->condition,p_stack_level,false); if (ret<0) return ERR_PARSE_ERROR; codegen.opcodes.push_back(GDFunction::OPCODE_ASSERT); codegen.opcodes.push_back(ret); } break; case GDParser::Node::TYPE_LOCAL_VAR: { const GDParser::LocalVarNode *lv = static_cast<const GDParser::LocalVarNode*>(s); codegen.add_stack_identifier(lv->name,p_stack_level++); codegen.alloc_stack(p_stack_level); new_identifiers++; } break; default: { //expression int ret = _parse_expression(codegen,s,p_stack_level,true); if (ret<0) return ERR_PARSE_ERROR; } break; } } codegen.pop_stack_identifiers(); return OK; }
int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root) { switch(p_expression->type) { //should parse variable declaration and adjust stack accordingly... case GDParser::Node::TYPE_IDENTIFIER: { //return identifier //wait, identifier could be a local variable or something else... careful here, must reference properly //as stack may be more interesting to work with //This could be made much simpler by just indexing "self", but done this way (with custom self-addressing modes) increases peformance a lot. const GDParser::IdentifierNode *in = static_cast<const GDParser::IdentifierNode*>(p_expression); StringName identifier = in->name; // TRY STACK! if (codegen.stack_identifiers.has(identifier)) { int pos = codegen.stack_identifiers[identifier]; return pos|(GDFunction::ADDR_TYPE_STACK_VARIABLE<<GDFunction::ADDR_BITS); } //TRY ARGUMENTS! if (!codegen.function_node || !codegen.function_node->_static) { // TRY MEMBER VARIABLES! //static function if (codegen.script->member_indices.has(identifier)) { int idx = codegen.script->member_indices[identifier]; return idx|(GDFunction::ADDR_TYPE_MEMBER<<GDFunction::ADDR_BITS); //argument (stack root) } } //TRY CLASS CONSTANTS GDScript *owner = codegen.script; while (owner) { GDScript *scr = owner; GDNativeClass *nc=NULL; while(scr) { if (scr->constants.has(identifier)) { //int idx=scr->constants[identifier]; int idx = codegen.get_name_map_pos(identifier); return idx|(GDFunction::ADDR_TYPE_CLASS_CONSTANT<<GDFunction::ADDR_BITS); //argument (stack root) } if (scr->native.is_valid()) nc=scr->native.ptr(); scr=scr->_base; } // CLASS C++ Integer Constant if (nc) { bool success=false; int constant = ObjectTypeDB::get_integer_constant(nc->get_name(),identifier,&success); if (success) { Variant key=constant; int idx; if (!codegen.constant_map.has(key)) { idx=codegen.constant_map.size(); codegen.constant_map[key]=idx; } else { idx=codegen.constant_map[key]; } return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //make it a local constant (faster access) } } owner=owner->_owner; } /* handled in constants now if (codegen.script->subclasses.has(identifier)) { //same with a subclass, make it a local constant. int idx = codegen.get_constant_pos(codegen.script->subclasses[identifier]); return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //make it a local constant (faster access) }*/ if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; return idx|(GDFunction::ADDR_TYPE_GLOBAL<<GDFunction::ADDR_BITS); //argument (stack root) } //not found, error _set_error("Identifier not found: "+String(identifier),p_expression); return -1; } break; case GDParser::Node::TYPE_CONSTANT: { //return constant const GDParser::ConstantNode *cn = static_cast<const GDParser::ConstantNode*>(p_expression); int idx; if (!codegen.constant_map.has(cn->value)) { idx=codegen.constant_map.size(); codegen.constant_map[cn->value]=idx; } else { idx=codegen.constant_map[cn->value]; } return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //argument (stack root) } break; case GDParser::Node::TYPE_SELF: { //return constant if (codegen.function_node && codegen.function_node->_static) { _set_error("'self' not present in static function!",p_expression); return -1; } return (GDFunction::ADDR_TYPE_SELF<<GDFunction::ADDR_BITS); } break; case GDParser::Node::TYPE_ARRAY: { const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode*>(p_expression); Vector<int> values; int slevel=p_stack_level; for(int i=0;i<an->elements.size();i++) { int ret = _parse_expression(codegen,an->elements[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } values.push_back(ret); } codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT_ARRAY); codegen.opcodes.push_back(values.size()); for(int i=0;i<values.size();i++) codegen.opcodes.push_back(values[i]); int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; } break; case GDParser::Node::TYPE_DICTIONARY: { const GDParser::DictionaryNode *dn = static_cast<const GDParser::DictionaryNode*>(p_expression); Vector<int> values; int slevel=p_stack_level; for(int i=0;i<dn->elements.size();i++) { int ret = _parse_expression(codegen,dn->elements[i].key,slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } values.push_back(ret); ret = _parse_expression(codegen,dn->elements[i].value,slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } values.push_back(ret); } codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT_DICTIONARY); codegen.opcodes.push_back(dn->elements.size()); for(int i=0;i<values.size();i++) codegen.opcodes.push_back(values[i]); int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; } break; case GDParser::Node::TYPE_OPERATOR: { //hell breaks loose const GDParser::OperatorNode *on = static_cast<const GDParser::OperatorNode*>(p_expression); switch(on->op) { //call/constructor operator case GDParser::OperatorNode::OP_PARENT_CALL: { ERR_FAIL_COND_V(on->arguments.size()<1,-1); const GDParser::IdentifierNode *in = (const GDParser::IdentifierNode *)on->arguments[0]; Vector<int> arguments; int slevel = p_stack_level; for(int i=1;i<on->arguments.size();i++) { int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } //push call bytecode codegen.opcodes.push_back(GDFunction::OPCODE_CALL_SELF_BASE); // basic type constructor codegen.opcodes.push_back(codegen.get_name_map_pos(in->name)); //instance codegen.opcodes.push_back(arguments.size()); //argument count codegen.alloc_call(arguments.size()); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); //arguments } break; case GDParser::OperatorNode::OP_CALL: { if (on->arguments[0]->type==GDParser::Node::TYPE_TYPE) { //construct a basic type ERR_FAIL_COND_V(on->arguments.size()<1,-1); const GDParser::TypeNode *tn = (const GDParser::TypeNode *)on->arguments[0]; int vtype = tn->vtype; Vector<int> arguments; int slevel = p_stack_level; for(int i=1;i<on->arguments.size();i++) { int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } //push call bytecode codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT); // basic type constructor codegen.opcodes.push_back(vtype); //instance codegen.opcodes.push_back(arguments.size()); //argument count codegen.alloc_call(arguments.size()); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); //arguments } else if (on->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) { //built in function ERR_FAIL_COND_V(on->arguments.size()<1,-1); Vector<int> arguments; int slevel = p_stack_level; for(int i=1;i<on->arguments.size();i++) { int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } codegen.opcodes.push_back(GDFunction::OPCODE_CALL_BUILT_IN); codegen.opcodes.push_back(static_cast<const GDParser::BuiltInFunctionNode*>(on->arguments[0])->function); codegen.opcodes.push_back(on->arguments.size()-1); codegen.alloc_call(on->arguments.size()-1); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); } else { //regular function ERR_FAIL_COND_V(on->arguments.size()<2,-1); const GDParser::Node *instance = on->arguments[0]; bool in_static=false; if (instance->type==GDParser::Node::TYPE_SELF) { //room for optimization } Vector<int> arguments; int slevel = p_stack_level; for(int i=0;i<on->arguments.size();i++) { int ret; if (i==0 && on->arguments[i]->type==GDParser::Node::TYPE_SELF && codegen.function_node && codegen.function_node->_static) { //static call to self ret=(GDFunction::ADDR_TYPE_CLASS<<GDFunction::ADDR_BITS); } else if (i==1) { if (on->arguments[i]->type!=GDParser::Node::TYPE_IDENTIFIER) { _set_error("Attempt to call a non-identifier.",on); return -1; } GDParser::IdentifierNode *id = static_cast<GDParser::IdentifierNode*>(on->arguments[i]); ret=codegen.get_name_map_pos(id->name); } else { ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } } arguments.push_back(ret); } codegen.opcodes.push_back(p_root?GDFunction::OPCODE_CALL:GDFunction::OPCODE_CALL_RETURN); // perform operator codegen.opcodes.push_back(on->arguments.size()-2); codegen.alloc_call(on->arguments.size()-2); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); } } break; case GDParser::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&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } //push call bytecode codegen.opcodes.push_back(arguments.size()==0?GDFunction::OPCODE_YIELD:GDFunction::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(GDFunction::OPCODE_YIELD_RESUME); //next will be where to place the result :) } break; //indexing operator case GDParser::OperatorNode::OP_INDEX: case GDParser::OperatorNode::OP_INDEX_NAMED: { ERR_FAIL_COND_V(on->arguments.size()!=2,-1); int slevel = p_stack_level; bool named=(on->op==GDParser::OperatorNode::OP_INDEX_NAMED); int from = _parse_expression(codegen,on->arguments[0],slevel); if (from<0) return from; int index; if (named) { index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); } else { if (on->arguments[1]->type==GDParser::Node::TYPE_CONSTANT && static_cast<const GDParser::ConstantNode*>(on->arguments[1])->value.get_type()==Variant::STRING) { //also, somehow, named (speed up anyway) StringName name = static_cast<const GDParser::ConstantNode*>(on->arguments[1])->value; index=codegen.get_name_map_pos(name); named=true; } else { //regular indexing if (from&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } index = _parse_expression(codegen,on->arguments[1],slevel); if (index<0) return index; } } codegen.opcodes.push_back(named?GDFunction::OPCODE_GET_NAMED:GDFunction::OPCODE_GET); // perform operator codegen.opcodes.push_back(from); // argument 1 codegen.opcodes.push_back(index); // argument 2 (unary only takes one parameter) } break; case GDParser::OperatorNode::OP_AND: { // AND operator with early out on failure int res = _parse_expression(codegen,on->arguments[0],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); int jump_fail_pos=codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen,on->arguments[1],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); int jump_fail_pos2=codegen.opcodes.size(); codegen.opcodes.push_back(0); codegen.alloc_stack(p_stack_level); //it will be used.. codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_TRUE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size()+3); codegen.opcodes[jump_fail_pos]=codegen.opcodes.size(); codegen.opcodes[jump_fail_pos2]=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_FALSE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; } break; case GDParser::OperatorNode::OP_OR: { // OR operator with early out on success int res = _parse_expression(codegen,on->arguments[0],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); codegen.opcodes.push_back(res); int jump_success_pos=codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen,on->arguments[1],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); codegen.opcodes.push_back(res); int jump_success_pos2=codegen.opcodes.size(); codegen.opcodes.push_back(0); codegen.alloc_stack(p_stack_level); //it will be used.. codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_FALSE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size()+3); codegen.opcodes[jump_success_pos]=codegen.opcodes.size(); codegen.opcodes[jump_success_pos2]=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_TRUE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; } break; //unary operators case GDParser::OperatorNode::OP_NEG: { if (!_create_unary_operator(codegen,on,Variant::OP_NEGATE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_NOT: { if (!_create_unary_operator(codegen,on,Variant::OP_NOT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_INVERT: { if (!_create_unary_operator(codegen,on,Variant::OP_BIT_NEGATE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_PREINC: { } break; //? case GDParser::OperatorNode::OP_PREDEC: { } break; case GDParser::OperatorNode::OP_INC: { } break; case GDParser::OperatorNode::OP_DEC: { } break; //binary operators (in precedence order) case GDParser::OperatorNode::OP_IN: { if (!_create_binary_operator(codegen,on,Variant::OP_IN,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_NOT_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_NOT_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_LESS: { if (!_create_binary_operator(codegen,on,Variant::OP_LESS,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_LESS_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_LESS_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_GREATER: { if (!_create_binary_operator(codegen,on,Variant::OP_GREATER,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_GREATER_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_GREATER_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_ADD: { if (!_create_binary_operator(codegen,on,Variant::OP_ADD,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_SUB: { if (!_create_binary_operator(codegen,on,Variant::OP_SUBSTRACT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_MUL: { if (!_create_binary_operator(codegen,on,Variant::OP_MULTIPLY,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_DIV: { if (!_create_binary_operator(codegen,on,Variant::OP_DIVIDE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_MOD: { if (!_create_binary_operator(codegen,on,Variant::OP_MODULE,p_stack_level)) return -1;} break; //case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; //case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_AND: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_AND,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_OR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_OR,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_XOR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_XOR,p_stack_level)) return -1;} break; //shift case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; //assignment operators case GDParser::OperatorNode::OP_ASSIGN_ADD: case GDParser::OperatorNode::OP_ASSIGN_SUB: case GDParser::OperatorNode::OP_ASSIGN_MUL: case GDParser::OperatorNode::OP_ASSIGN_DIV: case GDParser::OperatorNode::OP_ASSIGN_MOD: case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: case GDParser::OperatorNode::OP_ASSIGN: { ERR_FAIL_COND_V(on->arguments.size()!=2,-1); if (on->arguments[0]->type==GDParser::Node::TYPE_OPERATOR && (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX || static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED)) { //SET (chained) MODE!! int slevel=p_stack_level; GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]); /* Find chain of sets */ List<GDParser::OperatorNode*> chain; { //create get/set chain GDParser::OperatorNode* n=op; while(true) { chain.push_back(n); if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR) break; n = static_cast<GDParser::OperatorNode*>(n->arguments[0]); if (n->op!=GDParser::OperatorNode::OP_INDEX && n->op!=GDParser::OperatorNode::OP_INDEX_NAMED) break; } } /* Chain of gets */ //get at (potential) root stack pos, so it can be returned int prev_pos = _parse_expression(codegen,chain.back()->get()->arguments[0],slevel); if (prev_pos<0) return prev_pos; int retval=prev_pos; //print_line("retval: "+itos(retval)); if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } Vector<int> setchain; int prev_key_idx=-1; for(List<GDParser::OperatorNode*>::Element *E=chain.back();E;E=E->prev()) { if (E==chain.front()) //ignore first break; bool named = E->get()->op==GDParser::OperatorNode::OP_INDEX_NAMED; int key_idx; if (named) { key_idx = codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(E->get()->arguments[1])->name); //printf("named key %x\n",key_idx); } else { if (prev_pos&(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)) { slevel++; codegen.alloc_stack(slevel); } GDParser::Node *key = E->get()->arguments[1]; key_idx = _parse_expression(codegen,key,slevel); //printf("expr key %x\n",key_idx); //stack was raised here if retval was stack but.. } if (key_idx<0) return key_idx; codegen.opcodes.push_back(named ? GDFunction::OPCODE_GET_NAMED : GDFunction::OPCODE_GET); codegen.opcodes.push_back(prev_pos); codegen.opcodes.push_back(key_idx); slevel++; codegen.alloc_stack(slevel); int dst_pos = (GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)|slevel; codegen.opcodes.push_back(dst_pos); //add in reverse order, since it will be reverted setchain.push_back(dst_pos); setchain.push_back(key_idx); setchain.push_back(prev_pos); setchain.push_back(named ? GDFunction::OPCODE_SET_NAMED : GDFunction::OPCODE_SET); prev_pos=dst_pos; prev_key_idx=key_idx; } setchain.invert(); int set_index; bool named=false; if (static_cast<const GDParser::OperatorNode*>(op)->op==GDParser::OperatorNode::OP_INDEX_NAMED) { set_index=codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(op->arguments[1])->name); named=true; } else { set_index = _parse_expression(codegen,op->arguments[1],slevel+1); named=false; } if (set_index<0) return set_index; if (set_index&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } int set_value = _parse_assign_right_expression(codegen,on,slevel+1); if (set_value<0) return set_value; codegen.opcodes.push_back(named?GDFunction::OPCODE_SET_NAMED:GDFunction::OPCODE_SET); codegen.opcodes.push_back(prev_pos); codegen.opcodes.push_back(set_index); codegen.opcodes.push_back(set_value); for(int i=0;i<setchain.size();i+=4) { codegen.opcodes.push_back(setchain[i+0]); codegen.opcodes.push_back(setchain[i+1]); codegen.opcodes.push_back(setchain[i+2]); codegen.opcodes.push_back(setchain[i+3]); } return retval; } else { //ASSIGNMENT MODE!! int slevel = p_stack_level; int dst_address_a = _parse_expression(codegen,on->arguments[0],slevel); if (dst_address_a<0) return -1; if (dst_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } int src_address_b = _parse_assign_right_expression(codegen,on,slevel); if (src_address_b<0) return -1; codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); // perform operator codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) return dst_address_a; //if anything, returns wathever was assigned or correct stack position } } break; case GDParser::OperatorNode::OP_EXTENDS: { ERR_FAIL_COND_V(on->arguments.size()!=2,false); int slevel = p_stack_level; int src_address_a = _parse_expression(codegen,on->arguments[0],slevel); if (src_address_a<0) return -1; if (src_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) slevel++; //uses stack for return, increase stack int src_address_b = _parse_expression(codegen,on->arguments[1],slevel); if (src_address_b<0) return -1; codegen.opcodes.push_back(GDFunction::OPCODE_EXTENDS_TEST); // perform operator codegen.opcodes.push_back(src_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) } break; default: { ERR_EXPLAIN("Bug in bytecode compiler, unexpected operator #"+itos(on->op)+" in parse tree while parsing expression."); ERR_FAIL_V(0); //unreachable code } break; } int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; } break; //TYPE_TYPE, default: { ERR_EXPLAIN("Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); ERR_FAIL_V(-1); //unreachable code } break; } ERR_FAIL_V(-1); //unreachable code }
Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func) { Vector<int> bytecode; CodeGen codegen; codegen.class_node=p_class; codegen.script=p_script; codegen.function_node=p_func; codegen.stack_max=0; codegen.current_line=0; codegen.call_max=0; codegen.debug_stack=ScriptDebugger::get_singleton()!=NULL; int stack_level=0; if (p_func) { for(int i=0;i<p_func->arguments.size();i++) { int idx = i; codegen.add_stack_identifier(p_func->arguments[i],i); } stack_level=p_func->arguments.size(); } codegen.alloc_stack(stack_level); /* Parse initializer -if applies- */ bool is_initializer=false || !p_func; if (!p_func || String(p_func->name)=="_init") { //parse initializer for class members if (!p_func && p_class->extends_used && p_script->native.is_null()){ //call implicit parent constructor codegen.opcodes.push_back(GDFunction::OPCODE_CALL_SELF_BASE); codegen.opcodes.push_back(codegen.get_name_map_pos("_init")); codegen.opcodes.push_back(0); codegen.opcodes.push_back((GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)|0); } Error err = _parse_block(codegen,p_class->initializer,stack_level); if (err) return err; is_initializer=true; } /* Parse default argument code -if applies- */ Vector<int> defarg_addr; StringName func_name; if (p_func) { if (p_func->default_values.size()) { codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_TO_DEF_ARGUMENT); defarg_addr.push_back(codegen.opcodes.size()); for(int i=0;i<p_func->default_values.size();i++) { _parse_expression(codegen,p_func->default_values[i],stack_level,true); defarg_addr.push_back(codegen.opcodes.size()); } defarg_addr.invert(); } Error err = _parse_block(codegen,p_func->body,stack_level); if (err) return err; func_name=p_func->name; } else { func_name="_init"; } codegen.opcodes.push_back(GDFunction::OPCODE_END); GDFunction *gdfunc=NULL; //if (String(p_func->name)=="") { //initializer func // gdfunc = &p_script->initializer; //} else { //regular func p_script->member_functions[func_name]=GDFunction(); gdfunc = &p_script->member_functions[func_name]; //} if (p_func) gdfunc->_static=p_func->_static; //constants if (codegen.constant_map.size()) { gdfunc->_constant_count=codegen.constant_map.size(); gdfunc->constants.resize(codegen.constant_map.size()); gdfunc->_constants_ptr=&gdfunc->constants[0]; const Variant *K=NULL; while((K=codegen.constant_map.next(K))) { int idx = codegen.constant_map[*K]; gdfunc->constants[idx]=*K; } } else { gdfunc->_constants_ptr=NULL; gdfunc->_constant_count=0; } //global names if (codegen.name_map.size()) { gdfunc->global_names.resize(codegen.name_map.size()); gdfunc->_global_names_ptr = &gdfunc->global_names[0]; for(Map<StringName,int>::Element *E=codegen.name_map.front();E;E=E->next()) { gdfunc->global_names[E->get()]=E->key(); } gdfunc->_global_names_count=gdfunc->global_names.size(); } else { gdfunc->_global_names_ptr = NULL; gdfunc->_global_names_count =0; } if (codegen.opcodes.size()) { gdfunc->code=codegen.opcodes; gdfunc->_code_ptr=&gdfunc->code[0]; gdfunc->_code_size=codegen.opcodes.size(); } else { gdfunc->_code_ptr=NULL; gdfunc->_code_size=0; } if (defarg_addr.size()) { gdfunc->default_arguments=defarg_addr; gdfunc->_default_arg_count=defarg_addr.size(); gdfunc->_default_arg_ptr=&gdfunc->default_arguments[0]; } else { gdfunc->_default_arg_count=0; gdfunc->_default_arg_ptr=NULL; } gdfunc->_argument_count=p_func ? p_func->arguments.size() : 0; gdfunc->_stack_size=codegen.stack_max; gdfunc->_call_size=codegen.call_max; gdfunc->name=func_name; gdfunc->_script=p_script; gdfunc->source=source; #ifdef DEBUG_ENABLED { gdfunc->func_cname=(String(source)+" - "+String(func_name)).utf8(); gdfunc->_func_cname=gdfunc->func_cname.get_data(); } #endif if (p_func) { gdfunc->_initial_line=p_func->line; } else { gdfunc->_initial_line=0; } if (codegen.debug_stack) gdfunc->stack_debug=codegen.stack_debug; if (is_initializer) p_script->initializer=gdfunc; return OK; }