rouge-lang 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +11 -0
- data/.gitignore +20 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +6 -0
- data/LICENSE +19 -0
- data/README.md +119 -0
- data/Rakefile +8 -0
- data/bin/rouge +2 -0
- data/lib/boot.rg +402 -0
- data/lib/rouge.rb +56 -0
- data/lib/rouge/atom.rb +25 -0
- data/lib/rouge/builtins.rb +596 -0
- data/lib/rouge/compiler.rb +108 -0
- data/lib/rouge/context.rb +235 -0
- data/lib/rouge/metadata.rb +19 -0
- data/lib/rouge/namespace.rb +125 -0
- data/lib/rouge/printer.rb +78 -0
- data/lib/rouge/reader.rb +433 -0
- data/lib/rouge/repl.rb +82 -0
- data/lib/rouge/seq.rb +221 -0
- data/lib/rouge/symbol.rb +77 -0
- data/lib/rouge/var.rb +69 -0
- data/lib/rouge/version.rb +7 -0
- data/lib/rouge/wrappers.rb +27 -0
- data/misc/TODO +45 -0
- data/misc/vimrc +1 -0
- data/rouge-lang.gemspec +28 -0
- data/spec/atom_spec.rb +39 -0
- data/spec/builtins_spec.rb +708 -0
- data/spec/compiler_spec.rb +137 -0
- data/spec/context_spec.rb +293 -0
- data/spec/core_spec.rg +123 -0
- data/spec/metadata_spec.rb +59 -0
- data/spec/namespace_spec.rb +125 -0
- data/spec/printer_spec.rb +191 -0
- data/spec/reader_spec.rb +422 -0
- data/spec/rouge_spec.rb +66 -0
- data/spec/seq_spec.rb +202 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/symbol_spec.rb +35 -0
- data/spec/var_spec.rb +61 -0
- data/spec/wrappers_spec.rb +51 -0
- metadata +216 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rouge/wrappers'
|
3
|
+
|
4
|
+
module Rouge::Printer
|
5
|
+
class UnknownFormError < StandardError; end
|
6
|
+
|
7
|
+
def self.print(form, out)
|
8
|
+
case form
|
9
|
+
when Integer
|
10
|
+
out << form.to_s
|
11
|
+
when Rouge::Symbol
|
12
|
+
if form.ns_s
|
13
|
+
out << form.ns_s
|
14
|
+
out << "/"
|
15
|
+
end
|
16
|
+
out << form.name_s
|
17
|
+
when Symbol
|
18
|
+
out << form.inspect
|
19
|
+
when String
|
20
|
+
out << form.inspect
|
21
|
+
when Array
|
22
|
+
out << "["
|
23
|
+
form.each.with_index do |e, i|
|
24
|
+
out << " " unless i.zero?
|
25
|
+
print(e, out)
|
26
|
+
end
|
27
|
+
out << "]"
|
28
|
+
when Rouge::Seq::Empty
|
29
|
+
out << "()"
|
30
|
+
when Rouge::Seq::Cons
|
31
|
+
if form.length == 2 and form[0] == Rouge::Symbol[:quote]
|
32
|
+
out << "'"
|
33
|
+
print(form[1], out)
|
34
|
+
elsif form.length == 2 and form[0] == Rouge::Symbol[:var]
|
35
|
+
out << "#'"
|
36
|
+
print(form[1], out)
|
37
|
+
else
|
38
|
+
out << "("
|
39
|
+
form.each.with_index do |e, i|
|
40
|
+
out << " " unless i.zero?
|
41
|
+
print(e, out)
|
42
|
+
end
|
43
|
+
out << ")"
|
44
|
+
end
|
45
|
+
when Rouge::Var
|
46
|
+
out << "#'#{form.ns}/#{form.name}"
|
47
|
+
when Hash
|
48
|
+
out << "{"
|
49
|
+
form.each.with_index do |kv,i|
|
50
|
+
out << ", " unless i.zero?
|
51
|
+
print(kv[0], out)
|
52
|
+
out << " "
|
53
|
+
print(kv[1], out)
|
54
|
+
end
|
55
|
+
out << "}"
|
56
|
+
when NilClass
|
57
|
+
out << "nil"
|
58
|
+
when TrueClass
|
59
|
+
out << "true"
|
60
|
+
when FalseClass
|
61
|
+
out << "false"
|
62
|
+
when Class, Module
|
63
|
+
if form.name
|
64
|
+
out << "ruby/#{form.name.split('::').join('.')}"
|
65
|
+
else
|
66
|
+
out << form.inspect
|
67
|
+
end
|
68
|
+
when Rouge::Builtin
|
69
|
+
out << "rouge.builtin/#{form.inner.name}"
|
70
|
+
when Regexp
|
71
|
+
out << "#\"#{form.source}\""
|
72
|
+
else
|
73
|
+
out << form.inspect
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# vim: set sw=2 et cc=80:
|
data/lib/rouge/reader.rb
ADDED
@@ -0,0 +1,433 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rouge/wrappers'
|
3
|
+
|
4
|
+
class Rouge::Reader
|
5
|
+
class UnexpectedCharacterError < StandardError; end
|
6
|
+
class EndOfDataError < StandardError; end
|
7
|
+
|
8
|
+
attr_accessor :ns
|
9
|
+
|
10
|
+
@@gensym_counter = 0
|
11
|
+
|
12
|
+
def initialize(ns, input)
|
13
|
+
@ns = ns
|
14
|
+
@src = input
|
15
|
+
@n = 0
|
16
|
+
@gensyms = []
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def lex
|
21
|
+
r =
|
22
|
+
case peek
|
23
|
+
when MAYBE_NUMBER
|
24
|
+
number
|
25
|
+
when /:/
|
26
|
+
keyword
|
27
|
+
when /"/
|
28
|
+
string
|
29
|
+
when /\(/
|
30
|
+
Rouge::Seq::Cons[*list(')')]
|
31
|
+
when /\[/
|
32
|
+
list ']'
|
33
|
+
when /#/
|
34
|
+
dispatch
|
35
|
+
when SYMBOL
|
36
|
+
# SYMBOL after \[ and #, because it includes both
|
37
|
+
symbol_or_number
|
38
|
+
when /{/
|
39
|
+
map
|
40
|
+
when /'/
|
41
|
+
quotation
|
42
|
+
when /`/
|
43
|
+
syntaxquotation
|
44
|
+
when /~/
|
45
|
+
dequotation
|
46
|
+
when /\^/
|
47
|
+
metadata
|
48
|
+
when /@/
|
49
|
+
deref
|
50
|
+
when nil
|
51
|
+
reader_raise EndOfDataError, "in #lex"
|
52
|
+
else
|
53
|
+
reader_raise UnexpectedCharacterError, "#{peek.inspect} in #lex"
|
54
|
+
end
|
55
|
+
|
56
|
+
r
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def number
|
62
|
+
read_number(slurp(MAYBE_NUMBER))
|
63
|
+
end
|
64
|
+
|
65
|
+
def keyword
|
66
|
+
begin
|
67
|
+
slurp(/:"/)
|
68
|
+
@n -= 1
|
69
|
+
s = string
|
70
|
+
s.intern
|
71
|
+
rescue UnexpectedCharacterError
|
72
|
+
slurp(/^:[a-zA-Z0-9\-_!\?\*\/]+/)[1..-1].intern
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def string
|
77
|
+
s = ""
|
78
|
+
t = consume
|
79
|
+
while true
|
80
|
+
c = @src[@n]
|
81
|
+
|
82
|
+
if c.nil?
|
83
|
+
reader_raise EndOfDataError, "in string, got: #{s}"
|
84
|
+
end
|
85
|
+
|
86
|
+
@n += 1
|
87
|
+
|
88
|
+
if c == t
|
89
|
+
break
|
90
|
+
end
|
91
|
+
|
92
|
+
if c == ?\\
|
93
|
+
c = consume
|
94
|
+
|
95
|
+
case c
|
96
|
+
when nil
|
97
|
+
reader_raise EndOfDataError, "in escaped string, got: #{s}"
|
98
|
+
when /[abefnrstv]/
|
99
|
+
c = {?a => ?\a,
|
100
|
+
?b => ?\b,
|
101
|
+
?e => ?\e,
|
102
|
+
?f => ?\f,
|
103
|
+
?n => ?\n,
|
104
|
+
?r => ?\r,
|
105
|
+
?s => ?\s,
|
106
|
+
?t => ?\t,
|
107
|
+
?v => ?\v}[c]
|
108
|
+
else
|
109
|
+
# Just leave it be.
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
s += c
|
114
|
+
end
|
115
|
+
s.freeze
|
116
|
+
end
|
117
|
+
|
118
|
+
def list(ending)
|
119
|
+
consume
|
120
|
+
r = []
|
121
|
+
|
122
|
+
while true
|
123
|
+
if peek == ending
|
124
|
+
break
|
125
|
+
end
|
126
|
+
r << lex
|
127
|
+
end
|
128
|
+
|
129
|
+
consume
|
130
|
+
r.freeze
|
131
|
+
end
|
132
|
+
|
133
|
+
def symbol_or_number
|
134
|
+
s = slurp(SYMBOL)
|
135
|
+
if (s[0] == ?- or s[0] == ?+) and s[1..-1] =~ NUMBER
|
136
|
+
read_number(s)
|
137
|
+
else
|
138
|
+
Rouge::Symbol[s.intern]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def map
|
143
|
+
consume
|
144
|
+
r = {}
|
145
|
+
|
146
|
+
while true
|
147
|
+
if peek == '}'
|
148
|
+
break
|
149
|
+
end
|
150
|
+
k = lex
|
151
|
+
v = lex
|
152
|
+
r[k] = v
|
153
|
+
end
|
154
|
+
|
155
|
+
consume
|
156
|
+
r.freeze
|
157
|
+
end
|
158
|
+
|
159
|
+
def quotation
|
160
|
+
consume
|
161
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote], lex]
|
162
|
+
end
|
163
|
+
|
164
|
+
def syntaxquotation
|
165
|
+
consume
|
166
|
+
@gensyms.unshift(@@gensym_counter += 1)
|
167
|
+
r = dequote lex
|
168
|
+
@gensyms.shift
|
169
|
+
r
|
170
|
+
end
|
171
|
+
|
172
|
+
def dequotation
|
173
|
+
consume
|
174
|
+
if peek == ?@
|
175
|
+
consume
|
176
|
+
Rouge::Splice[lex].freeze
|
177
|
+
else
|
178
|
+
Rouge::Dequote[lex].freeze
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def dequote form
|
183
|
+
case form
|
184
|
+
when Rouge::Seq::Cons, Array
|
185
|
+
rest = []
|
186
|
+
group = []
|
187
|
+
form.each do |f|
|
188
|
+
if f.is_a? Rouge::Splice
|
189
|
+
if group.length > 0
|
190
|
+
rest << Rouge::Seq::Cons[Rouge::Symbol[:list], *group]
|
191
|
+
group = []
|
192
|
+
end
|
193
|
+
rest << f.inner
|
194
|
+
else
|
195
|
+
group << dequote(f)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
if group.length > 0
|
200
|
+
rest << Rouge::Seq::Cons[Rouge::Symbol[:list], *group]
|
201
|
+
end
|
202
|
+
|
203
|
+
r =
|
204
|
+
if rest.length == 1
|
205
|
+
rest[0]
|
206
|
+
else
|
207
|
+
Rouge::Seq::Cons[Rouge::Symbol[:concat], *rest]
|
208
|
+
end
|
209
|
+
|
210
|
+
if form.is_a?(Array)
|
211
|
+
Rouge::Seq::Cons[Rouge::Symbol[:apply],
|
212
|
+
Rouge::Symbol[:vector],
|
213
|
+
r]
|
214
|
+
elsif rest.length > 1
|
215
|
+
Rouge::Seq::Cons[Rouge::Symbol[:seq], r]
|
216
|
+
else
|
217
|
+
r
|
218
|
+
end
|
219
|
+
when Hash
|
220
|
+
Hash[form.map {|k,v| [dequote(k), dequote(v)]}]
|
221
|
+
when Rouge::Dequote
|
222
|
+
form.inner
|
223
|
+
when Rouge::Symbol
|
224
|
+
if form.ns.nil? and form.name_s =~ /(\#)$/
|
225
|
+
Rouge::Seq::Cons[
|
226
|
+
Rouge::Symbol[:quote],
|
227
|
+
Rouge::Symbol[
|
228
|
+
("#{form.name.to_s.gsub(/(\#)$/, '')}__" \
|
229
|
+
"#{@gensyms[0]}__auto__").intern]]
|
230
|
+
elsif form.ns or form.name_s =~ /^\./ or %w(& |).include? form.name_s
|
231
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote], form]
|
232
|
+
elsif form.ns.nil?
|
233
|
+
begin
|
234
|
+
var = @ns[form.name]
|
235
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
236
|
+
Rouge::Symbol[var.name]]
|
237
|
+
rescue Rouge::Namespace::VarNotFoundError
|
238
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
239
|
+
Rouge::Symbol[:"#{@ns.name}/#{form.name}"]]
|
240
|
+
end
|
241
|
+
else
|
242
|
+
raise "impossible, right?" # XXX: be bothered to ensure this is so
|
243
|
+
end
|
244
|
+
else
|
245
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote], form]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def regexp
|
250
|
+
s = ""
|
251
|
+
t = '"'
|
252
|
+
while true
|
253
|
+
c = @src[@n]
|
254
|
+
|
255
|
+
if c.nil?
|
256
|
+
reader_raise EndOfDataError, "in regexp, got: #{s}"
|
257
|
+
end
|
258
|
+
|
259
|
+
@n += 1
|
260
|
+
|
261
|
+
if c == t
|
262
|
+
break
|
263
|
+
end
|
264
|
+
|
265
|
+
if c == ?\\
|
266
|
+
c = "\\"
|
267
|
+
if peek == ?"
|
268
|
+
c << consume
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
s << c
|
273
|
+
end
|
274
|
+
|
275
|
+
Regexp.new(s).freeze
|
276
|
+
end
|
277
|
+
|
278
|
+
def dispatch
|
279
|
+
consume
|
280
|
+
case peek
|
281
|
+
when '('
|
282
|
+
body, count = dispatch_rewrite_fn(lex, 0)
|
283
|
+
Rouge::Seq::Cons[
|
284
|
+
Rouge::Symbol[:fn],
|
285
|
+
(1..count).map {|n| Rouge::Symbol[:"%#{n}"]}.freeze,
|
286
|
+
body]
|
287
|
+
when "'"
|
288
|
+
consume
|
289
|
+
Rouge::Seq::Cons[Rouge::Symbol[:var], lex]
|
290
|
+
when "_"
|
291
|
+
consume
|
292
|
+
lex
|
293
|
+
lex
|
294
|
+
when '"'
|
295
|
+
consume
|
296
|
+
regexp
|
297
|
+
else
|
298
|
+
reader_raise UnexpectedCharacterError, "#{peek.inspect} in #dispatch"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def dispatch_rewrite_fn form, count
|
303
|
+
case form
|
304
|
+
when Rouge::Seq::Cons, Array
|
305
|
+
mapped = form.map do |e|
|
306
|
+
e, count = dispatch_rewrite_fn(e, count)
|
307
|
+
e
|
308
|
+
end.freeze
|
309
|
+
|
310
|
+
if form.is_a?(Rouge::Seq::Cons)
|
311
|
+
[Rouge::Seq::Cons[*mapped], count]
|
312
|
+
else
|
313
|
+
[mapped, count]
|
314
|
+
end
|
315
|
+
when Rouge::Symbol
|
316
|
+
if form.name == :"%"
|
317
|
+
[Rouge::Symbol[:"%1"], [1, count].max]
|
318
|
+
elsif form.name.to_s =~ /^%(\d+)$/
|
319
|
+
[form, [$1.to_i, count].max]
|
320
|
+
else
|
321
|
+
[form, count]
|
322
|
+
end
|
323
|
+
else
|
324
|
+
[form, count]
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def metadata
|
329
|
+
consume
|
330
|
+
meta = lex
|
331
|
+
attach = lex
|
332
|
+
|
333
|
+
if not attach.class < Rouge::Metadata
|
334
|
+
reader_raise ArgumentError,
|
335
|
+
"metadata can only be applied to classes mixing in Rouge::Metadata"
|
336
|
+
end
|
337
|
+
|
338
|
+
meta =
|
339
|
+
case meta
|
340
|
+
when Symbol
|
341
|
+
{meta => true}
|
342
|
+
when String
|
343
|
+
{:tag => meta}
|
344
|
+
else
|
345
|
+
meta
|
346
|
+
end
|
347
|
+
|
348
|
+
extant = attach.meta
|
349
|
+
if extant.nil?
|
350
|
+
attach.meta = meta
|
351
|
+
else
|
352
|
+
attach.meta = extant.merge(meta)
|
353
|
+
end
|
354
|
+
|
355
|
+
attach
|
356
|
+
end
|
357
|
+
|
358
|
+
def deref
|
359
|
+
consume
|
360
|
+
Rouge::Seq::Cons[Rouge::Symbol[:"rouge.core/deref"], lex]
|
361
|
+
end
|
362
|
+
|
363
|
+
def slurp re
|
364
|
+
@src[@n..-1] =~ re
|
365
|
+
reader_raise UnexpectedCharacterError, "#{@src[@n]} in #slurp #{re}" if !$&
|
366
|
+
@n += $&.length
|
367
|
+
$&
|
368
|
+
end
|
369
|
+
|
370
|
+
def peek
|
371
|
+
while @src[@n] =~ /[\s,;]/
|
372
|
+
if $& == ";"
|
373
|
+
while @src[@n] =~ /[^\n]/
|
374
|
+
@n += 1
|
375
|
+
end
|
376
|
+
else
|
377
|
+
@n += 1
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
@src[@n]
|
382
|
+
end
|
383
|
+
|
384
|
+
def consume
|
385
|
+
c = peek
|
386
|
+
@n += 1
|
387
|
+
c
|
388
|
+
end
|
389
|
+
|
390
|
+
def reader_raise ex, m
|
391
|
+
around =
|
392
|
+
"#{@src[[@n - 3, 0].max...[@n, 0].max]}" +
|
393
|
+
"#{@src[@n]}" +
|
394
|
+
"#{(@src[@n + 1..@n + 3] || "").gsub(/\n.*$/, '')}"
|
395
|
+
|
396
|
+
line = @src[0...@n].count("\n") + 1
|
397
|
+
char = @src[0...@n].reverse.index("\n") || 0 + 1
|
398
|
+
|
399
|
+
raise ex,
|
400
|
+
"around: #{around}\n" +
|
401
|
+
" ^\n" +
|
402
|
+
"line #{line} char #{char}: #{m}"
|
403
|
+
end
|
404
|
+
|
405
|
+
def read_number s
|
406
|
+
if NUMBER.match s
|
407
|
+
eval s
|
408
|
+
else
|
409
|
+
reader_raise UnexpectedCharacterError, "#{s} in #read_number"
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# Loose expression for a possible numeric literal.
|
414
|
+
MAYBE_NUMBER = /^[+-]?\d[\da-fA-FxX\._+-]*/
|
415
|
+
|
416
|
+
# Ruby integer.
|
417
|
+
INT = /\d+(?:_\d+)*/
|
418
|
+
|
419
|
+
# Strict expression for a numeric literal.
|
420
|
+
NUMBER = /
|
421
|
+
^[+-]?
|
422
|
+
(?:
|
423
|
+
(?:0[xX][\da-fA-F]+) (?# Hexadecimal integer)
|
424
|
+
| (?:0[bB][01]+) (?# Binary integer)
|
425
|
+
| (?:0\d+) (?# Octal integer)
|
426
|
+
| (?:#{INT}(?:(?:\.#{INT})?(?:[eE][+-]?#{INT})?)?) (?# Integers and floats)
|
427
|
+
)\z
|
428
|
+
/ox
|
429
|
+
|
430
|
+
SYMBOL = /^(\.\[\])|([a-zA-Z0-9\-_!&\?\*\/\.\+\|=%$<>#]+)/
|
431
|
+
end
|
432
|
+
|
433
|
+
# vim: set sw=2 et cc=80:
|