From: Mikko Rasa Date: Mon, 14 Nov 2016 12:22:02 +0000 (+0200) Subject: Implement an import system X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=a0caabaed3aeb8947133d78986bfb4ae5ae3c893;p=libs%2Fgl.git Implement an import system This is the first of two major steps required to replicate the core functionality of the old ProgramBuilder system, namely generating standard shaders. The other is conditionally including pieces of code, which will be added soon. --- diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 63939409..82a324de 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -4,6 +4,7 @@ #include "error.h" #include "program.h" #include "programcompiler.h" +#include "resources.h" #include "shader.h" using namespace std; @@ -34,17 +35,20 @@ namespace GL { using namespace ProgramSyntax; ProgramCompiler::ProgramCompiler(): + resources(0), module(0) { } void ProgramCompiler::compile(const string &source) { + resources = 0; module = &parser.parse(source); process(); } -void ProgramCompiler::compile(IO::Base &io) +void ProgramCompiler::compile(IO::Base &io, Resources *res) { + resources = res; module = &parser.parse(io); process(); } @@ -102,6 +106,11 @@ Stage *ProgramCompiler::get_builtins(StageType type) void ProgramCompiler::process() { + list imports = apply >(module->shared); + for(list::iterator i=imports.end(); i!=imports.begin(); ) + import((*--i)->module); + apply(module->shared, set(imports.begin(), imports.end())); + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) generate(*i); for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ) @@ -113,6 +122,39 @@ void ProgramCompiler::process() } } +void ProgramCompiler::import(const string &name) +{ + if(!resources) + throw runtime_error("no resources"); + RefPtr io = resources->open_raw(name+".glsl"); + if(!io) + throw runtime_error(format("module %s not found", name)); + ProgramParser import_parser; + Module &imported_module = import_parser.parse(*io); + + inject_block(module->shared.content, imported_module.shared.content); + apply(module->shared); + for(list::iterator i=imported_module.stages.begin(); i!=imported_module.stages.end(); ++i) + { + list::iterator j; + for(j=module->stages.begin(); (j!=module->stages.end() && j->typetype); ++j) ; + if(j==module->stages.end() || j->type>i->type) + { + j = module->stages.insert(j, *i); + list::iterator k = j; + if(++k!=module->stages.end()) + k->previous = &*j; + if(j!=module->stages.begin()) + j->previous = &*--(k=j); + } + else + { + inject_block(j->content, i->content); + apply(*j); + } + } +} + void ProgramCompiler::generate(Stage &stage) { inject_block(stage.content, module->shared.content); @@ -262,6 +304,11 @@ void ProgramCompiler::Formatter::visit(Block &block) formatted += format("\n%s}", string(brace_indent*2, ' ')); } +void ProgramCompiler::Formatter::visit(Import &import) +{ + formatted += format("import %s;", import.module); +} + void ProgramCompiler::Formatter::visit(Layout &layout) { formatted += "layout("; @@ -327,7 +374,7 @@ void ProgramCompiler::Formatter::visit(FunctionDeclaration &func) (*i)->visit(*this); } formatted += ')'; - if(func.definition) + if(func.definition==&func) { formatted += '\n'; func.body.visit(*this); @@ -376,6 +423,56 @@ void ProgramCompiler::Formatter::visit(Return &ret) } +ProgramCompiler::DeclarationCombiner::DeclarationCombiner(): + toplevel(true), + remove_node(false) +{ } + +void ProgramCompiler::DeclarationCombiner::visit(Block &block) +{ + if(!toplevel) + return; + + SetForScope set(toplevel, false); + for(list >::iterator i=block.body.begin(); i!=block.body.end(); ) + { + remove_node = false; + (*i)->visit(*this); + if(remove_node) + block.body.erase(i++); + else + ++i; + } +} + +void ProgramCompiler::DeclarationCombiner::visit(FunctionDeclaration &func) +{ + vector &decls = functions[func.name]; + if(func.definition) + { + for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) + { + (*i)->definition = func.definition; + (*i)->body.body.clear(); + } + } + decls.push_back(&func); +} + +void ProgramCompiler::DeclarationCombiner::visit(VariableDeclaration &var) +{ + VariableDeclaration *&ptr = variables[var.name]; + if(ptr) + { + if(var.init_expression) + ptr->init_expression = var.init_expression; + remove_node = true; + } + else + ptr = &var; +} + + ProgramCompiler::VariableResolver::VariableResolver(): anonymous(false), record_target(false), diff --git a/source/programcompiler.h b/source/programcompiler.h index 2ef4aa7d..0c87acf0 100644 --- a/source/programcompiler.h +++ b/source/programcompiler.h @@ -9,6 +9,7 @@ namespace Msp { namespace GL { class Program; +class Resources; class ProgramCompiler { @@ -48,6 +49,7 @@ private: virtual void visit(ProgramSyntax::Assignment &); virtual void visit(ProgramSyntax::FunctionCall &); virtual void visit(ProgramSyntax::ExpressionStatement &); + virtual void visit(ProgramSyntax::Import &); virtual void visit(ProgramSyntax::Layout &); virtual void visit(ProgramSyntax::StructDeclaration &); virtual void visit(ProgramSyntax::VariableDeclaration &); @@ -58,6 +60,31 @@ private: virtual void visit(ProgramSyntax::Return &); }; + template + struct NodeGatherer: Visitor + { + typedef std::list ResultType; + + std::list nodes; + + const ResultType &get_result() const { return nodes; } + virtual void visit(T &n) { nodes.push_back(&n); } + }; + + struct DeclarationCombiner: Visitor + { + bool toplevel; + std::map > functions; + std::map variables; + bool remove_node; + + DeclarationCombiner(); + + virtual void visit(ProgramSyntax::Block &); + virtual void visit(ProgramSyntax::FunctionDeclaration &); + virtual void visit(ProgramSyntax::VariableDeclaration &); + }; + struct VariableResolver: Visitor { std::vector blocks; @@ -158,6 +185,7 @@ private: virtual void visit(ProgramSyntax::VariableDeclaration &); }; + Resources *resources; ProgramParser parser; ProgramSyntax::Module *module; @@ -165,7 +193,7 @@ public: ProgramCompiler(); void compile(const std::string &); - void compile(IO::Base &); + void compile(IO::Base &, Resources * = 0); void add_shaders(Program &); private: @@ -173,6 +201,7 @@ private: static ProgramSyntax::Module &get_builtins_module(); static ProgramSyntax::Stage *get_builtins(ProgramSyntax::StageType); void process(); + void import(const std::string &); void generate(ProgramSyntax::Stage &); bool optimize(ProgramSyntax::Stage &); static void inject_block(ProgramSyntax::Block &, const ProgramSyntax::Block &); diff --git a/source/programparser.cpp b/source/programparser.cpp index f11b5bf2..ddea9640 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -332,7 +332,9 @@ bool ProgramParser::is_identifier(const string &token) Node *ProgramParser::parse_global_declaration() { string token = peek_token(); - if(token=="layout") + if(token=="import") + return parse_import(); + else if(token=="layout") return parse_layout(); else if(token=="struct") return parse_struct_declaration(); @@ -383,6 +385,18 @@ Node *ProgramParser::parse_statement() throw runtime_error(format("Syntax error at '%s': expected a statement", token)); } +Import *ProgramParser::parse_import() +{ + if(cur_stage->type!=SHARED) + throw runtime_error("Imports are only allowed in the shared section"); + + expect("import"); + RefPtr import = new Import; + import->module = parse_token(); + expect(";"); + return import.release(); +} + Layout *ProgramParser::parse_layout() { expect("layout"); @@ -628,7 +642,7 @@ FunctionDeclaration *ProgramParser::parse_function_declaration() string token = peek_token(); if(token=="{") { - func->definition = true; + func->definition = func.get(); parse_block(func->body, true); } else if(token==";") diff --git a/source/programparser.h b/source/programparser.h index e2462516..4e8e38f0 100644 --- a/source/programparser.h +++ b/source/programparser.h @@ -76,6 +76,7 @@ private: ProgramSyntax::Node *parse_global_declaration(); ProgramSyntax::Node *parse_statement(); + ProgramSyntax::Import *parse_import(); ProgramSyntax::Layout *parse_layout(); void parse_block(ProgramSyntax::Block &, bool); ProgramSyntax::Expression *parse_expression(unsigned = 0); diff --git a/source/programsyntax.cpp b/source/programsyntax.cpp index 83cfbb08..f87488dc 100644 --- a/source/programsyntax.cpp +++ b/source/programsyntax.cpp @@ -87,6 +87,12 @@ void ExpressionStatement::visit(NodeVisitor &visitor) } +void Import::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + void Layout::visit(NodeVisitor &visitor) { visitor.visit(*this); @@ -130,7 +136,15 @@ void InterfaceBlock::visit(NodeVisitor &visitor) FunctionDeclaration::FunctionDeclaration(): - definition(false) + definition(0) +{ } + +FunctionDeclaration::FunctionDeclaration(const FunctionDeclaration &other): + return_type(other.return_type), + name(other.name), + parameters(other.parameters), + definition(other.definition==&other ? this : other.definition), + body(other.body) { } void FunctionDeclaration::visit(NodeVisitor &visitor) diff --git a/source/programsyntax.h b/source/programsyntax.h index 03b5aa88..9545760c 100644 --- a/source/programsyntax.h +++ b/source/programsyntax.h @@ -162,6 +162,14 @@ struct ExpressionStatement: Node virtual void visit(NodeVisitor &); }; +struct Import: Node +{ + std::string module; + + virtual Import *clone() const { return new Import(*this); } + virtual void visit(NodeVisitor &); +}; + struct Layout: Node { struct Qualifier @@ -226,10 +234,11 @@ struct FunctionDeclaration: Node std::string return_type; std::string name; std::vector > parameters; - bool definition; + FunctionDeclaration *definition; Block body; FunctionDeclaration(); + FunctionDeclaration(const FunctionDeclaration &); virtual FunctionDeclaration *clone() const { return new FunctionDeclaration(*this); } virtual void visit(NodeVisitor &); @@ -286,6 +295,7 @@ struct NodeVisitor virtual void visit(Assignment &); virtual void visit(FunctionCall &) { } virtual void visit(ExpressionStatement &) { } + virtual void visit(Import &) { } virtual void visit(Layout &) { } virtual void visit(StructDeclaration &) { } virtual void visit(VariableDeclaration &) { }