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,26 @@
1
+ module RbScheme
2
+ class Evaluator
3
+ extend Forwardable
4
+ include Helpers
5
+ include Symbol
6
+
7
+ def_delegator :@compiler, :compile
8
+ def_delegator :@vm, :exec, :vm_exec
9
+
10
+ def initialize
11
+ @compiler = Compiler.new
12
+ @vm = VM.new
13
+ Primitive.new.initialize_vm_primitive!
14
+ Extension.initialize_compound!(self)
15
+ end
16
+
17
+ def vm_eval(obj)
18
+ c = compile(obj, list, Set.new, list(intern("halt")))
19
+ vm_exec(list,
20
+ c,
21
+ 0,
22
+ list,
23
+ 0)
24
+ end
25
+ end # Evaluator
26
+ end # RbScheme
@@ -0,0 +1,55 @@
1
+ module RbScheme
2
+ class Executer
3
+ extend Forwardable
4
+ include Helpers
5
+
6
+ def_delegator :@parser, :read_expr
7
+ def_delegator :@evaluator, :vm_eval
8
+ def_delegator :@printer, :puts_lisp_object
9
+
10
+ def self.run(source)
11
+ new(source).exec
12
+ end
13
+
14
+ def initialize(source)
15
+ set_source!(source)
16
+ @evaluator = Evaluator.new
17
+ @printer = Printer.new
18
+ end
19
+
20
+ def set_source!(source)
21
+ @source = source
22
+ @parser = Parser.new(source)
23
+ end
24
+
25
+ def exit?(expr)
26
+ expr.is_a?(LSymbol) && expr.name == "exit"
27
+ end
28
+
29
+ def exec
30
+ if File.file?(@source)
31
+ exec_file
32
+ else
33
+ exec_repl
34
+ end
35
+ end
36
+
37
+ def exec_file
38
+ loop do
39
+ expr = read_expr
40
+ break if expr.nil?
41
+ vm_eval(expr)
42
+ end
43
+ end
44
+
45
+ def exec_repl
46
+ loop do
47
+ print "> "
48
+ expr = read_expr
49
+ return if expr.nil?
50
+ return if exit?(expr)
51
+ puts_lisp_object(vm_eval(expr))
52
+ end
53
+ end
54
+ end # Executer
55
+ end # RbScheme
@@ -0,0 +1,17 @@
1
+ module RbScheme
2
+ module Extension
3
+ def self.initialize_compound!(evaluator)
4
+ base = File.dirname(File.expand_path(__FILE__))
5
+ definitions = File.join(base, "extension/procedures.scm")
6
+
7
+ File.open(definitions) do |io|
8
+ parser = Parser.new(io)
9
+ loop do
10
+ expr = parser.read_expr
11
+ break if expr.nil?
12
+ evaluator.vm_eval(expr)
13
+ end
14
+ end
15
+ end
16
+ end # Extension
17
+ end # RbScheme
@@ -0,0 +1,7 @@
1
+ (define cadr
2
+ (lambda (lst)
3
+ (car (cdr lst))))
4
+
5
+ (define cddr
6
+ (lambda (lst)
7
+ (cdr (cdr lst))))
@@ -0,0 +1,25 @@
1
+ module RbScheme
2
+ module Global
3
+ @@global_table = {}
4
+
5
+ def self.defined?(key)
6
+ raise unless key.is_a? LSymbol
7
+ @@global_table.member?(key)
8
+ end
9
+
10
+ def self.put(key, value)
11
+ raise unless key.is_a? LSymbol
12
+ @@global_table[key] = value
13
+ value
14
+ end
15
+
16
+ def self.get(key)
17
+ raise unless key.is_a? LSymbol
18
+ @@global_table[key]
19
+ end
20
+
21
+ def self.variables
22
+ @@global_table.keys
23
+ end
24
+ end # Global
25
+ end
@@ -0,0 +1,42 @@
1
+ module RbScheme
2
+ module Helpers
3
+ # Constructor
4
+ def cons(car, cdr)
5
+ LCell.new(car, cdr)
6
+ end
7
+
8
+ def acons(key, val, cdr)
9
+ cons(cons(key, val), cdr)
10
+ end
11
+
12
+ def list(*args)
13
+ args.any? ? convert_to_list(args) : LCell.new
14
+ end
15
+
16
+ def convert_to_list(array)
17
+ result = list
18
+ array.reverse_each do |e|
19
+ result = cons(e, result)
20
+ end
21
+ result
22
+ end
23
+
24
+ def boolean(value)
25
+ value ? LTrue.instance : LFalse.instance
26
+ end
27
+
28
+ def check_length!(lst, n, name)
29
+ c = lst.count
30
+ unless c == n
31
+ raise ArgumentError, "#{name}: wrong number of arguments(given #{c}, expected #{n})"
32
+ end
33
+ end
34
+
35
+ def check_min_length!(lst, min, name)
36
+ c = lst.count
37
+ unless c >= min
38
+ raise ArgumentError, "#{name}: wrong number of arguments(given #{c}, expected #{min}..)"
39
+ end
40
+ end
41
+ end
42
+ end # RbScheme
@@ -0,0 +1,105 @@
1
+ require 'singleton'
2
+
3
+ module RbScheme
4
+ class LInt
5
+ attr_accessor :value
6
+
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ def ==(another)
12
+ return false unless another.is_a? LInt
13
+ value == another.value
14
+ end
15
+ end
16
+
17
+ class LCell
18
+ include Enumerable
19
+
20
+ attr_accessor :car, :cdr
21
+
22
+ def initialize(car = nil, cdr = nil)
23
+ @car = car
24
+ @cdr = cdr
25
+ end
26
+
27
+ def each
28
+ list = self
29
+ until list.null?
30
+ yield(list.car)
31
+ list = list.cdr
32
+ end
33
+ end
34
+
35
+ def null?
36
+ car == nil && cdr == nil
37
+ end
38
+
39
+ def cadr
40
+ @cdr.car
41
+ end
42
+
43
+ def cddr
44
+ @cdr.cdr
45
+ end
46
+
47
+ def caddr
48
+ @cdr.cdr.car
49
+ end
50
+
51
+ def cadddr
52
+ @cdr.cdr.cdr.car
53
+ end
54
+
55
+ def list?
56
+ cdr = @cdr
57
+ loop do
58
+ return false unless LCell === cdr
59
+ return true if cdr.null?
60
+ cdr = cdr.cdr
61
+ end
62
+ end
63
+
64
+ def ==(another)
65
+ l1 = self
66
+ l2 = another
67
+ loop do
68
+ if l1.is_a?(LCell) && l2.is_a?(LCell)
69
+ return false unless l1.car == l2.car
70
+ l1 = l1.cdr
71
+ l2 = l2.cdr
72
+ elsif !l1.is_a?(LCell) && !l2.is_a?(LCell)
73
+ return l1 == l2
74
+ else
75
+ return false
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ class LSymbol
83
+ attr_accessor :name
84
+
85
+ def initialize(name)
86
+ @name = name
87
+ end
88
+ end
89
+
90
+ class LDot
91
+ include Singleton
92
+ end
93
+
94
+ class LCloseParen
95
+ include Singleton
96
+ end
97
+
98
+ class LTrue
99
+ include Singleton
100
+ end
101
+
102
+ class LFalse
103
+ include Singleton
104
+ end
105
+ end # RbScheme
@@ -0,0 +1,146 @@
1
+ module RbScheme
2
+ class Parser
3
+ extend Forwardable
4
+ include Helpers
5
+ include Symbol
6
+
7
+ EOF = nil
8
+
9
+ def_delegator :@input, :getc
10
+
11
+ def self.read_expr(input)
12
+ new(input).read_expr
13
+ end
14
+
15
+ def initialize(input)
16
+ @input = input
17
+ end
18
+
19
+ def read_expr
20
+ loop do
21
+ c = getc
22
+ case c
23
+ when /\s/
24
+ next
25
+ when EOF
26
+ return nil
27
+ when ';'
28
+ skip_line
29
+ next
30
+ when '('
31
+ return read_list
32
+ when ')'
33
+ return LCloseParen.instance
34
+ when '.'
35
+ return LDot.instance
36
+ when '\''
37
+ return read_quote
38
+ when /\d/
39
+ return LInt.new(read_number(c.to_i))
40
+ when negative_number_pred
41
+ return LInt.new(-read_number(c.to_i))
42
+ when '#'
43
+ return read_hash
44
+ when symbol_rp
45
+ return read_symbol(c)
46
+ else
47
+ raise "Unexpected character - #{c}"
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def peek
55
+ c = getc
56
+ @input.ungetc(c)
57
+ c
58
+ end
59
+
60
+ def reverse_list(lst)
61
+ return lst if lst.null?
62
+ lst.reduce(list) { |res, e| cons(e, res) }
63
+ end
64
+
65
+ def skip_line
66
+ loop do
67
+ c = getc
68
+ case c
69
+ when EOF, "\n"
70
+ return
71
+ when "\r"
72
+ getc if "\n" == peek
73
+ return
74
+ end
75
+ end
76
+ end
77
+
78
+ def read_list
79
+ acc = list
80
+ loop do
81
+ obj = read_expr
82
+ raise "read_list: Unclosed parenthesis" if obj.nil?
83
+
84
+ case obj
85
+ when LCloseParen
86
+ return reverse_list(acc)
87
+ when LDot
88
+ last = read_expr
89
+ close = read_expr
90
+ if close.nil? || !(LCloseParen === close)
91
+ raise "read_list: Unclosed parenthesis"
92
+ end
93
+ if acc.null?
94
+ raise "read_list: dotted list must have car"
95
+ end
96
+
97
+ return acc.reduce(last) { |res, e| cons(e, res) }
98
+ else
99
+ acc = cons(obj, acc)
100
+ end
101
+ end
102
+ end
103
+
104
+ def read_quote
105
+ sym = intern("quote")
106
+ list(sym, read_expr)
107
+ end
108
+
109
+ def read_number(value)
110
+ result = value
111
+ while /\d/ === peek
112
+ result = result * 10 + getc.to_i
113
+ end
114
+ result
115
+ end
116
+
117
+ def read_hash
118
+ c = getc
119
+ case c
120
+ when 't'
121
+ LTrue.instance
122
+ when 'f'
123
+ LFalse.instance
124
+ else
125
+ raise "Unexpected hash literal #{c}"
126
+ end
127
+ end
128
+
129
+ def read_symbol(first_char)
130
+ result = first_char
131
+ while symbol_rp === peek
132
+ result += getc
133
+ end
134
+ intern(result)
135
+ end
136
+
137
+ def negative_number_pred
138
+ Proc.new {|c| '-' == c && /\d/ === peek}
139
+ end
140
+
141
+ def symbol_rp
142
+ allowed = '~!@$%^&*-_=+:/?<>'
143
+ Regexp.new("[A-Za-z0-9#{Regexp.escape(allowed)}]")
144
+ end
145
+ end # Parser
146
+ end # RbScheme
@@ -0,0 +1,111 @@
1
+ module RbScheme
2
+ class Primitive
3
+ extend Forwardable
4
+ include Helpers
5
+ include Symbol
6
+
7
+ def_delegators :@printer, :print_lisp_object, :puts_lisp_object
8
+
9
+ def initialize
10
+ @printer = Printer.new
11
+ end
12
+
13
+ def initialize_vm_primitive!
14
+ put_primitive_proc("+", lambda do |*nums|
15
+ sum = 0
16
+ nums.each do |n|
17
+ sum += n.value
18
+ end
19
+ LInt.new(sum)
20
+ end)
21
+
22
+ put_primitive_proc("-", lambda do |first, *rest|
23
+ result = first.value
24
+ if rest.any?
25
+ rest.each do |n|
26
+ result -= n.value
27
+ end
28
+ else
29
+ result = -result
30
+ end
31
+ LInt.new(result)
32
+ end)
33
+
34
+ put_primitive_proc("*", lambda do |*nums|
35
+ result = 1
36
+ nums.each do |n|
37
+ result *= n.value
38
+ end
39
+ LInt.new(result)
40
+ end)
41
+
42
+ put_primitive_proc("/", lambda do |first, *rest|
43
+ result = first.value
44
+ if rest.any?
45
+ rest.each do |n|
46
+ result /= n.value
47
+ end
48
+ else
49
+ result = 1 / result
50
+ end
51
+ LInt.new(result)
52
+ end)
53
+
54
+ put_primitive_proc("=", lambda do |n1, n2|
55
+ boolean(n1.value == n2.value)
56
+ end)
57
+
58
+ put_primitive_proc("<", lambda do |n1, n2|
59
+ boolean(n1.value < n2.value)
60
+ end)
61
+
62
+ put_primitive_proc(">", lambda do |n1, n2|
63
+ boolean(n1.value > n2.value)
64
+ end)
65
+
66
+ put_primitive_proc("null?", lambda do |lst|
67
+ boolean(lst.is_a?(LCell) && lst.null?)
68
+ end)
69
+
70
+ put_primitive_proc("cons", lambda do |e1, e2|
71
+ cons(e1, e2)
72
+ end)
73
+
74
+ put_primitive_proc("car", lambda do |c|
75
+ unless c.is_a?(LCell)
76
+ raise ArgumentError, "pair required, but got #{c}"
77
+ end
78
+ c.car
79
+ end)
80
+
81
+ put_primitive_proc("cdr", lambda do |c|
82
+ unless c.is_a?(LCell)
83
+ raise ArgumentError, "pair required, but got #{c}"
84
+ end
85
+ c.cdr
86
+ end)
87
+
88
+ put_primitive_proc("list", lambda do |*lst|
89
+ list(*lst)
90
+ end)
91
+
92
+ put_primitive_proc("display", lambda do |obj|
93
+ print_lisp_object(obj)
94
+ end)
95
+
96
+ put_primitive_proc("newline", lambda do
97
+ print("\n")
98
+ end)
99
+
100
+ put_primitive_proc("print", lambda do |obj|
101
+ puts_lisp_object(obj)
102
+ end)
103
+ # todo...
104
+ end
105
+
106
+ def put_primitive_proc(name, func)
107
+ prim = Procedure.new(name: name, func: func)
108
+ Global.put(intern(name), prim)
109
+ end
110
+ end # Primitive
111
+ end # RbScheme