Class: Lisp::Exception

Inherits:
Object show all
Defined in:
lib/rubylisp/exception.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.do_exception(name, with_message, args, env) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rubylisp/exception.rb', line 26

def self.do_exception(name, with_message, args, env)
  frame = env
  while !frame.nil?
    handlers = frame.value_of(Symbol.named("__handlers__"))
    unless handlers.nil?
      handler = handler_or_nil(handlers, for: name)
      unless handler.nil?
        handler.apply_to_without_evaluating(args, in: frame)
        break
      end
    end
    frame = frame.parent
    if frame.nil?
      exception_message = message.empty? ? "" : ": #{message}"
      raise "Unhandled Exception: #{exception_name}#{exception_message}"
    end
  end
end

.raise_impl(args, env) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/rubylisp/exception.rb', line 45

def self.raise_impl(args, env)
  raise "'raise' requires at least one argument." unless args.length > 0
  exception_name = args.car.evaluate(env)
  raise "'raise' requires an exception name as it's first argument." unless exception_name.string? || class_name.symbol?

  message = ""
  if args.length > 1
    message = args.cadr.evaluate(env)
    raise "The message parameter to 'raise' must be a string." unless message.string?
  end

  handler_args = args.length > 2 ? Lisp::ConsCell.array_to_list(args.cdr.to_a.collect {|a| a.evaluate(env)}) : Lisp::ConsCell.new
end

.registerObject



5
6
7
8
9
10
11
12
# File 'lib/rubylisp/exception.rb', line 5

def self.register
  Primitive.register("raise")     {|args, env| Lisp::Exception::raise_impl(args, env) }
  Primitive.register("reraise")   {|args, env| Lisp::Exception::reraise_impl(args, env) }
  Primitive.register("try")       {|args, env| Lisp::Exception::try_impl(args, env) }
  Primitive.register("reraise")   {|args, env| Lisp::Exception::reraise_impl(args, env) }
  Primitive.register("resume")    {|args, env| Lisp::Exception::resume_impl(args, env) }
  Primitive.register("restart")   {|args, env| Lisp::Exception::restart_impl(args, env) }
end

.reraise_impl(args, env) ⇒ Object



84
85
# File 'lib/rubylisp/exception.rb', line 84

def self.reraise_impl(args, env)
end

.restart_impl(args, env) ⇒ Object



92
93
# File 'lib/rubylisp/exception.rb', line 92

def self.restart_impl(args, env)
end

.resume_impl(args, env) ⇒ Object



88
89
# File 'lib/rubylisp/exception.rb', line 88

def self.resume_impl(args, env)
end

.try_impl(args, env) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rubylisp/exception.rb', line 60

def self.try_impl(args, env)
  raw_handlers = args.car
  body = args.cdr
  
  raise "Exception handlers must be a list." unless raw_handlers.list?
  raise "Exception handlers must be a list of pairs." unless raw_handlers.all? {|h| h.list?}
  raise "Exception clause must be a symbol/string or a list of symbol/string." unless raw_handlers.all? do |h|
    ex = h.car
    ex.symbol? || ex.string? || (ex.list? && ex.all? {|h2| h2.symbol? || h2.string?})
  end
  
  array_of_handlers = raw_handlers.to_a.collect do |h|
    ex = h.car
    f = h.cadr.evaluate(env)
  raise "Exception handler has to be a function." unless f.function?
    Lisp::ConsCell.cons(ex, f)
  end
  handlers = Lisp::ConsCell.array_to_list(array_of_handlers)
  env.bind_locally(Symbol.named("__handlers__"), handlers)
  
  body.evaluate_each(env)
end

Instance Method Details

#handler_or_nil(handlers, exception_name) ⇒ Object



15
16
17
18
19
20
21
22
23
24
# File 'lib/rubylisp/exception.rb', line 15

def handler_or_nil(handlers, exception_name)
  handlers.each do |handler_pair|
    exceptions = handler_pair.car
    if exceptions.eq(exception_name) || (exceptions.pair? && exceptions.include?(exception_name))
      handler_pair.cdr
    else
      nil
    end
  end
end