rouge-lang 0.0.7 → 0.0.8
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.
- 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
|