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
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:
|