X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=8c10c443002e130fa01f42b32ceb18cbe5f4d772;hp=3047e136e288303a5725fcdd2ec1d103b3290c2a;hb=HEAD;hpb=2b87464682733c875966c1aa3b3369efbd60b310 diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index 3047e136..615d75d4 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -1,6 +1,11 @@ +#include +#include #include #include +#include +#include "builtin.h" #include "glsl_error.h" +#include "modulecache.h" #include "parser.h" #undef interface @@ -11,66 +16,80 @@ namespace Msp { namespace GL { namespace SL { -Parser::Parser(): +Parser::Parser(ModuleCache *s): + mod_cache(s), preprocessor(tokenizer), module(0) { tokenizer.signal_preprocess.connect(sigc::mem_fun(&preprocessor, &Preprocessor::preprocess)); preprocessor.signal_version.connect(sigc::mem_fun(this, &Parser::set_required_version)); + preprocessor.signal_source.connect(sigc::mem_fun(this, &Parser::source_reference)); preprocessor.signal_stage_change.connect(sigc::mem_fun(this, &Parser::stage_change)); + preprocessor.signal_line.connect(sigc::mem_fun(this, &Parser::line_change)); } -Parser::~Parser() -{ - delete module; -} - -Module &Parser::parse(const string &s, const string &n, unsigned i) +void Parser::parse(Module &m, const string &s, const string &n, int i) { + SetForScope set_module(module, &m); source = s; - source_index = i; - parse_source(n); - return *module; + parse_source(n, i); } -Module &Parser::parse(IO::Base &io, const string &n, unsigned i) +void Parser::parse(Module &m, IO::Base &io, const string &n, int i) { + SetForScope set_module(module, &m); source = string(); - source_index = i; while(!io.eof()) { char buffer[4096]; unsigned len = io.read(buffer, sizeof(buffer)); source.append(buffer, len); } - parse_source(n); - return *module; + parse_source(n, i); } -void Parser::parse_source(const string &name) +void Parser::parse_source(const string &name, int index) { - while(1) - { - string::size_type slashes = source.find("//////"); - if(slashes==string::npos) - break; + cur_stage = &module->shared; + base_index = index; + source_index = index; + if(index>=0) + source_reference(1, name); - string::size_type newline = source.find('\n', slashes); - string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6)); - source.replace(slashes, newline-slashes, pragma); + if(const Stage *builtin = get_builtins(Stage::SHARED)) + { + for(const auto &kvp: builtin->types) + global_types.insert(kvp.first); } - delete module; - module = new Module; - cur_stage = &module->shared; - tokenizer.begin(name, source); - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); + 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")); } void Parser::set_required_version(const Version &ver) { - cur_stage->required_version = ver; + cur_stage->required_features.glsl_version = ver; +} + +void Parser::source_reference(unsigned index, const string &name) +{ + if(index<1 || base_index<0) + throw invalid_shader_source(tokenizer.get_location(), "Invalid source reference"); + + module->source_map.set_name(base_index+index-1, name); } void Parser::stage_change(Stage::Type stage) @@ -85,6 +104,37 @@ 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) +{ + if(index>0) + source_index = base_index+index-1; + else if(index==0) + source_index = 0; + else + index = source_index; + + string name = module->source_map.get_name(index); + if(name.empty()) + name = format("<%d>", index); + tokenizer.set_location(Location(name, line)); } string Parser::expect_type() @@ -103,6 +153,14 @@ string Parser::expect_identifier() return token; } +int Parser::expect_integer() +{ + string token = tokenizer.parse_token(); + if(!isnumrc(token)) + throw parse_error(tokenizer.get_location(), token, "an integer literal"); + return lexical_cast(token); +} + bool Parser::check(const string &token) { bool result = (tokenizer.peek_token()==token); @@ -118,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) @@ -140,28 +198,74 @@ bool Parser::is_qualifier(const string &token) is_precision_qualifier(token)); } -bool Parser::is_builtin_type(const string &token) -{ - static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$"); - return re.match(token); -} - bool Parser::is_type(const string &token) { - return is_builtin_type(token) || 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 +RefPtr Parser::create_node() +{ + RefPtr node = new T; + node->source = source_index; + node->line = tokenizer.get_location().line; + return node; +} + +template +RefPtr Parser::parse_with_recovery(RefPtr (Parser::*parse_func)()) +{ + tokenizer.clear_progress_mark(); + try + { + return (this->*parse_func)(); + } + catch(const invalid_shader_source &exc) + { + errors.push_back(exc.what()); + } + + if(tokenizer.get_last_token()!=";" || !tokenizer.get_progress_mark()) + { + unsigned scope_level = 0; + while(1) + { + if(tokenizer.peek_token()=="}" && scope_level==0) + { + if(!tokenizer.get_progress_mark()) + tokenizer.parse_token(); + break; + } + + string token = tokenizer.parse_token(); + if(token=="}") + { + --scope_level; + if(scope_level==0) + break; + } + else if(token=="{") + ++scope_level; + else if(token==";" && scope_level==0) + break; + else if(token.empty()) + break; + } + } + + return RefPtr(); } RefPtr Parser::parse_global_declaration() { - allow_stage_change = true; string token = tokenizer.peek_token(); - allow_stage_change = false; + SetFlag disallow(allow_stage_change, false); if(token=="import") return parse_import(); @@ -173,14 +277,22 @@ RefPtr Parser::parse_global_declaration() token = tokenizer.peek_token(); if(is_interface_qualifier(token) && tokenizer.peek_token(1)==";") { - RefPtr iface_lo = new InterfaceLayout; - iface_lo->source = source_index; - iface_lo->line = tokenizer.get_location().line; + 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(); @@ -188,6 +300,8 @@ RefPtr Parser::parse_global_declaration() return var; } } + else if(token=="typedef") + return parse_type_declaration(); else if(token=="struct") return parse_struct_declaration(); else if(is_interface_qualifier(token)) @@ -196,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)=="(") @@ -228,9 +348,7 @@ RefPtr Parser::parse_statement() return parse_return(); else if(token=="break" || token=="continue" || token=="discard") { - RefPtr jump = new Jump; - jump->source = source_index; - jump->line = tokenizer.get_location().line; + RefPtr jump = create_node(); jump->keyword = tokenizer.parse_token(); tokenizer.expect(";"); @@ -238,11 +356,14 @@ RefPtr Parser::parse_statement() } else if(is_qualifier(token) || is_type(token)) return parse_variable_declaration(); + else if(token==";") + { + tokenizer.parse_token(); + throw invalid_shader_source(tokenizer.get_location(), "Empty statement not allowed"); + } else if(!token.empty()) { - RefPtr expr = new ExpressionStatement; - expr->source = source_index; - expr->line = tokenizer.get_location().line; + RefPtr expr = create_node(); expr->expression = parse_expression(); tokenizer.expect(";"); @@ -258,29 +379,32 @@ RefPtr Parser::parse_import() throw invalid_shader_source(tokenizer.get_location(), "Imports are only allowed in the shared section"); tokenizer.expect("import"); - RefPtr import = new Import; - import->source = source_index; - import->line = tokenizer.get_location().line; + 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; } RefPtr Parser::parse_precision() { tokenizer.expect("precision"); - RefPtr precision = new Precision; - precision->source = source_index; - precision->line = tokenizer.get_location().line; + RefPtr precision = create_node(); precision->precision = tokenizer.parse_token(); if(!is_precision_qualifier(precision->precision)) throw parse_error(tokenizer.get_location(), precision->precision, "a precision qualifier"); - precision->type = tokenizer.parse_token(); - // Not entirely accurate; only float, int and sampler types are allowed - if(!is_builtin_type(precision->type)) - throw parse_error(tokenizer.get_location(), precision->type, "a builtin type"); + // TODO Add validation for this + precision->type = expect_type(); tokenizer.expect(";"); @@ -291,19 +415,26 @@ RefPtr Parser::parse_layout() { tokenizer.expect("layout"); tokenizer.expect("("); - RefPtr layout = new Layout; + RefPtr layout = create_node(); while(1) { string token = tokenizer.parse_token(); 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.identifier = token; - if(check("=")) - qual.value = tokenizer.parse_token(); + if((qual.has_value = check("="))) + { + if(qual.name=="constant_id" && tokenizer.peek_token()=="auto") + { + qual.value = -1; + tokenizer.parse_token(); + } + else + qual.value = expect_integer(); + } if(tokenizer.peek_token()==")") break; @@ -315,7 +446,8 @@ RefPtr Parser::parse_layout() return layout; } -void Parser::parse_block(Block &block, bool require_braces) +template +void Parser::parse_block(Block &block, bool require_braces, RefPtr (Parser::*parse_content)()) { bool have_braces = (require_braces || tokenizer.peek_token()=="{"); if(have_braces) @@ -324,10 +456,11 @@ void Parser::parse_block(Block &block, bool require_braces) if(have_braces) { while(tokenizer.peek_token()!="}") - block.body.push_back(parse_statement()); + if(RefPtr node = parse_with_recovery(parse_content)) + block.body.push_back(node); } else - block.body.push_back(parse_statement()); + block.body.push_back((this->*parse_content)()); block.use_braces = (require_braces || block.body.size()!=1); @@ -335,8 +468,9 @@ void Parser::parse_block(Block &block, bool require_braces) 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) @@ -348,7 +482,8 @@ RefPtr Parser::parse_expression(unsigned precedence) if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX)) oper = i; - if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=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; @@ -365,22 +500,25 @@ RefPtr Parser::parse_expression(unsigned precedence) } else if(token==".") { - RefPtr memacc = new MemberAccess; + RefPtr memacc = create_node(); memacc->left = left; + memacc->oper = oper; tokenizer.parse_token(); memacc->member = expect_identifier(); left = memacc; } else if(oper && oper->type==Operator::POSTFIX) { - RefPtr unary = new UnaryExpression; - unary->oper = tokenizer.parse_token(); - unary->prefix = false; + RefPtr unary = create_node(); + unary->oper = oper; + tokenizer.parse_token(); unary->expression = left; left = unary; } else if(oper && oper->type==Operator::BINARY) - left = parse_binary(left, oper); + 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; @@ -390,30 +528,24 @@ RefPtr Parser::parse_expression(unsigned precedence) if(token=="(") { tokenizer.parse_token(); - RefPtr parexpr = new ParenthesizedExpression; - parexpr->expression = parse_expression(); + left = parse_expression(); tokenizer.expect(")"); - left = parexpr; } else if(isdigit(token[0]) || token=="true" || token=="false") - { - RefPtr literal = new Literal; - literal->token = tokenizer.parse_token(); - left = literal; - } + left = parse_literal(); else if(is_identifier(token)) { - RefPtr var = new VariableReference; + RefPtr var = create_node(); var->name = expect_identifier(); left = var; left_var = var.get(); } else if(oper && oper->type==Operator::PREFIX) { - RefPtr unary = new UnaryExpression; - unary->oper = tokenizer.parse_token(); - unary->prefix = true; - unary->expression = parse_expression(oper->precedence); + RefPtr unary = create_node(); + unary->oper = oper; + tokenizer.parse_token(); + unary->expression = parse_expression(oper); left = unary; } else @@ -422,27 +554,64 @@ RefPtr Parser::parse_expression(unsigned precedence) } } -RefPtr Parser::parse_binary(const RefPtr &left, const Operator *oper) +RefPtr Parser::parse_literal() +{ + RefPtr literal = create_node(); + literal->token = tokenizer.parse_token(); + if(isdigit(literal->token[0])) + { + // TODO have the tokenizer return the type of the token + 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"); + else + throw parse_error(tokenizer.get_location(), literal->token, "a literal"); + + return literal; +} + +RefPtr Parser::parse_binary(const RefPtr &left, const Operator &oper) { - RefPtr binary = (oper->precedence==16 ? new Assignment : new BinaryExpression); + RefPtr binary = (oper.precedence==16 ? + static_cast >(create_node()) : create_node()); binary->left = left; - binary->oper = tokenizer.parse_token(); - if(binary->oper=="[") + binary->oper = &oper; + tokenizer.expect(oper.token); + if(oper.token2[0]) { binary->right = parse_expression(); - tokenizer.expect("]"); - binary->after = "]"; + 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 = new FunctionCall; + 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()!=")") { @@ -454,26 +623,125 @@ 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"); + + RefPtr type; + if(tokenizer.peek_token()=="image") + type = parse_image_type_declaration(); + else + type = parse_basic_type_declaration(); + + tokenizer.expect(";"); + add_type(*type); + return type; +} + +RefPtr Parser::parse_basic_type_declaration() +{ + RefPtr type = create_node(); + + if(tokenizer.peek_token()=="vector") + { + type->kind = BasicTypeDeclaration::VECTOR; + + tokenizer.parse_token(); + tokenizer.expect("("); + type->size = expect_integer(); + tokenizer.expect(")"); + } + + type->base = expect_type(); + type->name = expect_identifier(); + + if(type->kind==BasicTypeDeclaration::ALIAS && check("[")) + { + type->kind = BasicTypeDeclaration::ARRAY; + tokenizer.expect("]"); + } + + return type; +} + +RefPtr Parser::parse_image_type_declaration() +{ + tokenizer.expect("image"); + tokenizer.expect("("); + + RefPtr type = create_node(); + while(1) + { + string token = tokenizer.parse_token(); + if(token=="dimensions") + { + tokenizer.expect("="); + token = tokenizer.parse_token(); + if(token=="1") + type->dimensions = ImageTypeDeclaration::ONE; + else if(token=="2") + type->dimensions = ImageTypeDeclaration::TWO; + else if(token=="3") + type->dimensions = ImageTypeDeclaration::THREE; + else if(token=="cube") + type->dimensions = ImageTypeDeclaration::CUBE; + else + throw parse_error(tokenizer.get_location(), token, "dimensions"); + + if(check("[")) + { + type->array = true; + tokenizer.expect("]"); + } + } + else if(token=="sampled") + 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"); + + token = tokenizer.peek_token(); + if(token==")") + break; + + tokenizer.expect(","); + } + tokenizer.expect(")"); + + type->base = expect_type(); + type->name = expect_identifier(); + + return type; +} + RefPtr Parser::parse_struct_declaration() { tokenizer.expect("struct"); - RefPtr strct = new StructDeclaration; - strct->source = source_index; - strct->line = tokenizer.get_location().line; + RefPtr strct = create_node(); strct->name = expect_identifier(); - parse_block(strct->members, true); + parse_block(strct->members, true, &Parser::parse_variable_declaration); tokenizer.expect(";"); - declared_types.insert(strct->name); + add_type(*strct); return strct; } RefPtr Parser::parse_variable_declaration() { - RefPtr var = new VariableDeclaration; - var->source = source_index; - var->line = tokenizer.get_location().line; + RefPtr var = create_node(); string token = tokenizer.peek_token(); while(is_qualifier(token)) @@ -512,12 +780,23 @@ RefPtr Parser::parse_variable_declaration() return var; } +RefPtr Parser::parse_variable_declaration_with_layout() +{ + RefPtr layout; + if(tokenizer.peek_token()=="layout") + layout = parse_layout(); + + RefPtr var = parse_variable_declaration(); + var->layout = layout; + + return var; +} + RefPtr Parser::parse_function_declaration() { - RefPtr func = new FunctionDeclaration; - func->source = source_index; - func->line = tokenizer.get_location().line; + RefPtr func = create_node(); + func->virtua = check("virtual"); func->return_type = expect_type(); func->name = expect_identifier(); tokenizer.expect("("); @@ -526,7 +805,7 @@ RefPtr Parser::parse_function_declaration() if(!func->parameters.empty()) tokenizer.expect(","); - RefPtr var = new VariableDeclaration; + RefPtr var = create_node(); string token = tokenizer.peek_token(); if(token=="in" || token=="out" || token=="inout") var->interface = tokenizer.parse_token(); @@ -536,11 +815,13 @@ RefPtr Parser::parse_function_declaration() } tokenizer.expect(")"); + func->overrd = check("override"); + string token = tokenizer.peek_token(); if(token=="{") { func->definition = func.get(); - parse_block(func->body, true); + parse_block(func->body, true, &Parser::parse_statement); } else if(token==";") tokenizer.parse_token(); @@ -550,49 +831,60 @@ RefPtr Parser::parse_function_declaration() return func; } -RefPtr Parser::parse_interface_block() +RefPtr Parser::parse_interface_block() { - RefPtr iface = new InterfaceBlock; - iface->source = source_index; - iface->line = tokenizer.get_location().line; + RefPtr strct = create_node(); + RefPtr var = create_node(); - iface->interface = tokenizer.parse_token(); - if(!is_interface_qualifier(iface->interface)) - throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier"); + var->interface = tokenizer.parse_token(); + if(!is_interface_qualifier(var->interface)) + throw parse_error(tokenizer.get_location(), var->interface, "an interface qualifier"); - iface->name = expect_identifier(); - parse_block(iface->members, true); + 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); - return iface; + strct->block_declaration = var.release(); + add_type(*strct); + + return strct; } RefPtr Parser::parse_conditional() { tokenizer.expect("if"); - RefPtr cond = new Conditional; - cond->source = source_index; - cond->line = tokenizer.get_location().line; + RefPtr cond = create_node(); tokenizer.expect("("); cond->condition = parse_expression(); tokenizer.expect(")"); - parse_block(cond->body, false); + parse_block(cond->body, false, &Parser::parse_statement); string token = tokenizer.peek_token(); if(token=="else") { tokenizer.parse_token(); - parse_block(cond->else_body, false); + parse_block(cond->else_body, false, &Parser::parse_statement); } return cond; @@ -601,9 +893,7 @@ RefPtr Parser::parse_conditional() RefPtr Parser::parse_for() { tokenizer.expect("for"); - RefPtr loop = new Iteration; - loop->source = source_index; - loop->line = tokenizer.get_location().line; + RefPtr loop = create_node(); tokenizer.expect("("); string token = tokenizer.peek_token(); if(is_type(token)) @@ -612,7 +902,7 @@ RefPtr Parser::parse_for() { if(token!=";") { - RefPtr expr = new ExpressionStatement; + RefPtr expr = create_node(); expr->expression = parse_expression(); loop->init_statement = expr; } @@ -625,7 +915,7 @@ RefPtr Parser::parse_for() loop->loop_expression = parse_expression(); tokenizer.expect(")"); - parse_block(loop->body, false); + parse_block(loop->body, false, &Parser::parse_statement); return loop; } @@ -633,14 +923,12 @@ RefPtr Parser::parse_for() RefPtr Parser::parse_while() { tokenizer.expect("while"); - RefPtr loop = new Iteration; - loop->source = source_index; - loop->line = tokenizer.get_location().line; + RefPtr loop = create_node(); tokenizer.expect("("); loop->condition = parse_expression(); tokenizer.expect(")"); - parse_block(loop->body, false); + parse_block(loop->body, false, &Parser::parse_statement); return loop; } @@ -648,9 +936,7 @@ RefPtr Parser::parse_while() RefPtr Parser::parse_passthrough() { tokenizer.expect("passthrough"); - RefPtr pass = new Passthrough; - pass->source = source_index; - pass->line = tokenizer.get_location().line; + RefPtr pass = create_node(); if(cur_stage->type==Stage::GEOMETRY) { tokenizer.expect("["); @@ -664,9 +950,7 @@ RefPtr Parser::parse_passthrough() RefPtr Parser::parse_return() { tokenizer.expect("return"); - RefPtr ret = new Return; - ret->source = source_index; - ret->line = tokenizer.get_location().line; + RefPtr ret = create_node(); if(tokenizer.peek_token()!=";") ret->expression = parse_expression(); tokenizer.expect(";");