Rez: better error reporting

This commit is contained in:
Wolfgang Thaller 2015-07-19 00:59:46 +02:00
parent ee00fe1ec5
commit d26d88f5ee
11 changed files with 99 additions and 29 deletions

View File

@ -13,5 +13,16 @@ Diagnostic::Diagnostic(Severity sev, std::string msg, yy::location loc)
std::ostream &operator<<(std::ostream &out, const Diagnostic &d)
{
return out << d.location << ": " << d.message;
//return out << d.location << ": " << d.message;
const yy::location& loc = d.location;
if (loc.begin.filename)
out << *loc.begin.filename << ':';
out << loc.begin.line << ':' << loc.begin.column;
out << ": ";
if(d.severity >= Diagnostic::error)
out << "error";
else
out << "warning";
out << ": " << d.message;
return out;
}

View File

@ -147,7 +147,8 @@ int ResourceCompiler::getArrayIndex(const std::string &arrayName)
void ResourceCompiler::problem(Diagnostic d)
{
world.problem(d);
if(prePass)
world.problem(d);
}
void ResourceCompiler::beginArrayScope(std::string &arrayName, int index)

View File

@ -3,7 +3,7 @@
#include <cassert>
#include "ResourceCompiler.h"
#include "Diagnostic.h"
std::ostream &operator<<(std::ostream &out, TypeSpec ts)
@ -40,10 +40,20 @@ void FieldList::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
for(FieldPtr f : fields)
{
if(f->needsValue())
f->compile(compound->getItem(i++), compiler, prePass);
{
if(i >= compound->size())
compiler->problem(Diagnostic(Diagnostic::error,"not enough values specified", compound->location));
else
f->compile(compound->getItem(i++), compiler, prePass);
}
else
f->compile(nullptr, compiler, prePass);
}
if(i < compound->size())
{
compiler->problem(Diagnostic(Diagnostic::error,"extra value specified",
compound->getItem(i)->location));
}
}

View File

@ -10,6 +10,7 @@
#include "ResourceFork.h"
#include "BinaryIO.h"
#include "ResourceFile.h"
#include "Diagnostic.h"
namespace po = boost::program_options;
namespace fs = boost::filesystem;
@ -94,23 +95,34 @@ int main(int argc, const char *argv[])
if(options.count("input"))
for(std::string fn : options["input"].as<std::vector<std::string>>())
{
RezLexer lexer(fn);
try
{
RezLexer lexer(world, fn);
if(options.count("define"))
for(std::string define : options["define"].as<std::vector<std::string>>())
lexer.addDefine(define);
if(options.count("include"))
for(std::string path : options["include"].as<std::vector<std::string>>())
lexer.addIncludePath(path);
if(options.count("define"))
for(std::string define : options["define"].as<std::vector<std::string>>())
lexer.addDefine(define);
if(options.count("include"))
for(std::string path : options["include"].as<std::vector<std::string>>())
lexer.addIncludePath(path);
RezParser parser(lexer, world);
parser.parse();
RezParser parser(lexer, world);
parser.parse();
}
catch(...)
{
world.problem(Diagnostic(Diagnostic::fatalError,"unknown error",yy::location(&fn)));
}
}
if(world.hadErrors)
return 1;
rsrcFile.resources = world.getResources();
rsrcFile.creator = options["creator"].as<std::string>();
rsrcFile.type = options["type"].as<std::string>();
rsrcFile.write();
return 0;
}

View File

@ -6,6 +6,8 @@
#include <boost/regex.hpp>
#include "RezLexerWaveToken.h"
#include "RezWorld.h"
#include "Diagnostic.h"
namespace wave = boost::wave;
@ -88,12 +90,13 @@ struct RezLexer::Priv
}
};
RezLexer::RezLexer(std::string filename)
: RezLexer(filename, readContents(std::ifstream(filename)))
RezLexer::RezLexer(RezWorld& world, std::string filename)
: RezLexer(world, filename, readContents(std::ifstream(filename)))
{
}
RezLexer::RezLexer(std::string filename, const std::string &data)
RezLexer::RezLexer(RezWorld& world, std::string filename, const std::string &data)
: world(world), curFile(filename), lastLocation(&curFile)
{
pImpl.reset(new Priv(preFilter(data), filename));
@ -129,12 +132,32 @@ bool RezLexer::atEnd()
RezLexer::WaveToken RezLexer::nextWave()
{
if(pImpl->iter == pImpl->ctx.end())
return WaveToken();
else
try
{
WaveToken tok = *pImpl->iter++;
return tok;
if(pImpl->iter == pImpl->ctx.end())
return WaveToken();
else
{
WaveToken tok = *pImpl->iter++;
return tok;
}
}
catch(preprocess_exception e)
{
curFile = e.file_name();
auto yypos = yy::position(&curFile, e.line_no(), e.column_no());
yy::location loc(yypos);
lastLocation = loc;
world.problem(Diagnostic(
e.severity_level(e.get_errorcode()) >= util::severity_error
? Diagnostic::error
: Diagnostic::warning,
preprocess_exception::error_text(e.get_errorcode()), loc));
if(e.is_recoverable())
return nextWave();
else
return WaveToken();
}
}

View File

@ -4,14 +4,19 @@
#include <memory>
#include <string>
#include "location.hh"
class RezSymbol;
class RezWorld;
class RezLexer
{
RezWorld& world;
struct Priv;
std::unique_ptr<Priv> pImpl;
std::string curFile;
yy::location lastLocation;
class WaveToken;
@ -20,8 +25,8 @@ class RezLexer
WaveToken peekWave();
public:
RezLexer(std::string filename);
RezLexer(std::string filename, const std::string& data);
RezLexer(RezWorld& world, std::string filename);
RezLexer(RezWorld& world, std::string filename, const std::string& data);
~RezLexer();
RezSymbol nextToken();

View File

@ -155,6 +155,7 @@ RezSymbol RezLexer::nextToken()
curFile = pos.get_file().c_str();
auto yypos = yy::position(&curFile, pos.get_line(), pos.get_column());
yy::location loc(yypos);
lastLocation = loc;
if(tok == (UnknownTokenType | '"'))
{

View File

@ -7,7 +7,7 @@
#include "Diagnostic.h"
RezWorld::RezWorld()
: verboseFlag(false)
: verboseFlag(false), hadErrors(false)
{
}
@ -53,5 +53,6 @@ void RezWorld::addData(ResSpec spec, const std::string &data, yy::location loc)
void RezWorld::problem(Diagnostic d)
{
hadErrors = true;
std::cerr << d << std::endl;
}

View File

@ -34,6 +34,7 @@ public:
Resources& getResources() { return resources; }
bool verboseFlag;
bool hadErrors;
void problem(Diagnostic d);
};

View File

@ -6,6 +6,7 @@
#include "RezLexer.h"
#include "RezParser.generated.hh"
#include "ResourceCompiler.h"
#include "RezWorld.h"
#include <iostream>
@ -26,7 +27,8 @@ BOOST_AUTO_TEST_SUITE(LexSuite)
BOOST_AUTO_TEST_CASE(basicInt)
{
RezLexer lex("test", "123 0x456 0xaBcd9\n");
RezWorld world;
RezLexer lex(world, "test", "123 0x456 0xaBcd9\n");
CHECKSYM(RezParser::token::INTLIT, int, 123);
CHECKSYM(RezParser::token::INTLIT, int, 0x456);
@ -36,7 +38,8 @@ BOOST_AUTO_TEST_CASE(basicInt)
BOOST_AUTO_TEST_CASE(alternateHex)
{
RezLexer lex("test", "$456 $aBcd9\n");
RezWorld world;
RezLexer lex(world, "test", "$456 $aBcd9\n");
CHECKSYM(RezParser::token::INTLIT, int, 0x456);
CHECKSYM(RezParser::token::INTLIT, int, 0xabcd9);
@ -45,7 +48,8 @@ BOOST_AUTO_TEST_CASE(alternateHex)
BOOST_AUTO_TEST_CASE(noNewlineAtEOF)
{
RezLexer lex("test", "123 456");
RezWorld world;
RezLexer lex(world, "test", "123 456");
CHECKSYM(RezParser::token::INTLIT, int, 123);
CHECKSYM(RezParser::token::INTLIT, int, 456);
CHECKSYM_(0);
@ -53,7 +57,8 @@ BOOST_AUTO_TEST_CASE(noNewlineAtEOF)
BOOST_AUTO_TEST_CASE(strings)
{
RezLexer lex("test", R"rez(
RezWorld world;
RezLexer lex(world, "test", R"rez(
"Hello, world."
"Foo \n"
"\r Quux"

View File

@ -26,7 +26,7 @@ QDGlobals qd;
pascal void ButtonFrameProc(DialogRef dlg, DialogItemIndex itemNo)
{
DialogItemType type;
Handle itemH;
Handle itemH;
Rect box;
GetDialogItem(dlg, 1, &type, &itemH, &box);