Permalink
Browse files

improve error reporting

* highlight Atomy internals in backtraces as cyan
  * Rubinius does the same thing, except with blue
* highlight macroexpansions in backtraces as green, and show the expanding
  node's source location
* make toplevel Condition-style errors consistent with Ruby exception reports
* remove 'while expanding/loading X' progress reports now that the backtrace
  should be helpful enough
  • Loading branch information...
1 parent 9b9f354 commit e618993e260ece324464ff0a04a23e017815cc96 @vito committed Jun 14, 2012
Showing with 214 additions and 56 deletions.
  1. +1 −1 bin/atomy
  2. +21 −18 kernel/condition.ay
  3. +5 −0 kernel/repl.ay
  4. +168 −0 lib/atomy/backtrace.rb
  5. +10 −20 lib/atomy/boot.rb
  6. +7 −3 lib/atomy/code_loader.rb
  7. +2 −14 lib/atomy/module.rb
View
@@ -66,7 +66,7 @@ def run_atomy(options)
if file = options[:load] || ARGV[0]
$0 = file
run = ARGV.shift
- Atomy.load(file, options[:debug])
+ Atomy.run(file, options[:debug])
return if run
end
View
@@ -106,13 +106,12 @@ error(x) := do:
ExceptionError new(x) tap [err]:
err backtrace = x locations
- Error ->
- x tap [err]:
- err backtrace = Rubinius VM backtrace(0)
+ Error -> x
- _ ->
- SimpleError new(x) tap [err]:
- err backtrace = Rubinius VM backtrace(0)
+ _ -> SimpleError new(x)
+
+ unless(e backtrace):
+ e backtrace = Rubinius VM backtrace(1, true)
signal(e)
@@ -124,13 +123,11 @@ warning(x) :=
with-restarts(muffle-warning -> nil):
w =
x match:
- Warning ->
- x tap [wrn]:
- wrn backtrace = Rubinius VM backtrace(0)
+ Warning -> x
+
+ _ -> SimpleWarning new(x)
- _ ->
- SimpleWarning new(x) tap [wrn]:
- wrn backtrace = Rubinius VM backtrace(0)
+ w backtrace = Rubinius VM backtrace(1, true)
signal(w)
@@ -143,25 +140,31 @@ warning(x) :=
data(DefaultDebugger(@error))
DefaultDebugger(e) show-banner := do:
- puts("-" * 78)
- (e name + ": " + e message) split("\n") each [l]:
- puts("*** " + l)
+ puts("An error occurred:")
+
+ (msg . desc) = e message to-s split("\n")
+
+ puts(" " + msg + " (" + e name + ")")
+
+ desc each [l]:
+ puts(l)
DefaultDebugger(e) show-restarts := do:
puts("")
puts("restarts:")
^Restarts each-with-index [r, i]:
puts(" :" + i to-s + " -> " + r name to-s)
-DefaultDebugger(e) show-backtrace := do:
- Atomy trim-backtrace(e backtrace)!
- puts(Rubinius Backtrace backtrace(e backtrace) show)
+DefaultDebugger(e) show-backtrace :=
+ puts(Atomy Backtrace backtrace(e backtrace) show)
DefaultDebugger(e) run := do:
show-banner
if(^Restarts empty?)
then:
+ puts("")
+ puts("Backtrace:")
show-backtrace
exit(1)
else:
View
@@ -52,6 +52,11 @@ ReplDebugger run := do:
with-restarts(backtrace -> show-backtrace):
debug
+ReplDebugger(e) show-banner := do:
+ puts("-" * 78)
+ (e name + ": " + e message) split("\n") each [l]:
+ puts("*** " + l)
+
ReplDebugger debug := do:
show-restarts
View
@@ -0,0 +1,168 @@
+class Rubinius::Location
+ attr_reader :receiver
+end
+
+class Exception
+ def awesome_backtrace
+ @awesome_backtrace ||= Atomy::Backtrace.backtrace(@locations)
+ end
+end
+
+module Atomy
+ class Backtrace < Rubinius::Backtrace
+ def location_color(loc, first, macro)
+ return "\e[0;92m" if first && macro
+ return @first_color if first
+ return "\e[0;32m" if macro
+
+ atomy_root = File.expand_path("../../../", __FILE__)
+ if loc.prefix? atomy_root
+ loc.slice!(0, atomy_root.size + 1)
+ end
+
+ if loc =~ /^lib\/atomy/
+ "\e[0;36m"
+ elsif loc =~ /^kernel\/.*\.ay/
+ "\e[0;36m"
+ else
+ color_from_loc(loc, first)
+ end
+ end
+
+ def show(sep="\n", show_color=true)
+ first = true
+
+ show_color = false unless @colorize
+ if show_color
+ clear = "\033[0m"
+ else
+ clear = ""
+ end
+
+ max = 0
+ lines = []
+ last_method = nil
+ last_line = nil
+ last_name = nil
+ times = 0
+
+ @locations.each do |loc|
+ next if loc.file == "__wrapper__"
+
+ if loc.name == last_name and loc.method == last_method \
+ and loc.line == last_line
+ times += 1
+ else
+ lines.last[-2] = times if lines.size > 0
+ last_method = loc.method
+ last_line = loc.line
+ last_name = loc.name
+
+ if loc.receiver.is_a?(Atomy::Module) &&
+ loc.method.name.to_s.start_with?("_expand")
+ vars = loc.variables
+ node_idx = vars.method.local_names.to_a.index(:node)
+ node = vars.locals[node_idx]
+
+ ctx =
+ if node.context
+ "#{node.context.name}:#{node.line}"
+ else
+ "#{node.class.split("::").last}@#{node.line}"
+ end
+
+ str = "expand(#{ctx})"
+ macro = true
+ elsif loc.receiver.is_a?(Atomy::Module) &&
+ loc.is_block && loc.name == :__script__ &&
+ loc.method.name != :__block__
+ str = "#{loc.receiver.name}\#__script__"
+ macro = false
+ else
+ str = loc.describe
+ macro = false
+ end
+
+ max = str.size if str.size > max
+
+ lines << [str, loc, 1, macro]
+ times = 0
+ end
+ end
+
+ max_width = (@width * (MAX_WIDTH_PERCENTAGE / 100.0)).to_i
+ max = max_width if max > max_width
+
+ str = ""
+ lines.each do |recv, location, rec_times, macro|
+ pos = location.position(Dir.getwd)
+ color = show_color ? location_color(pos, first, macro) : ""
+ first = false # special handling for first line
+
+ spaces = max - recv.size
+ spaces = 0 if spaces < 0
+
+ if show_color and location.inlined?
+ start = " #{' ' * spaces}#{recv} #{@inline_effect}at#{clear}#{color} "
+ else
+ start = " #{' ' * spaces}#{recv} at "
+ end
+
+ # start.size without the escapes
+ start_size = 1 + spaces + recv.size + 4
+
+ line_break = @width - start_size - 1
+ line_break = nil if line_break < @min_width
+
+ if line_break and pos.size >= line_break
+ indent = start_size
+
+ new_pos = ""
+ bit = ""
+ parts = pos.split("/")
+ file = parts.pop
+
+ first = true
+ parts.each do |part|
+ if bit.size + part.size > line_break
+ new_pos << bit << "\n" << (' ' * indent)
+ bit = ""
+ end
+
+ bit << "/" unless first
+ first = false
+ bit << part
+ end
+
+ new_pos << bit
+ if bit.size + file.size > line_break
+ new_pos << "\n" << (' ' * indent)
+ end
+ new_pos << "/" << file
+ str << color
+ str << start
+ str << new_pos
+ str << clear
+ else
+ if start_size > @width - @min_width
+ str << "#{color} #{start}\\\n #{pos}#{clear}"
+ else
+ str << "#{color} #{start}#{pos}#{clear}"
+ end
+ end
+
+ if rec_times > 1
+ str << " (#{rec_times} times)"
+ end
+
+ if location.is_jit and $DEBUG
+ str << " (jit)"
+ end
+
+ str << sep
+ end
+
+ return str
+ end
+ end
+end
View
@@ -12,28 +12,17 @@ class Location
end
module Atomy
- def self.load(*as)
- CodeLoader.load_file *as
- rescue => e
- trim_backtrace!(e.locations)
- raise
+ def self.load(file, debug = false)
+ CodeLoader.load_file file, debug
end
- # clean up internal plumbing from backtraces
- def self.trim_backtrace!(bt)
- bt.reject! do |l|
- # wrapper methods (which call the matching branch)
- if l.file == "__wrapper__"
- true
-
- # module toplevel
- elsif l.is_block && l.name == :__module_init__ &&
- l.method.name != :__block__
- l.name = nil
- l.flags ^= 1
- false
- end
- end
+ def self.run(file, debug = false)
+ load(file, debug)
+ rescue SystemExit => e
+ Kernel.exit(e.status)
+ rescue Object => e
+ e.render "An exception occurred running #{file}"
+ Kernel.exit(1)
end
end
@@ -54,3 +43,4 @@ def self.trim_backtrace!(bt)
require base + "/precision"
require base + "/code_loader"
require base + "/rubygems"
+require base + "/backtrace"
View
@@ -99,8 +99,13 @@ def load_file(fn, debug = false)
cl = Rubinius::CodeLoader.new(cfn)
cm = cl.load_compiled_file(cfn, 0, 0)
- Rubinius.attach_method(:__module_init__, cm, mod.compile_context.constant_scope, mod)
- mod.__module_init__
+ Rubinius.attach_method(
+ :__script__,
+ cm,
+ mod.compile_context.constant_scope,
+ mod)
+
+ mod.__script__
end
mod
@@ -111,7 +116,6 @@ def load_file(fn, debug = false)
LOADED.delete file
end
- puts "when loading #{file}..."
raise
end
end
View
@@ -26,7 +26,7 @@ def compile_context
meth = proc {}.block.code
meth.metadata = nil
- meth.name = :"__module_init__"
+ meth.name = :__script__
meth.scope = scope
variables = Rubinius::VariableScope.synthesize(
@@ -50,7 +50,7 @@ def compile_context
end
def compile(gen, node)
- expand(node).bytecode(gen, self)
+ expand(node.in_context(self)).bytecode(gen, self)
end
def eval(string_or_node, line = 1, debug = false)
@@ -145,18 +145,6 @@ def expand(node)
else
node
end
- rescue
- if node.respond_to?(:show)
- begin
- $stderr.puts "while expanding #{node.show}"
- rescue
- $stderr.puts "while expanding #{node.inspect}"
- end
- else
- $stderr.puts "while expanding #{node.inspect}"
- end
-
- raise
end

0 comments on commit e618993

Please sign in to comment.