eolian: fix error cursor positioning

Previously, multi-char tokens (such as strings, docs etc) always put the error
cursor to the end of the token. That was confusing, so now the cursor always
appears at the beginning of the token instead (for multiline tokens, currently
only docs, the line number is also adjusted to point to the first line of the
doc token).

@fix
This commit is contained in:
Daniel Kolesa 2016-06-13 14:53:35 +01:00
parent 4fd1c4f25b
commit 922e4e9181
2 changed files with 65 additions and 36 deletions

View File

@ -154,8 +154,9 @@ static void next_line(Eo_Lexer *ls)
next_char(ls); next_char(ls);
ls->stream_line = ls->stream; ls->stream_line = ls->stream;
} }
if (++ls->line_number >= INT_MAX) if (++ls->iline_number >= INT_MAX)
eo_lexer_syntax_error(ls, "chunk has too many lines"); eo_lexer_syntax_error(ls, "chunk has too many lines");
ls->line_number = ls->iline_number;
ls->icolumn = ls->column = 0; ls->icolumn = ls->column = 0;
} }
@ -833,10 +834,15 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
case '[': case '[':
{ {
int dline = ls->line_number, dcol = ls->column; int dline = ls->line_number, dcol = ls->column;
const char *sline = ls->stream_line;
next_char(ls); next_char(ls);
if (ls->current != '[') return '['; if (ls->current != '[') return '[';
next_char(ls); next_char(ls);
read_doc(ls, tok, dline, dcol); read_doc(ls, tok, dline, dcol);
ls->column = dcol + 1;
/* doc is the only potentially multiline token */
ls->line_number = dline;
ls->stream_line = sline;
return TOK_DOC; return TOK_DOC;
} }
case '\0': case '\0':
@ -845,11 +851,13 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
next_char(ls); next_char(ls);
if (!ls->expr_mode || (ls->current != '=')) return '='; if (!ls->expr_mode || (ls->current != '=')) return '=';
next_char(ls); next_char(ls);
--ls->column;
return TOK_EQ; return TOK_EQ;
case '!': case '!':
next_char(ls); next_char(ls);
if (!ls->expr_mode || (ls->current != '=')) return '!'; if (!ls->expr_mode || (ls->current != '=')) return '!';
next_char(ls); next_char(ls);
--ls->column;
return TOK_NQ; return TOK_NQ;
case '>': case '>':
next_char(ls); next_char(ls);
@ -857,11 +865,13 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
if (ls->current == '=') if (ls->current == '=')
{ {
next_char(ls); next_char(ls);
--ls->column;
return TOK_GE; return TOK_GE;
} }
else if (ls->current == '>') else if (ls->current == '>')
{ {
next_char(ls); next_char(ls);
--ls->column;
return TOK_RSH; return TOK_RSH;
} }
return '>'; return '>';
@ -871,11 +881,13 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
if (ls->current == '=') if (ls->current == '=')
{ {
next_char(ls); next_char(ls);
--ls->column;
return TOK_LE; return TOK_LE;
} }
else if (ls->current == '<') else if (ls->current == '<')
{ {
next_char(ls); next_char(ls);
--ls->column;
return TOK_LSH; return TOK_LSH;
} }
return '<'; return '<';
@ -883,47 +895,62 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
next_char(ls); next_char(ls);
if (!ls->expr_mode || (ls->current != '&')) return '&'; if (!ls->expr_mode || (ls->current != '&')) return '&';
next_char(ls); next_char(ls);
--ls->column;
return TOK_AND; return TOK_AND;
case '|': case '|':
next_char(ls); next_char(ls);
if (!ls->expr_mode || (ls->current != '|')) return '|'; if (!ls->expr_mode || (ls->current != '|')) return '|';
next_char(ls); next_char(ls);
--ls->column;
return TOK_OR; return TOK_OR;
case '"': case '"':
if (!ls->expr_mode) {
{ int dcol = ls->column;
next_char(ls); if (!ls->expr_mode)
return '"'; {
} next_char(ls);
read_string(ls, tok); return '"';
return TOK_STRING; }
/* strings are not multiline for now at least */
read_string(ls, tok);
ls->column = dcol + 1;
return TOK_STRING;
}
case '\'': case '\'':
next_char(ls); {
if (!ls->expr_mode) return '\''; int dcol = ls->column;
if (ls->current == '\\') next_char(ls);
{ if (!ls->expr_mode) return '\'';
next_char(ls); if (ls->current == '\\')
eina_strbuf_reset(ls->buff); {
read_escape(ls); next_char(ls);
tok->value.c = (char)*eina_strbuf_string_get(ls->buff); eina_strbuf_reset(ls->buff);
} read_escape(ls);
else tok->value.c = (char)*eina_strbuf_string_get(ls->buff);
{ }
tok->value.c = ls->current; else
next_char(ls); {
} tok->value.c = ls->current;
if (ls->current != '\'') next_char(ls);
eo_lexer_lex_error(ls, "unfinished character", TOK_CHAR); }
next_char(ls); if (ls->current != '\'')
return TOK_CHAR; eo_lexer_lex_error(ls, "unfinished character", TOK_CHAR);
next_char(ls);
ls->column = dcol + 1;
return TOK_CHAR;
}
case '.': case '.':
next_char(ls); {
if (!ls->expr_mode) return '.'; int dcol = ls->column;
if (!isdigit(ls->current)) return '.'; next_char(ls);
eina_strbuf_reset(ls->buff); if (!ls->expr_mode) return '.';
eina_strbuf_append_char(ls->buff, '.'); if (!isdigit(ls->current)) return '.';
read_number(ls, tok); eina_strbuf_reset(ls->buff);
return TOK_NUMBER; eina_strbuf_append_char(ls->buff, '.');
read_number(ls, tok);
ls->column = dcol + 1;
return TOK_NUMBER;
}
default: default:
{ {
if (isspace(ls->current)) if (isspace(ls->current))
@ -934,8 +961,10 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
} }
else if (ls->expr_mode && isdigit(ls->current)) else if (ls->expr_mode && isdigit(ls->current))
{ {
int col = ls->column;
eina_strbuf_reset(ls->buff); eina_strbuf_reset(ls->buff);
read_number(ls, tok); read_number(ls, tok);
ls->column = col + 1;
return TOK_NUMBER; return TOK_NUMBER;
} }
if (ls->current && (isalnum(ls->current) if (ls->current && (isalnum(ls->current)
@ -998,7 +1027,7 @@ eo_lexer_set_input(Eo_Lexer *ls, const char *source)
ls->stream_line = ls->stream; ls->stream_line = ls->stream;
ls->source = eina_stringshare_add(source); ls->source = eina_stringshare_add(source);
ls->filename = get_filename(ls); ls->filename = get_filename(ls);
ls->line_number = 1; ls->iline_number = ls->line_number = 1;
ls->icolumn = ls->column = -1; ls->icolumn = ls->column = -1;
ls->decpoint = '.'; ls->decpoint = '.';
next_char(ls); next_char(ls);

View File

@ -136,8 +136,8 @@ typedef struct _Eo_Lexer
* it points to the beginning of it after the lexing is done, icolumn is * it points to the beginning of it after the lexing is done, icolumn is
* token unaware, always pointing to current column */ * token unaware, always pointing to current column */
int column, icolumn; int column, icolumn;
/* the current line number */ /* the current line number, token aware and unaware */
int line_number; int line_number, iline_number;
/* t: "normal" - token to lex into, "lookahead" - a lookahead token, used /* t: "normal" - token to lex into, "lookahead" - a lookahead token, used
* to look one token past "t", when we need to check for a token after the * to look one token past "t", when we need to check for a token after the
* current one and use it in a conditional without consuming the current * current one and use it in a conditional without consuming the current