diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/MainWindow.h | 2 | ||||
-rw-r--r-- | src/ModuleCache.cc | 87 | ||||
-rw-r--r-- | src/ModuleCache.h | 22 | ||||
-rw-r--r-- | src/context.cc | 1 | ||||
-rw-r--r-- | src/lexer.l | 3 | ||||
-rw-r--r-- | src/mainwin.cc | 7 | ||||
-rw-r--r-- | src/module.cc | 17 | ||||
-rw-r--r-- | src/module.h | 9 | ||||
-rw-r--r-- | src/openscad.cc | 3 | ||||
-rw-r--r-- | src/openscad.h | 2 | ||||
-rw-r--r-- | src/parser.y | 122 |
11 files changed, 165 insertions, 110 deletions
diff --git a/src/MainWindow.h b/src/MainWindow.h index 226689a..a0353a9 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -30,7 +30,7 @@ public: QString autoReloadInfo; Context root_ctx; - AbstractModule *root_module; // Result of parsing + Module *root_module; // Result of parsing ModuleInstantiation root_inst; // Top level instance AbstractNode *absolute_root_node; // Result of tree evaluation AbstractNode *root_node; // Root if the root modifier (!) is used diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc new file mode 100644 index 0000000..eaa7d33 --- /dev/null +++ b/src/ModuleCache.cc @@ -0,0 +1,87 @@ +#include "ModuleCache.h" +#include "module.h" +#include "printutils.h" +#include "boosty.h" +#include "openscad.h" + +#include <stdio.h> +#include <sstream> +#include <sys/stat.h> + +ModuleCache *ModuleCache::inst = NULL; + +Module *ModuleCache::evaluate(const std::string &filename) +{ + Module *cached = NULL; + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + stat(filename.c_str(), &st); + + std::stringstream idstream; + idstream << std::hex << st.st_mtime << "." << st.st_size; + std::string cache_id = idstream.str(); + + if (this->entries.find(filename) != this->entries.end() && + this->entries[filename].cache_id == cache_id) { +#ifdef DEBUG + PRINTB("Using cached library: %s (%s)", filename % cache_id); +#endif + PRINTB("%s", this->entries[filename].msg); + cached = &(*this->entries[filename].module); + } + + if (cached) { + cached->handleDependencies(); + return cached; + } + else { + if (this->entries.find(filename) != this->entries.end()) { + PRINTB("Recompiling cached library: %s (%s)", filename % cache_id); + } + else { + PRINTB("Compiling library '%s'.", filename); + } + } + + FILE *fp = fopen(filename.c_str(), "rt"); + if (!fp) { + fprintf(stderr, "WARNING: Can't open library file '%s'\n", filename.c_str()); + return NULL; + } + std::stringstream text; + char buffer[513]; + int ret; + while ((ret = fread(buffer, 1, 512, fp)) > 0) { + buffer[ret] = 0; + text << buffer; + } + fclose(fp); + + print_messages_push(); + + cache_entry e = { NULL, cache_id, std::string("WARNING: Library `") + filename + "' tries to recursively use itself!" }; + if (this->entries.find(filename) != this->entries.end()) + delete this->entries[filename].module; + this->entries[filename] = e; + + std::string pathname = boosty::stringy(fs::path(filename).parent_path()); + Module *lib_mod = dynamic_cast<Module*>(parse(text.str().c_str(), pathname.c_str(), 0)); + + if (lib_mod) { + this->entries[filename].module = lib_mod; + this->entries[filename].msg = print_messages_stack.back(); + } else { + this->entries.erase(filename); + } + + print_messages_pop(); + + return lib_mod; +} + +void ModuleCache::clear() +{ + this->entries.clear(); +} + diff --git a/src/ModuleCache.h b/src/ModuleCache.h new file mode 100644 index 0000000..57ff2e7 --- /dev/null +++ b/src/ModuleCache.h @@ -0,0 +1,22 @@ +#include <string> +#include <boost/unordered_map.hpp> + +class ModuleCache +{ +public: + static ModuleCache *instance() { if (!inst) inst = new ModuleCache; return inst; } + class Module *evaluate(const std::string &filename); + void clear(); + +private: + ModuleCache() {} + ~ModuleCache() {} + + static ModuleCache *inst; + + struct cache_entry { + class Module *module; + std::string cache_id, msg; + }; + boost::unordered_map<std::string, cache_entry> entries; +}; diff --git a/src/context.cc b/src/context.cc index b9e685c..f96a45b 100644 --- a/src/context.cc +++ b/src/context.cc @@ -162,6 +162,7 @@ AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const } if (this->usedlibs_p) { BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + assert(m.second); if (m.second->modules.find(inst.name()) != m.second->modules.end()) { Context ctx(this->parent, m.second); return m.second->modules[inst.name()]->evaluate(&ctx, &inst); diff --git a/src/lexer.l b/src/lexer.l index 5644ded..11f2aff 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -52,7 +52,7 @@ int lexerget_lineno(void); static void yyunput(int, char*) __attribute__((unused)); #endif extern const char *parser_input_buffer; -extern const char *parser_source_path; + extern std::string parser_source_path; #define YY_INPUT(buf,result,max_size) { \ if (yyin && yyin != stdin) { \ @@ -108,6 +108,7 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); } <cond_use>{ [^\t\r\n>]+ { filename = yytext; } ">" { + PRINTB("USE: %s", filename); BEGIN(INITIAL); fs::path usepath; if (boosty::is_absolute(fs::path(filename))) { diff --git a/src/mainwin.cc b/src/mainwin.cc index 9b24eea..8eebf09 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -25,6 +25,7 @@ */ #include "PolySetCache.h" +#include "ModuleCache.h" #include "MainWindow.h" #include "openscad.h" // examplesdir #include "parsersettings.h" @@ -695,6 +696,8 @@ void MainWindow::compile(bool procevents) goto fail; } + this->root_module->handleDependencies(); + // Evaluate CSG tree PRINT("Compiling design (CSG Tree generation)..."); if (procevents) @@ -1449,7 +1452,7 @@ void MainWindow::actionFlushCaches() #endif dxf_dim_cache.clear(); dxf_cross_cache.clear(); - Module::clear_library_cache(); + ModuleCache::instance()->clear(); } void MainWindow::viewModeActionsUncheck() @@ -1797,7 +1800,7 @@ void MainWindow::consoleOutput(const std::string &msg, void *userdata) void MainWindow::setCurrentOutput() { - set_output_handler(&MainWindow::consoleOutput, this); +// set_output_handler(&MainWindow::consoleOutput, this); } void MainWindow::clearCurrentOutput() diff --git a/src/module.cc b/src/module.cc index 6641ff7..7ad2e33 100644 --- a/src/module.cc +++ b/src/module.cc @@ -25,11 +25,13 @@ */ #include "module.h" +#include "ModuleCache.h" #include "node.h" #include "context.h" #include "expression.h" #include "function.h" #include "printutils.h" + #include <boost/foreach.hpp> #include <sstream> @@ -201,7 +203,18 @@ std::string Module::dump(const std::string &indent, const std::string &name) con return dump.str(); } -void Module::clear_library_cache() +void Module::handleDependencies() { - Module::libs_cache.clear(); + PRINTB_NOCACHE("Module::handleDependencies(): %p (%d libs %p)", this % this->usedlibs.size() % &this->usedlibs); + // Iterating manually since we want to modify the container while iterating + Module::ModuleContainer::iterator iter = this->usedlibs.begin(); + while (iter != this->usedlibs.end()) { + Module::ModuleContainer::iterator curr = iter++; + curr->second = ModuleCache::instance()->evaluate(curr->first); + PRINTB_NOCACHE(" %s: %p", curr->first % curr->second); + if (!curr->second) { + PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", curr->first); + this->usedlibs.erase(curr); + } + } } diff --git a/src/module.h b/src/module.h index 6c6529b..a490129 100644 --- a/src/module.h +++ b/src/module.h @@ -65,11 +65,9 @@ public: void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); } - static Module *compile_library(const std::string &filename); - static void clear_library_cache(); - typedef boost::unordered_map<std::string, class Module*> ModuleContainer; ModuleContainer usedlibs; + void handleDependencies(); std::vector<std::string> assignments_var; std::vector<Expression*> assignments_expr; @@ -87,11 +85,6 @@ public: protected: private: - struct libs_cache_ent { - Module *mod; - std::string cache_id, msg; - }; - static boost::unordered_map<std::string, libs_cache_ent> libs_cache; }; #endif diff --git a/src/openscad.cc b/src/openscad.cc index 11dad7c..39e3f4c 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -255,7 +255,7 @@ int main(int argc, char **argv) Context root_ctx; register_builtin(root_ctx); - AbstractModule *root_module; + Module *root_module; ModuleInstantiation root_inst; AbstractNode *root_node; @@ -278,6 +278,7 @@ int main(int argc, char **argv) std::string fpath = boosty::stringy(abspath.parent_path()); root_module = parse(text.str().c_str(), fpath.c_str(), false); if (!root_module) exit(1); + root_module->handleDependencies(); } fs::path fpath = boosty::absolute( fs::path(filename) ); diff --git a/src/openscad.h b/src/openscad.h index dab14cd..8b49ba2 100644 --- a/src/openscad.h +++ b/src/openscad.h @@ -27,7 +27,7 @@ #ifndef OPENSCAD_H #define OPENSCAD_H -extern class AbstractModule *parse(const char *text, const char *path, int debug); +extern class Module *parse(const char *text, const char *path, int debug); extern int get_fragments_from_r(double r, double fn, double fs, double fa); #include <string> diff --git a/src/parser.y b/src/parser.y index 15a754b..85fee48 100644 --- a/src/parser.y +++ b/src/parser.y @@ -43,7 +43,7 @@ #include <boost/foreach.hpp> #include <boost/filesystem.hpp> -using namespace boost::filesystem; +namespace fs = boost::filesystem; #include "boosty.h" int parser_error_pos = -1; @@ -56,7 +56,7 @@ int lexerlex_destroy(void); int lexerlex(void); std::vector<Module*> module_stack; -Module *module; +Module *currmodule; class ArgContainer { public: @@ -133,7 +133,7 @@ public: input: /* empty */ | - TOK_USE { module->usedlibs[$1] = NULL; } input | + TOK_USE { currmodule->usedlibs[$1] = NULL; } input | statement input ; inner_input: @@ -145,37 +145,38 @@ statement: '{' inner_input '}' | module_instantiation { if ($1) { - module->addChild($1); + currmodule->addChild($1); } else { delete $1; } } | TOK_ID '=' expr ';' { bool add_new_assignment = true; - for (size_t i = 0; i < module->assignments_var.size(); i++) { - if (module->assignments_var[i] != $1) + for (size_t i = 0; i < currmodule->assignments_var.size(); i++) { + if (currmodule->assignments_var[i] != $1) continue; - delete module->assignments_expr[i]; - module->assignments_expr[i] = $3; + delete currmodule->assignments_expr[i]; + currmodule->assignments_expr[i] = $3; add_new_assignment = false; } if (add_new_assignment) { - module->assignments_var.push_back($1); - module->assignments_expr.push_back($3); + currmodule->assignments_var.push_back($1); + currmodule->assignments_expr.push_back($3); free($1); } } | TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { - Module *p = module; - module_stack.push_back(module); - module = new Module(); - p->modules[$2] = module; - module->argnames = $4->argnames; - module->argexpr = $4->argexpr; + Module *p = currmodule; + module_stack.push_back(currmodule); + currmodule = new Module(); + PRINTB_NOCACHE("New module: %s %p", $2 % currmodule); + p->modules[$2] = currmodule; + currmodule->argnames = $4->argnames; + currmodule->argexpr = $4->argexpr; free($2); delete $4; } statement { - module = module_stack.back(); + currmodule = module_stack.back(); module_stack.pop_back(); } | TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { @@ -183,7 +184,7 @@ statement: func->argnames = $4->argnames; func->argexpr = $4->argexpr; func->expr = $8; - module->functions[$2] = func; + currmodule->functions[$2] = func; free($2); delete $4; } ';' ; @@ -560,101 +561,34 @@ void yyerror (char const *s) { // FIXME: We leak memory on parser errors... PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s); - module = NULL; + currmodule = NULL; } extern void lexerdestroy(); extern FILE *lexerin; extern const char *parser_input_buffer; const char *parser_input_buffer; -const char *parser_source_path; +std::string parser_source_path; -AbstractModule *parse(const char *text, const char *path, int debug) +Module *parse(const char *text, const char *path, int debug) { + PRINT_NOCACHE("New parser"); lexerin = NULL; parser_error_pos = -1; parser_input_buffer = text; - parser_source_path = path; + parser_source_path = std::string(path); module_stack.clear(); - module = new Module(); + Module *rootmodule = currmodule = new Module(); + PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule); parserdebug = debug; parserparse(); lexerdestroy(); lexerlex_destroy(); - if (!module) - return NULL; - - // Iterating manually since we want to modify the container while iterating - Module::ModuleContainer::iterator iter = module->usedlibs.begin(); - while (iter != module->usedlibs.end()) { - Module::ModuleContainer::iterator curr = iter++; - curr->second = Module::compile_library(curr->first); - if (!curr->second) { - PRINTB("WARNING: Failed to compile library '%s'.", curr->first); - module->usedlibs.erase(curr); - } - } + if (!rootmodule) return NULL; parser_error_pos = -1; - return module; -} - -boost::unordered_map<std::string, Module::libs_cache_ent> Module::libs_cache; - -Module *Module::compile_library(const std::string &filename) -{ - struct stat st; - memset(&st, 0, sizeof(struct stat)); - stat(filename.c_str(), &st); - - std::stringstream idstream; - idstream << std::hex << st.st_mtime << "." << st.st_size; - std::string cache_id = idstream.str(); - - if (libs_cache.find(filename) != libs_cache.end() && libs_cache[filename].cache_id == cache_id) { - PRINTB("%s", libs_cache[filename].msg); - return &(*libs_cache[filename].mod); - } - - FILE *fp = fopen(filename.c_str(), "rt"); - if (!fp) { - fprintf(stderr, "WARNING: Can't open library file '%s'\n", filename.c_str()); - return NULL; - } - std::stringstream text; - char buffer[513]; - int ret; - while ((ret = fread(buffer, 1, 512, fp)) > 0) { - buffer[ret] = 0; - text << buffer; - } - fclose(fp); - - print_messages_push(); - - PRINTB("Compiling library '%s'.", filename); - libs_cache_ent e = { NULL, cache_id, std::string("WARNING: Library `") + filename + "' tries to recursively use itself!" }; - if (libs_cache.find(filename) != libs_cache.end()) - delete libs_cache[filename].mod; - libs_cache[filename] = e; - - Module *backup_mod = module; - std::string pathname = boosty::stringy( fs::path(filename).parent_path() ); - Module *lib_mod = dynamic_cast<Module*>(parse(text.str().c_str(), pathname.c_str(), 0)); - module = backup_mod; - - if (lib_mod) { - libs_cache[filename].mod = lib_mod; - libs_cache[filename].msg = print_messages_stack.back(); - } else { - libs_cache.erase(filename); - } - - print_messages_pop(); - - return lib_mod; + return rootmodule; } - |