class Lisp::Debug

Attributes

eval_in_debug_repl[RW]
interactive[RW]
on_entry[RW]
on_error[RW]
single_step[RW]
target_env[RW]
trace[RW]

Public Class Methods

add_debug_on_entry_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 50
def self.add_debug_on_entry_impl(args, env)
  f = args.car
  return Lisp::Debug.process_error("the argument to add-debug-on-error has to be a function", env) unless f.function? || f.primitive?

  self.on_entry.add(f.name)
  f
end
debug_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 66
def self.debug_impl(args, env)
end
debug_on_entry_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 46
def self.debug_on_entry_impl(args, env)
  Lisp::ConsCell.array_to_list(self.on_entry.to_a.sort.map {|s| Lisp::String.with_value(s) })
end
debug_on_error_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 39
def self.debug_on_error_impl(args, env)
  flag = args.car
  return Lisp::Debug.process_error("the argument to debug-on-error has to be a boolean", env) unless flag.boolean?
  self.on_error = flag.value
  flag
end
debug_repl(env) click to toggle source
# File lib/rubylisp/debug.rb, line 103
def self.debug_repl(env)
  parser = Lisp::Parser.new
  puts("Debugging: #{env.current_code[0]}")
  while line = Readline.readline('D> ', true)
    if !line.empty?
      if line[0] == ':'
        tokens = line[1..-1].split
        case tokens[0]
        when '(+'
          f = func_or_nil(tokens[1], env)
          self.on_entry.add(f.name) unless f.nil?
        when '(-'
          f = func_or_nil(tokens[1], env)
          self.on_entry.delete(f.name) unless f.nil?
        when '('
          self.on_entry.to_a.sort.each {|f| puts f}
        when '?'
          puts "RubyLisp Debugger"
          puts "-----------------"
          puts ":(+ func  - debug on entry to func"
          puts ":(- func  - don't debug on entry to func"
          puts ":(        - show functions marked as debug on entry"
          puts ":?        - show this command summary"
          puts ":b        - show the environment stack"
          puts ":c        - continue, exiting the debugger"
          puts ":d        - do a full of the environment stack"
          puts ":e on/off - Enable/disable debug on error"
          puts ":f frame# - do a full dump of a single environment frame"
          puts ":q        - quit GoLisp"
          puts ":r sexpr  - return from the current evaluation with the specified value"
          puts ":s        - single step (run to the next evaluation)"
          puts ":t on/off - Enable/disable tracing"
          puts ":u        - continue until the enclosing environment frame is returned to"
          puts
        when 'b'
          env.dump_headers()
          puts
        when 'c'
          self.target_env = nil
          self.single_step = false
          self.eval_in_debug_repl = false
          return
        when 'd'
          env.dump
        when 'e'
          ok, state = process_state(tokens)
          self.on_error = state if ok
        when 'f'
          if tokens.size != 2
            puts "Missing frame number."
          else
            fnum = tokens[1].to_i
            env.dump_single_frame(fnum)
          end
        when 'q'
          exit()
        when 'r'
          self.eval_in_debug_repl = true
          code = parser.parse(tokens[1..-1].join(' '))
          return_value = code.evaluate(env)
          self.eval_in_debug_repl = false
          self.target_env = nil
          self.single_step = false
          self.eval_in_debug_repl = false
          return return_value
        when 's'
          self.single_step = true
          return
        when 't'
          ok, state = process_state(tokens)
          self.trace = state if ok
        when 'u'
          if env.previous.nil?
            puts "Already at top frame."
          else
            self.target_env = env
            return
          end
        end
      else
        begin 
          self.eval_in_debug_repl = true
          code = parser.parse(line)
          value = code.evaluate(env)
          self.eval_in_debug_repl = false
          puts value.to_s
        rescue Exception => ex
          puts "ERROR: #{ex}"
          puts ex.backtrace
        end
      end
    end
  end
end
debug_trace_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 32
def self.debug_trace_impl(args, env)
  flag = args.car
  return Lisp::Debug.process_error("the argument to debug-trace has to be a boolean", env) unless flag.boolean?
  self.trace = flag.value
  flag
end
dump_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 69
def self.dump_impl(args, env)
  env.dump()
end
log_eval(sexpr, env) click to toggle source
# File lib/rubylisp/debug.rb, line 213
def self.log_eval(sexpr, env)
  if !self.eval_in_debug_repl && self.trace
    depth = env.depth
    print("% #d: " % depth)
    print_dashes(depth)
    puts("> #{sexpr.to_s}")
  end
end
log_result(result, env) click to toggle source
# File lib/rubylisp/debug.rb, line 223
def self.log_result(result, env)
  if !self.eval_in_debug_repl && self.trace
    depth = env.depth
    print("% #d: <" % depth)
    print_dashes(depth)
    puts(" #{result.to_s}")
  end
end
print_dashes(level) click to toggle source
process_error(error_message, env) click to toggle source
# File lib/rubylisp/debug.rb, line 198
def self.process_error(error_message, env)
  if self.on_error && self.interactive
    puts "ERROR: #{error_message}"
    self.debug_repl(env)
  else
    raise error_message
  end
end
process_state(tokens) click to toggle source
# File lib/rubylisp/debug.rb, line 74
def self.process_state(tokens)
  if tokens.size != 2
    puts "Missing on/off"
    [false, false]
  else
    case tokens[1]
    when 'on'
      [true, true]
    when 'off'
      [true, false]
    else
      puts "on/off expected."
      [false, false]
    end
  end
end
register() click to toggle source
# File lib/rubylisp/debug.rb, line 15
def self.register
  self.trace = false
  self.on_error = false
  self.on_entry = Set.new
  self.single_step = false
  self.interactive = false
  
  Primitive.register("debug-trace", "1") {|args, env| Lisp::Debug::debug_trace_impl(args, env) }
  Primitive.register("debug-on-error", "1") {|args, env| Lisp::Debug::debug_on_error_impl(args, env) }
  Primitive.register("debug-on-entry", "0") {|args, env| Lisp::Debug::debug_on_entry_impl(args, env) }
  Primitive.register("add-debug-on-entry", "1") {|args, env| Lisp::Debug::add_debug_on_entry_impl(args, env) }
  Primitive.register("remove-debug-on-entry", "1") {|args, env| Lisp::Debug::remove_debug_on_entry_impl(args, env) }
  Primitive.register("debug", "0") {|args, env| Lisp::Debug::debug_impl(args, env) }
  Primitive.register("dump", "0") {|args, env| Lisp::Debug::dump_imp2l(args, env) }
end
remove_debug_on_entry_impl(args, env) click to toggle source
# File lib/rubylisp/debug.rb, line 58
def self.remove_debug_on_entry_impl(args, env)
  f = args.car
  return Lisp::Debug.process_error("the argument to remove-debug-on-error has to be a function", env) unless f.function?

  self.on_entry.remove(f.name)
  f
end

Public Instance Methods

func_or_nil(fname, env) click to toggle source
# File lib/rubylisp/debug.rb, line 92
def func_or_nil(fname, env)
  f = env.value_of(Lisp::Symbol.named(fname))
  if f.nil? || !f.function?
    puts "No such function."
    nil
  else
    f
  end
end