X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=8c10c443002e130fa01f42b32ceb18cbe5f4d772;hp=fd782648083bdb05a1aa700ca65d4ab8f15aa926;hb=HEAD;hpb=041ba4b1acd55337239c5ce24cc310118c621206 diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index fd782648..615d75d4 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -1,9 +1,11 @@ +#include #include #include #include #include #include "builtin.h" #include "glsl_error.h" +#include "modulecache.h" #include "parser.h" #undef interface @@ -14,7 +16,8 @@ namespace Msp { namespace GL { namespace SL { -Parser::Parser(): +Parser::Parser(ModuleCache *s): + mod_cache(s), preprocessor(tokenizer), module(0) { @@ -25,20 +28,16 @@ Parser::Parser(): preprocessor.signal_line.connect(sigc::mem_fun(this, &Parser::line_change)); } -Parser::~Parser() -{ - delete module; -} - -Module &Parser::parse(const string &s, const string &n, int i) +void Parser::parse(Module &m, const string &s, const string &n, int i) { + SetForScope set_module(module, &m); source = s; parse_source(n, i); - return *module; } -Module &Parser::parse(IO::Base &io, const string &n, int i) +void Parser::parse(Module &m, IO::Base &io, const string &n, int i) { + SetForScope set_module(module, &m); source = string(); while(!io.eof()) { @@ -47,39 +46,34 @@ Module &Parser::parse(IO::Base &io, const string &n, int i) source.append(buffer, len); } parse_source(n, i); - return *module; } void Parser::parse_source(const string &name, int index) { - delete module; - module = new Module; - cur_stage = &module->shared; base_index = index; source_index = index; if(index>=0) source_reference(1, name); - // TODO Need to somehow get type names from imports if(const Stage *builtin = get_builtins(Stage::SHARED)) { - for(map::const_iterator i=builtin->types.begin(); i!=builtin->types.end(); ++i) - declared_types.insert(i->first); - } - else - { - declared_types.insert("void"); - declared_types.insert("bool"); - declared_types.insert("int"); - declared_types.insert("float"); + for(const auto &kvp: builtin->types) + global_types.insert(kvp.first); } tokenizer.begin(source, name); allow_stage_change = true; while(!tokenizer.peek_token().empty()) if(RefPtr statement = parse_with_recovery(&Parser::parse_global_declaration)) + { cur_stage->content.body.push_back(statement); + if(next_global_declaration) + { + cur_stage->content.body.push_back(next_global_declaration); + next_global_declaration = 0; + } + } if(!errors.empty()) throw invalid_shader_source(join(errors.begin(), errors.end(), "\n")); @@ -110,6 +104,22 @@ void Parser::stage_change(Stage::Type stage) if(cur_stage->type!=Stage::SHARED) module->stages.back().previous = cur_stage; cur_stage = &module->stages.back(); + + stage_types.clear(); + if(const Stage *builtin = get_builtins(stage)) + { + for(const auto &kvp: builtin->types) + stage_types.insert(kvp.first); + } + for(const Module *m: imported_modules) + { + auto j = find_member(m->stages, stage, &Stage::type); + if(j!=m->stages.end()) + { + for(const auto &kvp: j->types) + stage_types.insert(kvp.first); + } + } } void Parser::line_change(int index, unsigned line) @@ -166,7 +176,7 @@ bool Parser::is_interface_qualifier(const string &token) bool Parser::is_sampling_qualifier(const string &token) { - return (token=="centroid" || token=="sample"); + return (token=="centroid" || token=="sample" || token=="patch"); } bool Parser::is_interpolation_qualifier(const string &token) @@ -190,13 +200,13 @@ bool Parser::is_qualifier(const string &token) bool Parser::is_type(const string &token) { - return declared_types.count(token); + return global_types.count(token) || stage_types.count(token); } bool Parser::is_identifier(const string &token) { static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$"); - return re.match(token); + return static_cast(re.match(token)); } template @@ -268,11 +278,21 @@ RefPtr Parser::parse_global_declaration() if(is_interface_qualifier(token) && tokenizer.peek_token(1)==";") { RefPtr iface_lo = create_node(); + iface_lo->layout.source = layout->source; + iface_lo->layout.line = layout->line; iface_lo->layout.qualifiers = layout->qualifiers; iface_lo->interface = tokenizer.parse_token(); tokenizer.expect(";"); return iface_lo; } + else if(is_interface_qualifier(token) && tokenizer.peek_token(2)=="{") + { + RefPtr iface_strct = parse_interface_block(); + VariableDeclaration *iface_var = iface_strct->block_declaration; + iface_var->layout = layout; + next_global_declaration = iface_var; + return iface_strct; + } else { RefPtr var = parse_variable_declaration(); @@ -290,10 +310,16 @@ RefPtr Parser::parse_global_declaration() if(is_type(next) || is_qualifier(next)) return parse_variable_declaration(); else - return parse_interface_block(); + { + RefPtr iface_strct = parse_interface_block(); + next_global_declaration = iface_strct->block_declaration; + return iface_strct; + } } else if(is_qualifier(token)) return parse_variable_declaration(); + else if(token=="virtual") + return parse_function_declaration(); else if(is_type(token)) { if(tokenizer.peek_token(2)=="(") @@ -356,6 +382,15 @@ RefPtr Parser::parse_import() RefPtr import = create_node(); import->module = expect_identifier(); tokenizer.expect(";"); + + if(mod_cache) + { + const Module &imported_mod = mod_cache->get_module(import->module); + imported_modules.push_back(&imported_mod); + for(const auto &kvp: imported_mod.shared.types) + global_types.insert(kvp.first); + } + return import; } @@ -387,9 +422,8 @@ RefPtr Parser::parse_layout() if(token==")") throw parse_error(tokenizer.get_location(), token, "a layout qualifier name"); - layout->qualifiers.push_back(Layout::Qualifier()); + layout->qualifiers.push_back(token); Layout::Qualifier &qual = layout->qualifiers.back(); - qual.name = token; if((qual.has_value = check("="))) { @@ -434,8 +468,9 @@ void Parser::parse_block(Block &block, bool require_braces, RefPtr (Parser::* tokenizer.expect("}"); } -RefPtr Parser::parse_expression(unsigned precedence) +RefPtr Parser::parse_expression(const Operator *outer_oper) { + unsigned outer_precedence = (outer_oper ? outer_oper->precedence+(outer_oper->assoc==Operator::RIGHT_TO_LEFT) : 20); RefPtr left; VariableReference *left_var = 0; while(1) @@ -447,8 +482,8 @@ RefPtr Parser::parse_expression(unsigned precedence) if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX)) oper = i; - bool lower_precedence = (oper && oper->type!=Operator::PREFIX && precedence && oper->precedence>=precedence); - if(token==";" || token==")" || token=="]" || token=="," || lower_precedence) + bool lower_precedence = (oper && oper->type!=Operator::PREFIX && oper->precedence>=outer_precedence); + if(token==";" || token==")" || token=="]" || token=="," || token==":" || lower_precedence) { if(left) return left; @@ -482,6 +517,8 @@ RefPtr Parser::parse_expression(unsigned precedence) } else if(oper && oper->type==Operator::BINARY) left = parse_binary(left, *oper); + else if(oper && oper->type==Operator::TERNARY) + left = parse_ternary(left, *oper); else throw parse_error(tokenizer.get_location(), token, "an operator"); left_var = 0; @@ -491,10 +528,8 @@ RefPtr Parser::parse_expression(unsigned precedence) if(token=="(") { tokenizer.parse_token(); - RefPtr parexpr = create_node(); - parexpr->expression = parse_expression(); + left = parse_expression(); tokenizer.expect(")"); - left = parexpr; } else if(isdigit(token[0]) || token=="true" || token=="false") left = parse_literal(); @@ -510,7 +545,7 @@ RefPtr Parser::parse_expression(unsigned precedence) RefPtr unary = create_node(); unary->oper = oper; tokenizer.parse_token(); - unary->expression = parse_expression(oper->precedence); + unary->expression = parse_expression(oper); left = unary; } else @@ -526,10 +561,14 @@ RefPtr Parser::parse_literal() if(isdigit(literal->token[0])) { // TODO have the tokenizer return the type of the token - if(isnumrc(literal->token)) - literal->value = lexical_cast(literal->token); - else + if(literal->token.back()=='u') + literal->value = lexical_cast(literal->token.substr(0, literal->token.size()-1)); + else if(literal->token.back()=='f') + literal->value = lexical_cast(literal->token.substr(0, literal->token.size()-1)); + else if(literal->token.find('.')!=string::npos) literal->value = lexical_cast(literal->token); + else + literal->value = lexical_cast(literal->token); } else if(literal->token=="true" || literal->token=="false") literal->value = (literal->token=="true"); @@ -546,21 +585,32 @@ RefPtr Parser::parse_binary(const RefPtr &left, co binary->left = left; binary->oper = &oper; tokenizer.expect(oper.token); - if(oper.token[0]=='[') + if(oper.token2[0]) { binary->right = parse_expression(); - tokenizer.expect("]"); + tokenizer.expect(oper.token2); } else - binary->right = parse_expression(oper.precedence+(oper.assoc==Operator::RIGHT_TO_LEFT)); + binary->right = parse_expression(&oper); return binary; } +RefPtr Parser::parse_ternary(const RefPtr &cond, const Operator &oper) +{ + RefPtr ternary = create_node(); + ternary->condition = cond; + ternary->oper = &oper; + tokenizer.expect("?"); + ternary->true_expr = parse_expression(&oper); + tokenizer.expect(":"); + ternary->false_expr = parse_expression(&oper); + return ternary; +} + RefPtr Parser::parse_function_call(const VariableReference &var) { RefPtr call = create_node(); call->name = var.name; - call->constructor = is_type(call->name); call->oper = &Operator::get_operator("(", Operator::POSTFIX); tokenizer.expect("("); while(tokenizer.peek_token()!=")") @@ -573,6 +623,15 @@ RefPtr Parser::parse_function_call(const VariableReference &var) return call; } +void Parser::add_type(TypeDeclaration &type) +{ + cur_stage->types[type.name] = &type; + if(cur_stage->type==Stage::SHARED) + global_types.insert(type.name); + else + stage_types.insert(type.name); +} + RefPtr Parser::parse_type_declaration() { tokenizer.expect("typedef"); @@ -584,7 +643,7 @@ RefPtr Parser::parse_type_declaration() type = parse_basic_type_declaration(); tokenizer.expect(";"); - declared_types.insert(type->name); + add_type(*type); return type; } @@ -648,6 +707,8 @@ RefPtr Parser::parse_image_type_declaration() type->sampled = true; else if(token=="shadow") type->shadow = true; + else if(token=="multisample") + type->multisample = true; else throw parse_error(tokenizer.get_location(), token, "image type attribute"); @@ -674,7 +735,7 @@ RefPtr Parser::parse_struct_declaration() parse_block(strct->members, true, &Parser::parse_variable_declaration); tokenizer.expect(";"); - declared_types.insert(strct->name); + add_type(*strct); return strct; } @@ -735,6 +796,7 @@ RefPtr Parser::parse_function_declaration() { RefPtr func = create_node(); + func->virtua = check("virtual"); func->return_type = expect_type(); func->name = expect_identifier(); tokenizer.expect("("); @@ -753,6 +815,8 @@ RefPtr Parser::parse_function_declaration() } tokenizer.expect(")"); + func->overrd = check("override"); + string token = tokenizer.peek_token(); if(token=="{") { @@ -767,29 +831,43 @@ RefPtr Parser::parse_function_declaration() return func; } -RefPtr Parser::parse_interface_block() +RefPtr Parser::parse_interface_block() { - RefPtr iface = create_node(); - - iface->interface = tokenizer.parse_token(); - if(!is_interface_qualifier(iface->interface)) - throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier"); + RefPtr strct = create_node(); + RefPtr var = create_node(); - iface->name = expect_identifier(); - iface->members = new Block; - parse_block(*iface->members, true, &Parser::parse_variable_declaration_with_layout); + var->interface = tokenizer.parse_token(); + if(!is_interface_qualifier(var->interface)) + throw parse_error(tokenizer.get_location(), var->interface, "an interface qualifier"); + + strct->block_name = expect_identifier(); + string name_base = format("_%s_%s", var->interface, strct->block_name); + strct->name = name_base; + for(unsigned i=1; (stage_types.count(strct->name) || global_types.count(strct->name)); ++i) + strct->name = format("%s_%d", name_base, i); + var->type = strct->name; + parse_block(strct->members, true, &Parser::parse_variable_declaration_with_layout); if(!check(";")) { - iface->instance_name = expect_identifier(); + var->name = expect_identifier(); if(check("[")) { - iface->array = true; - tokenizer.expect("]"); + var->array = true; + if(!check("]")) + { + var->array_size = parse_expression(); + tokenizer.expect("]"); + } } tokenizer.expect(";"); } + else + var->name = format("%s %s", var->interface, strct->block_name); + + strct->block_declaration = var.release(); + add_type(*strct); - return iface; + return strct; } RefPtr Parser::parse_conditional()