atomy 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/COPYING +30 -0
  2. data/README.md +1 -0
  3. data/bin/atomy +134 -0
  4. data/kernel/block.ay +30 -0
  5. data/kernel/boot.ay +10 -0
  6. data/kernel/comparison.ay +61 -0
  7. data/kernel/concurrency.ay +84 -0
  8. data/kernel/condition.ay +277 -0
  9. data/kernel/control-flow.ay +222 -0
  10. data/kernel/cosmetics.ay +3 -0
  11. data/kernel/data-delta.ay +105 -0
  12. data/kernel/data.ay +56 -0
  13. data/kernel/define.ay +93 -0
  14. data/kernel/doc.ay +453 -0
  15. data/kernel/documentation.ay +135 -0
  16. data/kernel/dynamic.ay +42 -0
  17. data/kernel/errors.ay +6 -0
  18. data/kernel/format.ay +13 -0
  19. data/kernel/format/data.ay +89 -0
  20. data/kernel/format/formatter.ay +345 -0
  21. data/kernel/format/parser.ay +13 -0
  22. data/kernel/hashes.ay +39 -0
  23. data/kernel/io.ay +244 -0
  24. data/kernel/namespaces.ay +63 -0
  25. data/kernel/node.ay +48 -0
  26. data/kernel/operators.ay +28 -0
  27. data/kernel/particles.ay +53 -0
  28. data/kernel/patterns.ay +256 -0
  29. data/kernel/precision.ay +148 -0
  30. data/kernel/pretty.ay +283 -0
  31. data/kernel/repl.ay +140 -0
  32. data/kernel/therie.ay +204 -0
  33. data/lib/ast/binary_send.rb +44 -0
  34. data/lib/ast/block.rb +268 -0
  35. data/lib/ast/constant.rb +88 -0
  36. data/lib/ast/internal/assign.rb +19 -0
  37. data/lib/ast/internal/block_pass.rb +21 -0
  38. data/lib/ast/internal/catch.rb +247 -0
  39. data/lib/ast/internal/class.rb +30 -0
  40. data/lib/ast/internal/class_variable.rb +23 -0
  41. data/lib/ast/internal/define.rb +174 -0
  42. data/lib/ast/internal/ensure.rb +135 -0
  43. data/lib/ast/internal/file.rb +14 -0
  44. data/lib/ast/internal/global_variable.rb +20 -0
  45. data/lib/ast/internal/if_then_else.rb +24 -0
  46. data/lib/ast/internal/instance_variable.rb +17 -0
  47. data/lib/ast/internal/let_macro.rb +35 -0
  48. data/lib/ast/internal/macro_quote.rb +23 -0
  49. data/lib/ast/internal/match.rb +53 -0
  50. data/lib/ast/internal/module.rb +30 -0
  51. data/lib/ast/internal/pattern.rb +17 -0
  52. data/lib/ast/internal/return.rb +29 -0
  53. data/lib/ast/internal/set.rb +19 -0
  54. data/lib/ast/internal/singleton_class.rb +18 -0
  55. data/lib/ast/internal/splat.rb +14 -0
  56. data/lib/ast/internal/when.rb +24 -0
  57. data/lib/ast/list.rb +25 -0
  58. data/lib/ast/macro.rb +37 -0
  59. data/lib/ast/node.rb +599 -0
  60. data/lib/ast/operator.rb +21 -0
  61. data/lib/ast/particle.rb +13 -0
  62. data/lib/ast/primitive.rb +20 -0
  63. data/lib/ast/quasi_quote.rb +20 -0
  64. data/lib/ast/quote.rb +13 -0
  65. data/lib/ast/send.rb +104 -0
  66. data/lib/ast/splice.rb +32 -0
  67. data/lib/ast/string.rb +23 -0
  68. data/lib/ast/unary.rb +44 -0
  69. data/lib/ast/unquote.rb +45 -0
  70. data/lib/ast/variable.rb +64 -0
  71. data/lib/atomy.kpeg.rb +3995 -0
  72. data/lib/code_loader.rb +137 -0
  73. data/lib/compiler/compiler.rb +155 -0
  74. data/lib/compiler/stages.rb +81 -0
  75. data/lib/formatter.kpeg.rb +1394 -0
  76. data/lib/macros.rb +317 -0
  77. data/lib/method.rb +261 -0
  78. data/lib/namespace.rb +236 -0
  79. data/lib/parser.rb +28 -0
  80. data/lib/patterns.rb +276 -0
  81. data/lib/patterns/any.rb +21 -0
  82. data/lib/patterns/attribute.rb +59 -0
  83. data/lib/patterns/block_pass.rb +54 -0
  84. data/lib/patterns/constant.rb +33 -0
  85. data/lib/patterns/default.rb +44 -0
  86. data/lib/patterns/head_tail.rb +63 -0
  87. data/lib/patterns/list.rb +77 -0
  88. data/lib/patterns/match.rb +45 -0
  89. data/lib/patterns/named.rb +55 -0
  90. data/lib/patterns/named_class.rb +46 -0
  91. data/lib/patterns/named_global.rb +46 -0
  92. data/lib/patterns/named_instance.rb +46 -0
  93. data/lib/patterns/particle.rb +29 -0
  94. data/lib/patterns/quasi_quote.rb +184 -0
  95. data/lib/patterns/quote.rb +33 -0
  96. data/lib/patterns/singleton_class.rb +31 -0
  97. data/lib/patterns/splat.rb +57 -0
  98. data/lib/util.rb +37 -0
  99. metadata +164 -0
data/COPYING ADDED
@@ -0,0 +1,30 @@
1
+ Copyright (c)2010, Alex Suraci
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above
12
+ copyright notice, this list of conditions and the following
13
+ disclaimer in the documentation and/or other materials provided
14
+ with the distribution.
15
+
16
+ * Neither the name of Alex Suraci nor the names of other
17
+ contributors may be used to endorse or promote products derived
18
+ from this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1 @@
1
+ Atomo-like language on the Rubinius VM.
data/bin/atomy ADDED
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env rbx
2
+
3
+ base = File.expand_path "../../lib/", __FILE__
4
+ kernel = File.expand_path "../../kernel/", __FILE__
5
+
6
+ require 'readline'
7
+ require 'optparse'
8
+
9
+ require base + "/macros"
10
+ require base + "/method"
11
+ require base + "/util"
12
+ require base + "/namespace"
13
+ require base + "/compiler/compiler"
14
+ require base + "/compiler/stages"
15
+ require base + "/parser"
16
+ require base + "/patterns"
17
+ require base + "/code_loader"
18
+
19
+ def require_atomy(*as)
20
+ before = Atomy::Namespace.get
21
+ begin
22
+ Atomy::CodeLoader.load_file *as
23
+ ensure
24
+ Atomy::Namespace.set(before)
25
+ end
26
+ end
27
+
28
+ options = {}
29
+
30
+ unless ARGV.empty? || ARGV[0][0] != ?-
31
+ OptionParser.new do |o|
32
+ o.banner = "usage: atomy [options]"
33
+
34
+ o.on("-B", "--print-bytecode", "print out compiled bytecode") do |v|
35
+ options[:debug] = v
36
+ end
37
+
38
+ o.on("-e", "--evaluate EXPR", "evaluate EXPR and print the result") do |v|
39
+ options[:evaluate] = v
40
+ end
41
+
42
+ o.on("-s", "--before-start EXPR", "evaluate EXPR beforehand") do |v|
43
+ options[:start] = v
44
+ end
45
+
46
+ o.on("-l", "--load FILE", "load FILENAME and start the REPL") do |v|
47
+ options[:load] = v
48
+ end
49
+
50
+ o.on("-d", "--documentation DIR", "generate documentation with output to DIR") do |v|
51
+ Atomy::CodeLoader.documentation = v
52
+ end
53
+
54
+ o.on_tail("-h", "--help", "show this message") do
55
+ puts o
56
+ exit
57
+ end
58
+ end.parse!
59
+ end
60
+
61
+ a = Time.now
62
+ puts "loading kernel"
63
+ require_atomy(kernel + "/boot.ay")
64
+ puts Time.now - a
65
+
66
+ Atomy::Namespace.ensure(:user)
67
+
68
+ def run_atomy(options)
69
+ if str = options[:evaluate] || options[:start]
70
+ $0 = "(eval)"
71
+ res = Atomy::Compiler.evaluate(
72
+ str,
73
+ nil,
74
+ "(eval)",
75
+ 1,
76
+ options[:debug]
77
+ )
78
+
79
+ if options[:evaluate]
80
+ res.send(Atomy.namespaced("atomy", "write").to_sym)
81
+ return
82
+ end
83
+ end
84
+
85
+ if file = options[:load] || ARGV[0]
86
+ $0 = file
87
+ require_atomy(file, ARGV[0] ? :run : :load, options[:debug])
88
+ return if ARGV[0]
89
+ end
90
+
91
+ if respond_to?(Atomy.namespaced("atomy", "repl").to_sym, true)
92
+ send(Atomy.namespaced("atomy", "repl").to_sym, File.expand_path("~/.atomy_history"))
93
+ else
94
+ $stderr.puts("main REPL startup failed! here's a basic one:")
95
+
96
+ history_file = File.expand_path("~/.atomy_history")
97
+
98
+ if File.exists?(history_file)
99
+ File.open(history_file, "r") do |f|
100
+ f.readlines.each do |l|
101
+ Readline::HISTORY << l.strip
102
+ end
103
+ end
104
+ end
105
+
106
+ begin
107
+ sane_history = []
108
+ while str = Readline.readline("> ")
109
+ next if str.empty?
110
+
111
+ sane_history << str
112
+
113
+ begin
114
+ res = Atomy::Compiler.evaluate str, TOPLEVEL_BINDING
115
+ if res.respond_to?(:pretty)
116
+ puts "=> #{res.pretty.render}"
117
+ else
118
+ puts "=> #{res.inspect}"
119
+ end
120
+ rescue StandardError => e
121
+ puts "ERROR!"
122
+ puts "#{e}:\n #{e.message}"
123
+ puts e.backtrace
124
+ end
125
+ end
126
+ ensure
127
+ File.open(history_file, "a") do |f|
128
+ f.puts(*sane_history)
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ run_atomy(options)
data/kernel/block.ay ADDED
@@ -0,0 +1,30 @@
1
+ namespace(atomy)
2
+
3
+ macro(x onto(&b)):
4
+ names [ctx]:
5
+ shadowed? = false
6
+
7
+ blk = b through-quotes [n]:
8
+ n match:
9
+ `@~(v: Atomy::AST::Variable) -> do:
10
+ shadowed? =! true
11
+ `(~ctx instance-variable-get(#~("@" + v name)))
12
+
13
+ 'self -> do:
14
+ shadowed? =! true
15
+ ctx
16
+
17
+ Atomy::AST::Send ? @private ->
18
+ n dup tap [p]:
19
+ p receiver = 'self
20
+
21
+ Atomy::AST::BinarySend ? @private ->
22
+ n dup tap [p]:
23
+ p lhs = 'self
24
+
25
+ _ ->
26
+ n
27
+
28
+ if(shadowed?)
29
+ then: `(do: ~ctx = self, ~blk block call-on-instance(~x))
30
+ else: `(~b block call-on-instance(~x))
data/kernel/boot.ay ADDED
@@ -0,0 +1,10 @@
1
+ macro(_LINE): line
2
+ macro(_FILE): Atomy::AST::File new(line)
3
+
4
+ macro(import(name)): `(require-atomy(~name, "load" to-sym))
5
+
6
+ "operators define cosmetics data comparison dynamic control-flow namespaces
7
+ patterns precision data-delta documentation particles hashes node block errors
8
+ doc pretty format concurrency io condition therie repl" split each [k]:
9
+ puts("loading " + k)
10
+ import(File expand-path("../", _FILE) + "/" + k)
@@ -0,0 +1,61 @@
1
+ module(Atomy::AST):
2
+ class(And < Node):
3
+ children(#a, #b)
4
+ generate
5
+
6
+ bytecode(g) := do:
7
+ pos(g)
8
+ done = g new-label
9
+ no = g new-label
10
+
11
+ @a compile(g)
12
+ g dup
13
+ g gif(done)
14
+
15
+ g pop
16
+ @b compile(g)
17
+
18
+ done set!
19
+
20
+ class(Or < Node):
21
+ children(#a, #b)
22
+ generate
23
+
24
+ bytecode(g) := do:
25
+ pos(g)
26
+ done = g new-label
27
+
28
+ @a compile(g)
29
+ g dup
30
+ g git(done)
31
+
32
+ g pop
33
+ @b compile(g)
34
+
35
+ done set!
36
+
37
+ class(Negate < Node):
38
+ children(#expression)
39
+ generate
40
+
41
+ bytecode(g) := do:
42
+ pos(g)
43
+ done = g new-label
44
+ yes = g new-label
45
+
46
+ @expression compile(g)
47
+ g git(yes)
48
+
49
+ g push-true
50
+ g goto(done)
51
+
52
+ yes set!
53
+ g push-false
54
+
55
+ done set!
56
+
57
+ macro(a && b): Atomy::AST::And new(line, a, b)
58
+ macro(a || b): Atomy::AST::Or new(line, a, b)
59
+ macro(!a): Atomy::AST::Negate new(line, a)
60
+ macro(a != b): `!(~a == ~b)
61
+ macro(a !~ b): `!(~a =~ ~b)
@@ -0,0 +1,84 @@
1
+ namespace(atomy)
2
+
3
+ require("actor")
4
+
5
+ title"Concurrency"
6
+
7
+ doc"
8
+ Get the current actor.
9
+ " spec {
10
+ => Actor
11
+ } for:
12
+ me := Actor current
13
+
14
+
15
+ section("Sending & Receiving"):
16
+ doc"
17
+ Send message \code{v} to the actor.
18
+ " spec {
19
+ => Actor
20
+ } for {
21
+ Actor <- v := send(v)
22
+ } examples:
23
+ a = spawn: receive { 42 -> #ok } write
24
+ a <- 42
25
+
26
+ doc"
27
+ Receive a message sent to the current actor that matches any of the \
28
+ patterns listed in \hl{body}. Blocks until a matching message is \
29
+ received. Non-matching messages are consumed and ignored.
30
+ " spec {
31
+ body contents all? [x]: x match { `(~_ -> ~_) -> true, _ -> false }
32
+ => any
33
+ } for {
34
+ macro(receive(&body)):
35
+ names [e]:
36
+ bs = body contents collect [`(~pat -> ~exp)]:
37
+ `(~e when('~pat to-pattern) [~pat]: ~exp)
38
+
39
+ `(Actor receive [~e]: ~*bs)
40
+ } examples:
41
+ a = spawn: receive { 1 -> #got-1 } write
42
+ a <- 0
43
+ a <- 2
44
+ a <- 1
45
+
46
+ doc"
47
+ Similar to \code{receive}, but with a timeout and an action to \
48
+ perform if it times out.
49
+ " spec {
50
+ body contents all? [x]: x match { `(~_ -> ~_) -> true, _ -> false }
51
+ timeout match: `(~_ -> ~_) -> true, _ -> false
52
+ => any
53
+ } for {
54
+ macro(receive(&body) after(timeout)):
55
+ names [e]:
56
+ bs = body contents collect [`(~pat -> ~exp)]:
57
+ `(~e when('~pat to-pattern) [~pat]: ~exp)
58
+
59
+ bs << `(~e after(~(timeout lhs)): ~(timeout rhs))
60
+
61
+ `(Actor receive [~e]: ~*bs)
62
+ } examples:
63
+ receive { 1 -> #ok } after(1 -> #too-slow)
64
+
65
+
66
+ section("Spawning"):
67
+ doc"
68
+ Spawn a new actor, performing \code{action}.
69
+ " spec {
70
+ => Actor
71
+ } for {
72
+ spawn(&action) := Actor send(#spawn, &action)
73
+ } examples:
74
+ spawn: (2 + 2) write
75
+
76
+ doc"
77
+ Spawn a new actor, performing \code{action}, linked to the current \
78
+ actor.
79
+ " spec {
80
+ => Actor
81
+ } for {
82
+ spawn-link(&action) := Actor send(#spawn-link, &action)
83
+ } examples:
84
+ spawn-link: (2 + 2) write
@@ -0,0 +1,277 @@
1
+ namespace(atomy)
2
+
3
+ title"Condition System"
4
+
5
+ doc"
6
+ Rather than traditional exceptions, Atomy sports a condition/restart \
7
+ system modeled on Common Lisp's design. The native Ruby exception handling \
8
+ is available, but conditions and restarts are much more flexible.
9
+ "
10
+
11
+ -- registered handlers/restarts
12
+ dynamic(handlers, [])
13
+ dynamic(restarts, [])
14
+
15
+ for-macro:
16
+ catcher(x) :=
17
+ Atomy::AST::Variable new(x line) $:
18
+ x match:
19
+ Atomy::AST::Variable ->
20
+ "restart:" + x name
21
+
22
+ Atomy::AST::Send ->
23
+ "restart:" + x method-name
24
+
25
+ data(Object):
26
+ Restart(@name, @action)
27
+
28
+ Restart invoke(*args) :=
29
+ throw(("restart:" + @name to-s) to-sym, @action [*args])
30
+
31
+ symbols(signal, warning, error, restart)
32
+
33
+ section("Conditions"):
34
+ doc"
35
+ Condition system hierarchy. You should subclass one of these to create \
36
+ your own conditions.
37
+ " for:
38
+ data(Object):
39
+ Condition:
40
+ Error(@backtrace):
41
+ SimpleError(@value)
42
+ ExceptionError(@exception)
43
+ NoRestartError(@name)
44
+ PortError(@port):
45
+ EndOfFile
46
+
47
+ Warning(@backtrace):
48
+ SimpleWarning(@value)
49
+
50
+ doc"
51
+ Get the name of a condition. By default, this will be the class name, \
52
+ but you may override this for your own behaviour.
53
+ " for:
54
+ Condition name := class name
55
+
56
+ ExceptionError name := @exception class name
57
+
58
+ doc"
59
+ A human-friendly message displayed for the condition. Override this.
60
+ " for:
61
+ Condition message := inspect
62
+
63
+ SimpleError message := @value to-s
64
+ ExceptionError message := @exception message
65
+ SimpleWarning message := @value to-s
66
+ NoRestartError message := "unknown restart " + @name show
67
+ EndOfFile message := "unexpected end-of-file for " + @port show
68
+
69
+
70
+ section("Handling"):
71
+ doc"
72
+ Invoke the \hl{name} restart, passing \hl{args} along to its callback.
73
+
74
+ See \hl{with-restarts}.
75
+ " spec {
76
+ name is-a?(Symbol)
77
+ => any
78
+ } for {
79
+ restart(name, *args) := do:
80
+ ^restarts each [r]:
81
+ when(r name == name):
82
+ r invoke(*args)
83
+
84
+ error(NoRestartError new(name))
85
+ } examples:
86
+ { with-restarts(foo -> 42):
87
+ signal(#bar)
88
+ } bind: #bar -> restart(#foo)
89
+
90
+
91
+ doc"
92
+ Register handlers for various signals for the duration of \hl{x}'s \
93
+ execution.
94
+
95
+ The body of \hl{y} is similar to \hl{match}; \hl{\italic{pattern} -> \
96
+ \italic{body}}.
97
+
98
+ The result is the result of \hl{body}.
99
+ " spec {
100
+ y contents all? [x]: x match { `(~_ -> ~_) -> true, _ -> false }
101
+ => any
102
+ } for {
103
+ macro(body bind(&y)):
104
+ names [a]:
105
+ callback = `([~a]: ~a match: ~*(y contents))
106
+ `(let(handlers = ^handlers + [~callback]):
107
+ ~body rescue:
108
+ (e: StandardError) -> error(e))
109
+ } examples:
110
+ { signal(#a) } bind: #a -> "got A!" print
111
+ { signal(#b) } bind: #a -> "got A!" print
112
+ { { signal(#a) } bind: #a -> "inner" print } bind: #a -> "outer" print
113
+
114
+
115
+ doc"
116
+ Register restarts available for the duration of \hl{body}'s execution.
117
+
118
+ The \hl{restarts} should be in the form of \
119
+ \hl{\italic{name}(*\italic{args}) -> \italic{body}}.
120
+
121
+ The result is the result of \hl{body}.
122
+ " spec {
123
+ => any
124
+ } for {
125
+ macro(with-restarts(*restarts, &block)):
126
+ rs = restarts collect [`(~n -> ~e)]:
127
+ n match:
128
+ Atomy::AST::Variable ->
129
+ `(Restart new(#~n, { ~e }))
130
+
131
+ Atomy::AST::Send -> do:
132
+ name = Atomy::AST::Variable new(0, n method-name)
133
+ `(Restart new(#~name, [~*(n arguments)] { ~e }))
134
+
135
+ body =
136
+ restarts reduce(
137
+ `{ ~block rescue: (e: StandardError) -> error(e) }
138
+ ) [x, `(~name -> ~_)]:
139
+ `{ catch(#~catcher(name), &~x) }
140
+
141
+ `(let(restarts = [~*rs] + ^restarts, &~body))
142
+ } examples:
143
+ { with-restarts(x -> 1, y -> 2):
144
+ signal(#a)
145
+ } bind: #a -> restart(#x)
146
+
147
+ { with-restarts(x -> 1, y -> 2):
148
+ signal(#a)
149
+ } bind: #a -> restart(#y)
150
+
151
+ { with-restarts(x(a) -> a * 7):
152
+ signal(#a)
153
+ } bind: #a -> restart(#x, 6)
154
+
155
+
156
+ section("Signalling"):
157
+ doc"
158
+ Signal a value through all bound handlers, nearest-first, stopping when \
159
+ a restart is invoked.
160
+ " spec {
161
+ => nil
162
+ } for {
163
+ signal(c) := do:
164
+ ^handlers reverse-each [callback]:
165
+ callback [c]
166
+
167
+ nil
168
+ } examples:
169
+ signal(#foo)
170
+ { signal(#foo) } bind: #foo -> "got foo" print
171
+
172
+
173
+ doc"
174
+ Like \hl{signal}, except that if no restart is invoked, the current \
175
+ \hl{^debugger} is started.
176
+
177
+ If the given value is not an \hl{Error}, it is wrapped in a \
178
+ \hl{SimpleError}. If the value is a Ruby \hl{Exception}, it is wrapped \
179
+ in an \hl{ExceptionError}.
180
+ " spec {
181
+ => _
182
+ } for {
183
+ error(x) := do:
184
+ e =
185
+ x match:
186
+ Exception ->
187
+ ExceptionError new(x) tap [err]:
188
+ err backtrace = x locations
189
+
190
+ Error ->
191
+ x tap [err]:
192
+ err backtrace = Rubinius::VM backtrace(0)
193
+
194
+ _ ->
195
+ SimpleError new(x) tap [err]:
196
+ err backtrace = Rubinius::VM backtrace(0)
197
+
198
+ signal(e)
199
+
200
+ with-output-to(^error-port):
201
+ ^debugger run(e)
202
+ } examples:
203
+ error("Oh no!")
204
+ { error("Oh no!") } bind: Error -> "INCOMING" print
205
+
206
+
207
+ doc"
208
+ Like \hl{signal}, except that if no restart is invoked, the warning is \
209
+ printed to \hl{^error-port}.
210
+
211
+ If the given value is not a \hl{Warning}, it is wrapped in a \
212
+ \hl{SimpleWarning}. Warning messages can be muffled by binding for \
213
+ \hl{Warning} and invoking the \hl{#muffle-warning} restart.
214
+ " spec {
215
+ => nil
216
+ } for {
217
+ warning(x) :=
218
+ with-restarts(muffle-warning -> nil):
219
+ w =
220
+ x match:
221
+ Warning ->
222
+ x tap [wrn]:
223
+ wrn backtrace = Rubinius::VM backtrace(0)
224
+
225
+ _ ->
226
+ SimpleWarning new(x) tap [wrn]:
227
+ wrn backtrace = Rubinius::VM backtrace(0)
228
+
229
+ signal(w)
230
+
231
+ with-output-to(^error-port):
232
+ (w name + ": " + w message) print
233
+
234
+ nil
235
+ } examples:
236
+ warning("Suspicious!")
237
+ { warning("Quiet, you!") } bind: Warning -> restart(#muffle-warning)
238
+
239
+
240
+ section("Debuggers"):
241
+ doc"
242
+ The default debugger. This will show the condition name, its message, \
243
+ and let the user pick from the available restarts.
244
+ " for:
245
+ class(DefaultDebugger):
246
+ class(<< self):
247
+ define(show-error-banner(e)):
248
+ ("-" * 78) print
249
+ (e name + ": " + e message) each-line [l]:
250
+ ("*** " + l) display
251
+
252
+ "\n" display
253
+
254
+ define(show-options-for(e)):
255
+ when(^restarts empty?):
256
+ exit(1)
257
+
258
+ "\n" display
259
+ "restarts:" print
260
+ ^restarts each-with-index [r, i]:
261
+ (" :" + i to-s + " -> " + r name to-s) print
262
+
263
+ define(run(e)):
264
+ show-error-banner(e)
265
+
266
+ show-options-for(e)
267
+
268
+ "!> " display
269
+ ^restarts [gets to-i] invoke
270
+
271
+ doc"
272
+ The current debugger. \hl{run} will be called with the condition as an \
273
+ argument.
274
+ " spec {
275
+ respond-to?(#run)
276
+ } for:
277
+ dynamic(debugger, DefaultDebugger)