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,108 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Rouge::Compiler
|
5
|
+
class Resolved
|
6
|
+
def initialize(res)
|
7
|
+
@res = res
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :res
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.compile(ns, lexicals, form)
|
14
|
+
case form
|
15
|
+
when Rouge::Symbol
|
16
|
+
name = form.name
|
17
|
+
is_new = (name[-1] == ?. and name.length > 1)
|
18
|
+
name = name[0..-2].to_sym if is_new
|
19
|
+
|
20
|
+
if !form.ns and
|
21
|
+
(lexicals.include?(name) or
|
22
|
+
(name[0] == ?. and name.length > 1) or
|
23
|
+
[:|, :&].include?(name))
|
24
|
+
# TODO: cache found ns/var/context or no. of context parents.
|
25
|
+
form
|
26
|
+
else
|
27
|
+
resolved = form.ns ? Rouge[form.ns] : ns
|
28
|
+
|
29
|
+
lookups = form.name_parts
|
30
|
+
resolved = resolved[lookups[0]]
|
31
|
+
i, count = 1, lookups.length
|
32
|
+
|
33
|
+
while i < count
|
34
|
+
resolved = resolved.deref if resolved.is_a?(Rouge::Var)
|
35
|
+
resolved = resolved.const_get(lookups[i])
|
36
|
+
i += 1
|
37
|
+
end
|
38
|
+
|
39
|
+
if is_new
|
40
|
+
klass = resolved
|
41
|
+
klass = klass.deref if klass.is_a?(Rouge::Var)
|
42
|
+
resolved = klass.method(:new)
|
43
|
+
end
|
44
|
+
|
45
|
+
Resolved.new resolved
|
46
|
+
end
|
47
|
+
when Array
|
48
|
+
form.map {|f| compile(ns, lexicals, f)}
|
49
|
+
when Hash
|
50
|
+
Hash[form.map {|k, v| [compile(ns, lexicals, k),
|
51
|
+
compile(ns, lexicals, v)]}]
|
52
|
+
when Rouge::Seq::ISeq
|
53
|
+
to_a = form.to_a
|
54
|
+
if to_a.empty?
|
55
|
+
return Rouge::Seq::Empty
|
56
|
+
end
|
57
|
+
|
58
|
+
head, *tail = to_a
|
59
|
+
|
60
|
+
if head.is_a?(Rouge::Symbol) and
|
61
|
+
(head.ns.nil? or head.ns == :"rouge.builtin") and
|
62
|
+
Rouge::Builtins.respond_to?("_compile_#{head.name}")
|
63
|
+
Rouge::Seq::Cons[*
|
64
|
+
Rouge::Builtins.send(
|
65
|
+
"_compile_#{head.name}",
|
66
|
+
ns, lexicals, *tail)]
|
67
|
+
else
|
68
|
+
head = compile(ns, lexicals, head)
|
69
|
+
|
70
|
+
# XXX ↓↓↓ This is insane ↓↓↓
|
71
|
+
if head.is_a?(Resolved) and
|
72
|
+
head.res.is_a?(Rouge::Var) and
|
73
|
+
head.res.deref.is_a?(Rouge::Macro)
|
74
|
+
# TODO: backtrace_fix
|
75
|
+
compile(ns, lexicals, head.res.deref.inner.call(*tail))
|
76
|
+
else
|
77
|
+
# Regular function call!
|
78
|
+
if tail.include? Rouge::Symbol[:|]
|
79
|
+
index = tail.index Rouge::Symbol[:|]
|
80
|
+
if tail.length == index + 2
|
81
|
+
# Function.
|
82
|
+
block = compile(ns, lexicals, tail[index + 1])
|
83
|
+
else
|
84
|
+
# Inline block.
|
85
|
+
block = compile(
|
86
|
+
ns, lexicals,
|
87
|
+
Rouge::Seq::Cons[Rouge::Symbol[:fn],
|
88
|
+
*tail[index + 1..-1]])
|
89
|
+
end
|
90
|
+
tail = tail[0...index]
|
91
|
+
else
|
92
|
+
block = nil
|
93
|
+
end
|
94
|
+
Rouge::Seq::Cons[
|
95
|
+
head,
|
96
|
+
*tail.map {|f| compile(ns, lexicals, f)},
|
97
|
+
*(block ? [Rouge::Symbol[:|],
|
98
|
+
block]
|
99
|
+
: [])]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
else
|
103
|
+
form
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# vim: set sw=2 et cc=80:
|
@@ -0,0 +1,235 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rouge/wrappers'
|
3
|
+
require 'rouge/namespace'
|
4
|
+
|
5
|
+
class Rouge::Context
|
6
|
+
class BindingNotFoundError < StandardError; end
|
7
|
+
class BadBindingError < StandardError; end
|
8
|
+
class ChangeContextException < Exception
|
9
|
+
def initialize(context); @context = context; end
|
10
|
+
attr_reader :context
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(parent_or_ns)
|
14
|
+
case parent_or_ns
|
15
|
+
when Rouge::Namespace
|
16
|
+
@ns = parent_or_ns
|
17
|
+
when Rouge::Context
|
18
|
+
@parent = parent_or_ns
|
19
|
+
@ns = @parent.ns
|
20
|
+
end
|
21
|
+
@table = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
if @table.include? key
|
26
|
+
@table[key]
|
27
|
+
elsif @parent
|
28
|
+
@parent[key]
|
29
|
+
elsif @ns
|
30
|
+
@ns[key]
|
31
|
+
else
|
32
|
+
raise BindingNotFoundError, key
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_here(key, value)
|
37
|
+
if Rouge::Symbol[key].ns != nil
|
38
|
+
raise BadBindingError, "cannot bind #{key.inspect}"
|
39
|
+
end
|
40
|
+
|
41
|
+
@table[key] = value
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_lexical(key, value)
|
45
|
+
if @table.include? key
|
46
|
+
@table[key] = value
|
47
|
+
elsif @parent
|
48
|
+
@parent.set_lexical key, value
|
49
|
+
else
|
50
|
+
raise BindingNotFoundError,
|
51
|
+
"setting #{key} to #{value.inspect}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def lexical_keys
|
56
|
+
@table.keys + (@parent ? @parent.lexical_keys : [])
|
57
|
+
end
|
58
|
+
|
59
|
+
# This readeval post-processes the backtrace. Accordingly, it should only
|
60
|
+
# be called by consumers, and never by Rouge internally itself, lest it
|
61
|
+
# catches an exception and processes the backtrace too early.
|
62
|
+
def readeval(input)
|
63
|
+
reader = Rouge::Reader.new(ns, input)
|
64
|
+
context = self
|
65
|
+
r = nil
|
66
|
+
|
67
|
+
while true
|
68
|
+
begin
|
69
|
+
form = reader.lex
|
70
|
+
rescue Rouge::Reader::EndOfDataError
|
71
|
+
return r
|
72
|
+
end
|
73
|
+
|
74
|
+
form = Rouge::Compiler.compile(context.ns, Set[*lexical_keys], form)
|
75
|
+
|
76
|
+
begin
|
77
|
+
r = context.eval(form)
|
78
|
+
rescue ChangeContextException => cce
|
79
|
+
context = cce.context
|
80
|
+
reader.ns = context.ns
|
81
|
+
end
|
82
|
+
end
|
83
|
+
rescue Exception => e
|
84
|
+
# Remove Rouge-related lines unless the exception originated in Rouge.
|
85
|
+
# root = File.dirname(File.dirname(__FILE__))
|
86
|
+
# e.backtrace.map! {|line|
|
87
|
+
# line.scan(root).length > 0 ? nil : line
|
88
|
+
# }.compact! unless e.backtrace[0].scan(root).length > 0
|
89
|
+
raise e
|
90
|
+
end
|
91
|
+
|
92
|
+
# Internal use only -- doesn't post-process backtrace.
|
93
|
+
def eval(form)
|
94
|
+
case form
|
95
|
+
when Rouge::Compiler::Resolved
|
96
|
+
result = form.res
|
97
|
+
if result.is_a?(Rouge::Var)
|
98
|
+
result.deref
|
99
|
+
else
|
100
|
+
result
|
101
|
+
end
|
102
|
+
when Rouge::Symbol
|
103
|
+
eval_symbol form
|
104
|
+
when Rouge::Seq::Cons
|
105
|
+
eval_cons form
|
106
|
+
when Hash
|
107
|
+
Hash[form.map {|k,v| [eval(k), eval(v)]}].freeze
|
108
|
+
when Array
|
109
|
+
form.map {|f| eval(f)}.freeze
|
110
|
+
else
|
111
|
+
form
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# +symbol+ should be a Rouge::Symbol.
|
116
|
+
def locate(symbol)
|
117
|
+
if !symbol.is_a?(Rouge::Symbol)
|
118
|
+
raise ArgumentError, "locate not called with R::S"
|
119
|
+
elsif symbol.ns
|
120
|
+
raise ArgumentError, "locate called with NS'd R::S #{symbol}"
|
121
|
+
end
|
122
|
+
|
123
|
+
if symbol.name_s[-1] == ?. and symbol.name_s.length > 1
|
124
|
+
lambda {|*args, &block|
|
125
|
+
self[symbol.name_s[0..-2].intern].new(*args, &block)
|
126
|
+
}
|
127
|
+
else
|
128
|
+
self[symbol.name]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
attr_reader :ns
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def eval_symbol(form)
|
137
|
+
if !form.ns and form.name_s[0] == ?. and form.name_s.length > 1
|
138
|
+
lambda {|receiver, *args, &block|
|
139
|
+
receiver.send(form.name_s[1..-1], *args, &block)
|
140
|
+
}
|
141
|
+
else
|
142
|
+
result = locate form
|
143
|
+
if result.is_a?(Rouge::Var)
|
144
|
+
result.deref
|
145
|
+
else
|
146
|
+
result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def eval_cons(form)
|
152
|
+
fun = eval form[0]
|
153
|
+
|
154
|
+
case fun
|
155
|
+
when Rouge::Builtin
|
156
|
+
backtrace_fix("(rouge):?:builtin: ", form) do
|
157
|
+
fun.inner.call self, *form.to_a[1..-1]
|
158
|
+
end
|
159
|
+
else
|
160
|
+
args = form.to_a[1..-1]
|
161
|
+
|
162
|
+
if args.include? Rouge::Symbol[:|]
|
163
|
+
index = args.index Rouge::Symbol[:|]
|
164
|
+
if args.length == index + 2
|
165
|
+
# Function.
|
166
|
+
block = eval args[index + 1]
|
167
|
+
else
|
168
|
+
# Inline block.
|
169
|
+
block = eval(Rouge::Seq::Cons[
|
170
|
+
Rouge::Symbol[:fn],
|
171
|
+
args[index + 1],
|
172
|
+
*args[index + 2..-1]
|
173
|
+
])
|
174
|
+
end
|
175
|
+
args = args[0...index]
|
176
|
+
else
|
177
|
+
block = nil
|
178
|
+
end
|
179
|
+
|
180
|
+
args = args.map {|f| eval(f)}
|
181
|
+
|
182
|
+
backtrace_fix("(rouge):?:lambda: ", form) do
|
183
|
+
eval_call(fun, args, block)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def eval_call(fun, args, block)
|
189
|
+
num_args = args.length
|
190
|
+
case fun
|
191
|
+
when Symbol
|
192
|
+
if num_args == 1 || num_args == 2
|
193
|
+
default = args[1]
|
194
|
+
if args[0].is_a? Hash
|
195
|
+
args[0].fetch(fun) { default }
|
196
|
+
else
|
197
|
+
default
|
198
|
+
end
|
199
|
+
else
|
200
|
+
raise ArgumentError,
|
201
|
+
"Wrong number of args (#{num_args}) passed to ruby/Symbol :#{fun}"
|
202
|
+
end
|
203
|
+
when Hash
|
204
|
+
if num_args == 1 || num_args == 2
|
205
|
+
default = args[1]
|
206
|
+
fun.fetch(args[0]) { default }
|
207
|
+
else
|
208
|
+
raise ArgumentError,
|
209
|
+
"Wrong number of args (#{num_args}) passed to ruby/Hash"
|
210
|
+
end
|
211
|
+
else
|
212
|
+
fun.call(*args, &block)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def backtrace_fix(name, form, &block)
|
217
|
+
begin
|
218
|
+
block.call
|
219
|
+
rescue Exception => e
|
220
|
+
# target = block.source_location.join(':')
|
221
|
+
# changed = 0
|
222
|
+
# $!.backtrace.map! {|line|
|
223
|
+
# if line.scan("#{target}:").size > 0 and changed == 0
|
224
|
+
# changed += 1
|
225
|
+
# Rouge.print(form, name.dup)
|
226
|
+
# else
|
227
|
+
# line
|
228
|
+
# end
|
229
|
+
# }
|
230
|
+
raise e
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# vim: set sw=2 et cc=80:
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rouge::Metadata
|
4
|
+
class InvalidMetadataError < StandardError; end
|
5
|
+
|
6
|
+
def meta
|
7
|
+
@meta
|
8
|
+
end
|
9
|
+
|
10
|
+
def meta= m
|
11
|
+
if m != nil and m.class != Hash
|
12
|
+
raise InvalidMetadataError, "bad metadata: #{m.inspect}"
|
13
|
+
end
|
14
|
+
|
15
|
+
@meta = m
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# vim: set sw=2 et cc=80:
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rouge/context'
|
3
|
+
require 'rouge/builtins'
|
4
|
+
require 'rouge/var'
|
5
|
+
require 'rouge/atom'
|
6
|
+
|
7
|
+
class Rouge::Namespace
|
8
|
+
@namespaces = {}
|
9
|
+
|
10
|
+
class VarNotFoundError < StandardError; end
|
11
|
+
class RecursiveNamespaceError < StandardError; end
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
raise ArgumentError, "bad ns name" unless @name.is_a? Symbol
|
16
|
+
@table = {}
|
17
|
+
@refers = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
"#<Rouge::NS #{@name.inspect}, " \
|
22
|
+
"refers #{@refers.map(&:inspect).join(", ")}>"
|
23
|
+
end
|
24
|
+
|
25
|
+
def refer(ns)
|
26
|
+
if ns.name == @name
|
27
|
+
raise RecursiveNamespaceError, "#@name will not refer #{ns.name}"
|
28
|
+
end
|
29
|
+
|
30
|
+
@refers << ns if not @refers.include? ns
|
31
|
+
end
|
32
|
+
|
33
|
+
def [](key)
|
34
|
+
if @table.include? key
|
35
|
+
return @table[key]
|
36
|
+
end
|
37
|
+
|
38
|
+
@refers.each do |ns|
|
39
|
+
begin
|
40
|
+
return ns[key]
|
41
|
+
rescue VarNotFoundError
|
42
|
+
# no-op
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
raise VarNotFoundError, key
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_here(key, value)
|
50
|
+
@table[key] = Rouge::Var.new(@name, key, value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def intern(key)
|
54
|
+
@table[key] ||= Rouge::Var.new(@name, key)
|
55
|
+
end
|
56
|
+
|
57
|
+
def read(input)
|
58
|
+
Rouge::Reader.new(self, input).lex
|
59
|
+
end
|
60
|
+
|
61
|
+
def clear
|
62
|
+
@table = {}
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :name, :refers
|
67
|
+
end
|
68
|
+
|
69
|
+
class << Rouge::Namespace
|
70
|
+
def exists?(ns)
|
71
|
+
@namespaces.include? ns
|
72
|
+
end
|
73
|
+
|
74
|
+
def [](ns)
|
75
|
+
r = @namespaces[ns]
|
76
|
+
return r if r
|
77
|
+
|
78
|
+
self[ns] = new(ns)
|
79
|
+
@namespaces[ns] = new(ns)
|
80
|
+
end
|
81
|
+
|
82
|
+
def []=(ns, value)
|
83
|
+
@namespaces[ns] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
def destroy(ns)
|
87
|
+
@namespaces.delete ns
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Rouge::Namespace::Ruby
|
92
|
+
@@cache = {}
|
93
|
+
|
94
|
+
def [](name)
|
95
|
+
return @@cache[name] if @@cache.include? name
|
96
|
+
if name =~ /^\$/
|
97
|
+
@@cache[name] = Rouge::Var.new(:ruby, name, eval(name.to_s))
|
98
|
+
else
|
99
|
+
@@cache[name] = Rouge::Var.new(:ruby, name, Kernel.const_get(name))
|
100
|
+
end
|
101
|
+
rescue NameError
|
102
|
+
raise Rouge::Namespace::VarNotFoundError, name
|
103
|
+
end
|
104
|
+
|
105
|
+
def set_here(name, value)
|
106
|
+
@@cache[name] = Rouge::Var.new(:ruby, name, value)
|
107
|
+
Kernel.const_set name, value
|
108
|
+
end
|
109
|
+
|
110
|
+
def name
|
111
|
+
:ruby
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
ns = Rouge::Namespace[:"rouge.builtin"]
|
116
|
+
Rouge::Builtins.methods(false).reject {|s| s =~ /^_compile_/}.each do |m|
|
117
|
+
ns.set_here m, Rouge::Builtin[Rouge::Builtins.method(m)]
|
118
|
+
end
|
119
|
+
Rouge::Builtins::SYMBOLS.each do |name, val|
|
120
|
+
ns.set_here name, val
|
121
|
+
end
|
122
|
+
|
123
|
+
Rouge::Namespace[:ruby] = Rouge::Namespace::Ruby.new
|
124
|
+
|
125
|
+
# vim: set sw=2 et cc=80:
|