diff options
author | clifford <clifford@b57f626f-c46c-0410-a088-ec61d464b74c> | 2010-02-28 13:48:04 (GMT) |
---|---|---|
committer | clifford <clifford@b57f626f-c46c-0410-a088-ec61d464b74c> | 2010-02-28 13:48:04 (GMT) |
commit | d3329838b4d948455277caa3c24df4b7b50fabb2 (patch) | |
tree | c132e689fbf28bc5d607461c83afdeb79b0adfa2 /src | |
parent | b12deeff5be0ce76af25d557480f29b0ed849dd6 (diff) |
Clifford Wolf:
Implemented 'use' statement
git-svn-id: http://svn.clifford.at/openscad/trunk@459 b57f626f-c46c-0410-a088-ec61d464b74c
Diffstat (limited to 'src')
-rw-r--r-- | src/context.cc | 35 | ||||
-rw-r--r-- | src/context.h | 1 | ||||
-rw-r--r-- | src/lexer.l | 7 | ||||
-rw-r--r-- | src/module.cc | 5 | ||||
-rw-r--r-- | src/module.h | 9 | ||||
-rw-r--r-- | src/parser.y | 72 |
6 files changed, 124 insertions, 5 deletions
diff --git a/src/context.cc b/src/context.cc index a9ccc98..5aec712b 100644 --- a/src/context.cc +++ b/src/context.cc @@ -36,6 +36,7 @@ Context::Context(const Context *parent) this->parent = parent; functions_p = NULL; modules_p = NULL; + usedlibs_p = NULL; inst_p = NULL; if (parent) document_path = parent->document_path; ctx_stack.append(this); @@ -96,6 +97,23 @@ Value Context::evaluate_function(QString name, const QVector<QString> &argnames, { if (functions_p && functions_p->contains(name)) return functions_p->value(name)->evaluate(this, argnames, argvalues); + if (usedlibs_p) { + QHashIterator<QString, Module*> i(*usedlibs_p); + while (i.hasNext()) { + i.next(); + if (i.value()->functions.contains(name)) { + Module *lib = i.value(); + Context ctx(parent); + ctx.functions_p = &lib->functions; + ctx.modules_p = &lib->modules; + ctx.usedlibs_p = &lib->usedlibs; + for (int j = 0; j < lib->assignments_var.size(); j++) { + ctx.set_variable(lib->assignments_var[j], lib->assignments_expr[j]->evaluate(&ctx)); + } + return i.value()->functions.value(name)->evaluate(&ctx, argnames, argvalues); + } + } + } if (parent) return parent->evaluate_function(name, argnames, argvalues); PRINTA("WARNING: Ignoring unkown function '%1'.", name); @@ -106,6 +124,23 @@ AbstractNode *Context::evaluate_module(const ModuleInstantiation *inst) const { if (modules_p && modules_p->contains(inst->modname)) return modules_p->value(inst->modname)->evaluate(this, inst); + if (usedlibs_p) { + QHashIterator<QString, Module*> i(*usedlibs_p); + while (i.hasNext()) { + i.next(); + if (i.value()->modules.contains(inst->modname)) { + Module *lib = i.value(); + Context ctx(parent); + ctx.functions_p = &lib->functions; + ctx.modules_p = &lib->modules; + ctx.usedlibs_p = &lib->usedlibs; + for (int j = 0; j < lib->assignments_var.size(); j++) { + ctx.set_variable(lib->assignments_var[j], lib->assignments_expr[j]->evaluate(&ctx)); + } + return i.value()->modules.value(inst->modname)->evaluate(&ctx, inst); + } + } + } if (parent) return parent->evaluate_module(inst); PRINTA("WARNING: Ignoring unkown module '%1'.", inst->modname); diff --git a/src/context.h b/src/context.h index fa67992..d5be745 100644 --- a/src/context.h +++ b/src/context.h @@ -13,6 +13,7 @@ public: QHash<QString, Value> config_variables; const QHash<QString, class AbstractFunction*> *functions_p; const QHash<QString, class AbstractModule*> *modules_p; + const QHash<QString, class Module*> *usedlibs_p; const class ModuleInstantiation *inst_p; QString document_path; diff --git a/src/lexer.l b/src/lexer.l index 24ec83b..c4406b6 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -89,7 +89,12 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" { QString filename(yytext); filename.remove(QRegExp("^use[ \t\r\n>]*<")); filename.remove(QRegExp(">$")); - parserlval.text = strdup(filename.toLocal8Bit()); + QFileInfo finfo(QDir(parser_source_path), filename); + if (!finfo.exists()) { + finfo = QFileInfo(QDir(librarydir), filename); + } + handle_dep(finfo.absoluteFilePath()); + parserlval.text = strdup(finfo.absoluteFilePath().toLocal8Bit()); return TOK_USE; } diff --git a/src/module.cc b/src/module.cc index a09f0d5..1a1e30e 100644 --- a/src/module.cc +++ b/src/module.cc @@ -137,6 +137,11 @@ AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *in c.functions_p = &functions; c.modules_p = &modules; + if (!usedlibs.empty()) + c.usedlibs_p = &usedlibs; + else + c.usedlibs_p = NULL; + for (int i = 0; i < assignments_var.size(); i++) { c.set_variable(assignments_var[i], assignments_expr[i]->evaluate(&c)); } diff --git a/src/module.h b/src/module.h index 66228dd..b680ea1 100644 --- a/src/module.h +++ b/src/module.h @@ -46,7 +46,14 @@ public: class Module : public AbstractModule { public: - QVector<QString> usedlibs; + QHash< QString, Module*> usedlibs; + + struct libs_cache_ent { + Module *mod; + QString cache_id, msg; + }; + static QHash<QString, libs_cache_ent> libs_cache; + static Module *compile_library(QString filename); QVector<QString> argnames; QVector<Expression*> argexpr; diff --git a/src/parser.y b/src/parser.y index 8d31cd5..81f691d 100644 --- a/src/parser.y +++ b/src/parser.y @@ -25,6 +25,15 @@ %{ +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QTextStream> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + #include "module.h" #include "expression.h" #include "value.h" @@ -118,7 +127,7 @@ public: input: /* empty */ | - TOK_USE { module->usedlibs.append($1); } input | + TOK_USE { module->usedlibs[$1] = NULL; } input | statement input ; inner_input: @@ -579,9 +588,66 @@ AbstractModule *parse(const char *text, const char *path, int debug) lexerlex_destroy(); - if (module) - parser_error_pos = -1; + if (!module) + return NULL; + QHashIterator<QString, Module*> i(module->usedlibs); + while (i.hasNext()) { + i.next(); + module->usedlibs[i.key()] = Module::compile_library(i.key()); + if (!module->usedlibs[i.key()]) { + PRINTF("WARNING: Failed to compile library `%s'.", i.key().toUtf8().data()); + } + } + + parser_error_pos = -1; return module; } +QHash<QString, Module::libs_cache_ent> Module::libs_cache; + +Module *Module::compile_library(QString filename) +{ + struct stat st; + memset(&st, 0, sizeof(struct stat)); + stat(filename.toAscii().data(), &st); + + QString cache_id; + cache_id.sprintf("%x.%x", (int)st.st_mtime, (int)st.st_size); + + if (libs_cache.contains(filename) && libs_cache[filename].cache_id == cache_id) { + PRINT(libs_cache[cache_id].msg); + return &(*libs_cache[filename].mod); + } + + QFile f(filename); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { + PRINTF("WARNING: Can't open library file `%s'.", filename.toUtf8().data()); + return NULL; + } + QString text = QTextStream(&f).readAll(); + + print_messages_push(); + + PRINTF("Compiling library `%s'.", filename.toUtf8().data()); + libs_cache_ent e = { NULL, cache_id, QString("WARNING: Library `%1' tries to recursively use itself!\n").arg(filename) }; + if (libs_cache.contains(filename)) + delete libs_cache[filename].mod; + libs_cache[filename] = e; + + Module *backup_mod = module; + Module *lib_mod = dynamic_cast<Module*>(parse(text.toLocal8Bit(), QFileInfo(filename).absoluteDir().absolutePath().toLocal8Bit(), 0)); + module = backup_mod; + + if (lib_mod) { + libs_cache[filename].mod = lib_mod; + libs_cache[filename].msg = print_messages_stack.last(); + } else { + libs_cache.remove(filename); + } + + print_messages_pop(); + + return lib_mod; +} + |