simplify parser error handling (and allow for wider usage of line infos)

master
Daniel Kolesa 2016-09-29 21:21:21 +02:00
parent cd515a4cff
commit 5d70e2c80f
4 changed files with 47 additions and 34 deletions

View File

@ -357,6 +357,7 @@ private:
struct CsErrorException;
struct CsSharedState;
struct GenState;
enum class CsLoopState {
Normal = 0, Break, Continue
@ -364,6 +365,7 @@ enum class CsLoopState {
struct OSTD_EXPORT CsState {
friend struct CsErrorException;
friend struct GenState;
CsSharedState *p_state;
CsIdentLink *p_callstack = nullptr;
@ -558,6 +560,7 @@ struct OSTD_EXPORT CsState {
private:
CsIdent *add_ident(CsIdent *id);
GenState *p_pstate = nullptr;
int p_inloop = 0;
CsAllocCb p_allocf;

View File

@ -8,30 +8,6 @@
namespace cscript {
static ostd::ConstCharRange cs_get_debug_fmt(
GenState &gs, ostd::ConstCharRange fmt, ostd::CharRange buf
) {
ostd::CharRange r = buf;
if (!gs.src_name.empty()) {
ostd::format(r, "%s:%d: %s", gs.src_name, gs.current_line, fmt);
} else {
ostd::format(r, "%d: %s", gs.current_line, fmt);
}
r.put('\0');
return buf.data();
}
template<typename ...A>
static void cs_error_line(
GenState &gs, ostd::ConstCharRange fmt, A &&...args
) {
ostd::Array<char, 256> buf;
auto rfmt = cs_get_debug_fmt(
gs, fmt, ostd::CharRange(buf.data(), buf.size())
);
throw CsErrorException(gs.cs, rfmt, ostd::forward<A>(args)...);
}
static ostd::ConstCharRange cs_parse_str(ostd::ConstCharRange str) {
while (!str.empty()) {
switch (*str) {
@ -93,7 +69,7 @@ ostd::ConstCharRange GenState::get_str() {
done:
auto ret = ostd::slice_until(beg, source);
if (current() != '\"') {
cs_error_line(*this, "unfinished string '%s'", ln);
throw CsErrorException(cs, "unfinished string '%s'", ln);
}
next_char();
return ret;
@ -152,7 +128,7 @@ void GenState::skip_comments() {
if (current() == '\\') {
char c = current(1);
if ((c != '\r') && (c != '\n')) {
cs_error_line(*this, "invalid line break");
throw CsErrorException(cs, "invalid line break");
}
/* skip backslash */
next_char();
@ -675,7 +651,7 @@ static void compileblockmain(GenState &gs, int wordtype, int prevargs) {
for (int brak = 1; brak;) {
switch (gs.skip_until("@\"/[]")) {
case '\0':
cs_error_line(gs, "missing \"]\"");
throw CsErrorException(gs.cs, "missing \"]\"");
return;
case '\"':
gs.get_str();
@ -704,7 +680,7 @@ static void compileblockmain(GenState &gs, int wordtype, int prevargs) {
if (brak > level) {
continue;
} else if (brak < level) {
cs_error_line(gs, "too many @s");
throw CsErrorException(gs.cs, "too many @s");
return;
}
if (!concs && prevargs >= MaxResults) {
@ -1554,7 +1530,7 @@ endstatement:
switch (gs.skip_until(")];/\n")) {
case '\0':
if (gs.current() != brak) {
cs_error_line(gs, "missing \"%c\"", char(brak));
throw CsErrorException(gs.cs, "missing \"%c\"", char(brak));
return;
}
return;
@ -1564,7 +1540,7 @@ endstatement:
gs.next_char();
return;
}
cs_error_line(gs, "unexpected \"%c\"", gs.current());
throw CsErrorException(gs.cs, "unexpected \"%c\"", gs.current());
return;
case '/':
gs.next_char();

View File

@ -112,6 +112,20 @@ ostd::ConstCharRange CsErrorException::save_msg(
if (msg.size() > sizeof(cs.p_errbuf)) {
msg = msg.slice(0, sizeof(cs.p_errbuf));
}
GenState *gs = cs.p_pstate;
if (gs) {
/* we can attach line number */
ostd::CharRange r(cs.p_errbuf, sizeof(cs.p_errbuf));
ostd::Ptrdiff sz = -1;
if (!gs->src_name.empty()) {
sz = ostd::format(r, "%s:%d: %s", gs->src_name, gs->current_line, msg);
} else {
sz = ostd::format(r, "%d: %s", gs->current_line, msg);
}
if (sz > 0) {
return ostd::ConstCharRange(cs.p_errbuf, sz);
}
}
memcpy(cs.p_errbuf, msg.data(), msg.size());
return ostd::ConstCharRange(cs.p_errbuf, msg.size());
}
@ -185,6 +199,7 @@ static inline ostd::Uint32 *forcecode(CsState &cs, CsValue &v) {
GenState gs(cs);
gs.code.reserve(64);
gs.gen_main(v.get_str());
gs.done();
v.set_code(reinterpret_cast<CsBytecode *>(gs.code.release() + 1));
code = reinterpret_cast<ostd::Uint32 *>(v.get_code());
}
@ -895,6 +910,7 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
gs.code.push(CsCodeExit);
break;
}
gs.done();
arg.set_code(
reinterpret_cast<CsBytecode *>(gs.code.release() + 1)
);
@ -911,6 +927,7 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
GenState gs(cs);
gs.code.reserve(64);
gs.gen_main(s);
gs.done();
arg.set_code(reinterpret_cast<CsBytecode *>(
gs.code.release() + 1
));
@ -1587,8 +1604,8 @@ static void cs_run(
GenState gs(cs);
gs.src_name = file;
gs.code.reserve(64);
/* FIXME range */
gs.gen_main(code.data(), CsValAny);
gs.gen_main(code, CsValAny);
gs.done();
runcode(cs, gs.code.data() + 1, ret);
if (int(gs.code[0]) >= 0x100) {
gs.code.release();

View File

@ -111,6 +111,8 @@ constexpr ostd::Size CsTypeStorageSize =
struct GenState {
CsState &cs;
GenState *prevps;
bool parsing = true;
CsVector<ostd::Uint32> code;
ostd::ConstCharRange source;
int current_line;
@ -118,8 +120,23 @@ struct GenState {
GenState() = delete;
GenState(CsState &csr):
cs(csr), code(), source(nullptr), current_line(1), src_name()
{}
cs(csr), prevps(csr.p_pstate), code(),
source(nullptr), current_line(1), src_name()
{
csr.p_pstate = this;
}
~GenState() {
done();
}
void done() {
if (!parsing) {
return;
}
cs.p_pstate = prevps;
parsing = false;
}
ostd::ConstCharRange get_str();
CsString get_str_dup(bool unescape = true);