fOOrth 0.6.10 → 0.6.11
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 +5 -5
- data/README.md +13 -2
- data/fOOrth.gemspec +2 -2
- data/integration/array_lib_tests.rb +10 -0
- data/integration/exception_lib_tests.rb +4 -0
- data/integration/hash_lib_tests.rb +9 -0
- data/integration/numeric_lib_tests.rb +326 -321
- data/integration/procedure_lib_tests.rb +16 -0
- data/integration/queue_lib_tests.rb +2 -1
- data/integration/stack_lib_tests.rb +2 -1
- data/integration/string_lib_tests.rb +11 -0
- data/integration/thread_lib_tests.rb +11 -8
- data/lib/fOOrth/compiler/context.rb +64 -64
- data/lib/fOOrth/compiler/context/locals.rb +34 -34
- data/lib/fOOrth/compiler/context/map_name.rb +85 -85
- data/lib/fOOrth/compiler/context/tags.rb +60 -48
- data/lib/fOOrth/compiler/process/procedure.rb +40 -0
- data/lib/fOOrth/library.rb +1 -0
- data/lib/fOOrth/library/array_library.rb +41 -21
- data/lib/fOOrth/library/command_library.rb +1 -1
- data/lib/fOOrth/library/compile_library.rb +266 -266
- data/lib/fOOrth/library/complex_library.rb +82 -80
- data/lib/fOOrth/library/float_library.rb +37 -0
- data/lib/fOOrth/library/hash_library.rb +14 -6
- data/lib/fOOrth/library/mutex_library.rb +4 -2
- data/lib/fOOrth/library/numeric_library.rb +359 -380
- data/lib/fOOrth/library/procedure_library.rb +69 -65
- data/lib/fOOrth/library/queue_library.rb +6 -1
- data/lib/fOOrth/library/rational_library.rb +89 -89
- data/lib/fOOrth/library/stack_library.rb +6 -1
- data/lib/fOOrth/library/string_library.rb +18 -6
- data/lib/fOOrth/monkey_patch/exceptions.rb +2 -6
- data/lib/fOOrth/version.rb +1 -1
- data/tests/compiler/context_tests.rb +188 -177
- data/tests/compiler/file_source_tests.rb +130 -130
- data/tests/compiler/parser_tests.rb +4 -4
- data/tests/compiler/string_source_tests.rb +4 -4
- data/tests/core_tests.rb +138 -138
- data/tests/monkey_patch/complex_test.rb +24 -24
- data/tests/monkey_patch/object_test.rb +49 -49
- data/tests/monkey_patch/string_test.rb +61 -61
- metadata +10 -10
@@ -1,65 +1,69 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
#* library/procedure_library.rb - Proc support for the fOOrth library.
|
4
|
-
module XfOOrth
|
5
|
-
|
6
|
-
#Connect the Proc class to the fOOrth class system.
|
7
|
-
Proc.create_foorth_proxy('Procedure')
|
8
|
-
|
9
|
-
# A no operation place holder for procedure literals
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# [
|
17
|
-
Proc.create_shared_method('.
|
18
|
-
&lambda {|vm|
|
19
|
-
|
20
|
-
# [
|
21
|
-
Proc.create_shared_method('.
|
22
|
-
&lambda {|vm|
|
23
|
-
|
24
|
-
# [
|
25
|
-
Proc.create_shared_method('.
|
26
|
-
&lambda {|vm|
|
27
|
-
|
28
|
-
# [
|
29
|
-
Proc.create_shared_method('.
|
30
|
-
&lambda {|vm|
|
31
|
-
|
32
|
-
# [procedure] .
|
33
|
-
Proc.create_shared_method('.
|
34
|
-
vm.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* library/procedure_library.rb - Proc support for the fOOrth library.
|
4
|
+
module XfOOrth
|
5
|
+
|
6
|
+
#Connect the Proc class to the fOOrth class system.
|
7
|
+
Proc.create_foorth_proxy('Procedure')
|
8
|
+
|
9
|
+
# A no operation place holder for procedure literals. This may seem odd but
|
10
|
+
# works because any word ending in '{{' is assumed to have a procedure literal
|
11
|
+
# attached to it. This is handled in compiler/process/procedure.rb. This code
|
12
|
+
# handles compiling the procedure and pushing a reference to it on the stack.
|
13
|
+
# Once this is done, this word need do nothing further so is a no-op.
|
14
|
+
VirtualMachine.create_shared_method('{{', MacroSpec, [:macro, " "])
|
15
|
+
|
16
|
+
# [procedure] .call [unspecified]
|
17
|
+
Proc.create_shared_method('.call', TosSpec, [],
|
18
|
+
&lambda {|vm| self.call(vm); })
|
19
|
+
|
20
|
+
# [owner procedure] .call_with [unspecified]
|
21
|
+
Proc.create_shared_method('.call_with', TosSpec, [],
|
22
|
+
&lambda {|vm| vm.pop.instance_exec(vm, &self); })
|
23
|
+
|
24
|
+
# [v procedure] .call_v [unspecified]
|
25
|
+
Proc.create_shared_method('.call_v', TosSpec, [],
|
26
|
+
&lambda {|vm| value = vm.pop; self.call(vm, value); })
|
27
|
+
|
28
|
+
# [x procedure] .call_x [unspecified]
|
29
|
+
Proc.create_shared_method('.call_x', TosSpec, [],
|
30
|
+
&lambda {|vm| index = vm.pop; self.call(vm, nil, index); })
|
31
|
+
|
32
|
+
# [v x procedure] .call_vx [unspecified]
|
33
|
+
Proc.create_shared_method('.call_vx', TosSpec, [],
|
34
|
+
&lambda {|vm| value, index = vm.popm(2); self.call(vm, value, index); })
|
35
|
+
|
36
|
+
# [procedure] .start [a_thread]
|
37
|
+
Proc.create_shared_method('.start', TosSpec, [], &lambda {|vm|
|
38
|
+
vm.push(self.do_thread_start(vm, '-'))
|
39
|
+
})
|
40
|
+
|
41
|
+
# [name procedure] .start_named [a_thread]
|
42
|
+
Proc.create_shared_method('.start_named', TosSpec, [], &lambda {|vm|
|
43
|
+
vm.push(self.do_thread_start(vm, vm.pop.to_s.freeze))
|
44
|
+
})
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
#A helper method in the Proc class for fOOrth threads.
|
49
|
+
class Proc
|
50
|
+
#Do the mechanics of starting a thread.
|
51
|
+
def do_thread_start(vm, vm_name)
|
52
|
+
block, interlock = self, Queue.new
|
53
|
+
|
54
|
+
result = Thread.new(vm.foorth_copy(vm_name)) do |vm_copy|
|
55
|
+
|
56
|
+
begin
|
57
|
+
self.foorth_init(vm_copy.compiler_reset.connect_vm_to_thread)
|
58
|
+
ensure
|
59
|
+
interlock.push(:ready)
|
60
|
+
end
|
61
|
+
|
62
|
+
vm_copy.instance_exec(vm_copy, &block)
|
63
|
+
end
|
64
|
+
|
65
|
+
interlock.pop
|
66
|
+
result
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -34,13 +34,18 @@ module XfOOrth
|
|
34
34
|
vm.push(self.empty?)
|
35
35
|
})
|
36
36
|
|
37
|
+
# [queue] .present? [a_boolean]
|
38
|
+
Queue.create_shared_method('.present?', TosSpec, [], &lambda {|vm|
|
39
|
+
vm.push(!self.empty?)
|
40
|
+
})
|
41
|
+
|
37
42
|
# [queue] .length [an_integer]
|
38
43
|
Queue.create_shared_method('.length', TosSpec, [], &lambda {|vm|
|
39
44
|
vm.push(self.length)
|
40
45
|
})
|
41
46
|
|
42
47
|
# [queue] .clear []
|
43
|
-
Queue.create_shared_method('.clear', TosSpec, [], &lambda {|vm|
|
48
|
+
Queue.create_shared_method('.clear!', TosSpec, [], &lambda {|vm|
|
44
49
|
self.clear
|
45
50
|
})
|
46
51
|
|
@@ -1,90 +1,90 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
#* library/rational_library.rb - Numeric support for the fOOrth library.
|
4
|
-
module XfOOrth
|
5
|
-
|
6
|
-
#Connect the Rational class to the fOOrth class system.
|
7
|
-
Rational.create_foorth_proxy
|
8
|
-
|
9
|
-
# Some conversion words.
|
10
|
-
# [n d] rational [n/d]
|
11
|
-
VirtualMachine.create_shared_method('rational', VmSpec, [], &lambda {|vm|
|
12
|
-
num,den = popm(2)
|
13
|
-
|
14
|
-
begin
|
15
|
-
push(Rational(num.to_foorth_r, den.to_foorth_r))
|
16
|
-
rescue
|
17
|
-
push(nil)
|
18
|
-
end
|
19
|
-
})
|
20
|
-
|
21
|
-
# Some conversion words.
|
22
|
-
# [n d] rational! [n/d]
|
23
|
-
VirtualMachine.create_shared_method('rational!', VmSpec, [], &lambda {|vm|
|
24
|
-
num,den = popm(2)
|
25
|
-
|
26
|
-
begin
|
27
|
-
push(Rational(num.to_foorth_r, den.to_foorth_r))
|
28
|
-
rescue
|
29
|
-
error "F40: Cannot coerce a #{num.foorth_name}, #{den.foorth_name} to a Rational"
|
30
|
-
end
|
31
|
-
})
|
32
|
-
|
33
|
-
# [err_limit float] .rationalize_to [rational]
|
34
|
-
Numeric.create_shared_method('.rationalize_to', TosSpec, [], &lambda {|vm|
|
35
|
-
err_limit = Float.foorth_coerce(vm.pop)
|
36
|
-
|
37
|
-
vm.push(self.rationalize(err_limit))
|
38
|
-
})
|
39
|
-
|
40
|
-
Complex.create_shared_method('.rationalize_to', TosSpec, [:stub])
|
41
|
-
|
42
|
-
# [rational] .split [numerator, denominator]
|
43
|
-
Rational.create_shared_method('.split', TosSpec, [],
|
44
|
-
&lambda {|vm| vm.push(self.numerator); vm.push(self.denominator); })
|
45
|
-
|
46
|
-
# [a] .to_r [n/d]
|
47
|
-
Object.create_shared_method('.to_r', TosSpec, [], &lambda {|vm|
|
48
|
-
begin
|
49
|
-
vm.push(Rational(self))
|
50
|
-
rescue
|
51
|
-
vm.push(nil)
|
52
|
-
end
|
53
|
-
})
|
54
|
-
|
55
|
-
# [a] .to_r! [n/d]
|
56
|
-
Object.create_shared_method('.to_r!', TosSpec, [], &lambda {|vm|
|
57
|
-
begin
|
58
|
-
vm.push(Rational(self))
|
59
|
-
rescue
|
60
|
-
error "F40: Cannot convert a #{self.foorth_name} to a Rational instance"
|
61
|
-
end
|
62
|
-
})
|
63
|
-
|
64
|
-
# [a_float] .to_r [n/d]
|
65
|
-
Float.create_shared_method('.to_r', TosSpec, [], &lambda {|vm|
|
66
|
-
begin
|
67
|
-
vm.push(self.rationalize)
|
68
|
-
rescue
|
69
|
-
vm.push(nil)
|
70
|
-
end
|
71
|
-
})
|
72
|
-
|
73
|
-
# [a_float] .to_r! [n/d]
|
74
|
-
Float.create_shared_method('.to_r!', TosSpec, [], &lambda {|vm|
|
75
|
-
begin
|
76
|
-
vm.push(self.rationalize)
|
77
|
-
rescue
|
78
|
-
error "F40: Cannot convert a #{self.foorth_name} to a Rational instance"
|
79
|
-
end
|
80
|
-
})
|
81
|
-
|
82
|
-
# [n/d] .numerator [n]
|
83
|
-
Numeric.create_shared_method('.numerator', TosSpec, [],
|
84
|
-
&lambda {|vm| vm.push(self.numerator); })
|
85
|
-
|
86
|
-
# [n/d] .denominator [d]
|
87
|
-
Numeric.create_shared_method('.denominator', TosSpec, [],
|
88
|
-
&lambda {|vm| vm.push(self.denominator); })
|
89
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* library/rational_library.rb - Numeric support for the fOOrth library.
|
4
|
+
module XfOOrth
|
5
|
+
|
6
|
+
#Connect the Rational class to the fOOrth class system.
|
7
|
+
Rational.create_foorth_proxy
|
8
|
+
|
9
|
+
# Some conversion words.
|
10
|
+
# [n d] rational [n/d]
|
11
|
+
VirtualMachine.create_shared_method('rational', VmSpec, [], &lambda {|vm|
|
12
|
+
num,den = popm(2)
|
13
|
+
|
14
|
+
begin
|
15
|
+
push(Rational(num.to_foorth_r, den.to_foorth_r))
|
16
|
+
rescue
|
17
|
+
push(nil)
|
18
|
+
end
|
19
|
+
})
|
20
|
+
|
21
|
+
# Some conversion words.
|
22
|
+
# [n d] rational! [n/d]
|
23
|
+
VirtualMachine.create_shared_method('rational!', VmSpec, [], &lambda {|vm|
|
24
|
+
num,den = popm(2)
|
25
|
+
|
26
|
+
begin
|
27
|
+
push(Rational(num.to_foorth_r, den.to_foorth_r))
|
28
|
+
rescue
|
29
|
+
error "F40: Cannot coerce a #{num.foorth_name}, #{den.foorth_name} to a Rational"
|
30
|
+
end
|
31
|
+
})
|
32
|
+
|
33
|
+
# [err_limit float] .rationalize_to [rational]
|
34
|
+
Numeric.create_shared_method('.rationalize_to', TosSpec, [], &lambda {|vm|
|
35
|
+
err_limit = Float.foorth_coerce(vm.pop)
|
36
|
+
|
37
|
+
vm.push(self.rationalize(err_limit))
|
38
|
+
})
|
39
|
+
|
40
|
+
Complex.create_shared_method('.rationalize_to', TosSpec, [:stub])
|
41
|
+
|
42
|
+
# [rational] .split [numerator, denominator]
|
43
|
+
Rational.create_shared_method('.split', TosSpec, [],
|
44
|
+
&lambda {|vm| vm.push(self.numerator); vm.push(self.denominator); })
|
45
|
+
|
46
|
+
# [a] .to_r [n/d]
|
47
|
+
Object.create_shared_method('.to_r', TosSpec, [], &lambda {|vm|
|
48
|
+
begin
|
49
|
+
vm.push(Rational(self))
|
50
|
+
rescue
|
51
|
+
vm.push(nil)
|
52
|
+
end
|
53
|
+
})
|
54
|
+
|
55
|
+
# [a] .to_r! [n/d]
|
56
|
+
Object.create_shared_method('.to_r!', TosSpec, [], &lambda {|vm|
|
57
|
+
begin
|
58
|
+
vm.push(Rational(self))
|
59
|
+
rescue
|
60
|
+
error "F40: Cannot convert a #{self.foorth_name} to a Rational instance"
|
61
|
+
end
|
62
|
+
})
|
63
|
+
|
64
|
+
# [a_float] .to_r [n/d]
|
65
|
+
Float.create_shared_method('.to_r', TosSpec, [], &lambda {|vm|
|
66
|
+
begin
|
67
|
+
vm.push(self.rationalize)
|
68
|
+
rescue
|
69
|
+
vm.push(nil)
|
70
|
+
end
|
71
|
+
})
|
72
|
+
|
73
|
+
# [a_float] .to_r! [n/d]
|
74
|
+
Float.create_shared_method('.to_r!', TosSpec, [], &lambda {|vm|
|
75
|
+
begin
|
76
|
+
vm.push(self.rationalize)
|
77
|
+
rescue
|
78
|
+
error "F40: Cannot convert a #{self.foorth_name} to a Rational instance"
|
79
|
+
end
|
80
|
+
})
|
81
|
+
|
82
|
+
# [n/d] .numerator [n]
|
83
|
+
Numeric.create_shared_method('.numerator', TosSpec, [],
|
84
|
+
&lambda {|vm| vm.push(self.numerator); })
|
85
|
+
|
86
|
+
# [n/d] .denominator [d]
|
87
|
+
Numeric.create_shared_method('.denominator', TosSpec, [],
|
88
|
+
&lambda {|vm| vm.push(self.denominator); })
|
89
|
+
|
90
90
|
end
|
@@ -14,7 +14,7 @@ module XfOOrth
|
|
14
14
|
})
|
15
15
|
|
16
16
|
#Clear the Stack object.
|
17
|
-
stack.create_shared_method('.clear', TosSpec, [], &lambda {|vm|
|
17
|
+
stack.create_shared_method('.clear!', TosSpec, [], &lambda {|vm|
|
18
18
|
@data.clear
|
19
19
|
})
|
20
20
|
|
@@ -46,6 +46,11 @@ module XfOOrth
|
|
46
46
|
vm.push(@data.empty?)
|
47
47
|
})
|
48
48
|
|
49
|
+
#[stack] .present? [a_boolean]
|
50
|
+
stack.create_shared_method('.present?', TosSpec, [], &lambda {|vm|
|
51
|
+
vm.push(!@data.empty?)
|
52
|
+
})
|
53
|
+
|
49
54
|
#[stack] .length [an_integer]
|
50
55
|
stack.create_shared_method('.length', TosSpec, [], &lambda {|vm|
|
51
56
|
vm.push(@data.length)
|
@@ -211,22 +211,34 @@ module XfOOrth
|
|
211
211
|
|
212
212
|
# ['fgh' 'abcdefgh'] .right? [boolean]
|
213
213
|
String.create_shared_method('.right?', TosSpec, [],
|
214
|
-
&lambda {|vm| vm.poke(self.end_with?(vm.peek))
|
214
|
+
&lambda {|vm| vm.poke(self.end_with?(vm.peek)) })
|
215
215
|
|
216
216
|
#Other String Methods
|
217
217
|
|
218
218
|
# ['cde' 'abcdefgh'] .contains? [boolean]
|
219
219
|
String.create_shared_method('.contains?', TosSpec, [],
|
220
|
-
&lambda {|vm| vm.poke(self.index(vm.peek).to_foorth_b)
|
220
|
+
&lambda {|vm| vm.poke(self.index(vm.peek).to_foorth_b) })
|
221
221
|
|
222
222
|
# ['cde' 'abcdefgh'] .posn [position or nil]
|
223
223
|
String.create_shared_method('.posn', TosSpec, [],
|
224
|
-
&lambda {|vm| vm.poke(self.index(vm.peek))
|
224
|
+
&lambda {|vm| vm.poke(self.index(vm.peek)) })
|
225
225
|
|
226
226
|
# ["a"] .length [n]
|
227
227
|
String.create_shared_method('.length', TosSpec, [],
|
228
228
|
&lambda {|vm| vm.push(self.length); })
|
229
229
|
|
230
|
+
# ["a"] .empty? [a_boolean]
|
231
|
+
String.create_shared_method('.empty?', TosSpec, [],
|
232
|
+
&lambda {|vm| vm.push(self.empty?) })
|
233
|
+
|
234
|
+
# ["a"] .present? [a_boolean]
|
235
|
+
String.create_shared_method('.present?', TosSpec, [],
|
236
|
+
&lambda {|vm| vm.push(!self.empty?) })
|
237
|
+
|
238
|
+
# ["a"] .clear! [a_boolean]
|
239
|
+
StringBuffer.create_shared_method('.clear!', TosSpec, [],
|
240
|
+
&lambda {|vm| self.clear })
|
241
|
+
|
230
242
|
# ["b", a] + ["ba"]; "ba" is a new object, distinct from "b"
|
231
243
|
String.create_shared_method('+', NosSpec, [],
|
232
244
|
&lambda {|vm| vm.poke((self + vm.peek.to_s).freeze) })
|
@@ -240,7 +252,7 @@ module XfOOrth
|
|
240
252
|
|
241
253
|
# ["b"*, a] >> ["ab"*]; "ab"* is the same object as "b"*
|
242
254
|
StringBuffer.create_shared_method('>>', NosSpec, [],
|
243
|
-
&lambda {|vm| vm.poke(self.prepend(vm.peek.to_s))
|
255
|
+
&lambda {|vm| vm.poke(self.prepend(vm.peek.to_s)) })
|
244
256
|
|
245
257
|
# ["b", n] * ["bbb..."]
|
246
258
|
String.create_shared_method('*', NosSpec, [], &lambda {|vm|
|
@@ -270,7 +282,7 @@ module XfOOrth
|
|
270
282
|
|
271
283
|
# ["stressed"] .reverse ["desserts"]
|
272
284
|
String.create_shared_method('.reverse', TosSpec, [],
|
273
|
-
&lambda {|vm| vm.push(self.to_s.reverse.freeze)
|
285
|
+
&lambda {|vm| vm.push(self.to_s.reverse.freeze) })
|
274
286
|
|
275
287
|
# ["stressed"*] .reverse* [] #Reverse the string in place.
|
276
288
|
StringBuffer.create_shared_method('.reverse*', TosSpec, [],
|
@@ -321,7 +333,7 @@ module XfOOrth
|
|
321
333
|
|
322
334
|
# [a_string] .shell []
|
323
335
|
String.create_shared_method('.shell', TosSpec, [], &lambda {|vm|
|
324
|
-
system(self)
|
336
|
+
system(self.chomp + "\n")
|
325
337
|
})
|
326
338
|
|
327
339
|
# [a_string] .shell_out [a_string]
|
@@ -108,13 +108,9 @@ end
|
|
108
108
|
#Extensions to the RunTimeError to support fOOrth
|
109
109
|
class RuntimeError
|
110
110
|
|
111
|
-
#Massage the messages a bit
|
112
|
-
#<br>Endemic Code Smells
|
113
|
-
#* :reek:FeatureEnvy
|
111
|
+
#Massage the messages a bit.
|
114
112
|
def message
|
115
|
-
|
116
|
-
msg["frozen"] && msg["frozen"] = "protected"
|
117
|
-
msg
|
113
|
+
super.gsub(/frozen/, "protected")
|
118
114
|
end
|
119
115
|
|
120
116
|
end
|
data/lib/fOOrth/version.rb
CHANGED
@@ -1,177 +1,188 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
$exclude_fOOrth_library = true
|
4
|
-
require_relative '../../lib/fOOrth'
|
5
|
-
gem 'minitest'
|
6
|
-
require 'minitest/autorun'
|
7
|
-
require 'minitest_visible'
|
8
|
-
|
9
|
-
class MockClass
|
10
|
-
def initialize; @data = {}; end
|
11
|
-
def []=(index, value); @data[index] = value; end
|
12
|
-
def map_foorth_shared(index); @data[index]; end
|
13
|
-
end
|
14
|
-
|
15
|
-
class MockObject
|
16
|
-
def initialize; @data = {}; end
|
17
|
-
def []=(index, value); @data[index] = value; end
|
18
|
-
def map_foorth_exclusive(index); @data[index]; end
|
19
|
-
end
|
20
|
-
|
21
|
-
#Test the monkey patches applied to the Object class.
|
22
|
-
class ContextTester < Minitest::Test
|
23
|
-
|
24
|
-
#Track mini-test progress.
|
25
|
-
include MinitestVisible
|
26
|
-
|
27
|
-
def test_data_store
|
28
|
-
context = XfOOrth::Context.new(45, stuff: 'buy', price: :plenty)
|
29
|
-
|
30
|
-
assert_equal(context.previous, 45)
|
31
|
-
assert_equal(context[:stuff], 'buy')
|
32
|
-
assert_equal(context[:price], :plenty)
|
33
|
-
|
34
|
-
context[:stuff] = 'sell'
|
35
|
-
assert_equal(context[:stuff], 'sell')
|
36
|
-
assert_equal(context[:price], :plenty)
|
37
|
-
|
38
|
-
context[:price] = 9.95
|
39
|
-
assert_equal(context[:stuff], 'sell')
|
40
|
-
assert_equal(context[:price], 9.95)
|
41
|
-
end
|
42
|
-
|
43
|
-
#Test level counting
|
44
|
-
def test_level_tracking
|
45
|
-
context = XfOOrth::Context.new(nil, stuff: 'buy')
|
46
|
-
assert_equal(context.depth, 1)
|
47
|
-
|
48
|
-
context = XfOOrth::Context.new(context, stuff: 'other')
|
49
|
-
assert_equal(context.depth, 2)
|
50
|
-
|
51
|
-
context = XfOOrth::Context.new(context, stuff: 'more')
|
52
|
-
assert_equal(context.depth, 3)
|
53
|
-
|
54
|
-
context = context.previous
|
55
|
-
assert_equal(context.depth, 2)
|
56
|
-
|
57
|
-
context = context.previous
|
58
|
-
assert_equal(context.depth, 1)
|
59
|
-
|
60
|
-
context = context.previous
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_the_nesting_of_scopes
|
65
|
-
context = XfOOrth::Context.new(nil, stuff: 'buy')
|
66
|
-
|
67
|
-
|
68
|
-
assert_equal(context[:stuff], 'buy')
|
69
|
-
context[:foo] = 1
|
70
|
-
context[:jelly] = 'donut'
|
71
|
-
assert_equal(context[:jelly], 'donut')
|
72
|
-
assert_equal(context[:stuff], 'buy')
|
73
|
-
assert_equal(context[:foo], 1)
|
74
|
-
|
75
|
-
context = XfOOrth::Context.new(context, stuff: 'other')
|
76
|
-
assert_equal(context[:foo], 1)
|
77
|
-
assert_equal(context[:jelly], 'donut')
|
78
|
-
assert_equal(context[:stuff], 'other')
|
79
|
-
context[:foo] = 2
|
80
|
-
assert_equal(context[:jelly], 'donut')
|
81
|
-
assert_equal(context[:stuff], 'other')
|
82
|
-
assert_equal(context[:foo], 2)
|
83
|
-
|
84
|
-
context = XfOOrth::Context.new(context, stuff: 'more')
|
85
|
-
assert_equal(context[:foo], 2)
|
86
|
-
assert_equal(context[:jelly], 'donut')
|
87
|
-
assert_equal(context[:stuff], 'more')
|
88
|
-
context[:foo] = 3
|
89
|
-
context[:jelly] = 'Berliner'
|
90
|
-
assert_equal(context[:jelly], 'Berliner')
|
91
|
-
assert_equal(context[:stuff], 'more')
|
92
|
-
assert_equal(context[:foo], 3)
|
93
|
-
|
94
|
-
context = context.previous
|
95
|
-
assert_equal(context[:foo], 2)
|
96
|
-
assert_equal(context[:jelly], 'donut')
|
97
|
-
assert_equal(context[:stuff], 'other')
|
98
|
-
|
99
|
-
context = context.previous
|
100
|
-
assert_equal(context[:foo], 1)
|
101
|
-
assert_equal(context[:jelly], 'donut')
|
102
|
-
assert_equal(context[:stuff], 'buy')
|
103
|
-
end
|
104
|
-
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
context = XfOOrth::Context.new(nil
|
118
|
-
|
119
|
-
name = '
|
120
|
-
sym = XfOOrth::SymbolMap.add_entry(name)
|
121
|
-
|
122
|
-
spec = context.map_with_defaults(name)
|
123
|
-
assert(spec.is_a?(XfOOrth::
|
124
|
-
end
|
125
|
-
|
126
|
-
def
|
127
|
-
mk =
|
128
|
-
context = XfOOrth::Context.new(nil,
|
129
|
-
|
130
|
-
name = '.
|
131
|
-
sym = XfOOrth::SymbolMap.add_entry(name)
|
132
|
-
mk[sym] = XfOOrth::TosSpec.new(name, sym, [])
|
133
|
-
spec = context.map_with_defaults(name)
|
134
|
-
assert(spec.is_a?(XfOOrth::TosSpec))
|
135
|
-
end
|
136
|
-
|
137
|
-
def
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
context = XfOOrth::Context.new(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
context.
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
$exclude_fOOrth_library = true
|
4
|
+
require_relative '../../lib/fOOrth'
|
5
|
+
gem 'minitest'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'minitest_visible'
|
8
|
+
|
9
|
+
class MockClass
|
10
|
+
def initialize; @data = {}; end
|
11
|
+
def []=(index, value); @data[index] = value; end
|
12
|
+
def map_foorth_shared(index); @data[index]; end
|
13
|
+
end
|
14
|
+
|
15
|
+
class MockObject
|
16
|
+
def initialize; @data = {}; end
|
17
|
+
def []=(index, value); @data[index] = value; end
|
18
|
+
def map_foorth_exclusive(index); @data[index]; end
|
19
|
+
end
|
20
|
+
|
21
|
+
#Test the monkey patches applied to the Object class.
|
22
|
+
class ContextTester < Minitest::Test
|
23
|
+
|
24
|
+
#Track mini-test progress.
|
25
|
+
include MinitestVisible
|
26
|
+
|
27
|
+
def test_data_store
|
28
|
+
context = XfOOrth::Context.new(45, stuff: 'buy', price: :plenty)
|
29
|
+
|
30
|
+
assert_equal(context.previous, 45)
|
31
|
+
assert_equal(context[:stuff], 'buy')
|
32
|
+
assert_equal(context[:price], :plenty)
|
33
|
+
|
34
|
+
context[:stuff] = 'sell'
|
35
|
+
assert_equal(context[:stuff], 'sell')
|
36
|
+
assert_equal(context[:price], :plenty)
|
37
|
+
|
38
|
+
context[:price] = 9.95
|
39
|
+
assert_equal(context[:stuff], 'sell')
|
40
|
+
assert_equal(context[:price], 9.95)
|
41
|
+
end
|
42
|
+
|
43
|
+
#Test level counting
|
44
|
+
def test_level_tracking
|
45
|
+
context = XfOOrth::Context.new(nil, stuff: 'buy')
|
46
|
+
assert_equal(context.depth, 1)
|
47
|
+
|
48
|
+
context = XfOOrth::Context.new(context, stuff: 'other')
|
49
|
+
assert_equal(context.depth, 2)
|
50
|
+
|
51
|
+
context = XfOOrth::Context.new(context, stuff: 'more')
|
52
|
+
assert_equal(context.depth, 3)
|
53
|
+
|
54
|
+
context = context.previous
|
55
|
+
assert_equal(context.depth, 2)
|
56
|
+
|
57
|
+
context = context.previous
|
58
|
+
assert_equal(context.depth, 1)
|
59
|
+
|
60
|
+
context = context.previous
|
61
|
+
assert_nil(context)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_the_nesting_of_scopes
|
65
|
+
context = XfOOrth::Context.new(nil, stuff: 'buy')
|
66
|
+
assert_nil(context[:foo])
|
67
|
+
assert_nil(context[:jelly])
|
68
|
+
assert_equal(context[:stuff], 'buy')
|
69
|
+
context[:foo] = 1
|
70
|
+
context[:jelly] = 'donut'
|
71
|
+
assert_equal(context[:jelly], 'donut')
|
72
|
+
assert_equal(context[:stuff], 'buy')
|
73
|
+
assert_equal(context[:foo], 1)
|
74
|
+
|
75
|
+
context = XfOOrth::Context.new(context, stuff: 'other')
|
76
|
+
assert_equal(context[:foo], 1)
|
77
|
+
assert_equal(context[:jelly], 'donut')
|
78
|
+
assert_equal(context[:stuff], 'other')
|
79
|
+
context[:foo] = 2
|
80
|
+
assert_equal(context[:jelly], 'donut')
|
81
|
+
assert_equal(context[:stuff], 'other')
|
82
|
+
assert_equal(context[:foo], 2)
|
83
|
+
|
84
|
+
context = XfOOrth::Context.new(context, stuff: 'more')
|
85
|
+
assert_equal(context[:foo], 2)
|
86
|
+
assert_equal(context[:jelly], 'donut')
|
87
|
+
assert_equal(context[:stuff], 'more')
|
88
|
+
context[:foo] = 3
|
89
|
+
context[:jelly] = 'Berliner'
|
90
|
+
assert_equal(context[:jelly], 'Berliner')
|
91
|
+
assert_equal(context[:stuff], 'more')
|
92
|
+
assert_equal(context[:foo], 3)
|
93
|
+
|
94
|
+
context = context.previous
|
95
|
+
assert_equal(context[:foo], 2)
|
96
|
+
assert_equal(context[:jelly], 'donut')
|
97
|
+
assert_equal(context[:stuff], 'other')
|
98
|
+
|
99
|
+
context = context.previous
|
100
|
+
assert_equal(context[:foo], 1)
|
101
|
+
assert_equal(context[:jelly], 'donut')
|
102
|
+
assert_equal(context[:stuff], 'buy')
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_getting_context_with_a_specific_tag
|
106
|
+
c1 = XfOOrth::Context.new(nil, ctrl: :procedure)
|
107
|
+
c2 = XfOOrth::Context.new(c1, ctrl: :if)
|
108
|
+
c3 = XfOOrth::Context.new(c2, ctrl: :loop)
|
109
|
+
|
110
|
+
assert_equal(c1, c3.get_context_by_ctrl(:procedure))
|
111
|
+
assert_equal(c2, c3.get_context_by_ctrl(:if))
|
112
|
+
assert_equal(c3, c3.get_context_by_ctrl(:loop))
|
113
|
+
assert_raises(XfOOrth::XfOOrthError) { c3.get_context_by_ctrl(:wrong) }
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_the_local_mapping_of_symbols
|
117
|
+
context = XfOOrth::Context.new(nil)
|
118
|
+
|
119
|
+
name = 'b'
|
120
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
121
|
+
context[sym] = XfOOrth::VmSpec.new(name, sym, [])
|
122
|
+
spec = context.map_with_defaults(name)
|
123
|
+
assert(spec.is_a?(XfOOrth::VmSpec))
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_the_class_mapping_of_symbols
|
127
|
+
mk = MockClass.new
|
128
|
+
context = XfOOrth::Context.new(nil, cls: mk)
|
129
|
+
|
130
|
+
name = '.c'
|
131
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
132
|
+
mk[sym] = XfOOrth::TosSpec.new(name, sym, [])
|
133
|
+
spec = context.map_with_defaults(name)
|
134
|
+
assert(spec.is_a?(XfOOrth::TosSpec))
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_the_exclusive_mapping_of_symbols
|
138
|
+
mk = MockObject.new
|
139
|
+
context = XfOOrth::Context.new(nil, obj: mk)
|
140
|
+
|
141
|
+
name = '.d'
|
142
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
143
|
+
mk[sym] = XfOOrth::TosSpec.new(name, sym, [])
|
144
|
+
spec = context.map_with_defaults(name)
|
145
|
+
assert(spec.is_a?(XfOOrth::TosSpec))
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_that_it_verifies_sets
|
149
|
+
context = XfOOrth::Context.new(nil, mode: :Execute, ctrl: :colon)
|
150
|
+
|
151
|
+
assert(context.check_set(:mode, [:Execute, :Compile]))
|
152
|
+
|
153
|
+
assert_raises(XfOOrth::XfOOrthError) do
|
154
|
+
context.check_set(:mode, [:Compile, :Deferred])
|
155
|
+
end
|
156
|
+
|
157
|
+
assert(context.check_set(:stuff, [nil]))
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_the_locating_of_the_receiver
|
161
|
+
context = XfOOrth::Context.new(nil, vm: 'vm_sample')
|
162
|
+
assert_equal('vm_sample', context.target)
|
163
|
+
|
164
|
+
context = XfOOrth::Context.new(context, cls: 'cls_sample')
|
165
|
+
assert_equal('cls_sample', context.target)
|
166
|
+
|
167
|
+
context = XfOOrth::Context.new(context, obj: 'obj_sample')
|
168
|
+
assert_equal('obj_sample', context.target)
|
169
|
+
|
170
|
+
context = XfOOrth::Context.new(nil)
|
171
|
+
assert_raises(XfOOrth::XfOOrthError) { context.target }
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_adding_and_removing_local_methods
|
175
|
+
context = XfOOrth::Context.new(nil, vm: 'vm_sample')
|
176
|
+
name = 'lm'
|
177
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
178
|
+
spec = context.create_local_method(name, XfOOrth::LocalSpec, [])
|
179
|
+
|
180
|
+
assert_equal(spec, context[sym])
|
181
|
+
|
182
|
+
context.remove_local_method(name)
|
183
|
+
|
184
|
+
assert_nil(context[sym])
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|