From e64a91b8ba7e0d2cd4af4154e3b9adcccb299854 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 3 May 2018 16:30:55 -0700 Subject: Better error reporting and codegen. --- nomsu.moon | 61 ++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'nomsu.moon') diff --git a/nomsu.moon b/nomsu.moon index 2dca565..81448aa 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -155,21 +155,27 @@ NOMSU_DEFS = with {} if @sub(start, start+#nodent-1) == nodent return start + #nodent - .error = (src,pos,err_msg)-> - --src = tostring(FILE_CACHE[lpeg.userdata.source_code.source.filename]) - if src\sub(pos,pos)\match("[\r\n]") - pos += #src\match("[ \t\n\r]*", pos) - line_no = 1 - text_loc = lpeg.userdata.source_code.source\sub(pos,pos) + .error = (src,end_pos,start_pos,err_msg)-> + seen_errors = lpeg.userdata.errors + if seen_errors[start_pos] + return true + err_pos = start_pos + --if src\sub(err_pos,err_pos)\match("[\r\n]") + -- err_pos += #src\match("[ \t\n\r]*", err_pos) + text_loc = lpeg.userdata.source_code.source\sub(err_pos,err_pos) line_no = text_loc\get_line_number! src = FILE_CACHE[text_loc.filename] - prev_line = src\sub(LINE_STARTS[src][line_no-1] or 1, LINE_STARTS[src][line_no]-2) + prev_line = line_no == 1 and "" or src\sub(LINE_STARTS[src][line_no-1] or 1, LINE_STARTS[src][line_no]-2) err_line = src\sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no+1] or 0)-2) next_line = src\sub(LINE_STARTS[src][line_no+1] or -1, (LINE_STARTS[src][line_no+2] or 0)-2) - pointer = ("-")\rep(pos-LINE_STARTS[src][line_no]) .. "^" - err_msg = (err_msg or "Parse error").." in #{lpeg.userdata.source_code.source.filename} on line #{line_no}:\n" - err_msg ..="\n#{prev_line}\n#{err_line}\n#{pointer}\n#{next_line}\n" - error(err_msg) + pointer = ("-")\rep(err_pos-LINE_STARTS[src][line_no]) .. "^" + err_msg = (err_msg or "Parse error").." at #{lpeg.userdata.source_code.source.filename}:#{line_no}:\n" + if #prev_line > 0 then err_msg ..= "\n"..prev_line + err_msg ..= "\n#{err_line}\n#{pointer}" + if #next_line > 0 then err_msg ..= "\n"..next_line + --error(err_msg) + seen_errors[start_pos] = err_msg + return true setmetatable(NOMSU_DEFS, {__index:(key)=> make_node = (start, value, stop)-> @@ -279,7 +285,6 @@ class NomsuCompiler -- TODO: repair error("Not currently functional.", 0) - -- TODO: figure out whether indent/dedent should affect first line dedent: (code)=> unless code\find("\n") return code @@ -307,7 +312,7 @@ class NomsuCompiler FILE_CACHE[filename] = nomsu_code nomsu_code = Nomsu(filename, nomsu_code) userdata = { - source_code:nomsu_code, indent_stack: {""} + source_code:nomsu_code, indent_stack: {""}, errors: {}, } old_userdata, lpeg.userdata = lpeg.userdata, userdata @@ -315,6 +320,13 @@ class NomsuCompiler lpeg.userdata = old_userdata assert tree, "In file #{colored.blue filename} failed to parse:\n#{colored.onyellow colored.black nomsu_code}" + + if next(userdata.errors) + keys = utils.keys(userdata.errors) + table.sort(keys) + errors = [userdata.errors[k] for k in *keys] + error(concat(errors, "\n\n"), 0) + return tree _nomsu_chunk_counter = 0 @@ -663,7 +675,7 @@ if arg and debug_getinfo(2).func != require export colors colors = require 'consolecolors' parser = re.compile([[ - args <- {| (flag ";")* {:inputs: {| ({file} ";")* |} :} |} ";"? !. + args <- {| (flag ";")* {:inputs: {| ({file} ";")* |} :} {:nomsu_args: {| ("--;" ({[^;]*} ";")*)? |} :} ";"? |} !. flag <- {:interactive: ("-i" -> true) :} / {:verbose: ("-v" -> true) :} @@ -681,7 +693,7 @@ if arg and debug_getinfo(2).func != require print [=[ Nomsu Compiler -Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-f] [-s] [--help] [-o output] [-p print_file] file1 file2... +Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-f] [-s] [--help] [-o output] [-p print_file] file1 file2... [-- nomsu args...] OPTIONS -i Run the compiler in interactive mode (REPL) @@ -697,6 +709,7 @@ OPTIONS os.exit! nomsu = NomsuCompiler! + nomsu.environment.arg = args.nomsu_args ok, to_lua = pcall -> require('moonscript.base').to_lua if not ok then to_lua = nil @@ -820,14 +833,17 @@ OPTIONS output_file\write("local IMMEDIATE = true;\n"..tostring(code)) output_file\flush! + parse_errs = {} for input in *args.inputs if args.syntax -- Check syntax: for input_file in all_files(input) - nomsu\parse(io.open(input_file)\read("*a")) - if print_file - print_file\write("All files parsed successfully!\n") - print_file\flush! + ok,err = pcall nomsu.parse, nomsu, Nomsu(input_file, io.open(input_file)\read("*a")) + if not ok + insert parse_errs, err + elseif print_file + print_file\write("Parse succeeded: #{input_file}\n") + print_file\flush! elseif args.format -- Auto-format for input_file in all_files(input) @@ -844,6 +860,13 @@ OPTIONS else nomsu\run_file(input, compile_fn) + if #parse_errs > 0 + io.stderr\write concat(parse_errs, "\n\n") + io.stderr\flush! + os.exit(false, true) + elseif args.syntax + os.exit(true, true) + if args.interactive -- REPL while true -- cgit v1.2.3