rus3 0.1.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 +7 -0
- data/.github/workflows/main.yml +18 -0
- data/.gitignore +56 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +21 -0
- data/LICENSE +21 -0
- data/README.md +182 -0
- data/Rakefile +20 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/examples/fact.scm +10 -0
- data/examples/fib.scm +9 -0
- data/examples/iota.scm +13 -0
- data/exe/rus3 +5 -0
- data/lib/rus3.rb +52 -0
- data/lib/rus3/char.rb +6 -0
- data/lib/rus3/error.rb +127 -0
- data/lib/rus3/evaluator.rb +75 -0
- data/lib/rus3/pair.rb +67 -0
- data/lib/rus3/parser.rb +71 -0
- data/lib/rus3/parser/lexer.rb +119 -0
- data/lib/rus3/parser/scheme_parser.rb +322 -0
- data/lib/rus3/port.rb +6 -0
- data/lib/rus3/printer.rb +28 -0
- data/lib/rus3/procedure/control.rb +35 -0
- data/lib/rus3/procedure/list.rb +289 -0
- data/lib/rus3/procedure/predicate.rb +308 -0
- data/lib/rus3/procedure/write.rb +130 -0
- data/lib/rus3/repl.rb +236 -0
- data/lib/rus3/version.rb +5 -0
- data/rus3.gemspec +34 -0
- metadata +77 -0
@@ -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
|