rouge-lang 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/bin/rouge +32 -13
- data/lib/rouge.rb +1 -5
- data/lib/rouge/builtins.rb +5 -0
- data/lib/rouge/context.rb +1 -1
- data/lib/rouge/printer.rb +2 -0
- data/lib/rouge/reader.rb +207 -140
- data/lib/rouge/repl.rb +3 -1
- data/lib/rouge/version.rb +1 -1
- data/spec/builtins_spec.rb +16 -10
- data/spec/core_spec.rg +3 -0
- data/spec/printer_spec.rb +1 -0
- data/spec/reader_spec.rb +37 -10
- data/spec/rouge_spec.rb +5 -1
- metadata +4 -4
data/.gitignore
CHANGED
data/bin/rouge
CHANGED
@@ -4,25 +4,37 @@ $: << "#{File.dirname(__FILE__)}/../lib"
|
|
4
4
|
require 'rouge'
|
5
5
|
require 'optparse'
|
6
6
|
|
7
|
+
# Boots Rouge and evaluates code in a new context. Prints non-nil results if
|
8
|
+
# print is true.
|
9
|
+
def evaluate(code, print = false)
|
10
|
+
Rouge.boot!
|
11
|
+
res = Rouge::Context.new(Rouge[:user]).readeval(code)
|
12
|
+
|
13
|
+
if print && res
|
14
|
+
puts Rouge.print(res, '')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
7
18
|
options = {:backtrace => true}
|
8
19
|
|
9
20
|
option_parser = OptionParser.new do |opts|
|
10
|
-
opts.banner = "rouge [switch] [filename]"
|
21
|
+
opts.banner = "Usage: rouge [switch] [filename]"
|
11
22
|
|
12
23
|
opts.on('-v', '--version', 'Print version number') do
|
13
24
|
puts "Rouge #{Rouge::VERSION}"
|
14
25
|
exit 0
|
15
26
|
end
|
16
27
|
|
17
|
-
opts.on('-e STR', '--eval STR',
|
18
|
-
|
19
|
-
|
28
|
+
opts.on('-e STR', '--eval STR',
|
29
|
+
'Evaluate expressions in STR; print non-nil results') do |str|
|
30
|
+
evaluate(str, true)
|
20
31
|
exit 0
|
21
32
|
end
|
22
33
|
|
23
34
|
opts.on('--time-startup', 'Report boot up time') do
|
35
|
+
start = Time.now
|
24
36
|
Rouge.boot!
|
25
|
-
puts Time.now -
|
37
|
+
puts Time.now - start
|
26
38
|
exit 0
|
27
39
|
end
|
28
40
|
|
@@ -37,8 +49,20 @@ rescue OptionParser::MissingArgument => e
|
|
37
49
|
puts "rouge: #{e}"
|
38
50
|
end
|
39
51
|
|
40
|
-
|
41
|
-
|
52
|
+
# Using a standalone '-', which traditionally is the switch for indicating
|
53
|
+
# acceptance of standard input, causes some subtle issues with the
|
54
|
+
# OptionParser.
|
55
|
+
if ARGV.include?('-')
|
56
|
+
code = ''
|
57
|
+
while line = STDIN.gets
|
58
|
+
code << line
|
59
|
+
end
|
60
|
+
evaluate(code, true)
|
61
|
+
exit 0
|
62
|
+
end
|
63
|
+
|
64
|
+
if ARGV.length >= 1
|
65
|
+
file = ARGV.shift
|
42
66
|
|
43
67
|
if File.file?(file)
|
44
68
|
code = File.read(file)
|
@@ -52,13 +76,8 @@ if ARGV.length == 1
|
|
52
76
|
code = code[code.index("\n") + 1..-1]
|
53
77
|
end
|
54
78
|
|
55
|
-
|
56
|
-
Rouge::Context.new(Rouge[:user]).readeval(code)
|
57
|
-
|
79
|
+
evaluate(code)
|
58
80
|
exit 0
|
59
|
-
elsif ARGV.length > 1
|
60
|
-
STDERR.puts option_parser.help
|
61
|
-
exit 1
|
62
81
|
end
|
63
82
|
|
64
83
|
Rouge.repl(options)
|
data/lib/rouge.rb
CHANGED
@@ -4,11 +4,6 @@ if RUBY_VERSION < "1.9"
|
|
4
4
|
STDERR.puts "Rouge will probably not run on anything less than Ruby 1.9."
|
5
5
|
end
|
6
6
|
|
7
|
-
module Rouge; end
|
8
|
-
|
9
|
-
start = Time.now
|
10
|
-
Rouge.define_singleton_method :start, lambda {start}
|
11
|
-
|
12
7
|
module Rouge
|
13
8
|
require 'rouge/version'
|
14
9
|
require 'rouge/wrappers'
|
@@ -36,6 +31,7 @@ module Rouge
|
|
36
31
|
|
37
32
|
core = Rouge[:"rouge.core"]
|
38
33
|
core.refer builtin
|
34
|
+
core.set_here(:"*command-line-args*", ARGV)
|
39
35
|
|
40
36
|
user = Rouge[:user]
|
41
37
|
user.refer builtin
|
data/lib/rouge/builtins.rb
CHANGED
@@ -245,8 +245,13 @@ class << Rouge::Builtins
|
|
245
245
|
|
246
246
|
def ns(context, name, *args)
|
247
247
|
ns = Rouge[name.name]
|
248
|
+
ns.refer Rouge[:"ruby"]
|
248
249
|
ns.refer Rouge[:"rouge.builtin"]
|
249
250
|
|
251
|
+
unless name.name == :"rouge.core"
|
252
|
+
ns.refer Rouge[:"rouge.core"]
|
253
|
+
end
|
254
|
+
|
250
255
|
args.each do |arg|
|
251
256
|
kind, *params = arg.to_a
|
252
257
|
|
data/lib/rouge/context.rb
CHANGED
data/lib/rouge/printer.rb
CHANGED
data/lib/rouge/reader.rb
CHANGED
@@ -3,7 +3,9 @@ require 'rouge/wrappers'
|
|
3
3
|
|
4
4
|
class Rouge::Reader
|
5
5
|
class UnexpectedCharacterError < StandardError; end
|
6
|
+
class NumberFormatError < StandardError; end
|
6
7
|
class EndOfDataError < StandardError; end
|
8
|
+
class EOFError < StandardError; end
|
7
9
|
|
8
10
|
attr_accessor :ns
|
9
11
|
|
@@ -17,54 +19,179 @@ class Rouge::Reader
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def lex
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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 EOFError, "in #lex"
|
52
|
+
else
|
53
|
+
reader_raise UnexpectedCharacterError, "#{peek.inspect} in #lex"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Loose expression for a possible numeric literal.
|
60
|
+
MAYBE_NUMBER = /^[+\-]?\d[\da-fA-FxX._+\-\/]*/
|
61
|
+
|
62
|
+
# Ruby integer.
|
63
|
+
INT = /\d+(?:_\d+)*/
|
64
|
+
|
65
|
+
# Strict expression for a numeric literal.
|
66
|
+
NUMBER = /
|
67
|
+
[+\-]?
|
68
|
+
(?:
|
69
|
+
(?:#{INT}(?:(?:\.#{INT})?(?:[eE][+\-]?#{INT})?)?) (?# Integers and floats)
|
70
|
+
| (?:0
|
71
|
+
(?:
|
72
|
+
(?:[xX][\da-fA-F]+) (?# Hexadecimal integer)
|
73
|
+
| (?:[bB][01]+) (?# Binary integer)
|
74
|
+
| (?:[0-7]+) (?# Octal integer)
|
75
|
+
)?
|
76
|
+
)
|
77
|
+
)
|
78
|
+
/ox
|
79
|
+
|
80
|
+
RATIONAL = /#{NUMBER}\/#{NUMBER}/o
|
81
|
+
|
82
|
+
SYMBOL = /
|
83
|
+
^(\.\[\])
|
84
|
+
|(\.?[-+]@)
|
85
|
+
|([a-zA-Z0-9\-_!&\?\*\/\.\+\|=%$<>#]+)
|
86
|
+
/x
|
87
|
+
|
88
|
+
# Advances the current character position by n characters and returns the
|
89
|
+
# updated character position.
|
90
|
+
def advance! n = 1
|
91
|
+
@n += n.abs
|
92
|
+
end
|
93
|
+
|
94
|
+
# Retracts the current character position by n characters and returns the
|
95
|
+
# updated character position.
|
96
|
+
def retract! n = 1
|
97
|
+
pos = @n - n.abs
|
98
|
+
|
99
|
+
if pos > 0
|
100
|
+
@n = pos
|
101
|
+
else
|
102
|
+
@n = 0
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns the character currently beneath the cursor.
|
107
|
+
def current_char
|
108
|
+
@src[@n]
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the string of characters matching the regular expression re relative
|
112
|
+
# to the cursor position. The cursor position is then advanced by n characters
|
113
|
+
# where n is the length of the returned string.
|
114
|
+
def slurp re
|
115
|
+
re.match(@src[@n..-1])
|
116
|
+
|
117
|
+
if $&
|
118
|
+
advance!($&.length)
|
119
|
+
$&
|
120
|
+
else
|
121
|
+
reader_raise UnexpectedCharacterError, "#{current_char} in #slurp #{re}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Advances the cursor position beyond whitespace and comments and returns the
|
126
|
+
# resulting character.
|
127
|
+
def peek
|
128
|
+
while /[\s,;]/.match(current_char)
|
129
|
+
if $& == ";"
|
130
|
+
while /[^\n]/.match(current_char)
|
131
|
+
advance!
|
132
|
+
end
|
51
133
|
else
|
52
|
-
|
134
|
+
advance!
|
53
135
|
end
|
136
|
+
end
|
54
137
|
|
55
|
-
|
138
|
+
current_char
|
56
139
|
end
|
57
140
|
|
58
|
-
|
141
|
+
# Returns the result of peek and advances the cursor position by character.
|
142
|
+
def consume
|
143
|
+
c = peek
|
144
|
+
advance!
|
145
|
+
c
|
146
|
+
end
|
147
|
+
|
148
|
+
# Raises the exception ex with the message msg including line information
|
149
|
+
# where the error occured. If the optional string cause is given, a more
|
150
|
+
# detailed report will be displayed.
|
151
|
+
def reader_raise ex, msg, cause = nil
|
152
|
+
# Locate the beginning of the line.
|
153
|
+
n = @n
|
154
|
+
until n == 0 || @src[n - 1] == "\n"
|
155
|
+
n -= 1
|
156
|
+
end
|
157
|
+
|
158
|
+
lines = @src[n..-1].lines.to_a
|
159
|
+
line = lines.first
|
160
|
+
line_no = (@src.lines.to_a.index(line) || 0) + 1
|
59
161
|
|
60
|
-
|
61
|
-
|
162
|
+
if cause
|
163
|
+
error_position = line.index(cause)
|
164
|
+
indicator = (" " * error_position) << ("^" * cause.length)
|
165
|
+
info = "on line #{line_no} at char #{error_position}"
|
166
|
+
parts = [msg, line.chomp, indicator, info]
|
167
|
+
else
|
168
|
+
info = "on line #{line_no}"
|
169
|
+
parts = [msg, info]
|
170
|
+
end
|
171
|
+
|
172
|
+
raise ex, parts.join("\n")
|
173
|
+
end
|
174
|
+
|
175
|
+
def number s = slurp(MAYBE_NUMBER)
|
176
|
+
if /\A#{NUMBER}\z/o.match(s)
|
177
|
+
# Match decimal numbers but not hexadecimal numbers.
|
178
|
+
if /[.eE]/.match(s) && /[^xX]/.match(s)
|
179
|
+
Float(s)
|
180
|
+
else
|
181
|
+
Integer(s)
|
182
|
+
end
|
183
|
+
elsif /\A#{RATIONAL}\z/o.match(s)
|
184
|
+
numerator, denominator = s.split("/").map {|s| number(s) }
|
185
|
+
Rational(numerator, denominator)
|
186
|
+
else
|
187
|
+
reader_raise NumberFormatError, "Invalid number #{s}", s
|
188
|
+
end
|
62
189
|
end
|
63
190
|
|
64
191
|
def keyword
|
65
192
|
begin
|
66
193
|
slurp(/:"/)
|
67
|
-
|
194
|
+
retract!
|
68
195
|
s = string
|
69
196
|
s.intern
|
70
197
|
rescue UnexpectedCharacterError
|
@@ -76,13 +203,13 @@ class Rouge::Reader
|
|
76
203
|
s = ""
|
77
204
|
t = consume
|
78
205
|
while true
|
79
|
-
c =
|
206
|
+
c = current_char
|
80
207
|
|
81
208
|
if c.nil?
|
82
|
-
reader_raise EndOfDataError, "in string, got: #{s}"
|
209
|
+
reader_raise EndOfDataError, "in string, got: \"#{s}"
|
83
210
|
end
|
84
211
|
|
85
|
-
|
212
|
+
advance!
|
86
213
|
|
87
214
|
if c == t
|
88
215
|
break
|
@@ -93,23 +220,25 @@ class Rouge::Reader
|
|
93
220
|
|
94
221
|
case c
|
95
222
|
when nil
|
96
|
-
reader_raise EndOfDataError, "in escaped string, got: #{s}"
|
223
|
+
reader_raise EndOfDataError, "in escaped string, got: \"#{s}"
|
97
224
|
when /[abefnrstv]/
|
98
|
-
c = {
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
225
|
+
c = {
|
226
|
+
?a => ?\a,
|
227
|
+
?b => ?\b,
|
228
|
+
?e => ?\e,
|
229
|
+
?f => ?\f,
|
230
|
+
?n => ?\n,
|
231
|
+
?r => ?\r,
|
232
|
+
?s => ?\s,
|
233
|
+
?t => ?\t,
|
234
|
+
?v => ?\v
|
235
|
+
}[c]
|
107
236
|
else
|
108
237
|
# Just leave it be.
|
109
238
|
end
|
110
239
|
end
|
111
240
|
|
112
|
-
s
|
241
|
+
s << c
|
113
242
|
end
|
114
243
|
s.freeze
|
115
244
|
end
|
@@ -118,21 +247,21 @@ class Rouge::Reader
|
|
118
247
|
consume
|
119
248
|
r = []
|
120
249
|
|
121
|
-
|
122
|
-
if peek == ending
|
123
|
-
break
|
124
|
-
end
|
250
|
+
until peek == ending
|
125
251
|
r << lex
|
126
252
|
end
|
127
253
|
|
128
254
|
consume
|
129
255
|
r.freeze
|
256
|
+
rescue EOFError
|
257
|
+
reader_raise EndOfDataError, "in #list"
|
130
258
|
end
|
131
259
|
|
132
260
|
def symbol_or_number
|
133
261
|
s = slurp(SYMBOL)
|
134
|
-
|
135
|
-
|
262
|
+
|
263
|
+
if MAYBE_NUMBER.match(s)
|
264
|
+
number(s)
|
136
265
|
else
|
137
266
|
Rouge::Symbol[s.intern]
|
138
267
|
end
|
@@ -142,22 +271,22 @@ class Rouge::Reader
|
|
142
271
|
consume
|
143
272
|
r = {}
|
144
273
|
|
145
|
-
|
146
|
-
|
147
|
-
break
|
148
|
-
end
|
149
|
-
k = lex
|
150
|
-
v = lex
|
274
|
+
until peek == '}'
|
275
|
+
k, v = lex, lex
|
151
276
|
r[k] = v
|
152
277
|
end
|
153
278
|
|
154
279
|
consume
|
155
280
|
r.freeze
|
281
|
+
rescue EOFError
|
282
|
+
reader_raise EndOfDataError, "in #map"
|
156
283
|
end
|
157
284
|
|
158
285
|
def quotation
|
159
286
|
consume
|
160
287
|
Rouge::Seq::Cons[Rouge::Symbol[:quote], lex]
|
288
|
+
rescue EOFError
|
289
|
+
reader_raise EndOfDataError, "in #quotation"
|
161
290
|
end
|
162
291
|
|
163
292
|
def syntaxquotation
|
@@ -166,6 +295,8 @@ class Rouge::Reader
|
|
166
295
|
r = dequote(lex)
|
167
296
|
@gensyms.shift
|
168
297
|
r
|
298
|
+
rescue EOFError
|
299
|
+
reader_raise EndOfDataError, "in #syntaxquotation"
|
169
300
|
end
|
170
301
|
|
171
302
|
def dequotation
|
@@ -176,6 +307,8 @@ class Rouge::Reader
|
|
176
307
|
else
|
177
308
|
Rouge::Dequote[lex].freeze
|
178
309
|
end
|
310
|
+
rescue EOFError
|
311
|
+
reader_raise EndOfDataError, "in #dequotation"
|
179
312
|
end
|
180
313
|
|
181
314
|
def dequote form
|
@@ -250,13 +383,13 @@ class Rouge::Reader
|
|
250
383
|
terminator = '"'
|
251
384
|
|
252
385
|
while true
|
253
|
-
char =
|
386
|
+
char = current_char
|
254
387
|
|
255
388
|
if char.nil?
|
256
389
|
reader_raise EndOfDataError, "in regexp, got: #{expression}"
|
257
390
|
end
|
258
391
|
|
259
|
-
|
392
|
+
advance!
|
260
393
|
|
261
394
|
if char == terminator
|
262
395
|
break
|
@@ -281,12 +414,13 @@ class Rouge::Reader
|
|
281
414
|
s = Set.new
|
282
415
|
|
283
416
|
until peek == '}'
|
284
|
-
|
285
|
-
s.add el
|
417
|
+
s.add(lex)
|
286
418
|
end
|
287
419
|
|
288
420
|
consume
|
289
421
|
s.freeze
|
422
|
+
rescue EOFError
|
423
|
+
reader_raise EndOfDataError, "in #set"
|
290
424
|
end
|
291
425
|
|
292
426
|
def dispatch
|
@@ -314,6 +448,8 @@ class Rouge::Reader
|
|
314
448
|
else
|
315
449
|
reader_raise UnexpectedCharacterError, "#{peek.inspect} in #dispatch"
|
316
450
|
end
|
451
|
+
rescue EOFError
|
452
|
+
reader_raise EndOfDataError, "in #dispatch"
|
317
453
|
end
|
318
454
|
|
319
455
|
def dispatch_rewrite_fn form, count
|
@@ -370,85 +506,16 @@ class Rouge::Reader
|
|
370
506
|
end
|
371
507
|
|
372
508
|
attach
|
509
|
+
rescue EOFError
|
510
|
+
reader_raise EndOfDataError, "in #meta"
|
373
511
|
end
|
374
512
|
|
375
513
|
def deref
|
376
514
|
consume
|
377
515
|
Rouge::Seq::Cons[Rouge::Symbol[:"rouge.core/deref"], lex]
|
516
|
+
rescue EOFError
|
517
|
+
reader_raise EndOfDataError, "in #deref"
|
378
518
|
end
|
379
|
-
|
380
|
-
def slurp re
|
381
|
-
@src[@n..-1] =~ re
|
382
|
-
reader_raise UnexpectedCharacterError, "#{@src[@n]} in #slurp #{re}" if !$&
|
383
|
-
@n += $&.length
|
384
|
-
$&
|
385
|
-
end
|
386
|
-
|
387
|
-
def peek
|
388
|
-
while @src[@n] =~ /[\s,;]/
|
389
|
-
if $& == ";"
|
390
|
-
while @src[@n] =~ /[^\n]/
|
391
|
-
@n += 1
|
392
|
-
end
|
393
|
-
else
|
394
|
-
@n += 1
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
@src[@n]
|
399
|
-
end
|
400
|
-
|
401
|
-
def consume
|
402
|
-
c = peek
|
403
|
-
@n += 1
|
404
|
-
c
|
405
|
-
end
|
406
|
-
|
407
|
-
def reader_raise ex, m
|
408
|
-
around =
|
409
|
-
"#{@src[[@n - 3, 0].max...[@n, 0].max]}" +
|
410
|
-
"#{@src[@n]}" +
|
411
|
-
"#{(@src[@n + 1..@n + 3] || "").gsub(/\n.*$/, '')}"
|
412
|
-
|
413
|
-
line = @src[0...@n].count("\n") + 1
|
414
|
-
char = @src[0...@n].reverse.index("\n") || 0 + 1
|
415
|
-
|
416
|
-
raise ex,
|
417
|
-
"around: #{around}\n" +
|
418
|
-
" ^\n" +
|
419
|
-
"line #{line} char #{char}: #{m}"
|
420
|
-
end
|
421
|
-
|
422
|
-
def read_number s
|
423
|
-
if NUMBER.match s
|
424
|
-
if s =~ /[.eE]/
|
425
|
-
Float(s)
|
426
|
-
else
|
427
|
-
Integer(s)
|
428
|
-
end
|
429
|
-
else
|
430
|
-
reader_raise UnexpectedCharacterError, "#{s} in #read_number"
|
431
|
-
end
|
432
|
-
end
|
433
|
-
|
434
|
-
# Loose expression for a possible numeric literal.
|
435
|
-
MAYBE_NUMBER = /^[+-]?\d[\da-fA-FxX\._+-]*/
|
436
|
-
|
437
|
-
# Ruby integer.
|
438
|
-
INT = /\d+(?:_\d+)*/
|
439
|
-
|
440
|
-
# Strict expression for a numeric literal.
|
441
|
-
NUMBER = /
|
442
|
-
^[+-]?
|
443
|
-
(?:
|
444
|
-
(?:0[xX][\da-fA-F]+) (?# Hexadecimal integer)
|
445
|
-
| (?:0[bB][01]+) (?# Binary integer)
|
446
|
-
| (?:0\d+) (?# Octal integer)
|
447
|
-
| (?:#{INT}(?:(?:\.#{INT})?(?:[eE][+-]?#{INT})?)?) (?# Integers and floats)
|
448
|
-
)\z
|
449
|
-
/ox
|
450
|
-
|
451
|
-
SYMBOL = /^(\.\[\])|(\.?[-+]@)|([a-zA-Z0-9\-_!&\?\*\/\.\+\|=%$<>#]+)/
|
452
519
|
end
|
453
520
|
|
454
521
|
# vim: set sw=2 et cc=80:
|
data/lib/rouge/repl.rb
CHANGED
@@ -24,7 +24,7 @@ module Rouge::REPL
|
|
24
24
|
input = Readline.readline(prompt, true)
|
25
25
|
else
|
26
26
|
prompt = "#{" " * [0, context.ns.name.length - 2].max}#_=> "
|
27
|
-
input
|
27
|
+
input << "\n" + Readline.readline(prompt, true)
|
28
28
|
end
|
29
29
|
|
30
30
|
if input.nil?
|
@@ -39,6 +39,8 @@ module Rouge::REPL
|
|
39
39
|
next
|
40
40
|
rescue Rouge::Reader::UnexpectedCharacterError => reader_err
|
41
41
|
repl_error.call reader_err
|
42
|
+
rescue Rouge::Reader::NumberFormatError => reader_err
|
43
|
+
repl_error.call reader_err
|
42
44
|
end
|
43
45
|
|
44
46
|
chaining = false
|
data/lib/rouge/version.rb
CHANGED
data/spec/builtins_spec.rb
CHANGED
@@ -154,7 +154,7 @@ describe Rouge::Builtins do
|
|
154
154
|
|
155
155
|
describe "storing its own name" do
|
156
156
|
let(:fn) { context.readeval('(fn lmnop [])') }
|
157
|
-
|
157
|
+
|
158
158
|
it { fn.to_s.should eq :lmnop }
|
159
159
|
end
|
160
160
|
|
@@ -251,9 +251,9 @@ describe Rouge::Builtins do
|
|
251
251
|
|
252
252
|
describe "evaluating and returning one argument" do
|
253
253
|
let(:subcontext) { Rouge::Context.new context }
|
254
|
-
|
254
|
+
|
255
255
|
before { subcontext.set_here :x, lambda {4} }
|
256
|
-
|
256
|
+
|
257
257
|
it { subcontext.readeval('(do (x))').should eq 4 }
|
258
258
|
end
|
259
259
|
|
@@ -332,6 +332,12 @@ describe Rouge::Builtins do
|
|
332
332
|
ROUGE
|
333
333
|
Rouge::Namespace[:y].should be Rouge::Namespace[:moop]
|
334
334
|
end
|
335
|
+
|
336
|
+
it "should refer rouge.core and ruby" do
|
337
|
+
context.readeval "(ns toast)"
|
338
|
+
Rouge[:toast].refers.should include(Rouge[:"rouge.core"])
|
339
|
+
Rouge[:toast].refers.should include(Rouge[:"ruby"])
|
340
|
+
end
|
335
341
|
end
|
336
342
|
|
337
343
|
it "should compile without compiling any of its components" do
|
@@ -353,7 +359,7 @@ describe Rouge::Builtins do
|
|
353
359
|
|
354
360
|
describe "after readeval (def ...)" do
|
355
361
|
before { context.readeval("(def b 'c)") }
|
356
|
-
|
362
|
+
|
357
363
|
it { expect { context.readeval("(defmacro a [] b)")
|
358
364
|
}.to_not raise_exception }
|
359
365
|
end
|
@@ -405,7 +411,7 @@ describe Rouge::Builtins do
|
|
405
411
|
end
|
406
412
|
|
407
413
|
it "should compile multi-arg form with names bound" do
|
408
|
-
# TODO: consider breaking out these two test assertion
|
414
|
+
# TODO: consider breaking out these two test assertion
|
409
415
|
# blocks into their own context: they actually both fail
|
410
416
|
# in isolation but those failures are masked because
|
411
417
|
# the "Rouge::Builtins._compile_defmacro" test passes,
|
@@ -418,13 +424,13 @@ describe Rouge::Builtins do
|
|
418
424
|
# lexicals.should eq Set[:f]
|
419
425
|
# [:a1]
|
420
426
|
#end
|
421
|
-
#
|
427
|
+
#
|
422
428
|
#Rouge::Compiler.should_receive(:compile).
|
423
429
|
# with(ns, kind_of(Set), [:a2]) do |n, lexicals, f|
|
424
430
|
# lexicals.should eq Set[:g]
|
425
431
|
# [:a2]
|
426
432
|
#end
|
427
|
-
#
|
433
|
+
#
|
428
434
|
Rouge::Builtins._compile_defmacro(
|
429
435
|
ns, Set.new,
|
430
436
|
Rouge::Symbol[:barge],
|
@@ -443,7 +449,7 @@ describe Rouge::Builtins do
|
|
443
449
|
describe "apply" do
|
444
450
|
let(:a) { lambda {|*args| args} }
|
445
451
|
let(:subcontext) { Rouge::Context.new context }
|
446
|
-
|
452
|
+
|
447
453
|
before { subcontext.set_here :a, a }
|
448
454
|
|
449
455
|
describe "calling a function with the argument list" do
|
@@ -645,7 +651,7 @@ describe Rouge::Builtins do
|
|
645
651
|
let(:x) { lambda {} }
|
646
652
|
|
647
653
|
before { context.set_here :x, x }
|
648
|
-
|
654
|
+
|
649
655
|
it { context.readeval("(destructure [a | b] [1 | x])").to_s.
|
650
656
|
should eq({Rouge::Symbol[:a] => 1,
|
651
657
|
Rouge::Symbol[:b] => x}.to_s) }
|
@@ -674,7 +680,7 @@ describe Rouge::Builtins do
|
|
674
680
|
Rouge::Builtins._compile_destructure(
|
675
681
|
ns, Set.new, Rouge::Symbol[:z], Rouge::Symbol[:z])
|
676
682
|
}.to raise_exception }
|
677
|
-
|
683
|
+
|
678
684
|
it { expect {
|
679
685
|
Rouge::Builtins._compile_destructure(
|
680
686
|
ns, Set[:y], Rouge::Symbol[:z], Rouge::Symbol[:y])
|
data/spec/core_spec.rg
CHANGED
data/spec/printer_spec.rb
CHANGED
data/spec/reader_spec.rb
CHANGED
@@ -39,12 +39,23 @@ describe Rouge::Reader do
|
|
39
39
|
it { @ns.read("-0333").should eq(-219) }
|
40
40
|
end
|
41
41
|
|
42
|
-
context "
|
43
|
-
it {
|
44
|
-
|
42
|
+
context "rationals" do
|
43
|
+
it { @ns.read("1/2").should be_an_instance_of Rational }
|
44
|
+
it { @ns.read("0b1000/0x4").should eq(Rational(2, 1)) }
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
context "bad numbers" do
|
48
|
+
it {
|
49
|
+
expect {
|
50
|
+
@ns.read("1.2.3")
|
51
|
+
}.to raise_exception Rouge::Reader::NumberFormatError
|
52
|
+
}
|
53
|
+
|
54
|
+
it {
|
55
|
+
expect {
|
56
|
+
@ns.read("12..")
|
57
|
+
}.to raise_exception Rouge::Reader::NumberFormatError
|
58
|
+
}
|
48
59
|
end
|
49
60
|
end
|
50
61
|
|
@@ -266,10 +277,10 @@ describe Rouge::Reader do
|
|
266
277
|
|
267
278
|
describe "empty reads" do
|
268
279
|
it { expect { @ns.read("")
|
269
|
-
}.to raise_exception(Rouge::Reader::
|
280
|
+
}.to raise_exception(Rouge::Reader::EOFError) }
|
270
281
|
|
271
282
|
it { expect { @ns.read(" \n ")
|
272
|
-
}.to raise_exception(Rouge::Reader::
|
283
|
+
}.to raise_exception(Rouge::Reader::EOFError) }
|
273
284
|
end
|
274
285
|
|
275
286
|
describe "comments" do
|
@@ -277,7 +288,7 @@ describe Rouge::Reader do
|
|
277
288
|
it { @ns.read("[42 ;what!\n15]").should eq [42, 15] }
|
278
289
|
|
279
290
|
it { expect { @ns.read(";what!")
|
280
|
-
}.to raise_exception(Rouge::Reader::
|
291
|
+
}.to raise_exception(Rouge::Reader::EOFError) }
|
281
292
|
|
282
293
|
it { @ns.read(";what!\nhmm").should eq Rouge::Symbol[:hmm] }
|
283
294
|
end
|
@@ -427,8 +438,7 @@ describe Rouge::Reader do
|
|
427
438
|
r.lex.should eq Rouge::Symbol[:b]
|
428
439
|
r.lex.should eq Rouge::Symbol[:c]
|
429
440
|
|
430
|
-
expect { r.lex
|
431
|
-
}.to raise_exception(Rouge::Reader::EndOfDataError)
|
441
|
+
expect { r.lex }.to raise_exception(Rouge::Reader::EOFError)
|
432
442
|
end
|
433
443
|
end
|
434
444
|
|
@@ -443,6 +453,23 @@ describe Rouge::Reader do
|
|
443
453
|
describe "regexp" do
|
444
454
|
it { @ns.read('#"abc"').should be_an_instance_of Regexp }
|
445
455
|
end
|
456
|
+
|
457
|
+
describe "bad reads" do
|
458
|
+
let(:ex) { Rouge::Reader::EndOfDataError }
|
459
|
+
it { expect { @ns.read('(') }.to raise_exception(ex) }
|
460
|
+
it { expect { @ns.read('{') }.to raise_exception(ex) }
|
461
|
+
it { expect { @ns.read('[') }.to raise_exception(ex) }
|
462
|
+
it { expect { @ns.read('"') }.to raise_exception(ex) }
|
463
|
+
it { expect { @ns.read("'") }.to raise_exception(ex) }
|
464
|
+
it { expect { @ns.read('`') }.to raise_exception(ex) }
|
465
|
+
it { expect { @ns.read('~') }.to raise_exception(ex) }
|
466
|
+
it { expect { @ns.read('@') }.to raise_exception(ex) }
|
467
|
+
it { expect { @ns.read('#(') }.to raise_exception(ex) }
|
468
|
+
it { expect { @ns.read('#{') }.to raise_exception(ex) }
|
469
|
+
it { expect { @ns.read("#'") }.to raise_exception(ex) }
|
470
|
+
it { expect { @ns.read("#_") }.to raise_exception(ex) }
|
471
|
+
it { expect { @ns.read('#"') }.to raise_exception(ex) }
|
472
|
+
end
|
446
473
|
end
|
447
474
|
|
448
475
|
# vim: set sw=2 et cc=80:
|
data/spec/rouge_spec.rb
CHANGED
@@ -18,6 +18,10 @@ describe Rouge do
|
|
18
18
|
@ns[:defn].should be_an_instance_of Rouge::Macro
|
19
19
|
}.should_not raise_exception(Rouge::Context::BindingNotFoundError)
|
20
20
|
end
|
21
|
+
|
22
|
+
it "should contain special variables" do
|
23
|
+
@ns[:"*command-line-args*"].should be_an_instance_of Rouge::Var
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
describe "the user namespace" do
|
@@ -45,7 +49,7 @@ describe Rouge do
|
|
45
49
|
|
46
50
|
total = r[:passed] + r[:failed].length
|
47
51
|
|
48
|
-
message =
|
52
|
+
message =
|
49
53
|
"#{total} example#{total == 1 ? "" : "s"}, " +
|
50
54
|
"#{r[:failed].length} failure#{r[:failed].length == 1 ? "" : "s"}"
|
51
55
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rouge-lang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -188,7 +188,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
188
188
|
version: '0'
|
189
189
|
segments:
|
190
190
|
- 0
|
191
|
-
hash:
|
191
|
+
hash: 809418637
|
192
192
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
193
|
none: false
|
194
194
|
requirements:
|
@@ -197,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
197
|
version: '0'
|
198
198
|
segments:
|
199
199
|
- 0
|
200
|
-
hash:
|
200
|
+
hash: 809418637
|
201
201
|
requirements: []
|
202
202
|
rubyforge_project:
|
203
203
|
rubygems_version: 1.8.24
|