rus3 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,308 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3::Procedure
4
+
5
+ module Predicate
6
+
7
+ include Rus3::EmptyList
8
+
9
+ # Returns true if the arguemnt represents a list structure.
10
+ # Note that an empty list is a list.
11
+ def list?(obj)
12
+ obj.instance_of?(Array)
13
+ end
14
+
15
+ # :stopdoc:
16
+
17
+ # Equivalence predicates:
18
+ #
19
+ # In R5RS, three equivalence predicates are defined such as eqv?,
20
+ # eq? and equal?.
21
+ #
22
+ # `equal?` has been defined in Object class and the reference
23
+ # manual says that this method must not re-defined. So,
24
+ # `equal?` is not defined here.
25
+
26
+ # :startdoc:
27
+
28
+ def eqv?(obj1, obj2)
29
+ obj1 == obj2
30
+ end
31
+
32
+ def eq?(obj1, obj2)
33
+ obj1.equal?(obj2)
34
+ end
35
+
36
+ # :stopdoc:
37
+
38
+ # Value types:
39
+ #
40
+ # R5RS says "no objects satiscies more than one of the following
41
+ # predicates". That is, Scheme has 9 value types at least.
42
+ #
43
+ # Most of them have suitable types in Ruby built-in classes. Rus3
44
+ # provides some classes for the rest of them.
45
+ #
46
+ # boolean? ---> FalseClass or TrueClass
47
+ # pair? ------> Rus3::Pair
48
+ # symbol? ----> Symbol
49
+ # number? ----> Numeric
50
+ # char? ------> Rus3::Char
51
+ # string? ----> String
52
+ # vector? ----> Array
53
+ # port? ------> Rus3::Port
54
+ # procedure? -> Proc
55
+
56
+ # :startdoc:
57
+
58
+ def boolean?(obj)
59
+ obj.instance_of?(FalseClass) or obj.instance_of?(TrueClass)
60
+ end
61
+
62
+ def pair?(obj)
63
+ obj.instance_of?(Array) or obj.instance_of?(Rus3::Pair)
64
+ end
65
+
66
+ def symbol?(obj)
67
+ obj.is_a?(Symbol) && obj != Rus3::UNDEF
68
+ end
69
+
70
+ def number?(obj)
71
+ obj.is_a?(Numeric)
72
+ end
73
+
74
+ def char?(obj)
75
+ false
76
+ end
77
+
78
+ def string?(obj)
79
+ obj.kind_of?(String)
80
+ end
81
+
82
+ def vector?(obj)
83
+ false
84
+ end
85
+
86
+ def port?(obj)
87
+ false
88
+ end
89
+
90
+ def procedure?(obj)
91
+ obj.instance_of?(Proc)
92
+ end
93
+
94
+ # :startdoc:
95
+
96
+ # :stopdoc:
97
+
98
+ # Numeric types:
99
+ #
100
+ # Scheme has more predicates for number values.
101
+ #
102
+ # complex
103
+ # real
104
+ # rational
105
+ # integer
106
+ #
107
+ # R5RS says, "Mathematically, numbers may be arranged into a tower
108
+ # of subtypes in which each level is a subset of the level above
109
+ # it:"
110
+ #
111
+ # That is, {integer} < {rational} < {real} < {complex}.
112
+
113
+ # :startdoc:
114
+
115
+ def complex?(num)
116
+ num.is_a?(Complex) || real?(num)
117
+ end
118
+
119
+ def real?(num)
120
+ num.is_a?(Float) || rational?(num)
121
+ end
122
+
123
+ def rational?(num)
124
+ num.is_a?(Rational) || integer?(num)
125
+ end
126
+
127
+ def integer?(num)
128
+ num.is_a?(Integer)
129
+ end
130
+
131
+ # :stopdoc:
132
+
133
+ # Tests a number for a particular property.
134
+
135
+ # :startdoc:
136
+
137
+ def zero?(z)
138
+ raise Rus3::NumberRequiredError, z unless number?(z)
139
+ z.zero?
140
+ end
141
+
142
+ def positive?(r)
143
+ raise Rus3::RealNumberRequiredError, r unless real?(r)
144
+ r.positive?
145
+ end
146
+
147
+ def negative?(r)
148
+ raise Rus3::RealNumberRequiredError, r unless real?(r)
149
+ r.negative?
150
+ end
151
+
152
+ def odd?(n)
153
+ raise Rus3::IntegerRequiredError, n unless integer?(n)
154
+ n.odd?
155
+ end
156
+
157
+ def even?(n)
158
+ raise Rus3::IntegerRequiredError, n unless integer?(n)
159
+ n.even?
160
+ end
161
+
162
+ # :stopdoc:
163
+
164
+ # Characters:
165
+ #
166
+ # ...
167
+
168
+ # :startdoc:
169
+
170
+ def char_eq?(char1, char2)
171
+ false
172
+ end
173
+
174
+ def char_lt?(char1, char2)
175
+ false
176
+ end
177
+
178
+ def char_gt?(char1, char2)
179
+ false
180
+ end
181
+
182
+ def char_le?(char1, char2)
183
+ false
184
+ end
185
+
186
+ def char_ge?(char1, char2)
187
+ false
188
+ end
189
+
190
+ def char_ci_eq?(char1, char2)
191
+ false
192
+ end
193
+
194
+ def char_ci_lt?(char1, char2)
195
+ false
196
+ end
197
+
198
+ def char_ci_gt?(char1, char2)
199
+ false
200
+ end
201
+
202
+ def char_ci_le?(char1, char2)
203
+ false
204
+ end
205
+
206
+ def char_ci_ge?(char1, char2)
207
+ false
208
+ end
209
+
210
+ def char_alphabetic?(char)
211
+ false
212
+ end
213
+
214
+ def char_numeric?(char)
215
+ false
216
+ end
217
+
218
+ def char_whitespace?(char)
219
+ false
220
+ end
221
+
222
+ def char_upper_case?(letter)
223
+ false
224
+ end
225
+
226
+ def char_lower_case?(letter)
227
+ false
228
+ end
229
+
230
+ # :stopdoc:
231
+
232
+ # Strings:
233
+
234
+ # :startdoc:
235
+
236
+ def check_string(*objs)
237
+ objs.each { |obj|
238
+ raise Rus3::StringRequiredError, obj unless string?(obj)
239
+ }
240
+ end
241
+ private :check_string
242
+
243
+ def string_eq?(str1, str2)
244
+ check_string(str1, str2)
245
+ str1 == str2
246
+ end
247
+
248
+ def string_ci_eq?(str1, str2)
249
+ check_string(str1, str2)
250
+ str1.downcase == str2.downcase
251
+ end
252
+
253
+ def string_lt?(str1, str2)
254
+ check_string(str1, str2)
255
+ str1 < str2
256
+ end
257
+
258
+ def string_gt?(str1, str2)
259
+ check_string(str1, str2)
260
+ str1 > str2
261
+ end
262
+
263
+ def string_le?(str1, str2)
264
+ check_string(str1, str2)
265
+ str1 <= str2
266
+ end
267
+
268
+ def string_ge?(str1, str2)
269
+ check_string(str1, str2)
270
+ str1 >= str2
271
+ end
272
+
273
+ def string_ci_lt?(str1, str2)
274
+ check_string(str1, str2)
275
+ str1.downcase < str2.downcase
276
+ end
277
+
278
+ def string_ci_gt?(str1, str2)
279
+ check_string(str1, str2)
280
+ str1.downcase > str2.downcase
281
+ end
282
+
283
+ def string_ci_le?(str1, str2)
284
+ check_string(str1, str2)
285
+ str1.downcase <= str2.downcase
286
+ end
287
+
288
+ def string_ci_ge?(str1, str2)
289
+ check_string(str1, str2)
290
+ str1.downcase >= str2.downcase
291
+ end
292
+
293
+ # :stopdoc:
294
+
295
+ # Ports:
296
+
297
+ # :startdoc:
298
+
299
+ def input_port?(obj)
300
+ false
301
+ end
302
+
303
+ def output_port?(obj)
304
+ false
305
+ end
306
+
307
+ end
308
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3::Procedure
4
+ module Write
5
+
6
+ include Predicate
7
+ include Rus3::EmptyList
8
+
9
+ def write(obj)
10
+ print any_to_string(obj)
11
+ Rus3::UNDEF
12
+ end
13
+
14
+ def display(obj)
15
+ puts any_to_string(obj)
16
+ Rus3::UNDEF
17
+ end
18
+
19
+ # :stopdoc:
20
+
21
+ private
22
+
23
+ TYPES = [
24
+ :null, # empty list
25
+ :boolean, # #f or #t
26
+ :pair, # (foo . bar)
27
+ :symbol,
28
+ :number,
29
+ :char,
30
+ :string,
31
+ :vector,
32
+ :port,
33
+ :procedure,
34
+ ]
35
+
36
+ def private_method(name)
37
+ m = nil
38
+ if self.class.private_method_defined?(name)
39
+ um = self.class.instance_method(name)
40
+ m = um.bind(self)
41
+ end
42
+ m
43
+ end
44
+
45
+ def type(obj)
46
+ obj_type = nil
47
+ TYPES.each { |type|
48
+ predicate_name = "#{type}?".intern
49
+ next unless respond_to?(predicate_name)
50
+
51
+ predicate_prc = method(predicate_name)
52
+ if predicate_prc.call(obj)
53
+ obj_type = type
54
+ break
55
+ end
56
+ }
57
+ obj_type || :undef
58
+ end
59
+
60
+ def any_to_string(obj)
61
+ prc_name = "#{type(obj)}_to_string".intern
62
+ prc = private_method(prc_name)
63
+ prc ? prc.call(obj) : obj.to_s
64
+ end
65
+
66
+ def null_to_string(obj)
67
+ "()"
68
+ end
69
+
70
+ def boolean_to_string(obj)
71
+ obj ? "#t" : "#f"
72
+ end
73
+
74
+ def pair_to_string(obj)
75
+ if null?(obj)
76
+ # ()
77
+ null_to_string(obj)
78
+ elsif list?(obj)
79
+ # (1 2 3 4)
80
+ result = obj.map {|e| any_to_string(e) }
81
+ "(#{result.join(' ')})"
82
+ else
83
+ # (1 2 3 . 4)
84
+ # ==> (1 . (2 . (3 . 4)))
85
+ result = any_to_string(obj.car)
86
+ cp = obj.cdr
87
+
88
+ while pair?(cp)
89
+ result += " "
90
+ result += any_to_string(cp.car)
91
+ cp = cp.cdr
92
+ end
93
+
94
+ result += " . "
95
+ result += any_to_string(cp)
96
+ "(#{result})"
97
+ end
98
+ end
99
+
100
+ def symbol_to_string(obj)
101
+ ":#{obj}"
102
+ end
103
+
104
+ def number_to_string(obj)
105
+ obj.to_s
106
+ end
107
+
108
+ def char_to_string(obj)
109
+ # TODO:
110
+ end
111
+
112
+ def string_to_string(obj)
113
+ "\"#{obj}\""
114
+ end
115
+
116
+ def vector_to_string(obj)
117
+ # TODO:
118
+ end
119
+
120
+ def port_to_string(obj)
121
+ # TODO:
122
+ end
123
+
124
+ def procedure_to_string(obj)
125
+ # TODO:
126
+ end
127
+
128
+ # :startdoc:
129
+ end
130
+ end
data/lib/rus3/repl.rb ADDED
@@ -0,0 +1,236 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+
5
+ # Provides a very simple Read Eval Print Loop mechanism of Rus3.
6
+ #
7
+ # Features:
8
+ #
9
+ # Each evaluated value is recorded into the value history.
10
+ #
11
+ # _, _last_value : retrieves the last evaluated value
12
+ # _his(n), _history(n) : retrieves the n-th value in the
13
+ # history.
14
+ # _his, _history : prints all values in the history
15
+ #
16
+ # Short usage:
17
+ #
18
+ # require "rus3"
19
+ # Rus3::Repl.start
20
+
21
+ class Repl
22
+
23
+ # Indicates the version of the Repl class.
24
+ VERSION = "0.1.0"
25
+
26
+ class << self
27
+
28
+ # Starts REPL.
29
+ def start(verbose: false)
30
+ repl = Repl.new(verbose: verbose)
31
+ repl.loop
32
+ end
33
+
34
+ end
35
+
36
+ # Hods major component names of the REPL.
37
+ COMPONENTS = {
38
+ :parser => Parser::DEFAULT_PARSER,
39
+ :evaluator => Evaluator,
40
+ :printer => nil,
41
+ }
42
+
43
+ # Prompt for input.
44
+ PROMPT = "Rus3> "
45
+
46
+ # A message to print at exitting.
47
+ FAREWELL_MESSAGE = "Bye!"
48
+
49
+ @@value_history = [] # :nodoc:
50
+
51
+ attr_accessor :verbose # :nodoc:
52
+
53
+ def initialize(verbose: false)
54
+ COMPONENTS.each { |name, klass|
55
+ instance_variable_set("@#{name}", klass.nil? ? self : klass.new)
56
+ }
57
+
58
+ @prompt = PROMPT
59
+ @parser.prompt = PROMPT unless @parser.nil?
60
+
61
+ @verbose = verbose
62
+ @evaluator.verbose = verbose
63
+ @printer.verbose = verbose
64
+
65
+ define_constants
66
+ define_help_feature
67
+ define_history_feature
68
+ define_load_feature
69
+
70
+ greeting
71
+ end
72
+
73
+ def loop
74
+ msg = Kernel.loop { # LOOP
75
+ begin
76
+ exp = @parser.read(STDIN) # READ
77
+ rescue SchemeSyntaxError => e
78
+ puts "ERROR: %s" % e
79
+ next
80
+ end
81
+ break FAREWELL_MESSAGE if exp.nil?
82
+
83
+ begin
84
+ value = @evaluator.eval(exp) # EVAL
85
+ rescue SyntaxError, StandardError => e
86
+ puts "ERROR: %s" % e
87
+ next
88
+ end
89
+
90
+ history_push(value)
91
+
92
+ @printer.print(value) # PRINT
93
+ }
94
+ puts "#{msg}" unless msg.nil?
95
+ end
96
+
97
+ # Shows the greeting message.
98
+ def greeting
99
+ puts "A simple REPL for Rus3:"
100
+ puts "- Rus3 version: #{Rus3::VERSION}"
101
+ puts " - REPL version: #{VERSION}"
102
+ COMPONENTS.keys.each { |comp_name|
103
+ Kernel.print " - "
104
+ print_version(comp_name)
105
+ }
106
+ end
107
+
108
+ # :stopdoc:
109
+
110
+ protected
111
+
112
+ require "readline"
113
+
114
+ def read(io = STDIN)
115
+ Readline::readline(@prompt, true)
116
+ end
117
+
118
+ def eval(exp)
119
+ exp
120
+ end
121
+
122
+ def print(obj)
123
+ prefix = "==> "
124
+ prefix += "[#{obj.class}]: " if @verbose
125
+ Kernel.print prefix
126
+ pp obj
127
+ end
128
+
129
+ private
130
+
131
+ def define_constants # :nodoc:
132
+ return if @evaluator.nil?
133
+
134
+ r = @evaluator.binding.receiver
135
+
136
+ r.instance_eval {
137
+ self.class.const_set(:RUS3_VERSION, "#{VERSION}")
138
+ }
139
+ end
140
+
141
+ def define_help_feature # :nodoc:
142
+ return if @evaluator.nil?
143
+
144
+ r = @evaluator.binding.receiver
145
+
146
+ r.instance_eval {
147
+ def _help
148
+ puts <<HELP
149
+ A simple REPL for Rus3.
150
+
151
+ FEATURES:
152
+
153
+ History of evaluated values:
154
+ - `_last_value` : refers the last evaluated value (short: `_`)
155
+ - `_history(n)` : refers the n-th value in the history (short: `_his(n)`)
156
+ - `_history` : prints all entries in the history (short: `_his`)
157
+
158
+ Help:
159
+ - `_help` : prints this message
160
+ HELP
161
+ end
162
+ }
163
+ end
164
+
165
+ def define_history_feature # :nodoc:
166
+ return if @evaluator.nil?
167
+
168
+ r = @evaluator.binding.receiver
169
+
170
+ r.instance_variable_set(:@value_history, @@value_history)
171
+ r.instance_eval {
172
+
173
+ def _last_value
174
+ @value_history[-1]
175
+ end
176
+ alias :_ :_last_value
177
+
178
+ def _history(arg = nil)
179
+ if arg.nil?
180
+ @value_history.each_with_index { |value, i|
181
+ Kernel.print "#{i}: "
182
+ display(value)
183
+ }
184
+ UNDEF
185
+ else
186
+ num = arg.to_i
187
+ if (0...@value_history.size).cover?(num)
188
+ @value_history[num]
189
+ else
190
+ raise OutOfRangeError, num
191
+ end
192
+ end
193
+ end
194
+ alias :_his :_history
195
+
196
+ }
197
+ end
198
+
199
+ def define_load_feature
200
+ return if @evaluator.nil?
201
+
202
+ r = @evaluator.binding.receiver
203
+
204
+ r.instance_variable_set(:@scm_parser, Parser::SchemeParser.new)
205
+ r.instance_eval {
206
+ def load_scm(path)
207
+ raise Rus3::CannotFindFileError, path unless FileTest.exist?(path)
208
+ scm_source = nil
209
+ File.open(path, "r") {|f| scm_source = f.readlines(chomp: true)}
210
+ s_exp = scm_source.join(" ")
211
+ r_exp = @scm_parser.parse(s_exp)
212
+ self.binding.eval(r_exp)
213
+ end
214
+ }
215
+ end
216
+
217
+ def print_version(comp_name)
218
+ component = instance_variable_get("@#{comp_name}")
219
+ if component.nil? or component == self
220
+ puts "using built-in #{comp_name.upcase}"
221
+ else
222
+ puts "#{component.version}"
223
+ end
224
+ end
225
+
226
+ def history_push(value)
227
+ prev_value = @@value_history[-1]
228
+ if prev_value != value and UNDEF != value
229
+ @@value_history << value if prev_value != value
230
+ end
231
+ end
232
+
233
+ # :startdoc:
234
+
235
+ end
236
+ end