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
@@ -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")