diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2015-11-24 17:30:09 +0000 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2015-11-24 17:30:09 +0000 |
commit | a6a6ee4f86f354477e4b5d374dba4c4e90d03df6 (patch) | |
tree | 4afdaa2aa73ad8c2a666dacbec8c58a376ee4c67 | |
parent | 5e6124ea7eb07797e2df2d8ea5aa07e951ed4168 (diff) | |
parent | 0cde41427841ad6f031175e9312f536837e40d35 (diff) | |
download | lace-a6a6ee4f86f354477e4b5d374dba4c4e90d03df6.tar.gz |
Merge branch 'subword-errors' of git://git.gitano.org.uk/personal/richardmaw/lacev1.2
-rw-r--r-- | lib/lace/builtin.lua | 17 | ||||
-rw-r--r-- | lib/lace/error.lua | 67 | ||||
-rw-r--r-- | lib/lace/lex.lua | 4 | ||||
-rw-r--r-- | test/test-lace.engine.lua | 4 |
4 files changed, 73 insertions, 19 deletions
diff --git a/lib/lace/builtin.lua b/lib/lace/builtin.lua index 147da6a..b0c7ad1 100644 --- a/lib/lace/builtin.lua +++ b/lib/lace/builtin.lua @@ -35,7 +35,12 @@ local function run_conditions(exec_context, cond, anyof) end local res, msg = engine.test(exec_context, name) if res == nil then - msg.words = {i} + local subwords = msg.words + if subwords and #subwords > 0 then + msg.words = {{nr = i, sub = subwords}} + else + msg.words = {i} + end return nil, msg end if invert then @@ -208,7 +213,15 @@ local function _compile_any_all_of(compcontext, mtype, first, second, ...) end return { - fn = run_conditions, + fn = (function(exec_context, cond, anyof) + local pass, msg = run_conditions(exec_context, cond, anyof) + if pass == nil then + -- Offset error location by anyof/allof word + err.offset(msg, 1) + return nil, msg + end + return pass, msg + end), args = { { first, second, ...}, mtype == "anyof" } } end diff --git a/lib/lace/error.lua b/lib/lace/error.lua index 96998bd..6277233 100644 --- a/lib/lace/error.lua +++ b/lib/lace/error.lua @@ -49,7 +49,12 @@ local function _offset(err, offs) err.words = {} end for k, w in ipairs(err.words) do - err.words[k] = w + offs + if type(w) == "table" then + nr = w.nr + err.words[k] = {nr = nr + offs, sub=w.sub} + else + err.words[k] = w + offs + end end return err end @@ -96,23 +101,55 @@ local function _render(err) ret[3] = srcline.original -- The fourth line is the highlight for each word in question local wordset = {} - for _, word in ipairs(err.words) do - wordset[word] = true - end - local hlstr = "" - local cpos = 1 - for w, info in ipairs(srcline.content) do - -- Ensure that we're up to the start position of the word - while (cpos < info.spos) do - hlstr = hlstr .. " " - cpos = cpos + 1 + local function build_wordset(words, wordset) + for _, word in ipairs(words) do + if type(word) ~= "table" then + wordset[word] = true + else + local subwordset = {} + build_wordset(word.sub, subwordset) + wordset[word.nr] = subwordset + end end - -- Highlight this word if appropriate - while (cpos <= info.epos) do - hlstr = hlstr .. (wordset[w] and "^" or " ") - cpos = cpos + 1 + end + build_wordset(err.words, wordset) + + local function mark_my_words(line, wordset) + local hlstr, cpos = "", 1 + for w, info in ipairs(line) do + -- Ensure that we're up to the start position of the word + while (cpos < info.spos) do + hlstr = hlstr .. " " + cpos = cpos + 1 + end + -- TODO: The subword can be defined in a different line entirely, + -- at which point it's not a subword of word in this line. + -- This is the norm for explicit definitions. + -- Eventually we should trace back to the define's + -- definition and highlight where in that line the problem is. + if type(wordset[w]) == "table" and info.sub then + -- space for [ + hlstr, cpos = hlstr .. " ", cpos + 1 + + -- mark subword + local subhlstr, subcpos = mark_my_words(info.sub, wordset[w]) + hlstr = hlstr .. subhlstr + cpos = cpos + subcpos + + -- space for ] + hlstr, cpos = hlstr .. " ", cpos + 1 + else + -- Highlight this word if appropriate + while (cpos <= info.epos) do + hlstr = hlstr .. (wordset[w] and "^" or " ") + cpos = cpos + 1 + end + end end + return hlstr, cpos end + local hlstr, _ = mark_my_words(srcline.content, wordset) + ret[4] = hlstr -- The rendered error is those four strings joined by newlines return table.concat(ret, "\n") diff --git a/lib/lace/lex.lua b/lib/lace/lex.lua index d7d18da..3bd9ec2 100644 --- a/lib/lace/lex.lua +++ b/lib/lace/lex.lua @@ -46,6 +46,10 @@ local function _lex_one_line(line, terminator) else if c == terminator and quoting == false then -- Reached the terminator, break out + -- The terminator is not actually part of the last word in the line + -- so we push back that character, + -- since it's the only case we actually need to put any back. + cpos = cpos - 1 break elseif c == "'" and quoting == false then -- Start single quotes diff --git a/test/test-lace.engine.lua b/test/test-lace.engine.lua index c5f7751..936a2ed 100644 --- a/test/test-lace.engine.lua +++ b/test/test-lace.engine.lua @@ -263,7 +263,7 @@ function suite.subdefine_err_reported() assert(line1 == "woah", "The first line must mention the error") assert(line2 == "real-subdefine-error :: 2", "The second line is where the error happened") assert(line3 == 'allow "Yay" [error]', "The third line is the original line") - assert(line4 == " ^^^^^^^", "The fourth line highlights relevant words") + assert(line4 == " ^^^^^ ", "The fourth line highlights relevant words") end function suite.subsubdefine_works() @@ -286,7 +286,7 @@ function suite.subsubdefine_err_reported() assert(line1 == "woah", "The first line must mention the error") assert(line2 == "real-subsubdefine-error :: 1", "The second line is where the error happened") assert(line3 == 'allow "FAIL" [anyof [equal jeff banana] [error]]', "The third line is the original line") - assert(line4 == " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", "The fourth line highlights relevant words") + assert(line4 == " ^^^^^ ", "The fourth line highlights relevant words") end local count_ok = 0 |