mirror of https://github.com/vitalif/openscad
Initial implementation of ModuleCache and dependency tracking of used modules
parent
44ff853990
commit
b9d218e137
|
@ -256,8 +256,13 @@ o Caching
|
|||
- Test that caching is actually performed (speedup + same results)
|
||||
- Test the modifier characters correctly influence the cache (also when
|
||||
added/removed)
|
||||
- Test the individual caches
|
||||
- PolySetCache
|
||||
- CGALCache
|
||||
- nodecache
|
||||
- ModuleCache
|
||||
o other tests
|
||||
- export
|
||||
- cmd-line tests
|
||||
- leaf nodes having children, e.g. cube() cylinder();
|
||||
- dependency tracking
|
||||
- dependency tracking (use and include)
|
||||
|
|
|
@ -188,6 +188,7 @@ HEADERS += src/parsersettings.h \
|
|||
src/traverser.h \
|
||||
src/nodecache.h \
|
||||
src/nodedumper.h \
|
||||
src/ModuleCache.h \
|
||||
src/PolySetCache.h \
|
||||
src/PolySetEvaluator.h \
|
||||
src/CSGTermEvaluator.h \
|
||||
|
@ -230,6 +231,7 @@ SOURCES += src/mathc99.cc \
|
|||
src/nodedumper.cc \
|
||||
src/traverser.cc \
|
||||
src/PolySetEvaluator.cc \
|
||||
src/ModuleCache.cc \
|
||||
src/PolySetCache.cc \
|
||||
src/Tree.cc \
|
||||
\
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) );
|
||||
|
|
|
@ -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>
|
||||
|
|
122
src/parser.y
122
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;
|
||||
return rootmodule;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -309,6 +309,7 @@ set(CORE_SOURCES
|
|||
../src/expr.cc
|
||||
../src/func.cc
|
||||
../src/module.cc
|
||||
../src/ModuleCache.cc
|
||||
../src/node.cc
|
||||
../src/context.cc
|
||||
../src/csgterm.cc
|
||||
|
@ -402,6 +403,12 @@ target_link_libraries(echotest tests-nocgal tests-core ${QT_LIBRARIES} ${OPENGL_
|
|||
add_executable(dumptest dumptest.cc)
|
||||
target_link_libraries(dumptest tests-common tests-nocgal ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
|
||||
|
||||
#
|
||||
# modulecachetest
|
||||
#
|
||||
add_executable(modulecachetest modulecachetest.cc)
|
||||
target_link_libraries(modulecachetest tests-common tests-nocgal ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
|
||||
|
||||
#
|
||||
# csgtexttest
|
||||
#
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* OpenSCAD (www.openscad.org)
|
||||
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
|
||||
* Marius Kintel <marius@kintel.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* As a special exception, you have permission to link this program
|
||||
* with the CGAL library and distribute executables, as long as you
|
||||
* follow the requirements of the GNU GPL in regard to all of the
|
||||
* software in the executable aside from CGAL.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tests-common.h"
|
||||
#include "openscad.h"
|
||||
#include "parsersettings.h"
|
||||
#include "node.h"
|
||||
#include "module.h"
|
||||
#include "context.h"
|
||||
#include "value.h"
|
||||
#include "export.h"
|
||||
#include "builtin.h"
|
||||
#include "Tree.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace fs = boost::filesystem;
|
||||
#include "boosty.h"
|
||||
|
||||
std::string commandline_commands;
|
||||
std::string currentdir;
|
||||
QString examplesdir;
|
||||
|
||||
using std::string;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_set_output_format(_TWO_DIGIT_EXPONENT);
|
||||
#endif
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
const char *outfilename = argv[2];
|
||||
|
||||
int rc = 0;
|
||||
|
||||
Builtins::instance()->initialize();
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
fs::path original_path = fs::current_path();
|
||||
|
||||
currentdir = boosty::stringy( fs::current_path() );
|
||||
|
||||
parser_init(QCoreApplication::instance()->applicationDirPath().toStdString());
|
||||
set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries"));
|
||||
|
||||
Context root_ctx;
|
||||
register_builtin(root_ctx);
|
||||
|
||||
AbstractModule *root_module;
|
||||
ModuleInstantiation root_inst;
|
||||
AbstractNode *root_node;
|
||||
|
||||
root_module = parsefile(filename);
|
||||
if (!root_module) {
|
||||
fprintf(stderr, "Error: Unable to parse input file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fs::current_path(fs::path(filename).parent_path());
|
||||
|
||||
AbstractNode::resetIndexCounter();
|
||||
root_node = root_module->evaluate(&root_ctx, &root_inst);
|
||||
|
||||
delete root_node;
|
||||
delete root_module;
|
||||
|
||||
fs::current_path(original_path);
|
||||
|
||||
fprintf(stderr, "Second parse\n");
|
||||
root_module = parsefile(filename);
|
||||
if (!root_module) {
|
||||
fprintf(stderr, "Error: Unable to parse second time\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
AbstractNode::resetIndexCounter();
|
||||
root_node = root_module->evaluate(&root_ctx, &root_inst);
|
||||
|
||||
delete root_node;
|
||||
delete root_module;
|
||||
|
||||
Builtins::instance(true);
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -7,9 +7,9 @@
|
|||
#include <QFileInfo>
|
||||
#include <sstream>
|
||||
|
||||
AbstractModule *parsefile(const char *filename)
|
||||
Module *parsefile(const char *filename)
|
||||
{
|
||||
AbstractModule *root_module = NULL;
|
||||
Module *root_module = NULL;
|
||||
|
||||
QFileInfo fileInfo(filename);
|
||||
handle_dep(filename);
|
||||
|
@ -27,6 +27,9 @@ AbstractModule *parsefile(const char *filename)
|
|||
fclose(fp);
|
||||
text << "\n" << commandline_commands;
|
||||
root_module = parse(text.str().c_str(), fileInfo.absolutePath().toLocal8Bit(), false);
|
||||
if (root_module) {
|
||||
root_module->handleDependencies();
|
||||
}
|
||||
}
|
||||
return root_module;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef TESTS_COMMON_H_
|
||||
#define TESTS_COMMON_H_
|
||||
|
||||
class AbstractModule *parsefile(const char *filename);
|
||||
class Module *parsefile(const char *filename);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue