rb-scheme 0.3.5

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.
@@ -0,0 +1,42 @@
1
+ module RbScheme
2
+ class Primitive
3
+ class Procedure
4
+ attr_reader :func, :name, :required_arg_num, :arg_list
5
+
6
+ def initialize(attrs = {})
7
+ @name = attrs[:name]
8
+ @func = attrs[:func]
9
+ parse_parameter_info(attrs[:func])
10
+ end
11
+
12
+ def call(args)
13
+ check_arg_num!(args)
14
+ func.call(*args)
15
+ end
16
+
17
+ private
18
+
19
+ def parse_parameter_info(fn)
20
+ @required_arg_num = 0
21
+ fn.parameters.each do |p|
22
+ param_type = p[0]
23
+ case param_type
24
+ when :req
25
+ @required_arg_num += 1
26
+ when :rest
27
+ @arg_list = true
28
+ end
29
+ end
30
+ end
31
+
32
+ def check_arg_num!(args)
33
+ if required_arg_num > args.count
34
+ message = arg_list ?
35
+ "primitive procedure #{name}: required at least #{required_arg_num} arguments, got #{args.count}" :
36
+ "primitive procedure #{name}: required #{required_arg_num} arguments, got #{args.count}"
37
+ raise ArgumentError, message
38
+ end
39
+ end
40
+ end # Procedure
41
+ end # Primitive
42
+ end # RbScheme
@@ -0,0 +1,108 @@
1
+ module RbScheme
2
+ class Printer
3
+ def puts_lisp_object(obj)
4
+ print_lisp_object(obj)
5
+ print "\n"
6
+ end
7
+
8
+ def print_lisp_object(obj)
9
+ case obj
10
+ when LInt
11
+ print obj.value
12
+ when LSymbol
13
+ print obj.name
14
+ when LTrue
15
+ print "#t"
16
+ when LFalse
17
+ print "#f"
18
+ when primitive_procedure
19
+ print "#<subr>"
20
+ when compound_procedure
21
+ print "#<closure>"
22
+ when LCell
23
+ if obj.null?
24
+ print("()")
25
+ return
26
+ end
27
+
28
+ print "("
29
+ loop do
30
+ print_lisp_object(obj.car)
31
+ case obj.cdr
32
+ when LCell
33
+ if obj.cdr.null?
34
+ print(")")
35
+ return
36
+ end
37
+
38
+ print(" ")
39
+ obj = obj.cdr
40
+ else
41
+ print(" . ")
42
+ print_lisp_object(obj.cdr)
43
+ print(")")
44
+ return
45
+ end
46
+ end
47
+ else
48
+ raise "bug - error unexpected type #{obj}"
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def compound_procedure
55
+ # expression (lambda ...) is compiled into Array
56
+ Array
57
+ end
58
+
59
+ def primitive_procedure
60
+ Primitive::Procedure
61
+ end
62
+
63
+ # for debug
64
+ def print_debug(obj)
65
+ case obj
66
+ when LInt
67
+ print obj.value
68
+ when LSymbol
69
+ print obj.name
70
+ when LTrue
71
+ print "#t"
72
+ when LFalse
73
+ print "#f"
74
+ when primitive_procedure
75
+ print "#<subr>"
76
+ when compound_procedure
77
+ print "#<closure>"
78
+ when LCell
79
+ if obj.null?
80
+ print("()")
81
+ return
82
+ end
83
+
84
+ print "("
85
+ loop do
86
+ print_debug(obj.car)
87
+ case obj.cdr
88
+ when LCell
89
+ if obj.cdr.null?
90
+ print(")")
91
+ return
92
+ end
93
+
94
+ print(" ")
95
+ obj = obj.cdr
96
+ else
97
+ print(" . ")
98
+ print_debug(obj.cdr)
99
+ print(")")
100
+ return
101
+ end
102
+ end
103
+ else
104
+ print ("ruby(#{obj})")
105
+ end
106
+ end
107
+ end # Printer
108
+ end # RbScheme
@@ -0,0 +1,14 @@
1
+ module RbScheme
2
+ module Symbol
3
+ @@symbols = {}
4
+
5
+ def intern(name)
6
+ key = name.to_sym
7
+ return @@symbols[key] if @@symbols.has_key?(key)
8
+
9
+ sym = LSymbol.new(name)
10
+ @@symbols[key] = sym
11
+ sym
12
+ end
13
+ end # Symbol
14
+ end # RbScheme
@@ -0,0 +1,3 @@
1
+ module RbScheme
2
+ VERSION = '0.3.5'
3
+ end
@@ -0,0 +1,281 @@
1
+ module RbScheme
2
+ class VM
3
+ extend Forwardable
4
+ include Helpers
5
+ include Symbol
6
+
7
+ def_delegators :@stack, :push, :index, :index_set!, :save_stack, :restore_stack
8
+
9
+ def initialize
10
+ @stack = Stack.new
11
+ end
12
+
13
+ def exec(acc, exp, frame_p, cls, stack_p)
14
+ loop do
15
+ case exp.car
16
+ when intern("halt")
17
+ check_length!(exp.cdr, 0, "halt")
18
+ return acc
19
+ when intern("refer-local")
20
+ check_length!(exp.cdr, 2, "refer-local")
21
+ n, x = exp.cdr.to_a
22
+
23
+ acc = index(frame_p, n)
24
+ exp = x
25
+ when intern("refer-free")
26
+ check_length!(exp.cdr, 2, "refer-free")
27
+ n, x = exp.cdr.to_a
28
+
29
+ acc = index_closure(cls, n)
30
+ exp = x
31
+ when intern("refer-global")
32
+ check_length!(exp.cdr, 2, "refer-free")
33
+ key, x = exp.cdr.to_a
34
+
35
+ acc = Global.get(key)
36
+ exp = x
37
+ when intern("indirect")
38
+ check_length!(exp.cdr, 1, "indirect")
39
+ x = exp.cadr
40
+
41
+ acc = acc.unbox
42
+ exp = x
43
+ when intern("constant")
44
+ check_length!(exp.cdr, 2, "constant")
45
+ obj, x = exp.cdr.to_a
46
+
47
+ acc = obj
48
+ exp = x
49
+ when intern("close")
50
+ check_length!(exp.cdr, 5, "close")
51
+ param_count, variadic, free_count, body, x = exp.cdr.to_a
52
+
53
+ acc = closure(body, param_count, variadic, free_count, stack_p)
54
+ exp = x
55
+ stack_p = stack_p - free_count
56
+ when intern("box")
57
+ check_length!(exp.cdr, 2, "box")
58
+ n, x = exp.cdr.to_a
59
+
60
+ index_set!(stack_p, n, Box.new(index(stack_p, n)))
61
+ exp = x
62
+ when intern("test")
63
+ check_length!(exp.cdr, 2, "test")
64
+ thenx, elsex = exp.cdr.to_a
65
+
66
+ exp = LFalse === acc ? elsex : thenx
67
+ when intern("assign-local")
68
+ check_length!(exp.cdr, 2, "assign-local")
69
+ n, x = exp.cdr.to_a
70
+
71
+ index(frame_p, n).set_box!(acc)
72
+ exp = x
73
+ when intern("assign-free")
74
+ check_length!(exp.cdr, 2, "assign-free")
75
+ n, x = exp.cdr.to_a
76
+
77
+ index_closure(cls, n).set_box!(acc)
78
+ exp = x
79
+ when intern("assign-global")
80
+ check_length!(exp.cdr, 2, "assign-global")
81
+ key, x = exp.cdr.to_a
82
+
83
+ Global.put(key, acc)
84
+ exp = x
85
+ when intern("conti")
86
+ check_length!(exp.cdr, 1, "conti")
87
+ x = exp.cadr
88
+
89
+ acc = continuation(stack_p)
90
+ exp = x
91
+ when intern("nuate")
92
+ check_length!(exp.cdr, 2, "nuate")
93
+ saved_stack, x = exp.cdr.to_a
94
+
95
+ exp = x
96
+ stack_p = restore_stack(saved_stack)
97
+ when intern("frame")
98
+ check_length!(exp.cdr, 2, "frame")
99
+ ret, x = exp.cdr.to_a
100
+
101
+ exp = x
102
+ stack_p = push(ret, push(frame_p, push(cls, stack_p)))
103
+ when intern("argument")
104
+ check_length!(exp.cdr, 1, "argument")
105
+ x = exp.cadr
106
+
107
+ exp = x
108
+ stack_p = push(acc, stack_p)
109
+ when intern("shift")
110
+ check_length!(exp.cdr, 3, "shift")
111
+ n, m, x = exp.cdr.to_a
112
+
113
+ exp = x
114
+ stack_p = shift_args(n, m, stack_p)
115
+ when intern("apply")
116
+ check_length!(exp.cdr, 1, "apply")
117
+ arg_count = exp.cadr
118
+
119
+ if primitive_procedure?(acc)
120
+ acc = apply_primitive(acc, arg_count, stack_p)
121
+ exp, frame_p, cls, stack_p = return_primitive(stack_p, arg_count)
122
+ elsif compound_procedure?(acc)
123
+ check_parameter!(closure_param_count(acc), arg_count, variadic_closure?(acc))
124
+ if variadic_closure?(acc)
125
+ stack_p = collect_arguments(stack_p, closure_param_count(acc), arg_count)
126
+ end
127
+ exp, frame_p, cls = apply_compound(acc, stack_p)
128
+ else
129
+ raise "invalid application"
130
+ end
131
+ when intern("return")
132
+ check_length!(exp.cdr, 1, "return")
133
+ n = exp.cadr
134
+ s = stack_p - n
135
+
136
+ exp = index(s, 0)
137
+ frame_p = index(s, 1)
138
+ cls = index(s, 2)
139
+ stack_p = s - 3
140
+ else
141
+ raise "Unknown instruction - #{exp.car}"
142
+ end
143
+ end
144
+ end
145
+
146
+ def collect_arguments(stack_p, cls_param_count, arg_count)
147
+ req = cls_param_count - 1
148
+ list_length = arg_count - req
149
+ unless list_length == 0
150
+ collect_arguments_as_list(stack_p, arg_count, list_length)
151
+ shift_required_variables(stack_p, req, arg_count)
152
+ stack_p - arg_count + cls_param_count
153
+ else
154
+ add_empty_list_as_argument(stack_p, arg_count)
155
+ stack_p + 1
156
+ end
157
+ end
158
+
159
+ def collect_arguments_as_list(stack_p, arg_count, length)
160
+ lst = list
161
+ i = arg_count
162
+ length.times do
163
+ lst = cons(index(stack_p, i - 1), lst)
164
+ i -= 1
165
+ end
166
+ index_set!(stack_p, arg_count - 1, lst)
167
+ end
168
+
169
+ def shift_required_variables(stack_p, required_count, arg_count)
170
+ j = required_count
171
+ k = arg_count - 2
172
+ required_count.times do
173
+ index_set!(stack_p, k, index(stack_p, j - 1))
174
+ j -= 1
175
+ k -= 1
176
+ end
177
+ end
178
+
179
+ def add_empty_list_as_argument(stack_p, arg_count)
180
+ last = arg_count - 1
181
+ 0.upto(last) do |n|
182
+ v = index(stack_p, n)
183
+ index_set!(stack_p, n - 1, v)
184
+ end
185
+ index_set!(stack_p, last, list)
186
+ end
187
+
188
+ def apply_primitive(prim_proc, arg_count, stack_p)
189
+ i = 0
190
+ args = []
191
+ arg_count.times do
192
+ args.push(index(stack_p, i))
193
+ i += 1
194
+ end
195
+ prim_proc.call(args)
196
+ end
197
+
198
+ def return_primitive(stack_p, arg_count)
199
+ s = stack_p - arg_count
200
+ # [exp, frame_p, cls, stack_p]
201
+ [index(s, 0), index(s, 1), index(s, 2), s -3]
202
+ end
203
+
204
+ def apply_compound(acc, stack_p)
205
+ # [exp, frame_p, cls]
206
+ [closure_body(acc), stack_p, acc]
207
+ end
208
+
209
+ def primitive_procedure?(procedure)
210
+ procedure.is_a?(Primitive::Procedure)
211
+ end
212
+
213
+ def compound_procedure?(procedure)
214
+ procedure.is_a?(Array)
215
+ end
216
+
217
+ def shift_args(n, m, s)
218
+ i = n - 1
219
+ until i < 0
220
+ index_set!(s, i + m, index(s, i))
221
+ i -= 1
222
+ end
223
+ s - m
224
+ end
225
+
226
+ CLOSURE_OFFSET = 3
227
+ def closure(body, param_count, variadic, free_count, stack_p)
228
+ v = Array.new(free_count + CLOSURE_OFFSET)
229
+ v[0] = body
230
+ v[1] = param_count
231
+ v[2] = variadic
232
+
233
+ i = 0
234
+ until i == free_count
235
+ v[i + CLOSURE_OFFSET] = index(stack_p, i)
236
+ i += 1
237
+ end
238
+ v
239
+ end
240
+
241
+ def closure_body(cls)
242
+ cls[0]
243
+ end
244
+
245
+ def closure_param_count(cls)
246
+ cls[1]
247
+ end
248
+
249
+ def variadic_closure?(cls)
250
+ # 1: true, 0: false
251
+ cls[2] == 1
252
+ end
253
+
254
+ def index_closure(cls, n)
255
+ cls[n + CLOSURE_OFFSET]
256
+ end
257
+
258
+ def check_parameter!(expect, got, variadic)
259
+ if variadic
260
+ unless (expect - 1) <= got
261
+ raise ArgumentError,
262
+ "closure: required at least #{expect} arguments, got #{got}"
263
+ end
264
+ else
265
+ unless expect == got
266
+ raise ArgumentError,
267
+ "closure: required #{expect} arguments, got #{got}"
268
+ end
269
+ end
270
+ end
271
+
272
+ def continuation(stack_p)
273
+ body = list(intern("refer-local"),
274
+ 0,
275
+ list(intern("nuate"),
276
+ save_stack(stack_p),
277
+ list(intern("return"), 0)))
278
+ closure(body, 1, 0, 0, stack_p)
279
+ end
280
+ end # VM
281
+ end # RbScheme