summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/context.cc35
-rw-r--r--src/context.h1
-rw-r--r--src/lexer.l7
-rw-r--r--src/module.cc5
-rw-r--r--src/module.h9
-rw-r--r--src/parser.y72
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;
+}
+
contact: Jan Huwald // Impressum