rus3 0.1.2 → 0.2.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/Gemfile.lock +1 -1
- data/README.md +14 -6
- data/exe/rus3 +26 -2
- data/lib/rus3.rb +3 -0
- data/lib/rus3/ast.rb +70 -0
- data/lib/rus3/ast/branch_node.rb +412 -0
- data/lib/rus3/ast/error.rb +8 -0
- data/lib/rus3/ast/leaf_node.rb +55 -0
- data/lib/rus3/error.rb +15 -1
- data/lib/rus3/evaluator.rb +38 -54
- data/lib/rus3/evaluator/environment.rb +25 -0
- data/lib/rus3/evaluator/scheme_evaluator.rb +79 -0
- data/lib/rus3/evaluator/translator.rb +337 -0
- data/lib/rus3/{parser/lexer.rb → lexer.rb} +22 -52
- data/lib/rus3/parser.rb +39 -23
- data/lib/rus3/parser/scheme_parser.rb +595 -306
- data/lib/rus3/procedure/char.rb +21 -17
- data/lib/rus3/procedure/control.rb +28 -24
- data/lib/rus3/procedure/list.rb +210 -207
- data/lib/rus3/procedure/predicate.rb +267 -264
- data/lib/rus3/procedure/utils.rb +20 -16
- data/lib/rus3/procedure/vector.rb +68 -65
- data/lib/rus3/procedure/write.rb +107 -103
- data/lib/rus3/repl.rb +57 -47
- data/lib/rus3/token.rb +35 -0
- data/lib/rus3/version.rb +2 -2
- metadata +11 -3
@@ -1,306 +1,309 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rus3
|
3
|
+
module Rus3
|
4
|
+
module Procedure
|
5
|
+
|
6
|
+
module Predicate
|
7
|
+
|
8
|
+
include Rus3::EmptyList
|
9
|
+
|
10
|
+
# Returns true if the arguemnt represents a list structure.
|
11
|
+
# Note that an empty list is a list.
|
12
|
+
def list?(obj)
|
13
|
+
obj.instance_of?(Array)
|
14
|
+
end
|
15
|
+
|
16
|
+
# :stopdoc:
|
17
|
+
|
18
|
+
# Equivalence predicates:
|
19
|
+
#
|
20
|
+
# In R5RS, three equivalence predicates are defined such as eqv?,
|
21
|
+
# eq? and equal?.
|
22
|
+
#
|
23
|
+
# `equal?` has been defined in Object class and the reference
|
24
|
+
# manual says that this method must not re-defined. So,
|
25
|
+
# `equal?` is not defined here.
|
26
|
+
|
27
|
+
# :startdoc:
|
28
|
+
|
29
|
+
def eqv?(obj1, obj2)
|
30
|
+
obj1 == obj2
|
31
|
+
end
|
32
|
+
|
33
|
+
def eq?(obj1, obj2)
|
34
|
+
obj1.equal?(obj2)
|
35
|
+
end
|
36
|
+
|
37
|
+
# :stopdoc:
|
38
|
+
|
39
|
+
# Value types:
|
40
|
+
#
|
41
|
+
# R5RS says "no objects satiscies more than one of the following
|
42
|
+
# predicates". That is, Scheme has 9 value types at least.
|
43
|
+
#
|
44
|
+
# Most of them have suitable types in Ruby built-in classes. Rus3
|
45
|
+
# provides some classes for the rest of them.
|
46
|
+
#
|
47
|
+
# boolean? ---> FalseClass or TrueClass
|
48
|
+
# pair? ------> Array (as a list) or Rus3::Pair (as a dotted pair)
|
49
|
+
# symbol? ----> Symbol
|
50
|
+
# number? ----> Numeric
|
51
|
+
# char? ------> Rus3::Char
|
52
|
+
# string? ----> String
|
53
|
+
# vector? ----> Rus3::Vector
|
54
|
+
# port? ------> Rus3::Port
|
55
|
+
# procedure? -> Proc
|
56
|
+
|
57
|
+
# :startdoc:
|
58
|
+
|
59
|
+
def boolean?(obj)
|
60
|
+
obj.instance_of?(FalseClass) or obj.instance_of?(TrueClass)
|
61
|
+
end
|
62
|
+
|
63
|
+
def pair?(obj)
|
64
|
+
obj.instance_of?(Array) or obj.instance_of?(Rus3::Pair)
|
65
|
+
end
|
66
|
+
|
67
|
+
def symbol?(obj)
|
68
|
+
obj.instance_of?(Symbol) && obj != Rus3::UNDEF
|
69
|
+
end
|
70
|
+
|
71
|
+
def number?(obj)
|
72
|
+
obj.kind_of?(Numeric)
|
73
|
+
end
|
74
|
+
|
75
|
+
def char?(obj)
|
76
|
+
obj.instance_of?(Rus3::Char)
|
77
|
+
end
|
78
|
+
|
79
|
+
def string?(obj)
|
80
|
+
obj.kind_of?(String)
|
81
|
+
end
|
82
|
+
|
83
|
+
# procedure (R5RS/R7RS): (vector? obj)
|
84
|
+
def vector?(obj)
|
85
|
+
obj.instance_of?(Rus3::Vector)
|
86
|
+
end
|
87
|
+
|
88
|
+
def port?(obj)
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
92
|
+
def procedure?(obj)
|
93
|
+
obj.instance_of?(Proc)
|
94
|
+
end
|
95
|
+
|
96
|
+
# :startdoc:
|
97
|
+
|
98
|
+
# :stopdoc:
|
99
|
+
|
100
|
+
# Numeric types:
|
101
|
+
#
|
102
|
+
# Scheme has more predicates for number values.
|
103
|
+
#
|
104
|
+
# complex
|
105
|
+
# real
|
106
|
+
# rational
|
107
|
+
# integer
|
108
|
+
#
|
109
|
+
# R5RS says, "Mathematically, numbers may be arranged into a tower
|
110
|
+
# of subtypes in which each level is a subset of the level above
|
111
|
+
# it:"
|
112
|
+
#
|
113
|
+
# That is, {integer} < {rational} < {real} < {complex}.
|
114
|
+
|
115
|
+
# :startdoc:
|
116
|
+
|
117
|
+
def complex?(num)
|
118
|
+
num.is_a?(Complex) || real?(num)
|
119
|
+
end
|
120
|
+
|
121
|
+
def real?(num)
|
122
|
+
num.is_a?(Float) || rational?(num)
|
123
|
+
end
|
124
|
+
|
125
|
+
def rational?(num)
|
126
|
+
num.is_a?(Rational) || integer?(num)
|
127
|
+
end
|
128
|
+
|
129
|
+
def integer?(num)
|
130
|
+
num.is_a?(Integer)
|
131
|
+
end
|
132
|
+
|
133
|
+
# :stopdoc:
|
134
|
+
|
135
|
+
# Tests a number for a particular property.
|
4
136
|
|
5
|
-
|
137
|
+
# :startdoc:
|
138
|
+
|
139
|
+
def zero?(z)
|
140
|
+
raise Rus3::NumberRequiredError, z unless number?(z)
|
141
|
+
z.zero?
|
142
|
+
end
|
143
|
+
|
144
|
+
def positive?(r)
|
145
|
+
raise Rus3::RealNumberRequiredError, r unless real?(r)
|
146
|
+
r.positive?
|
147
|
+
end
|
6
148
|
|
7
|
-
|
149
|
+
def negative?(r)
|
150
|
+
raise Rus3::RealNumberRequiredError, r unless real?(r)
|
151
|
+
r.negative?
|
152
|
+
end
|
8
153
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
154
|
+
def odd?(n)
|
155
|
+
raise Rus3::IntegerRequiredError, n unless integer?(n)
|
156
|
+
n.odd?
|
157
|
+
end
|
14
158
|
|
15
|
-
|
159
|
+
def even?(n)
|
160
|
+
raise Rus3::IntegerRequiredError, n unless integer?(n)
|
161
|
+
n.even?
|
162
|
+
end
|
16
163
|
|
17
|
-
|
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.
|
164
|
+
# :stopdoc:
|
25
165
|
|
26
|
-
|
166
|
+
# Characters:
|
27
167
|
|
28
|
-
|
29
|
-
obj1 == obj2
|
30
|
-
end
|
168
|
+
# :startdoc:
|
31
169
|
|
32
|
-
|
33
|
-
|
34
|
-
|
170
|
+
def char_eq?(char1, char2)
|
171
|
+
Rus3::Char.compare_chars(char1, char2, :==)
|
172
|
+
end
|
35
173
|
|
36
|
-
|
37
|
-
|
38
|
-
|
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? ------> Array (as a list) or Rus3::Pair (as a dotted pair)
|
48
|
-
# symbol? ----> Symbol
|
49
|
-
# number? ----> Numeric
|
50
|
-
# char? ------> Rus3::Char
|
51
|
-
# string? ----> String
|
52
|
-
# vector? ----> Rus3::Vector
|
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
|
174
|
+
def char_lt?(char1, char2)
|
175
|
+
Rus3::Char.compare_chars(char1, char2, :<)
|
176
|
+
end
|
61
177
|
|
62
|
-
|
63
|
-
|
64
|
-
|
178
|
+
def char_gt?(char1, char2)
|
179
|
+
Rus3::Char.compare_chars(char1, char2, :>)
|
180
|
+
end
|
181
|
+
|
182
|
+
def char_le?(char1, char2)
|
183
|
+
Rus3::Char.compare_chars(char1, char2, :<=)
|
184
|
+
end
|
185
|
+
|
186
|
+
def char_ge?(char1, char2)
|
187
|
+
Rus3::Char.compare_chars(char1, char2, :>=)
|
188
|
+
end
|
189
|
+
|
190
|
+
def char_ci_eq?(char1, char2)
|
191
|
+
Rus3::Char.compare_chars(char1, char2, :==, ignore_case: true)
|
192
|
+
end
|
193
|
+
|
194
|
+
def char_ci_lt?(char1, char2)
|
195
|
+
Rus3::Char.compare_chars(char1, char2, :<, ignore_case: true)
|
196
|
+
end
|
65
197
|
|
66
|
-
|
67
|
-
|
68
|
-
|
198
|
+
def char_ci_gt?(char1, char2)
|
199
|
+
Rus3::Char.compare_chars(char1, char2, :>, ignore_case: true)
|
200
|
+
end
|
201
|
+
|
202
|
+
def char_ci_le?(char1, char2)
|
203
|
+
Rus3::Char.compare_chars(char1, char2, :<=, ignore_case: true)
|
204
|
+
end
|
69
205
|
|
70
|
-
|
71
|
-
|
72
|
-
|
206
|
+
def char_ci_ge?(char1, char2)
|
207
|
+
Rus3::Char.compare_chars(char1, char2, :>=, ignore_case: true)
|
208
|
+
end
|
73
209
|
|
74
|
-
|
75
|
-
|
76
|
-
|
210
|
+
def char_alphabetic?(char)
|
211
|
+
Rus3::Char.alphabetic?(char)
|
212
|
+
end
|
77
213
|
|
78
|
-
|
79
|
-
|
80
|
-
|
214
|
+
def char_numeric?(char)
|
215
|
+
Rus3::Char.numeric?(char)
|
216
|
+
end
|
81
217
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
218
|
+
def char_whitespace?(char)
|
219
|
+
Rus3::Char.whitespace?(char)
|
220
|
+
end
|
86
221
|
|
87
|
-
|
88
|
-
|
89
|
-
|
222
|
+
def char_upper_case?(letter)
|
223
|
+
Rus3::Char.upper_case?(letter)
|
224
|
+
end
|
90
225
|
|
91
|
-
|
92
|
-
|
93
|
-
|
226
|
+
def char_lower_case?(letter)
|
227
|
+
Rus3::Char.lower_case?(letter)
|
228
|
+
end
|
94
229
|
|
95
|
-
|
96
|
-
|
97
|
-
# :stopdoc:
|
98
|
-
|
99
|
-
# Numeric types:
|
100
|
-
#
|
101
|
-
# Scheme has more predicates for number values.
|
102
|
-
#
|
103
|
-
# complex
|
104
|
-
# real
|
105
|
-
# rational
|
106
|
-
# integer
|
107
|
-
#
|
108
|
-
# R5RS says, "Mathematically, numbers may be arranged into a tower
|
109
|
-
# of subtypes in which each level is a subset of the level above
|
110
|
-
# it:"
|
111
|
-
#
|
112
|
-
# That is, {integer} < {rational} < {real} < {complex}.
|
113
|
-
|
114
|
-
# :startdoc:
|
115
|
-
|
116
|
-
def complex?(num)
|
117
|
-
num.is_a?(Complex) || real?(num)
|
118
|
-
end
|
230
|
+
# :stopdoc:
|
119
231
|
|
120
|
-
|
121
|
-
num.is_a?(Float) || rational?(num)
|
122
|
-
end
|
232
|
+
# Strings:
|
123
233
|
|
124
|
-
|
125
|
-
num.is_a?(Rational) || integer?(num)
|
126
|
-
end
|
234
|
+
# :startdoc:
|
127
235
|
|
128
|
-
|
129
|
-
|
130
|
-
|
236
|
+
def check_string(*objs)
|
237
|
+
objs.each { |obj|
|
238
|
+
raise Rus3::StringRequiredError, obj unless string?(obj)
|
239
|
+
}
|
240
|
+
end
|
241
|
+
private :check_string
|
131
242
|
|
132
|
-
|
243
|
+
def string_eq?(str1, str2)
|
244
|
+
check_string(str1, str2)
|
245
|
+
str1 == str2
|
246
|
+
end
|
133
247
|
|
134
|
-
|
248
|
+
def string_ci_eq?(str1, str2)
|
249
|
+
check_string(str1, str2)
|
250
|
+
str1.downcase == str2.downcase
|
251
|
+
end
|
135
252
|
|
136
|
-
|
253
|
+
def string_lt?(str1, str2)
|
254
|
+
check_string(str1, str2)
|
255
|
+
str1 < str2
|
256
|
+
end
|
137
257
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
258
|
+
def string_gt?(str1, str2)
|
259
|
+
check_string(str1, str2)
|
260
|
+
str1 > str2
|
261
|
+
end
|
142
262
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
263
|
+
def string_le?(str1, str2)
|
264
|
+
check_string(str1, str2)
|
265
|
+
str1 <= str2
|
266
|
+
end
|
147
267
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
268
|
+
def string_ge?(str1, str2)
|
269
|
+
check_string(str1, str2)
|
270
|
+
str1 >= str2
|
271
|
+
end
|
152
272
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
273
|
+
def string_ci_lt?(str1, str2)
|
274
|
+
check_string(str1, str2)
|
275
|
+
str1.downcase < str2.downcase
|
276
|
+
end
|
157
277
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
# :stopdoc:
|
164
|
-
|
165
|
-
# Characters:
|
278
|
+
def string_ci_gt?(str1, str2)
|
279
|
+
check_string(str1, str2)
|
280
|
+
str1.downcase > str2.downcase
|
281
|
+
end
|
166
282
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
283
|
+
def string_ci_le?(str1, str2)
|
284
|
+
check_string(str1, str2)
|
285
|
+
str1.downcase <= str2.downcase
|
286
|
+
end
|
172
287
|
|
173
|
-
|
174
|
-
|
175
|
-
|
288
|
+
def string_ci_ge?(str1, str2)
|
289
|
+
check_string(str1, str2)
|
290
|
+
str1.downcase >= str2.downcase
|
291
|
+
end
|
176
292
|
|
177
|
-
|
178
|
-
Rus3::Char.compare_chars(char1, char2, :>)
|
179
|
-
end
|
293
|
+
# :stopdoc:
|
180
294
|
|
181
|
-
|
182
|
-
Rus3::Char.compare_chars(char1, char2, :<=)
|
183
|
-
end
|
295
|
+
# Ports:
|
184
296
|
|
185
|
-
|
186
|
-
Rus3::Char.compare_chars(char1, char2, :>=)
|
187
|
-
end
|
297
|
+
# :startdoc:
|
188
298
|
|
189
|
-
|
190
|
-
|
191
|
-
|
299
|
+
def input_port?(obj)
|
300
|
+
false
|
301
|
+
end
|
192
302
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
def char_ci_gt?(char1, char2)
|
198
|
-
Rus3::Char.compare_chars(char1, char2, :>, ignore_case: true)
|
199
|
-
end
|
200
|
-
|
201
|
-
def char_ci_le?(char1, char2)
|
202
|
-
Rus3::Char.compare_chars(char1, char2, :<=, ignore_case: true)
|
203
|
-
end
|
204
|
-
|
205
|
-
def char_ci_ge?(char1, char2)
|
206
|
-
Rus3::Char.compare_chars(char1, char2, :>=, ignore_case: true)
|
207
|
-
end
|
208
|
-
|
209
|
-
def char_alphabetic?(char)
|
210
|
-
Rus3::Char.alphabetic?(char)
|
211
|
-
end
|
212
|
-
|
213
|
-
def char_numeric?(char)
|
214
|
-
Rus3::Char.numeric?(char)
|
215
|
-
end
|
216
|
-
|
217
|
-
def char_whitespace?(char)
|
218
|
-
Rus3::Char.whitespace?(char)
|
219
|
-
end
|
220
|
-
|
221
|
-
def char_upper_case?(letter)
|
222
|
-
Rus3::Char.upper_case?(letter)
|
223
|
-
end
|
224
|
-
|
225
|
-
def char_lower_case?(letter)
|
226
|
-
Rus3::Char.lower_case?(letter)
|
227
|
-
end
|
228
|
-
|
229
|
-
# :stopdoc:
|
230
|
-
|
231
|
-
# Strings:
|
232
|
-
|
233
|
-
# :startdoc:
|
234
|
-
|
235
|
-
def check_string(*objs)
|
236
|
-
objs.each { |obj|
|
237
|
-
raise Rus3::StringRequiredError, obj unless string?(obj)
|
238
|
-
}
|
239
|
-
end
|
240
|
-
private :check_string
|
241
|
-
|
242
|
-
def string_eq?(str1, str2)
|
243
|
-
check_string(str1, str2)
|
244
|
-
str1 == str2
|
245
|
-
end
|
246
|
-
|
247
|
-
def string_ci_eq?(str1, str2)
|
248
|
-
check_string(str1, str2)
|
249
|
-
str1.downcase == str2.downcase
|
250
|
-
end
|
251
|
-
|
252
|
-
def string_lt?(str1, str2)
|
253
|
-
check_string(str1, str2)
|
254
|
-
str1 < str2
|
255
|
-
end
|
256
|
-
|
257
|
-
def string_gt?(str1, str2)
|
258
|
-
check_string(str1, str2)
|
259
|
-
str1 > str2
|
260
|
-
end
|
261
|
-
|
262
|
-
def string_le?(str1, str2)
|
263
|
-
check_string(str1, str2)
|
264
|
-
str1 <= str2
|
265
|
-
end
|
266
|
-
|
267
|
-
def string_ge?(str1, str2)
|
268
|
-
check_string(str1, str2)
|
269
|
-
str1 >= str2
|
270
|
-
end
|
271
|
-
|
272
|
-
def string_ci_lt?(str1, str2)
|
273
|
-
check_string(str1, str2)
|
274
|
-
str1.downcase < str2.downcase
|
275
|
-
end
|
276
|
-
|
277
|
-
def string_ci_gt?(str1, str2)
|
278
|
-
check_string(str1, str2)
|
279
|
-
str1.downcase > str2.downcase
|
280
|
-
end
|
281
|
-
|
282
|
-
def string_ci_le?(str1, str2)
|
283
|
-
check_string(str1, str2)
|
284
|
-
str1.downcase <= str2.downcase
|
285
|
-
end
|
286
|
-
|
287
|
-
def string_ci_ge?(str1, str2)
|
288
|
-
check_string(str1, str2)
|
289
|
-
str1.downcase >= str2.downcase
|
290
|
-
end
|
291
|
-
|
292
|
-
# :stopdoc:
|
293
|
-
|
294
|
-
# Ports:
|
295
|
-
|
296
|
-
# :startdoc:
|
297
|
-
|
298
|
-
def input_port?(obj)
|
299
|
-
false
|
300
|
-
end
|
303
|
+
def output_port?(obj)
|
304
|
+
false
|
305
|
+
end
|
301
306
|
|
302
|
-
def output_port?(obj)
|
303
|
-
false
|
304
307
|
end
|
305
308
|
|
306
309
|
end
|