atomy 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,256 @@
1
+ namespace(atomy)
2
+
3
+ module(Atomy::Patterns):
4
+ export:
5
+ class(RuntimeClass < Pattern):
6
+ initialize(@body, @name) := #ok
7
+
8
+ construct(g) := do:
9
+ get(g)
10
+ @body construct(g)
11
+ @body compile(g)
12
+ g send(#name, 0)
13
+ g send(#new, 2)
14
+
15
+ (== b) :=
16
+ b kind-of?(RuntimeClass) &&
17
+ @body == b body &&
18
+ @name == b name
19
+
20
+ target(g) :=
21
+ @body compile(g)
22
+
23
+ matches?(g) := do:
24
+ Atomy const-from-string(g, @name)
25
+ g swap
26
+ g kind-of
27
+
28
+ class(Predicate < Pattern):
29
+ initialize(@pattern, @test) := #ok
30
+
31
+ construct(g) := do:
32
+ get(g)
33
+ @pattern construct(g)
34
+ @test construct(g)
35
+ g send(#new, 2)
36
+
37
+ (== b) :=
38
+ b kind-of?(Predicate) &&
39
+ @pattern == b pattern &&
40
+ @test == b test
41
+
42
+ target(g) := @pattern target(g)
43
+
44
+ matches?(g) := do:
45
+ mismatch = g new-label
46
+ done = g new-label
47
+
48
+ g dup
49
+ @pattern matches?(g)
50
+ g gif(mismatch)
51
+
52
+ `{ ~@test } bytecode(g)
53
+ g send(#block, 0)
54
+ g swap
55
+ g send(#call-on-instance, 1)
56
+ g goto(done)
57
+
58
+ mismatch set!
59
+ g pop
60
+ g push-false
61
+
62
+ done set!
63
+
64
+ deconstruct(g, locals = Hash new) :=
65
+ @pattern deconstruct(g, locals)
66
+
67
+ local-names := @pattern local-names
68
+
69
+ bindings := @pattern bindings
70
+
71
+ class(With < Pattern):
72
+ initialize(@expression, @pattern) := #ok
73
+
74
+ construct(g) := do:
75
+ get(g)
76
+ @expression construct(g)
77
+ @pattern construct(g)
78
+ g send(#new, 2)
79
+
80
+ (== b) :=
81
+ b kind-of?(With) &&
82
+ @expression == b expression &&
83
+ @pattern == b pattern
84
+
85
+ target(g) := Any new target(g)
86
+
87
+ matches?(g) := do:
88
+ `{ ~@expression } bytecode(g)
89
+ g send(#block, 0)
90
+ g swap
91
+ g send(#call-on-instance, 1)
92
+ @pattern matches?(g)
93
+
94
+ deconstruct(g, locals = Hash new) := do:
95
+ `{ ~@expression } bytecode(g)
96
+ g send(#block, 0)
97
+ g swap
98
+ g send(#call-on-instance, 1)
99
+ @pattern deconstruct(g, locals)
100
+
101
+ local-names := @pattern local-names
102
+
103
+ bindings := @pattern bindings
104
+
105
+ class(And < Pattern):
106
+ initialize(@a, @b) := #ok
107
+
108
+ construct(g) := do:
109
+ get(g)
110
+ @a construct(g)
111
+ @b construct(g)
112
+ g send(#new, 2)
113
+
114
+ (== b) :=
115
+ b kind-of?(And) &&
116
+ @a == b a &&
117
+ @b == b b
118
+
119
+ target(g) :=
120
+ @a target(g)
121
+
122
+ matches?(g) := do:
123
+ mismatch = g new-label
124
+ done = g new-label
125
+
126
+ g dup
127
+ @a matches?(g)
128
+ g gif(mismatch)
129
+
130
+ @b matches?(g)
131
+ g dup
132
+ g git(done)
133
+
134
+ mismatch set!
135
+ g pop
136
+ g push-false
137
+
138
+ done set!
139
+
140
+ deconstruct(g, locals = Hash new) := do:
141
+ g dup
142
+ @a deconstruct(g, locals)
143
+ @b deconstruct(g, locals)
144
+
145
+ local-names := [@a local-names + @b local-names] uniq
146
+
147
+ class(Or < Pattern):
148
+ initialize(@a, @b) := #ok
149
+
150
+ construct(g) := do:
151
+ get(g)
152
+ @a construct(g)
153
+ @b construct(g)
154
+ g send(#new, 2)
155
+
156
+ (== b) :=
157
+ b kind-of?(Or) &&
158
+ @a == b a &&
159
+ @b == b b
160
+
161
+ target(g) :=
162
+ @a target(g)
163
+
164
+ matches?(g) := do:
165
+ matched = g new-label
166
+ done = g new-label
167
+
168
+ g dup
169
+ @a matches?(g)
170
+ g git(matched)
171
+
172
+ @b matches?(g)
173
+ g dup
174
+ g gif(done)
175
+
176
+ matched set!
177
+ g pop
178
+ g push-true
179
+
180
+ done set!
181
+
182
+ deconstruct(g, locals = #[]) := do:
183
+ b = g new-label
184
+ done = g new-label
185
+
186
+ g dup
187
+ g dup
188
+ @a matches?(g)
189
+ g gif(b)
190
+
191
+ @a deconstruct(g, locals)
192
+ g pop
193
+ g goto(done)
194
+
195
+ b set!
196
+ g pop
197
+ @b deconstruct(g, locals)
198
+
199
+ done set!
200
+
201
+ local-names := [@a local-names + @b local-names] uniq
202
+
203
+
204
+ -- base patterns
205
+ module(Atomy::AST):
206
+ export:
207
+ Variable pattern :=
208
+ Atomy::Patterns::Named new $:
209
+ @name
210
+ Atomy::Patterns::Any new
211
+
212
+ Primitive pattern :=
213
+ Atomy::Patterns::Match new(@value)
214
+
215
+ List pattern :=
216
+ Atomy::Patterns::List new $:
217
+ @elements collect [e]: e to-pattern
218
+
219
+ Constant pattern :=
220
+ Atomy::Patterns::Constant new(self)
221
+
222
+ ScopedConstant pattern :=
223
+ Atomy::Patterns::Constant new(self)
224
+
225
+ ToplevelConstant pattern :=
226
+ Atomy::Patterns::Constant new(self)
227
+
228
+ Quote pattern :=
229
+ Atomy::Patterns::Quote new(@expression)
230
+
231
+ Block pattern :=
232
+ Atomy::Patterns::SingletonClass new(self)
233
+
234
+ Particle pattern :=
235
+ Atomy::Patterns::Particle new(@name to-sym)
236
+
237
+ QuasiQuote pattern :=
238
+ Atomy::Patterns::QuasiQuote new(self)
239
+
240
+ Send pattern :=
241
+ if(@block)
242
+ then:
243
+ Atomy::Patterns::Named new $:
244
+ @method-name
245
+ @block contents [0] to-pattern
246
+ else:
247
+ Atomy::Patterns::Attribute new $:
248
+ @receiver
249
+ @method-name
250
+ @arguments
251
+
252
+ String pattern :=
253
+ Atomy::Patterns::Match new(@value)
254
+
255
+ Node pattern :=
256
+ raise("unknown pattern: " + self inspect)
@@ -0,0 +1,148 @@
1
+ namespace(atomy)
2
+
3
+ export:
4
+ module(Atomy::Patterns):
5
+ -- pattern precision hierarchy, from least precise to most
6
+ [ [ Any, BlockPass, Splat, Attribute,
7
+ NamedClass, NamedGlobal, NamedInstance
8
+ ]
9
+
10
+ [Constant, SingletonClass, RuntimeClass]
11
+
12
+ [HeadTail]
13
+
14
+ [List, QuasiQuote, Particle]
15
+
16
+ [Match, Quote]
17
+ ] each-with-index [ps, i]:
18
+ ps each [a]:
19
+ a send(#define-method, #precision):
20
+ i
21
+
22
+ Pattern precision := 0
23
+
24
+ Named precision := @pattern precision
25
+
26
+ Predicate precision :=
27
+ @pattern precision + 1
28
+
29
+ (a: Pattern) <=> (b: Pattern) :=
30
+ a precision <=> b precision
31
+
32
+ (a: BlockPass) <=> (b: BlockPass) :=
33
+ a pattern <=> b pattern
34
+
35
+ -- if one constant is a subclass of another, it is
36
+ -- higher precision.
37
+ (a: Constant) <=> (b: Constant) :=
38
+ condition:
39
+ (a ancestors nil? || b ancestors nil?) ->
40
+ 0
41
+
42
+ (a ancestors first == b ancestors first) ->
43
+ 0
44
+
45
+ b ancestors include?(a ancestors first) ->
46
+ -1
47
+
48
+ a ancestors include?(b ancestors first) ->
49
+ 1
50
+
51
+ otherwise ->
52
+ 0
53
+
54
+ (a: HeadTail) <=> (b: HeadTail) :=
55
+ Atomy::Patterns
56
+ compare([a head, a tail], [b head, b tail])
57
+
58
+ (a: List) <=> (b: List) :=
59
+ Atomy::Patterns
60
+ compare(a patterns, b patterns)
61
+
62
+ (a: Splat) <=> (b: Splat) :=
63
+ a pattern <=> b pattern
64
+
65
+ (a: Default) <=> (b: Default) :=
66
+ a pattern <=> b pattern
67
+ (d: Default) <=> (p: Pattern) := d pattern <=> p
68
+ (p: Pattern) <=> (d: Default) := p <=> d pattern
69
+
70
+ (a: Named) <=> (b: Named) :=
71
+ a pattern <=> b pattern
72
+ (n: Named) <=> (p: Pattern) :=
73
+ n pattern <=> p
74
+ (p: Pattern) <=> (n: Named) :=
75
+ p <=> n pattern
76
+
77
+
78
+ -- equivalence ignores named patterns
79
+ (a: Named) =~ (b: Named) :=
80
+ a pattern =~ b pattern
81
+ Named =~ (p: Pattern) := pattern =~ p
82
+ Pattern =~ (n: Named) := (=~ n pattern)
83
+
84
+ Any =~ Any := true
85
+
86
+ (a: BlockPass) =~ (b: BlockPass) :=
87
+ a pattern =~ b pattern
88
+
89
+ (a: Constant) =~ (b: Constant) :=
90
+ a constant =~ b constant
91
+
92
+ (a: Default) =~ (b: Default) :=
93
+ a pattern =~ b pattern
94
+ Default =~ (p: Pattern) := pattern =~ p
95
+ Pattern =~ (n: Default) := (=~ n pattern)
96
+
97
+ (a: HeadTail) =~ (b: HeadTail) :=
98
+ a head =~ b head && a tail =~ b tail
99
+
100
+ (a: List) =~ (b: List) :=
101
+ a patterns zip(b patterns) all? [[a, b]]:
102
+ when(a nil? || b nil?):
103
+ return(false)
104
+
105
+ a =~ b
106
+
107
+ (a: Match) =~ (b: Match) :=
108
+ a value == b value
109
+
110
+ (a: SingletonClass) =~ (b: SingletonClass) :=
111
+ a body == b body
112
+
113
+ NamedClass =~ NamedClass := true
114
+
115
+ NamedGlobal =~ NamedGlobal := true
116
+
117
+ NamedInstance =~ NamedInstance := true
118
+
119
+ (a: Particle) =~ (b: Particle) :=
120
+ a value == b value
121
+
122
+ (a: QuasiQuote) =~ (b: QuasiQuote) :=
123
+ -- TODO: go through quotes.
124
+ a expression == b expression
125
+
126
+ (a: Quote) =~ (b: Quote) :=
127
+ a expression == b expression
128
+
129
+ (a: Splat) =~ (b: Splat) :=
130
+ a pattern =~ b pattern
131
+
132
+ (a: Attribute) =~ (b: Attribute) :=
133
+ a receiver == b receiver &&
134
+ a name == b name &&
135
+ a arguments == b arguments
136
+
137
+ Pattern =~ Pattern := false
138
+
139
+
140
+ -- helper for comparing aggregate patterns like lists
141
+ { self } compare(xs, ys) := do:
142
+ total = 0
143
+
144
+ xs zip(ys) [[x, y]]:
145
+ unless(x nil? || y nil?):
146
+ total += x <=> y
147
+
148
+ total <=> 0
data/kernel/pretty.ay ADDED
@@ -0,0 +1,283 @@
1
+ namespace(atomy/pretty)
2
+
3
+ dynamic(multiline?, false)
4
+ dynamic(context, #top)
5
+ dynamic(colored?, false)
6
+
7
+ comma-delim(ds) :=
8
+ hsep(comma punctuate(ds))
9
+
10
+ ident(n) := text(n [0, 1] + n [1 .. -1] tr("_", "-") gsub("_ns_", "/"))
11
+
12
+ module(Atomy::AST):
13
+ Block unamb := pretty
14
+ ClassVariable unamb := pretty
15
+ Constant unamb := pretty
16
+ GlobalVariable unamb := pretty
17
+ (InlinedBody ? @contents size < 2) unamb := pretty
18
+ InstanceVariable unamb := pretty
19
+ List unamb := pretty
20
+ Particle unamb := pretty
21
+ Primitive unamb := pretty
22
+ QuasiQuote unamb := pretty
23
+ Quote unamb := pretty
24
+ ScopedConstant unamb := pretty
25
+ Send unamb :=
26
+ if(from?(#binary, #send))
27
+ then: pretty
28
+ else: Doc parens(pretty)
29
+ Splice unamb := pretty
30
+ String unamb := pretty
31
+ ToplevelConstant unamb := pretty
32
+ Unary unamb := pretty
33
+ Unquote unamb := pretty
34
+ Variable unamb := pretty
35
+ Node unamb := Doc parens(pretty)
36
+ _ unamb := pretty
37
+
38
+ from(*where, &y) :=
39
+ let(context = where flatten, &y)
40
+
41
+ from?(*where) :=
42
+ [^context, where] match:
43
+ [(a: Array), (b: Array)] ->
44
+ a any? [x]: b include?(x)
45
+ [(a: Array), b] ->
46
+ a include?(b)
47
+ [a, (b: Array)] ->
48
+ b include?(a)
49
+ [a, b] ->
50
+ a == b
51
+
52
+ export-to(atomy):
53
+ String pretty := super colored(#yellow)
54
+ Integer pretty := super colored(#blue)
55
+ Float pretty := super colored(#blue)
56
+ TrueClass pretty := super colored(#green)
57
+ FalseClass pretty := super colored(#red)
58
+ NilClass pretty := super colored(#black)
59
+ Object pretty := Doc text(inspect)
60
+
61
+ Object show := pretty render
62
+
63
+ Doc pretty := self
64
+
65
+ Array pretty :=
66
+ doc: brackets(comma-delim(self all-pretty))
67
+
68
+ Particle pretty := doc:
69
+ wildcard = [c]:
70
+ if(c equal?(_undefined))
71
+ then: '_
72
+ else: c
73
+
74
+ operator? = self message to-s !~ r"^[a-z_]"
75
+
76
+ args = self arguments collect(&#(wildcard [_]))
77
+
78
+ msg+args =
79
+ if(operator?)
80
+ then:
81
+ text(self message to-s) <+> args first unamb
82
+ else:
83
+ ident(self message to-s) <>
84
+ parens(comma-delim(args all-pretty))
85
+
86
+ partial =
87
+ if(self receiver equal?(_undefined))
88
+ then:
89
+ if(operator?)
90
+ then: parens(msg+args)
91
+ else: msg+args
92
+ else: parens(self receiver unamb <+> msg+args)
93
+
94
+ text("#") <> partial
95
+
96
+ Particle to-s := show
97
+
98
+ Symbol pretty := do:
99
+ s = to-s
100
+ if(s =~ r"^[\p{Ll}_]([\p{L}\d\p{S}!@#%&*\-_\\:.\/\?])*$"(u))
101
+ then: Doc text("#") <> Doc ident(s)
102
+ else: Doc text("#") <> s pretty
103
+
104
+ Hash pretty := doc:
105
+ text("#") <>
106
+ brackets $:
107
+ comma-delim $:
108
+ self to-a collect [[k, v]]:
109
+ k unamb <+> text("->") <+> v unamb
110
+
111
+ module(Atomy::AST):
112
+ Assign pretty :=
113
+ from(#assign):
114
+ doc: @lhs unamb <+> text("=") <+> @rhs unamb
115
+
116
+ BinarySend pretty :=
117
+ from(#binary):
118
+ doc: @lhs unamb <+> text(@operator) <+> @rhs unamb
119
+
120
+ Block pretty :=
121
+ doc:
122
+ args =
123
+ if(@arguments empty?)
124
+ then: empty
125
+ else: brackets(from(#list): comma-delim(@arguments all-pretty))
126
+
127
+ contents = from(#list): comma-delim(@contents all-pretty)
128
+ if(from?(#send-block) && from?(#top))
129
+ then: args <> colon <+> contents
130
+ else: args <+> lbrace <+> contents <+> rbrace
131
+
132
+ BlockPass pretty :=
133
+ from(#unary):
134
+ doc: text("&") <> @body unamb
135
+
136
+ Class pretty := doc:
137
+ sub =
138
+ if(@superclass kind-of?(Primitive) && @superclass value == #nil)
139
+ then: empty
140
+ else: text("<") <+> from(#binary): @superclass unamb
141
+
142
+ name =
143
+ @name match:
144
+ Rubinius::AST::ClassName -> text(@name) name to-s
145
+ _ -> @name unamb
146
+
147
+ body = lbrace <+> semi-delim(@body) expressions <+> rbrace
148
+
149
+ text("class") <> text("(") <> name <+> sub <> text(")") <+> body
150
+
151
+ ClassVariable pretty := doc: ident(name to-s)
152
+
153
+ Constant pretty := doc: text(@identifier)
154
+
155
+ Define pretty :=
156
+ from(#define):
157
+ doc: @lhs unamb <+> text(":=") <+> @body unamb
158
+
159
+ GlobalVariable pretty := doc: ident(name to-s)
160
+
161
+ InstanceVariable pretty := doc: ident(name to-s)
162
+
163
+ List pretty :=
164
+ from(#list):
165
+ doc: brackets(comma-delim(@elements all-pretty))
166
+
167
+ Macro pretty := doc:
168
+ text("macro") <+> parens(@pattern pretty) <+> @body pretty
169
+
170
+ Particle pretty := doc: text("#") <> ident(@name)
171
+
172
+ Primitive pretty := doc:
173
+ @value match:
174
+ -- TODO: glitch with #doc/#onto
175
+ #"self" -> text("self")
176
+ #true -> text("true")
177
+ #false -> text("false")
178
+ #nil -> text("nil")
179
+ x -> text(x inspect)
180
+
181
+ QuasiQuote pretty :=
182
+ from(#unary):
183
+ doc: text("`") <> @expression unamb
184
+
185
+ Quote pretty :=
186
+ from(#unary):
187
+ doc: text("'") <> @expression unamb
188
+
189
+ ScopedConstant pretty :=
190
+ from(#scoped-constant):
191
+ doc:
192
+ @parent unamb <> text("::") <> text(@identifier)
193
+
194
+ Send pretty :=
195
+ doc:
196
+ block =
197
+ from(#send-block, ^context):
198
+ if(@block) then: @block unamb; else: empty
199
+
200
+ with-block = [x]:
201
+ condition:
202
+ ^multiline? && @block is-a?(Block) -> do:
203
+ cs = from(#top): vcat(@block contents all-pretty) nest(2)
204
+ if(from?(#top))
205
+ then: x <> colon // cs
206
+ else: x <+> lbrace // cs // rbrace
207
+
208
+ from?(#top) && @block is-a?(Block) && @block arguments empty? ->
209
+ x <> block
210
+
211
+ otherwise ->
212
+ x <+> block
213
+
214
+ args =
215
+ from(#list):
216
+ if(@arguments empty?)
217
+ then: empty
218
+ else: parens(comma-delim(@arguments all-pretty))
219
+
220
+ condition:
221
+ @receiver kind-of?(Primitive) && @receiver value == #"self" ->
222
+ with-block [ident(@method-name) <> args]
223
+
224
+ otherwise ->
225
+ with-block [
226
+ from(#send) { @receiver unamb } <+>
227
+ ident(@method-name) <> args
228
+ ]
229
+
230
+ Splice pretty :=
231
+ from(#unary):
232
+ doc: text("~*") <> @expression unamb
233
+
234
+ String pretty := Doc text(@value inspect)
235
+
236
+ ToplevelConstant pretty := doc: text("::") <> text(@identifier)
237
+
238
+ Unary pretty :=
239
+ from(#unary):
240
+ doc: text(@operator) <> @receiver unamb
241
+
242
+ Unquote pretty :=
243
+ from(#unary):
244
+ doc: text("~") <> @expression unamb
245
+
246
+ Variable pretty := doc: ident(@name)
247
+
248
+ InlinedBody pretty := doc:
249
+ if(^multiline?)
250
+ then:
251
+ from(#top): vcat(@expressions all-pretty)
252
+ else:
253
+ from(#list): comma-delim(@expressions all-pretty)
254
+
255
+ Or pretty := `(~@a || ~@b) pretty
256
+
257
+ And pretty := `(~@a && ~@b) pretty
258
+
259
+ Ensure pretty := doc:
260
+ @body pretty <+> text("ensuring:") <+> @ensure pretty
261
+
262
+
263
+ Array all-pretty := collect [x]: x pretty
264
+
265
+ Doc colored(color) := do:
266
+ -- only makes sense to colorize if we're outputting to a terminal
267
+ unless(^output-port tty? && ^colored?):
268
+ return(self)
269
+
270
+ codes =
271
+ [ #black
272
+ #red
273
+ #green
274
+ #yellow
275
+ #blue
276
+ #magenta
277
+ #cyan
278
+ #white
279
+ ] zip((0 .. 7) to-a)
280
+
281
+ hash = Hash [codes]
282
+
283
+ Doc text("\e[9" + hash [color] to-s + "m") <> self <> Doc text("\e[0m")