diff options
-rw-r--r-- | drivers/gles3/shader_compiler_gles3.cpp | 47 | ||||
-rw-r--r-- | servers/visual/shader_language.cpp | 136 | ||||
-rw-r--r-- | servers/visual/shader_language.h | 22 |
3 files changed, 183 insertions, 22 deletions
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index bdd54543d2..419decce29 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -438,26 +438,44 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::BlockNode *bnode = (SL::BlockNode *)p_node; //variables - code += _mktab(p_level - 1) + "{\n"; - for (Map<StringName, SL::BlockNode::Variable>::Element *E = bnode->variables.front(); E; E = E->next()) { - - code += _mktab(p_level) + _prestr(E->get().precision) + _typestr(E->get().type) + " " + _mkid(E->key()) + ";\n"; + if (!bnode->single_statement) { + code += _mktab(p_level - 1) + "{\n"; } - + for (int i = 0; i < bnode->statements.size(); i++) { String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions); - if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) { - // FIXME: if (A || A) ? I am hesitant to delete one of them, could be copy-paste error. + if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement ) { code += scode; //use directly } else { code += _mktab(p_level) + scode + ";\n"; } } - code += _mktab(p_level - 1) + "}\n"; + if (!bnode->single_statement) { + code += _mktab(p_level - 1) + "}\n"; + } } break; + case SL::Node::TYPE_VARIABLE_DECLARATION: { + SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; + + String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype); + for(int i=0;i<vdnode->declarations.size();i++) { + if (i>0) { + declaration+=","; + } else { + declaration+=" "; + } + declaration += _mkid(vdnode->declarations[i].name); + if (vdnode->declarations[i].initializer) { + declaration+="="; + declaration+=_dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions); + } + } + + code+=declaration; + } break; case SL::Node::TYPE_VARIABLE: { SL::VariableNode *vnode = (SL::VariableNode *)p_node; @@ -600,6 +618,13 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions) + ")\n"; code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions); + } else if (cfnode->flow_op == SL::FLOW_OP_FOR) { + + String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions); + String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions); + String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions); + code += _mktab(p_level) + "for (" +left+";"+middle+";"+right+")\n"; + code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions); } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { @@ -611,6 +636,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) { code = "discard;"; + } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) { + + code = "continue;"; + } else if (cfnode->flow_op == SL::FLOW_OP_BREAK) { + + code = "break;"; } } break; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 0684cb1701..c7b02c92f7 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -79,7 +79,11 @@ String ShaderLanguage::get_operator_text(Operator p_op) { "|", "^", "~", - "++" + "++", + "--", + "?", + ":", + "++", "--", "()", "construct", @@ -3116,6 +3120,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat tk = _get_token(); + VariableDeclarationNode *vardecl = alloc_node<VariableDeclarationNode>(); + vardecl->datatype=type; + vardecl->precision=precision; + + p_block->statements.push_back(vardecl); + while (true) { if (tk.type != TK_IDENTIFIER) { @@ -3133,8 +3143,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat var.type = type; var.precision = precision; var.line = tk_line; + p_block->variables[name] = var; + VariableDeclarationNode::Declaration decl; + + decl.name=name; + decl.initializer=NULL; + tk = _get_token(); if (tk.type == TK_OP_ASSIGN) { @@ -3143,22 +3159,19 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat if (!n) return ERR_PARSE_ERROR; - OperatorNode *assign = alloc_node<OperatorNode>(); - VariableNode *vnode = alloc_node<VariableNode>(); - vnode->name = name; - vnode->datatype_cache = type; - assign->arguments.push_back(vnode); - assign->arguments.push_back(n); - assign->op = OP_ASSIGN; - p_block->statements.push_back(assign); - tk = _get_token(); + decl.initializer = n; - if (!_validate_operator(assign)) { - _set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(type) + "'"); + if (var.type!=n->get_datatype()) { + _set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'"); return ERR_PARSE_ERROR; + } + tk = _get_token(); + } + vardecl->declarations.push_back(decl); + if (tk.type == TK_COMMA) { tk = _get_token(); //another variable @@ -3221,7 +3234,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat //if () {} tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after if"); + _set_error("Expected '(' after while"); return ERR_PARSE_ERROR; } @@ -3243,7 +3256,64 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat cf->blocks.push_back(block); p_block->statements.push_back(cf); - Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue); + Error err = _parse_block(block, p_builtin_types, true, true, true); + if (err) + return err; + } else if (tk.type == TK_CF_FOR) { + //if () {} + tk = _get_token(); + if (tk.type != TK_PARENTHESIS_OPEN) { + _set_error("Expected '(' after for"); + return ERR_PARSE_ERROR; + } + + ControlFlowNode *cf = alloc_node<ControlFlowNode>(); + cf->flow_op = FLOW_OP_FOR; + + BlockNode *init_block = alloc_node<BlockNode>(); + init_block->parent_block = p_block; + init_block->single_statement=true; + cf->blocks.push_back(init_block); + if (_parse_block(init_block,p_builtin_types,true,false,false)!=OK) { + return ERR_PARSE_ERROR; + } + + Node *n = _parse_and_reduce_expression(init_block, p_builtin_types); + if (!n) + return ERR_PARSE_ERROR; + + if (n->get_datatype()!=TYPE_BOOL) { + _set_error("Middle expression is expected to be boolean."); + return ERR_PARSE_ERROR; + + } + + tk = _get_token(); + if (tk.type != TK_SEMICOLON) { + _set_error("Expected ';' after middle expression"); + return ERR_PARSE_ERROR; + } + + cf->expressions.push_back(n); + + n = _parse_and_reduce_expression(init_block, p_builtin_types); + if (!n) + return ERR_PARSE_ERROR; + + cf->expressions.push_back(n); + + tk = _get_token(); + if (tk.type != TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' after third expression"); + return ERR_PARSE_ERROR; + } + + BlockNode *block = alloc_node<BlockNode>(); + block->parent_block = p_block; + cf->blocks.push_back(block); + p_block->statements.push_back(cf); + + Error err = _parse_block(block, p_builtin_types, true, true, true); if (err) return err; @@ -3320,6 +3390,44 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat } p_block->statements.push_back(flow); + } else if (tk.type == TK_CF_BREAK) { + + + if (!p_can_break) { + //all is good + _set_error("Breaking is not allowed here"); + } + + ControlFlowNode *flow = alloc_node<ControlFlowNode>(); + flow->flow_op = FLOW_OP_BREAK; + + pos = _get_tkpos(); + tk = _get_token(); + if (tk.type != TK_SEMICOLON) { + //all is good + _set_error("Expected ';' after break"); + } + + p_block->statements.push_back(flow); + } else if (tk.type == TK_CF_CONTINUE) { + + + if (!p_can_break) { + //all is good + _set_error("Contiuning is not allowed here"); + } + + ControlFlowNode *flow = alloc_node<ControlFlowNode>(); + flow->flow_op = FLOW_OP_CONTINUE; + + pos = _get_tkpos(); + tk = _get_token(); + if (tk.type != TK_SEMICOLON) { + //all is good + _set_error("Expected ';' after continue"); + } + + p_block->statements.push_back(flow); } else { diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index f00b4c5a97..50f5cebeaa 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -266,6 +266,7 @@ public: TYPE_FUNCTION, TYPE_BLOCK, TYPE_VARIABLE, + TYPE_VARIABLE_DECLARATION, TYPE_CONSTANT, TYPE_OPERATOR, TYPE_CONTROL_FLOW, @@ -315,6 +316,25 @@ public: } }; + struct VariableDeclarationNode : public Node { + + DataPrecision precision; + DataType datatype; + + struct Declaration { + + StringName name; + Node *initializer; + }; + + Vector<Declaration> declarations; + virtual DataType get_datatype() const { return datatype; } + + VariableDeclarationNode() { + type = TYPE_VARIABLE_DECLARATION; + } + }; + struct ConstantNode : public Node { DataType datatype; @@ -346,10 +366,12 @@ public: Map<StringName, Variable> variables; List<Node *> statements; + bool single_statement; BlockNode() { type = TYPE_BLOCK; parent_block = NULL; parent_function = NULL; + single_statement=false; } }; |