Fix issue 214. When a syntax error is reported, we report the source file name
and the line number within the source file where the error occurred. This works even if the syntax error is within an included file. The parse() function, and the places where it is called, have been changed as necessary to enforce the convention that the second argument is the source filename, and not the name of the parent directory containing the source file. Previously, different calls to parse() made different assumptions about the meaning of the second argument, which probably means include and import were broken in some cases.
This commit is contained in:
parent
5af6ce171c
commit
a60ba41b77
6 changed files with 43 additions and 29 deletions
|
|
@ -105,8 +105,8 @@ bool ModuleCache::evaluate(const std::string &filename, FileModule *&module)
|
|||
|
||||
FileModule *oldmodule = lib_mod;
|
||||
|
||||
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
|
||||
lib_mod = dynamic_cast<FileModule*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
|
||||
fs::path pathname = fs::path(filename);
|
||||
lib_mod = dynamic_cast<FileModule*>(parse(textbuf.str().c_str(), pathname, false));
|
||||
PRINTDB(" compiled module: %p", lib_mod);
|
||||
|
||||
// We defer deletion so we can ensure that the new module won't
|
||||
|
|
|
|||
35
src/lexer.l
35
src/lexer.l
|
|
@ -54,7 +54,7 @@ int lexerget_lineno(void);
|
|||
static void yyunput(int, char*) __attribute__((unused));
|
||||
#endif
|
||||
extern const char *parser_input_buffer;
|
||||
extern std::string parser_source_path;
|
||||
extern fs::path parser_sourcefile;
|
||||
extern FileModule *rootmodule;
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) { \
|
||||
|
|
@ -79,8 +79,9 @@ extern FileModule *rootmodule;
|
|||
|
||||
void to_utf8(const char *, char *);
|
||||
void includefile();
|
||||
fs::path sourcepath();
|
||||
std::vector<fs::path> path_stack;
|
||||
fs::path sourcefile();
|
||||
std::vector<fs::path> filename_stack;
|
||||
std::vector<int> lineno_stack;
|
||||
std::vector<FILE*> openfiles;
|
||||
std::vector<std::string> openfilenames;
|
||||
|
||||
|
|
@ -121,7 +122,7 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
|
|||
[^\t\r\n>]+ { filename = yytext; }
|
||||
">" {
|
||||
BEGIN(INITIAL);
|
||||
fs::path fullpath = find_valid_path(sourcepath(), fs::path(filename), &openfilenames);
|
||||
fs::path fullpath = find_valid_path(sourcefile().parent_path(), fs::path(filename), &openfilenames);
|
||||
if (fullpath.empty()) {
|
||||
PRINTB("WARNING: Can't open library '%s'.", filename);
|
||||
parserlval.text = strdup(filename.c_str());
|
||||
|
|
@ -134,7 +135,11 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
|
|||
}
|
||||
|
||||
<<EOF>> {
|
||||
if(!path_stack.empty()) path_stack.pop_back();
|
||||
if (!filename_stack.empty()) filename_stack.pop_back();
|
||||
if (!lineno_stack.empty()) {
|
||||
yylineno = lineno_stack.back();
|
||||
lineno_stack.pop_back();
|
||||
}
|
||||
if (yyin && yyin != stdin) {
|
||||
assert(!openfiles.empty());
|
||||
fclose(openfiles.back());
|
||||
|
|
@ -237,11 +242,12 @@ void to_utf8(const char *str, char *out)
|
|||
}
|
||||
}
|
||||
|
||||
fs::path sourcepath()
|
||||
// Filename of the source file currently being lexed.
|
||||
fs::path sourcefile()
|
||||
{
|
||||
if (!path_stack.empty()) return path_stack.back();
|
||||
if (!filename_stack.empty()) return filename_stack.back();
|
||||
|
||||
return fs::path(parser_source_path);
|
||||
return parser_sourcefile;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -249,12 +255,12 @@ fs::path sourcepath()
|
|||
1) include <sourcepath/path/file>
|
||||
2) include <librarydir/path/file>
|
||||
|
||||
Globals used: filepath, sourcepath, filename
|
||||
Globals used: filepath, sourcefile, filename
|
||||
*/
|
||||
void includefile()
|
||||
{
|
||||
fs::path localpath = fs::path(filepath) / filename;
|
||||
fs::path fullpath = find_valid_path(sourcepath(), localpath, &openfilenames);
|
||||
fs::path fullpath = find_valid_path(sourcefile().parent_path(), localpath, &openfilenames);
|
||||
if (!fullpath.empty()) {
|
||||
rootmodule->registerInclude(boosty::stringy(localpath), boosty::stringy(fullpath));
|
||||
}
|
||||
|
|
@ -267,17 +273,19 @@ void includefile()
|
|||
std::string fullname = boosty::stringy(fullpath);
|
||||
|
||||
filepath.clear();
|
||||
path_stack.push_back(fullpath.parent_path());
|
||||
filename_stack.push_back(fullpath);
|
||||
|
||||
handle_dep(fullname);
|
||||
|
||||
yyin = fopen(fullname.c_str(), "r");
|
||||
if (!yyin) {
|
||||
PRINTB("WARNING: Can't open include file '%s'.", boosty::stringy(localpath));
|
||||
path_stack.pop_back();
|
||||
filename_stack.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
lineno_stack.push_back(yylineno);
|
||||
yylineno = 1;
|
||||
openfiles.push_back(yyin);
|
||||
openfilenames.push_back(fullname);
|
||||
filename.clear();
|
||||
|
|
@ -294,5 +302,6 @@ void lexerdestroy()
|
|||
for (auto f : openfiles) fclose(f);
|
||||
openfiles.clear();
|
||||
openfilenames.clear();
|
||||
path_stack.clear();
|
||||
filename_stack.clear();
|
||||
lineno_stack.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1695,9 +1695,10 @@ void MainWindow::compileTopLevelDocument()
|
|||
delete this->root_module;
|
||||
this->root_module = NULL;
|
||||
|
||||
this->root_module = parse(fulltext.c_str(),
|
||||
this->fileName.isEmpty() ? "" :
|
||||
QFileInfo(this->fileName).absolutePath().toLocal8Bit(), false);
|
||||
fs::path fname = fs::path(
|
||||
this->fileName.isEmpty() ? "" :
|
||||
QFileInfo(this->fileName).absolutePath().toLocal8Bit());
|
||||
this->root_module = parse(fulltext.c_str(), fname, false);
|
||||
}
|
||||
|
||||
void MainWindow::checkAutoReload()
|
||||
|
|
|
|||
|
|
@ -394,8 +394,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
text += "\n" + commandline_commands;
|
||||
fs::path abspath = boosty::absolute(filename);
|
||||
std::string parentpath = boosty::stringy(abspath.parent_path());
|
||||
root_module = parse(text.c_str(), parentpath.c_str(), false);
|
||||
root_module = parse(text.c_str(), abspath, false);
|
||||
if (!root_module) {
|
||||
PRINTB("Can't parse file '%s'!\n", filename.c_str());
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
extern class FileModule *parse(const char *text, const char *path, int debug);
|
||||
// forward declaration
|
||||
namespace boost { namespace filesystem { class path; }};
|
||||
|
||||
extern class FileModule *parse(const char *text, const boost::filesystem::path &filename, int debug);
|
||||
|
||||
#include <string>
|
||||
extern std::string commandline_commands;
|
||||
|
|
|
|||
18
src/parser.y
18
src/parser.y
|
|
@ -56,6 +56,7 @@ int parserlex(void);
|
|||
void yyerror(char const *s);
|
||||
|
||||
int lexerget_lineno(void);
|
||||
fs::path sourcefile(void);
|
||||
int lexerlex_destroy(void);
|
||||
int lexerlex(void);
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ extern void lexerdestroy();
|
|||
extern FILE *lexerin;
|
||||
extern const char *parser_input_buffer;
|
||||
const char *parser_input_buffer;
|
||||
std::string parser_source_path;
|
||||
fs::path parser_sourcefile;
|
||||
|
||||
%}
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ if_statement:
|
|||
{
|
||||
$<ifelse>$ = new IfElseModuleInstantiation();
|
||||
$<ifelse>$->arguments.push_back(Assignment("", shared_ptr<Expression>($3)));
|
||||
$<ifelse>$->setPath(parser_source_path);
|
||||
$<ifelse>$->setPath(boosty::stringy(parser_sourcefile.parent_path()));
|
||||
scope_stack.push(&$<ifelse>$->scope);
|
||||
}
|
||||
child_statement
|
||||
|
|
@ -299,7 +300,7 @@ single_module_instantiation:
|
|||
{
|
||||
$$ = new ModuleInstantiation($1);
|
||||
$$->arguments = *$3;
|
||||
$$->setPath(parser_source_path);
|
||||
$$->setPath(boosty::stringy(parser_sourcefile.parent_path()));
|
||||
free($1);
|
||||
delete $3;
|
||||
}
|
||||
|
|
@ -590,19 +591,20 @@ int parserlex(void)
|
|||
|
||||
void yyerror (char const *s)
|
||||
{
|
||||
// FIXME: We leak memory on parser errors...
|
||||
PRINTB("ERROR: Parser error in line %d: %s\n", lexerget_lineno() % s);
|
||||
// FIXME: We leak memory on parser errors...
|
||||
PRINTB("ERROR: Parser error in file %s, line %d: %s\n",
|
||||
sourcefile() % lexerget_lineno() % s);
|
||||
}
|
||||
|
||||
FileModule *parse(const char *text, const char *path, int debug)
|
||||
FileModule *parse(const char *text, const fs::path &filename, int debug)
|
||||
{
|
||||
lexerin = NULL;
|
||||
parser_error_pos = -1;
|
||||
parser_input_buffer = text;
|
||||
parser_source_path = boosty::absolute(std::string(path)).string();
|
||||
parser_sourcefile = boosty::absolute(filename);
|
||||
|
||||
rootmodule = new FileModule();
|
||||
rootmodule->setModulePath(path);
|
||||
rootmodule->setModulePath(boosty::stringy(filename.parent_path()));
|
||||
scope_stack.push(&rootmodule->scope);
|
||||
// PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue