rouge-lang 0.0.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.
- 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
data/lib/rouge/repl.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'readline'
|
3
|
+
|
4
|
+
module Rouge::REPL; end
|
5
|
+
|
6
|
+
class << Rouge::REPL
|
7
|
+
def repl_error(e)
|
8
|
+
STDOUT.puts "!! #{e.class}: #{e.message}"
|
9
|
+
STDOUT.puts "#{e.backtrace.join "\n"}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def repl(argv)
|
13
|
+
context = Rouge::Context.new Rouge[:user]
|
14
|
+
|
15
|
+
if ARGV == ["--time-startup"]
|
16
|
+
STDOUT.puts Time.now - Rouge.start
|
17
|
+
exit(0)
|
18
|
+
elsif argv.length == 1
|
19
|
+
f = File.read(argv[0])
|
20
|
+
if f[0] == ?#
|
21
|
+
f = f[f.index("\n") + 1..-1]
|
22
|
+
end
|
23
|
+
|
24
|
+
context.readeval(f)
|
25
|
+
exit(0)
|
26
|
+
elsif argv.length > 1
|
27
|
+
STDERR.puts "!! usage: #$0 [FILE]"
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
count = 0
|
32
|
+
chaining = false
|
33
|
+
while true
|
34
|
+
if not chaining
|
35
|
+
prompt = "#{context.ns.name}=> "
|
36
|
+
input = Readline.readline(prompt, true)
|
37
|
+
else
|
38
|
+
prompt = "#{" " * [0, context.ns.name.length - 2].max}#_=> "
|
39
|
+
input += "\n" + Readline.readline(prompt, true)
|
40
|
+
end
|
41
|
+
|
42
|
+
if input.nil?
|
43
|
+
STDOUT.print "\n"
|
44
|
+
break
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
form = context.ns.read(input)
|
49
|
+
rescue Rouge::Reader::EndOfDataError
|
50
|
+
chaining = true
|
51
|
+
next
|
52
|
+
rescue Rouge::Reader::UnexpectedCharacterError => reader_err
|
53
|
+
repl_error reader_err
|
54
|
+
end
|
55
|
+
|
56
|
+
chaining = false
|
57
|
+
begin
|
58
|
+
form = Rouge::Compiler.compile(
|
59
|
+
context.ns,
|
60
|
+
Set[*context.lexical_keys],
|
61
|
+
form)
|
62
|
+
result = context.eval(form)
|
63
|
+
|
64
|
+
Rouge.print(result, STDOUT)
|
65
|
+
STDOUT.puts
|
66
|
+
|
67
|
+
count += 1 if count < 10
|
68
|
+
count.downto(2) do |i|
|
69
|
+
context.set_here :"*#{i}", context[:"*#{i - 1}"]
|
70
|
+
end
|
71
|
+
context.set_here :"*1", result
|
72
|
+
rescue Rouge::Context::ChangeContextException => cce
|
73
|
+
context = cce.context
|
74
|
+
count = 0
|
75
|
+
rescue => e
|
76
|
+
repl_error e
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# vim: set sw=2 et cc=80:
|
data/lib/rouge/seq.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rouge::Seq
|
4
|
+
Empty = Object.new
|
5
|
+
|
6
|
+
class Cons; end
|
7
|
+
|
8
|
+
module ISeq; end
|
9
|
+
|
10
|
+
module ASeq
|
11
|
+
include ISeq
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"(#{to_a.map(&:inspect).join " "})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s; inspect; end
|
18
|
+
|
19
|
+
def seq; self; end
|
20
|
+
|
21
|
+
def first; raise NotImplementedError; end
|
22
|
+
def next; raise NotImplementedError; end
|
23
|
+
|
24
|
+
def more
|
25
|
+
s = self.next
|
26
|
+
if s.nil?
|
27
|
+
Empty
|
28
|
+
else
|
29
|
+
s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def cons(o)
|
34
|
+
Cons.new(o, self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def length
|
38
|
+
l = 0
|
39
|
+
cursor = self
|
40
|
+
|
41
|
+
while cursor != Empty
|
42
|
+
l += 1
|
43
|
+
cursor = cursor.more
|
44
|
+
end
|
45
|
+
|
46
|
+
l
|
47
|
+
end
|
48
|
+
|
49
|
+
alias count length
|
50
|
+
|
51
|
+
def [](i)
|
52
|
+
return to_a[i] if i.is_a? Range
|
53
|
+
|
54
|
+
cursor = self
|
55
|
+
|
56
|
+
i += self.length if i < 0
|
57
|
+
|
58
|
+
while i > 0
|
59
|
+
i -= 1
|
60
|
+
cursor = cursor.more
|
61
|
+
return nil if cursor == Empty
|
62
|
+
end
|
63
|
+
|
64
|
+
cursor.first
|
65
|
+
end
|
66
|
+
|
67
|
+
def ==(seq)
|
68
|
+
(seq.is_a?(ISeq) and self.to_a == seq.to_a) or
|
69
|
+
(seq.is_a?(::Array) and self.to_a == seq)
|
70
|
+
end
|
71
|
+
|
72
|
+
def each(&block)
|
73
|
+
return self.enum_for(:each) if block.nil?
|
74
|
+
|
75
|
+
yield self.first
|
76
|
+
|
77
|
+
cursor = self.more
|
78
|
+
while cursor != Empty
|
79
|
+
yield cursor.first
|
80
|
+
cursor = cursor.more
|
81
|
+
end
|
82
|
+
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
def map(&block)
|
87
|
+
return self.enum_for(:map) if block.nil?
|
88
|
+
|
89
|
+
r = []
|
90
|
+
self.each {|e| r << block.call(e)}
|
91
|
+
r
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_a
|
95
|
+
r = []
|
96
|
+
self.each {|e| r << e}
|
97
|
+
r
|
98
|
+
end
|
99
|
+
|
100
|
+
def map(&block)
|
101
|
+
Cons[*to_a.map(&block)]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class << Empty
|
106
|
+
include ASeq
|
107
|
+
|
108
|
+
def inspect; "()"; end
|
109
|
+
def to_s; inspect; end
|
110
|
+
|
111
|
+
def seq; nil; end
|
112
|
+
def first; nil; end
|
113
|
+
def next; nil; end
|
114
|
+
|
115
|
+
def each(&block)
|
116
|
+
return self.enum_for(:each) if block.nil?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Empty.freeze
|
121
|
+
|
122
|
+
class Cons
|
123
|
+
include ASeq
|
124
|
+
|
125
|
+
def initialize(head, tail)
|
126
|
+
if tail and !tail.is_a?(ISeq)
|
127
|
+
raise ArgumentError,
|
128
|
+
"tail should be an ISeq, not #{tail.inspect} (#{tail.class})"
|
129
|
+
end
|
130
|
+
|
131
|
+
@head, @tail = head, tail
|
132
|
+
end
|
133
|
+
|
134
|
+
def first; @head; end
|
135
|
+
def next; Rouge::Seq.seq @tail; end
|
136
|
+
|
137
|
+
def self.[](*elements)
|
138
|
+
return Empty if elements.length.zero?
|
139
|
+
|
140
|
+
head = nil
|
141
|
+
(elements.length - 1).downto(0).each do |i|
|
142
|
+
head = new(elements[i], head.freeze)
|
143
|
+
end
|
144
|
+
|
145
|
+
head.freeze
|
146
|
+
end
|
147
|
+
|
148
|
+
attr_reader :head, :tail
|
149
|
+
end
|
150
|
+
|
151
|
+
class Array
|
152
|
+
include ASeq
|
153
|
+
|
154
|
+
def initialize(array, i)
|
155
|
+
@array, @i = array, i
|
156
|
+
end
|
157
|
+
|
158
|
+
def first
|
159
|
+
@array[@i]
|
160
|
+
end
|
161
|
+
|
162
|
+
def next
|
163
|
+
if @i + 1 < @array.length
|
164
|
+
Array.new(@array, @i + 1)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Lazy
|
170
|
+
include ISeq
|
171
|
+
|
172
|
+
def initialize(body)
|
173
|
+
@body = body
|
174
|
+
@realized = false
|
175
|
+
end
|
176
|
+
|
177
|
+
def seq
|
178
|
+
if @realized
|
179
|
+
@result
|
180
|
+
else
|
181
|
+
@result = Rouge::Seq.seq(@body.call) || Empty
|
182
|
+
@realized = true
|
183
|
+
@result
|
184
|
+
end
|
185
|
+
rescue UnknownSeqError
|
186
|
+
@realized = true
|
187
|
+
@result = Empty
|
188
|
+
raise
|
189
|
+
end
|
190
|
+
|
191
|
+
def method_missing(sym, *args, &block)
|
192
|
+
seq.send(sym, *args, &block)
|
193
|
+
end
|
194
|
+
|
195
|
+
def inspect; seq.inspect; end
|
196
|
+
def to_s; seq.to_s; end
|
197
|
+
end
|
198
|
+
|
199
|
+
UnknownSeqError = Class.new(StandardError)
|
200
|
+
|
201
|
+
def self.seq(form)
|
202
|
+
case form
|
203
|
+
when ISeq
|
204
|
+
form.seq
|
205
|
+
when NilClass
|
206
|
+
form
|
207
|
+
when ::Array
|
208
|
+
if form.empty?
|
209
|
+
nil
|
210
|
+
else
|
211
|
+
Rouge::Seq::Array.new(form, 0)
|
212
|
+
end
|
213
|
+
when Enumerator
|
214
|
+
seq(form.to_a)
|
215
|
+
else
|
216
|
+
raise UnknownSeqError, form.inspect
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# vim: set sw=2 et cc=80:
|
data/lib/rouge/symbol.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rouge/metadata'
|
3
|
+
|
4
|
+
class Rouge::Symbol
|
5
|
+
include Rouge::Metadata
|
6
|
+
|
7
|
+
# The symbols for t/f/n are the Ruby objects themselves.
|
8
|
+
LOOKUP = {
|
9
|
+
:true => true,
|
10
|
+
:false => false,
|
11
|
+
:nil => nil,
|
12
|
+
}
|
13
|
+
|
14
|
+
KNOWNS = {
|
15
|
+
:/ => [nil, :/],
|
16
|
+
:"./" => [nil, :"./"],
|
17
|
+
:"rouge.core//" => [:"rouge.core", :/],
|
18
|
+
:"rouge.core/./" => [:"rouge.core", :"./"]
|
19
|
+
}
|
20
|
+
|
21
|
+
CACHE = {}
|
22
|
+
|
23
|
+
def initialize(sym)
|
24
|
+
if r = KNOWNS[sym]
|
25
|
+
@ns = r[0]
|
26
|
+
@name = r[1]
|
27
|
+
else
|
28
|
+
str = sym.to_s
|
29
|
+
solidus = str.rindex('/')
|
30
|
+
if solidus
|
31
|
+
@ns = str[0...solidus].intern
|
32
|
+
@name = str[solidus + 1..-1].intern
|
33
|
+
else
|
34
|
+
@ns = nil
|
35
|
+
@name = sym
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@ns_s = @ns.to_s unless @ns.nil?
|
40
|
+
@name_s = @name.to_s
|
41
|
+
|
42
|
+
# split(sep, 0) means a trailing '.' won't become an empty component. (0
|
43
|
+
# is default) Contrast with split(sep, -1).
|
44
|
+
@name_parts =
|
45
|
+
@name_s.length > 1 ? @name_s.split('.', 0).map(&:intern) : [@name]
|
46
|
+
|
47
|
+
@new_sym = (@name_s[-1] == ?. and @name_s.length > 1)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.[](inner)
|
51
|
+
return LOOKUP[inner] if LOOKUP.include? inner
|
52
|
+
c = CACHE[inner]
|
53
|
+
return c.dup if c
|
54
|
+
# Note: don't cache symbols themselves, they may have metadata.
|
55
|
+
c = new inner
|
56
|
+
CACHE[inner] = c.dup.freeze
|
57
|
+
c
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_sym
|
61
|
+
:"#{@ns ? "#@ns/" : ""}#@name"
|
62
|
+
end
|
63
|
+
|
64
|
+
def inspect
|
65
|
+
"Rouge::Symbol[#{to_sym.inspect}]"
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s; inspect; end
|
69
|
+
|
70
|
+
def ==(right)
|
71
|
+
right.is_a?(Rouge::Symbol) and right.ns == @ns and right.name == @name
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :ns, :name, :ns_s, :name_s, :name_parts, :new_sym
|
75
|
+
end
|
76
|
+
|
77
|
+
# vim: set sw=2 et cc=80:
|
data/lib/rouge/var.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Rouge::Var
|
4
|
+
@@stack = []
|
5
|
+
|
6
|
+
def initialize(ns, name, root=Rouge::Var::UnboundSentinel)
|
7
|
+
@ns = ns
|
8
|
+
@name = name
|
9
|
+
raise ArgumentError, "bad var ns" unless ns.is_a? Symbol
|
10
|
+
raise ArgumentError, "bad var name" unless name.is_a? Symbol
|
11
|
+
if root == Rouge::Var::UnboundSentinel
|
12
|
+
@root = Rouge::Var::Unbound.new self
|
13
|
+
else
|
14
|
+
@root = root
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(var)
|
19
|
+
var.is_a?(Rouge::Var) and @ns == var.ns and @name == var.name
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :ns, :name
|
23
|
+
|
24
|
+
def deref
|
25
|
+
@@stack.reverse_each do |map|
|
26
|
+
if map.include? @name
|
27
|
+
return map[@name]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@root
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
"Rouge::Var.new(#{@ns.inspect}, #{@name.inspect}, #{@root.inspect})"
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
inspect
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.push(map)
|
43
|
+
@@stack << map
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.pop
|
47
|
+
@@stack.pop
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Rouge::Var::UnboundSentinel = Object.new
|
52
|
+
class << Rouge::Var::UnboundSentinel
|
53
|
+
def inspect; "#<Rouge::Var::UnboundSentinel>"; end
|
54
|
+
def to_s; inspect; end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Rouge::Var::Unbound
|
58
|
+
def initialize(var)
|
59
|
+
@var = var
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(ub)
|
63
|
+
@var == ub.var
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :var
|
67
|
+
end
|
68
|
+
|
69
|
+
# vim: set sw=2 et cc=80:
|