diff options
Diffstat (limited to 'lua/lexers/output.lua')
| -rw-r--r-- | lua/lexers/output.lua | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/lua/lexers/output.lua b/lua/lexers/output.lua new file mode 100644 index 0000000..0ff9f1c --- /dev/null +++ b/lua/lexers/output.lua @@ -0,0 +1,97 @@ +-- Copyright 2022-2024 Mitchell. See LICENSE. +-- LPeg lexer for tool output. +-- If a warning or error is recognized, tags its filename, line, column (if available), +-- and message, and sets the line state to 1 for an error (first bit), and 2 for a warning +-- (second bit). +-- This is similar to Lexilla's errorlist lexer. + +local lexer = lexer +local starts_line = lexer.starts_line +local P, S = lpeg.P, lpeg.S + +local lex = lexer.new(..., {lex_by_line = true}) + +-- Tags a pattern as plain text. +local function text(patt) return lex:tag(lexer.DEFAULT, patt) end + +-- Tags a pattern as a filename. +local function filename(patt) return lex:tag('filename', patt) end + +-- Typical line and column number patterns. +local line = text('line ')^-1 * lex:tag('line', lexer.dec_num) +local column = lex:tag('column', lexer.dec_num) + +-- Tags a pattern as an error/warning/etc. message. +local function message(patt) return lex:tag('message', patt) end + +-- Immediately marks the current line as an error. +-- This should only be specified at the end of a rule, or else LPeg may backtrack and mistakenly +-- mark a non-error line. +local function mark_error(_, pos) + lexer.line_state[lexer.line_from_position(pos)] = 1 + return true +end + +-- Immediately marks the current line as a warning. +-- This should only be specified at the end of a rule, or else LPeg may backtrack and mistakenly +-- mark a non-warning line. +local function mark_warning(_, pos) + lexer.line_state[lexer.line_from_position(pos)] = 2 + return true +end + +-- filename:line: message (ruby) +-- filename:line:col: message (c, cpp, go, ...) +-- filename: line X: message (bash) +local c_filename = filename((lexer.nonnewline - ':')^1) +local colon = text(':' * P(' ')^-1) +local warning = message(lexer.to_eol('warning: ')) * mark_warning +local note = message(lexer.to_eol('note: ')) -- do not mark +local error = message(lexer.to_eol()) * mark_error +lex:add_rule('common', starts_line(c_filename) * colon * line * colon * (column * colon)^-1 * + (warning + note + error)) + +-- prog: filename:line: message (awk, lua) +lex:add_rule('prog', starts_line(text(lexer.word)) * colon * c_filename * colon * line * colon * + (warning + error)) + +-- File "filename", line X (python) +local py_filename = filename((lexer.nonnewline - '"')^1) +lex:add_rule('python', + starts_line(text('File "'), true) * py_filename * text('", ') * line * mark_error) + +-- filename(line): error: message (d, cuda) +local lparen, rparen = text('('), text(')') +local d_filename = filename((lexer.nonnewline - '(')^1) +local d_error = message(lexer.to_eol(S('Ee') * 'rror')) * mark_error +lex:add_rule('dmd', starts_line(d_filename) * lparen * line * rparen * colon * d_error) + +-- "filename" line X: message (gnuplot) +local gp_filename = filename((lexer.nonnewline - '"')^1) +lex:add_rule('gnuplot', starts_line(text('"')) * gp_filename * text('" ') * line * colon * error) + +-- at com.path(filename:line) (java) +lex:add_rule('java', + starts_line(text('at ' * (lexer.nonnewline - '(')^1), true) * lparen * c_filename * colon * line * + rparen * mark_error) + +-- message in filename on line X (php) +lex:add_rule('php', starts_line(message((lexer.nonnewline - ' in ')^1)) * text(' in ') * + filename((lexer.nonnewline - ' on ')^1) * text(' on ') * line * mark_error) + +-- filename(line, col): message (vb, csharp, fsharp, ...) +lex:add_rule('vb', + starts_line(filename((lexer.nonnewline - '(')^1)) * lparen * line * text(', ') * column * rparen * + colon * error) + +-- message at filename line X (perl) +lex:add_rule('perl', starts_line(message((lexer.nonnewline - ' at ')^1)) * text(' at ') * + filename((lexer.nonnewline - ' line ')^1) * text(' line ') * line * mark_error) + +-- CMake Error at filename:line: (cmake) +lex:add_rule('cmake', + starts_line(text('CMake Error at ')) * c_filename * colon * line * colon * mark_error) + +lex:add_rule('any_line', lex:tag(lexer.DEFAULT, lexer.to_eol())) + +return lex |
