diff options
| author | Bruce Hill <bitbucket@bruce-hill.com> | 2017-09-05 22:58:27 -0700 |
|---|---|---|
| committer | Bruce Hill <bitbucket@bruce-hill.com> | 2017-09-05 22:58:27 -0700 |
| commit | 7e9bacfb20365a20da0fa9f2fb61a207402ab737 (patch) | |
| tree | ced0f598bba97ab8cfc9955709c8ec734ca166d0 | |
| parent | 2e9a3cdf009e80caced01f81dc34d2968346d429 (diff) | |
Overhaul of error messages. Much cleaner now.
| -rw-r--r-- | nomic.moon | 52 |
1 files changed, 27 insertions, 25 deletions
@@ -16,7 +16,6 @@ get_line_indentation = (line)-> for c in leading_space\gmatch "[\t ]" sum += indent_amounts[c] - class Game new:(parent)=> @defs = setmetatable({}, {__index:parent and parent.defs}) @@ -112,9 +111,6 @@ class Game replacement_grammar = re.compile(replace_grammar, defs) replaced = replacement_grammar\match(replacement) tree = lingo\match replaced - if tree.value.errors and #tree.value.errors.value > 0 - ret = helpers.transform(tree.value.errors) - return ret result = helpers.transform(tree.value.body) helpers.lua(result) return @@ -148,8 +144,8 @@ class Game if @debug print("PARSING:\n#{str}") lingo = [=[ - file <- ({ {| %new_line? {:body: block :} %new_line? ({:errors: errors :})? |} }) -> File - errors <- ({ {.+} }) -> Errors + file <- ({ {| %new_line? {:body: block :} %new_line? (errors)? |} }) -> File + errors <- (({.+}) => error_handler) block <- ({ {| statement (%new_line statement)* |} }) -> Block statement <- ({ (functioncall / expression) }) -> Statement one_liner <- ({ {| @@ -172,14 +168,14 @@ class Game thunk <- ({ ":" %ws? - ((%indent %new_line block %dedent (%new_line "..")?) + ((%indent %new_line block ((%dedent (%new_line "..")?) / errors)) / (one_liner (%ws? (%new_line? ".."))?)) }) -> Thunk word <- ({ !number {%wordchar+} }) -> Word expression <- ({ (longstring / string / number / variable / list / thunk / subexpression) }) -> Expression string <- ({ (!('"..' %ws? %nl)) '"' {(("\" .) / [^"])*} '"' }) -> String - longstring <- ({ '"..' %ws? %indent %nl {(!%dedent .)* (%nl %ws? %eol)*} %new_line '.."' }) -> Longstring + longstring <- ({ '"..' %ws? %indent %nl {(!%dedent .)* (%nl %ws? %eol)*} ((%new_line '.."') / errors) }) -> Longstring number <- ({ {'-'? [0-9]+ ("." [0-9]+)?} }) -> Number variable <- ({ ("%" {%wordchar+}) }) -> Var @@ -188,7 +184,7 @@ class Game / ("(..)" %ws? %indent %new_line ((({ {| indented_fn_bits |} }) -> FunctionCall) / expression) %dedent (%new_line "..")?) list <- ({ {| - ("[..]" %ws? %indent %new_line indented_list ","? %dedent (%new_line "..")?) + ("[..]" %ws? %indent %new_line indented_list ","? ((%dedent (%new_line "..")?) / errors)) / ("[" %ws? (list_items ","?)? %ws?"]") |} }) -> List list_items <- (expression (list_sep list_items)?) @@ -227,12 +223,28 @@ class Game indent: #(nl * blank_line^0 * Cmt(spaces^-1, check_indent)) dedent: #(nl * blank_line^0 * Cmt(spaces^-1, check_dedent)) new_line: nl * blank_line^0 * Cmt(spaces^-1, check_nodent) + error_handler: (src,pos,errors)-> + line_no = 1 + for _ in src\sub(1,-#errors)\gmatch("\n") do line_no += 1 + err_pos = #src - #errors + 1 + if errors\sub(1,1) == "\n" + -- Indentation error + err_pos += #errors\match("[ \t]*", 2) + start_of_err_line = err_pos + while src\sub(start_of_err_line, start_of_err_line) != "\n" do start_of_err_line -= 1 + start_of_prev_line = start_of_err_line - 1 + while src\sub(start_of_prev_line, start_of_prev_line) != "\n" do start_of_prev_line -= 1 + + prev_line,err_line,next_line = src\match("([^\n]*)\n([^\n]*)\n([^\n]*)", start_of_prev_line+1) + + pointer = ("-")\rep(err_pos - start_of_err_line + 1) .. "^" + error("\nParse error on line #{line_no}:\n|#{prev_line}\n|#{err_line}\n#{pointer}\n|#{next_line}") setmetatable(defs, { __index: (t,key)-> --print("WORKING for #{key}") - fn = (src, value, ...)-> - token = {type: key, src:src, value: value} + fn = (src, value, errors)-> + token = {type: key, :src, :value, :errors} return token t[key] = fn return fn @@ -245,13 +257,14 @@ class Game assert tree, "Failed to parse: #{str}" return tree - transform: (tree, indent_level=0, parent=nil)=> + transform: (tree, indent_level=0, parent=nil, src=nil)=> + if src == nil then src = tree.src indented = (fn)-> export indent_level indent_level += 1 fn! indent_level -= 1 - transform = (t,parent)-> self\transform(t, indent_level, parent or tree) + transform = (t,parent)-> self\transform(t, indent_level, parent or tree, src) ind = (line) -> (" ")\rep(indent_level)..line ded = (lines)-> if not lines.match then error("WTF: #{utils.repr(lines)}") @@ -283,10 +296,6 @@ class Game switch tree.type when "File" - if tree.value.errors and #tree.value.errors.value > 0 - ret = transform(tree.value.errors) - return ret - lua "return (function(game, vars)" indented -> lua "local ret" @@ -294,10 +303,6 @@ class Game lua "return ret" lua "end)" - when "Errors" - -- TODO: Better error reporting via tree.src - error("\nParse error on: #{utils.repr(tree.value\match("[^\n]*"), true)}") - when "Block" for chunk in *tree.value lua transform(chunk) @@ -473,10 +478,7 @@ class Game test_src, expected = test\sub(1,start-1), test\sub(stop+1,-1) expected = expected\match'[\n]*(.*[^\n])' tree = self\parse(test_src) - got = if tree.value.errors and #tree.value.errors.value > 0 - self\stringify_tree(tree.value.errors) - else - self\stringify_tree(tree.value.body) + got = self\stringify_tree(tree.value.body) if got != expected error"TEST FAILED!\nSource:\n#{test_src}\nExpected:\n#{expected}\n\nGot:\n#{got}" |
