fOOrth 0.5.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.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rdoc_options +17 -0
  4. data/Gemfile +4 -0
  5. data/README.md +67 -0
  6. data/bin/fOOrth +8 -0
  7. data/demo.rb +24 -0
  8. data/fOOrth.gemspec +40 -0
  9. data/fOOrth.reek +109 -0
  10. data/integration/README.md +12 -0
  11. data/integration/_FILE_test.foorth +5 -0
  12. data/integration/array_lib_tests.rb +360 -0
  13. data/integration/class_lib_tests.rb +116 -0
  14. data/integration/clone_lib_tests.rb +108 -0
  15. data/integration/comparison_tests.rb +132 -0
  16. data/integration/compile_lib_tests.rb +190 -0
  17. data/integration/ctrl_struct_lib_tests.rb +80 -0
  18. data/integration/data_ref_lib_tests.rb +43 -0
  19. data/integration/exception_lib_tests.rb +86 -0
  20. data/integration/fiber_bundle_tests.rb +380 -0
  21. data/integration/hash_lib_tests.rb +120 -0
  22. data/integration/in_stream_test_1.txt +4 -0
  23. data/integration/load_test_one.foorth +6 -0
  24. data/integration/load_test_two.foorth +4 -0
  25. data/integration/numeric_lib_tests.rb +321 -0
  26. data/integration/object_lib_tests.rb +38 -0
  27. data/integration/procedure_lib_tests.rb +40 -0
  28. data/integration/queue_lib_tests.rb +66 -0
  29. data/integration/stack_lib_tests.rb +70 -0
  30. data/integration/standard_lib_tests.rb +208 -0
  31. data/integration/stdio_lib_tests.rb +52 -0
  32. data/integration/stream_lib_tests.rb +196 -0
  33. data/integration/string_lib_tests.rb +217 -0
  34. data/integration/support/foorth_testing.rb +135 -0
  35. data/integration/thread_lib_tests.rb +83 -0
  36. data/integration/time_lib_tests.rb +791 -0
  37. data/integration/vm_lib_tests.rb +38 -0
  38. data/lib/fOOrth.rb +57 -0
  39. data/lib/fOOrth/compiler.rb +78 -0
  40. data/lib/fOOrth/compiler/context.rb +49 -0
  41. data/lib/fOOrth/compiler/context/locals.rb +34 -0
  42. data/lib/fOOrth/compiler/context/map_name.rb +92 -0
  43. data/lib/fOOrth/compiler/context/tags.rb +48 -0
  44. data/lib/fOOrth/compiler/modes.rb +32 -0
  45. data/lib/fOOrth/compiler/modes/compiled.rb +41 -0
  46. data/lib/fOOrth/compiler/modes/deferred.rb +57 -0
  47. data/lib/fOOrth/compiler/modes/delayed.rb +40 -0
  48. data/lib/fOOrth/compiler/modes/nested.rb +34 -0
  49. data/lib/fOOrth/compiler/modes/suspend.rb +32 -0
  50. data/lib/fOOrth/compiler/parser.rb +26 -0
  51. data/lib/fOOrth/compiler/parser/get_string.rb +71 -0
  52. data/lib/fOOrth/compiler/parser/normal.rb +53 -0
  53. data/lib/fOOrth/compiler/parser/skip.rb +50 -0
  54. data/lib/fOOrth/compiler/parser/special.rb +42 -0
  55. data/lib/fOOrth/compiler/process.rb +47 -0
  56. data/lib/fOOrth/compiler/process/generate.rb +24 -0
  57. data/lib/fOOrth/compiler/process/get_token.rb +23 -0
  58. data/lib/fOOrth/compiler/process/procedure.rb +55 -0
  59. data/lib/fOOrth/compiler/process/string.rb +20 -0
  60. data/lib/fOOrth/compiler/source.rb +51 -0
  61. data/lib/fOOrth/compiler/source/console.rb +70 -0
  62. data/lib/fOOrth/compiler/source/file_source.rb +37 -0
  63. data/lib/fOOrth/compiler/source/read_point.rb +46 -0
  64. data/lib/fOOrth/compiler/source/string_source.rb +28 -0
  65. data/lib/fOOrth/compiler/token.rb +37 -0
  66. data/lib/fOOrth/compiler/word_specs.rb +178 -0
  67. data/lib/fOOrth/core.rb +27 -0
  68. data/lib/fOOrth/core/class.rb +116 -0
  69. data/lib/fOOrth/core/object.rb +78 -0
  70. data/lib/fOOrth/core/virtual_machine.rb +28 -0
  71. data/lib/fOOrth/debug.rb +13 -0
  72. data/lib/fOOrth/debug/context_dump.rb +31 -0
  73. data/lib/fOOrth/debug/dbg_puts.rb +17 -0
  74. data/lib/fOOrth/debug/display_abort.rb +37 -0
  75. data/lib/fOOrth/debug/vm_dump.rb +27 -0
  76. data/lib/fOOrth/initialize.rb +83 -0
  77. data/lib/fOOrth/interpreter.rb +24 -0
  78. data/lib/fOOrth/interpreter/add_to_hash.rb +17 -0
  79. data/lib/fOOrth/interpreter/data_stack.rb +125 -0
  80. data/lib/fOOrth/interpreter/do_loop.rb +55 -0
  81. data/lib/fOOrth/interpreter/squash.rb +25 -0
  82. data/lib/fOOrth/library.rb +38 -0
  83. data/lib/fOOrth/library/array_library.rb +577 -0
  84. data/lib/fOOrth/library/bundle_library.rb +112 -0
  85. data/lib/fOOrth/library/class_library.rb +90 -0
  86. data/lib/fOOrth/library/clone_library.rb +72 -0
  87. data/lib/fOOrth/library/command_library.rb +205 -0
  88. data/lib/fOOrth/library/compile_library.rb +181 -0
  89. data/lib/fOOrth/library/complex_library.rb +81 -0
  90. data/lib/fOOrth/library/ctrl_struct_library.rb +116 -0
  91. data/lib/fOOrth/library/data_ref_library.rb +100 -0
  92. data/lib/fOOrth/library/duration/arithmetic.rb +114 -0
  93. data/lib/fOOrth/library/duration/formatter.rb +152 -0
  94. data/lib/fOOrth/library/duration/intervals.rb +233 -0
  95. data/lib/fOOrth/library/duration/make.rb +75 -0
  96. data/lib/fOOrth/library/duration_library.rb +52 -0
  97. data/lib/fOOrth/library/fiber_library.rb +120 -0
  98. data/lib/fOOrth/library/hash_library.rb +203 -0
  99. data/lib/fOOrth/library/in_stream_library.rb +81 -0
  100. data/lib/fOOrth/library/integer_library.rb +104 -0
  101. data/lib/fOOrth/library/mutex_library.rb +31 -0
  102. data/lib/fOOrth/library/numeric_library.rb +380 -0
  103. data/lib/fOOrth/library/object_library.rb +80 -0
  104. data/lib/fOOrth/library/other_value_types_library.rb +96 -0
  105. data/lib/fOOrth/library/out_stream_library.rb +146 -0
  106. data/lib/fOOrth/library/procedure_library.rb +65 -0
  107. data/lib/fOOrth/library/queue_library.rb +47 -0
  108. data/lib/fOOrth/library/rational_library.rb +90 -0
  109. data/lib/fOOrth/library/stack_library.rb +56 -0
  110. data/lib/fOOrth/library/stdio_library.rb +56 -0
  111. data/lib/fOOrth/library/string_library.rb +285 -0
  112. data/lib/fOOrth/library/stubs.rb +76 -0
  113. data/lib/fOOrth/library/sync_bundle_library.rb +50 -0
  114. data/lib/fOOrth/library/thread_library.rb +73 -0
  115. data/lib/fOOrth/library/time_library.rb +302 -0
  116. data/lib/fOOrth/library/vm_library.rb +105 -0
  117. data/lib/fOOrth/main.rb +125 -0
  118. data/lib/fOOrth/monkey_patch.rb +14 -0
  119. data/lib/fOOrth/monkey_patch/complex.rb +30 -0
  120. data/lib/fOOrth/monkey_patch/exceptions.rb +154 -0
  121. data/lib/fOOrth/monkey_patch/false.rb +11 -0
  122. data/lib/fOOrth/monkey_patch/float.rb +22 -0
  123. data/lib/fOOrth/monkey_patch/integer.rb +22 -0
  124. data/lib/fOOrth/monkey_patch/nil.rb +11 -0
  125. data/lib/fOOrth/monkey_patch/numeric.rb +33 -0
  126. data/lib/fOOrth/monkey_patch/object.rb +43 -0
  127. data/lib/fOOrth/monkey_patch/rational.rb +31 -0
  128. data/lib/fOOrth/monkey_patch/string.rb +51 -0
  129. data/lib/fOOrth/symbol_map.rb +82 -0
  130. data/lib/fOOrth/version.rb +7 -0
  131. data/license.txt +21 -0
  132. data/rakefile.rb +65 -0
  133. data/reek.txt +1 -0
  134. data/sire.rb +132 -0
  135. data/t.txt +3 -0
  136. data/test.foorth +5 -0
  137. data/tests/compiler/context_tests.rb +180 -0
  138. data/tests/compiler/file_source_test_one.txt +1 -0
  139. data/tests/compiler/file_source_test_three.txt +3 -0
  140. data/tests/compiler/file_source_test_two.txt +3 -0
  141. data/tests/compiler/file_source_tests.rb +130 -0
  142. data/tests/compiler/mode_tests.rb +45 -0
  143. data/tests/compiler/parser_tests.rb +116 -0
  144. data/tests/compiler/spec_tests.rb +113 -0
  145. data/tests/compiler/string_source_tests.rb +128 -0
  146. data/tests/core_tests.rb +138 -0
  147. data/tests/interpreter/data_stack_tests.rb +119 -0
  148. data/tests/monkey_patch/coerce_test.rb +131 -0
  149. data/tests/monkey_patch/complex_test.rb +25 -0
  150. data/tests/monkey_patch/numeric_test.rb +62 -0
  151. data/tests/monkey_patch/object_test.rb +49 -0
  152. data/tests/monkey_patch/rational_test.rb +57 -0
  153. data/tests/monkey_patch/string_test.rb +53 -0
  154. data/tests/symbol_map_tests.rb +53 -0
  155. metadata +366 -0
@@ -0,0 +1,75 @@
1
+ # coding: utf-8
2
+
3
+ #* library/duration/make.rb - Support for duration constructor.
4
+ module XfOOrth
5
+
6
+ #* library/duration/make.rb - Support for duration constructor.
7
+ class Duration
8
+ #The length of time of the duration.
9
+ attr_accessor :period
10
+
11
+ #Create a duration instance.
12
+ #<br>Parameters
13
+ #* period - The period of time of the duration.
14
+ def initialize(period)
15
+ @period = period.rationalize
16
+ end
17
+ end
18
+
19
+ #Connect the Duration class to the fOOrth class system
20
+ Duration.create_foorth_proxy("Duration")
21
+
22
+ #Stub out .new
23
+ Duration.create_exclusive_method('.new', TosSpec, [:stub])
24
+
25
+ #Helper Methods .to_duration and .to_duration!
26
+
27
+ #[number] .to_duration [a_duration]
28
+ Object.create_shared_method('.to_duration', TosSpec, [], &lambda {|vm|
29
+ begin
30
+ vm.push(Duration.new(self))
31
+ rescue
32
+ vm.push(nil)
33
+ end
34
+ })
35
+
36
+ #[number] .to_duration! [a_duration]
37
+ Object.create_shared_method('.to_duration!', TosSpec, [], &lambda {|vm|
38
+ begin
39
+ vm.push(Duration.new(self))
40
+ rescue
41
+ error "F40: Cannot convert #{self.foorth_name} to a Duration instance"
42
+ end
43
+ })
44
+
45
+ Array.create_shared_method('.to_duration', TosSpec, [], &lambda {|vm|
46
+ begin
47
+ result, interval = 0, Duration::INTERVALS.reverse_each
48
+ self.reverse_each {|value| result += value * interval.next.to_r }
49
+ vm.push(Duration.new(result))
50
+ rescue
51
+ vm.push(nil)
52
+ end
53
+ })
54
+
55
+ Array.create_shared_method('.to_duration!', TosSpec, [], &lambda {|vm|
56
+ begin
57
+ result, interval = 0, Duration::INTERVALS.reverse_each
58
+ self.reverse_each {|value| result += value * interval.next.to_r }
59
+ vm.push(Duration.new(result))
60
+ rescue
61
+ error "F40: Cannot convert #{self.foorth_name} to a Duration instance"
62
+ end
63
+ })
64
+
65
+ #[a_duration] .to_duration [a_duration]
66
+ Duration.create_shared_method('.to_duration', TosSpec, [], &lambda {|vm|
67
+ vm.push(self)
68
+ })
69
+
70
+ #[a_duration] .to_duration! [a_duration]
71
+ Duration.create_shared_method('.to_duration!', TosSpec, [], &lambda {|vm|
72
+ vm.push(self)
73
+ })
74
+
75
+ end
@@ -0,0 +1,52 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'duration/make'
4
+ require_relative 'duration/arithmetic'
5
+ require_relative 'duration/intervals'
6
+ require_relative 'duration/formatter'
7
+
8
+ #* library/duration_library.rb - The duration support fOOrth library.
9
+ module XfOOrth
10
+
11
+ #The duration class adds support for intervals of time that are not
12
+ #directly associated with a date or time. Like 10 minutes as opposed
13
+ #to July 4, 2015 5:43 PM.
14
+ class Duration
15
+
16
+ #Convert this duration to an array.
17
+ #<br>Endemic Code Smells
18
+ #* :reek:FeatureEnvy -- false positive.
19
+ def to_a
20
+ balance = @period
21
+
22
+ Duration::INTERVALS.map do |item|
23
+ interval = item.to_r
24
+
25
+ if interval > 1
26
+ value = (balance / interval).to_i
27
+ balance -= value * interval
28
+ value
29
+ else
30
+ balance.to_f
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ #Pass off all unknown methods to the period data.
37
+ def method_missing(symbol, *args, &block)
38
+ @period.send(symbol, *args, &block)
39
+ end
40
+
41
+ end
42
+
43
+ #[a_duration] .to_a [an_array]
44
+ Duration.create_shared_method('.to_a', TosSpec, [], &lambda{|vm|
45
+ vm.push(self.to_a)
46
+ })
47
+
48
+ #Default conversion to string. See duration/formatter for formatted output.
49
+ Duration.create_shared_method('.to_s', TosSpec, [], &lambda {|vm|
50
+ vm.push("Duration instance <#{self.period.to_f} seconds>" )
51
+ })
52
+ end
@@ -0,0 +1,120 @@
1
+ # coding: utf-8
2
+
3
+ #* library/fiber_library.rb - The fOOrth Fiber class library.
4
+ module XfOOrth
5
+
6
+ #Define the Fiber class.
7
+ Object.create_foorth_subclass('Fiber').new_class
8
+
9
+ #The fOOrth Fiber class.
10
+ class XfOOrth_Fiber
11
+
12
+ #Tag for newly created fibers.
13
+ NEW = "new".freeze
14
+
15
+ #Tag for running fibers.
16
+ ALIVE = "alive".freeze
17
+
18
+ #Tag for defunct fibers.
19
+ DEAD = "dead".freeze
20
+
21
+ #Build up the fiber instance. A fiber is a light-weight coroutine.
22
+ def initialize(stack=[], &block)
23
+ @stack = stack
24
+ @fiber = Fiber.new &lambda{|vm| block.call(vm); nil}
25
+ @status = NEW
26
+ end
27
+
28
+ #Return this fiber as a fiber.
29
+ def to_foorth_fiber
30
+ self
31
+ end
32
+
33
+ #What is the status of this fiber?
34
+ def status
35
+ @status || DEAD
36
+ end
37
+
38
+ #Let the fiber run for one step.
39
+ def step(vm)
40
+ vm.data_stack, vm.fiber, @save = @stack, self, vm.data_stack
41
+ @status = @fiber.resume(vm)
42
+ rescue FiberError
43
+ error "F72: The fiber is dead, no further steps can be taken."
44
+ ensure
45
+ vm.data_stack, vm.fiber, @stack = @save, nil, vm.data_stack
46
+ end
47
+
48
+ #Yield back to the thread.
49
+ def yield
50
+ Fiber.yield(ALIVE)
51
+ end
52
+
53
+ #Yield a value back to the thread.
54
+ def yield_value(value)
55
+ @save << value
56
+ Fiber.yield(ALIVE)
57
+ end
58
+ end
59
+
60
+ #The .new method is stubbed out for fibers.
61
+ XfOOrth_Fiber.create_exclusive_method('.new', TosSpec, [:stub])
62
+
63
+ # [Fiber] .new{{ ... }} [a_fiber]
64
+ XfOOrth_Fiber.create_exclusive_method('.new{{', NosSpec, [], &lambda {|vm|
65
+ vm.push(XfOOrth_Fiber.new(&vm.pop))
66
+ })
67
+
68
+ # [a_procedure] .to_fiber [a_fiber]
69
+ Proc.create_shared_method('.to_fiber', TosSpec, [], &lambda {|vm|
70
+ vm.push(XfOOrth_Fiber.new(&self))
71
+ })
72
+
73
+ # [Fiber] .current [a_fiber or nil]
74
+ XfOOrth_Fiber.create_exclusive_method('.current', NosSpec, [], &lambda {|vm|
75
+ vm.push(vm.fiber)
76
+ })
77
+
78
+ # [a_fiber] .to_fiber [a_fiber]
79
+ XfOOrth_Fiber.create_shared_method('.to_fiber', TosSpec, [], &lambda {|vm|
80
+ vm.push(self)
81
+ })
82
+
83
+ # [a_fiber] .step [undefined]; The fiber performs a processing step.
84
+ XfOOrth_Fiber.create_shared_method('.step', TosSpec, [], &lambda {|vm|
85
+ self.step(vm)
86
+ })
87
+
88
+ # [] yield []; Yields obj to the containing thread.
89
+ VirtualMachine.create_shared_method('yield', VmSpec, [], &lambda {|vm|
90
+ error 'F71: May only yield in a fiber.' unless (fiber = vm.fiber)
91
+ fiber.yield
92
+ })
93
+
94
+ # [obj] .yield []; Yields obj to the containing thread.
95
+ VirtualMachine.create_shared_method('.yield', VmSpec, [], &lambda {|vm|
96
+ error 'F71: May only yield in a fiber.' unless (fiber = vm.fiber)
97
+ fiber.yield_value(vm.pop)
98
+ })
99
+
100
+ # [a_fiber] .alive? [a_boolean]; Is the fiber still alive?
101
+ XfOOrth_Fiber.create_shared_method('.alive?', TosSpec, [], &lambda {|vm|
102
+ vm.push(!@status.nil?)
103
+ })
104
+
105
+ # [a_fiber] .alive? [a_string]; Is the fiber still alive?
106
+ XfOOrth_Fiber.create_shared_method('.status', TosSpec, [], &lambda {|vm|
107
+ vm.push(status)
108
+ })
109
+
110
+ end
111
+
112
+ #Monkey patch Procedure to support fibers.
113
+ class Proc
114
+
115
+ #Convert this procedure to a fiber.
116
+ def to_foorth_fiber
117
+ XfOOrth::XfOOrth_Fiber.new(&self)
118
+ end
119
+
120
+ end
@@ -0,0 +1,203 @@
1
+ # coding: utf-8
2
+
3
+ #* library/hash_library.rb - Hash support for the fOOrth library.
4
+ module XfOOrth
5
+
6
+ #Connect the Array class to the fOOrth class system.
7
+ Hash.create_foorth_proxy
8
+
9
+ # [] Hash .new [{}]; create an empty hash.
10
+ # The default implementation from Object is used for this.
11
+
12
+ #[object Hash] .new_default [hash]
13
+ Hash.create_exclusive_method('.new_default', TosSpec, [], &lambda{|vm|
14
+ begin
15
+ vm.poke(Hash.new(vm.peek))
16
+ rescue
17
+ vm.data_stack.pop
18
+ raise
19
+ end
20
+ })
21
+
22
+ #[Hash] .new_default{{ ... }} [{}]
23
+ Hash.create_exclusive_method('.new_default{{', NosSpec, [], &lambda{|vm|
24
+ begin
25
+ block = vm.peek
26
+
27
+ vm.poke(Hash.new do |hsh, idx|
28
+ cvm = Thread.current[:vm]
29
+ hsh.instance_exec(cvm, nil, idx, &block)
30
+ cvm.pop
31
+ end)
32
+ rescue
33
+ vm.data_stack.pop
34
+ raise
35
+ end
36
+ })
37
+
38
+ #[object hash] .default []
39
+ Hash.create_shared_method('.default', TosSpec, [], &lambda{|vm|
40
+ self.default = vm.pop
41
+ })
42
+
43
+ #[object] .default{{ ... }} []
44
+ Hash.create_shared_method('.default{{', NosSpec, [], &lambda{|vm|
45
+ block = vm.pop
46
+
47
+ self.default_proc = lambda do |hsh, idx|
48
+ cvm = Thread.current[:vm]
49
+ hsh.instance_exec(cvm, nil, idx, &block)
50
+ cvm.pop
51
+ end
52
+ })
53
+
54
+ # [] { k1 v1 -> ... kn vn -> } [{k1=>v1,...kn=>vn}]; a hash literal value
55
+ VirtualMachine.create_shared_method('{', VmSpec, [:immediate], &lambda { |vm|
56
+ vm.nest_mode('vm.push(Hash.new); ', :hash_literal)
57
+
58
+ vm.context.create_local_method('->', LocalSpec, [:immediate],
59
+ &lambda {|vm| vm.process_text('vm.add_to_hash; ') })
60
+
61
+ vm.context.create_local_method('}', LocalSpec, [:immediate],
62
+ &lambda {|vm| vm.unnest_mode('', [:hash_literal]) })
63
+ })
64
+
65
+ # [hash] .each{{ ... }} [unspecified]
66
+ Hash.create_shared_method('.each{{', NosSpec, [], &lambda { |vm|
67
+ block = vm.pop
68
+ self.each { |idx, val| block.call(vm, val, idx) }
69
+ })
70
+
71
+ # [i h] .[]@ [h[i]]
72
+ Hash.create_shared_method('.[]@', TosSpec, [],
73
+ &lambda {|vm| vm.poke(self[vm.peek]); })
74
+
75
+ # [v i h] .[]! []; h[i]=v
76
+ Hash.create_shared_method('.[]!', TosSpec, [],
77
+ &lambda {|vm| value, index = vm.popm(2); self[index] = value; })
78
+
79
+ # [{"a"=>1, "b"=>2}] .length [2]]
80
+ Hash.create_shared_method('.length', TosSpec, [],
81
+ &lambda {|vm| vm.push(self.length); })
82
+
83
+ # [a_hash] .empty? [a_boolean]]
84
+ Hash.create_shared_method('.empty?', TosSpec, [],
85
+ &lambda {|vm| vm.push(self.empty?); })
86
+
87
+ # [h] .keys [[keys]]
88
+ Hash.create_shared_method('.keys', TosSpec, [],
89
+ &lambda {|vm| vm.push(self.keys); })
90
+
91
+ # [h] .values [[values]]
92
+ Hash.create_shared_method('.values', TosSpec, [],
93
+ &lambda {|vm| vm.push(self.values); })
94
+
95
+ # [h] .strmax2 [widest_key widest_value]
96
+ Hash.create_shared_method('.strmax2', TosSpec, [], &lambda {|vm|
97
+ widest_key = 0
98
+ widest_value = 0
99
+
100
+ self.each {|key, value|
101
+ key.foorth_strlen(vm)
102
+ temp = vm.pop
103
+ widest_key = widest_key > temp ? widest_key : temp
104
+
105
+ value.foorth_strlen(vm)
106
+ temp = vm.pop
107
+ widest_value = widest_value > temp ? widest_value : temp
108
+ }
109
+
110
+ vm.push(widest_key)
111
+ vm.push(widest_value)
112
+ })
113
+
114
+ # [hash] .to_s [string]
115
+ Hash.create_shared_method('.to_s', TosSpec, [], &lambda {|vm|
116
+ result = "{ "
117
+
118
+ self.each do |key, value|
119
+ key.to_foorth_s(vm)
120
+ result << (vm.pop || key.inspect) + " "
121
+
122
+ value.to_foorth_s(vm)
123
+ result << (vm.pop || value.inspect) + " -> "
124
+ end
125
+
126
+ vm.push(result + "}")
127
+ })
128
+
129
+ #[a_hash] .to_h [a_hash]
130
+ Hash.create_shared_method('.to_h', TosSpec, [],
131
+ &lambda{|vm| vm.push(self)})
132
+
133
+ #[a_hash] .to_a [an_array]
134
+ Hash.create_shared_method('.to_a', TosSpec, [],
135
+ &lambda{|vm| vm.push(self.values)})
136
+
137
+ # [a_hash] .map{{ ... }} [mapped_hash]
138
+ Hash.create_shared_method('.map{{', NosSpec, [], &lambda { |vm|
139
+ block = vm.pop
140
+ result = {}
141
+
142
+ self.each do |idx, val|
143
+ block.call(vm, val, idx)
144
+ result[idx] = vm.pop
145
+ end
146
+
147
+ vm.push(result)
148
+ })
149
+
150
+ # [a_hash] .select{{ ... }} [selected_hash]
151
+ Hash.create_shared_method('.select{{', NosSpec, [], &lambda { |vm|
152
+ block = vm.pop
153
+ result = {}
154
+
155
+ self.each do |idx, val|
156
+ block.call(vm, val, idx)
157
+ result[idx] = val if vm.pop
158
+ end
159
+
160
+ vm.push(result)
161
+ })
162
+
163
+
164
+ # [h] .pp []; pretty print the hash!
165
+ Hash.create_shared_method('.pp', TosSpec, [], &lambda {|vm|
166
+ self.foorth_strmax2(vm)
167
+ value_width = vm.pop
168
+ key_width = vm.pop
169
+
170
+ width = value_width + key_width + 3
171
+ cols = (width < 79) ? (79 / width) : 1
172
+ col = (1..cols).cycle
173
+
174
+ self.each do |key, value|
175
+ key.to_foorth_s(vm)
176
+ key_str = vm.pop
177
+
178
+ value.to_foorth_s(vm)
179
+ value_str = vm.pop
180
+
181
+ if cols > 1
182
+ print "#{key_str.rjust(key_width)}=>#{value_str.ljust(value_width)} "
183
+ else
184
+ print "#{key_str.rjust(key_width)}=>#{value_str}"
185
+ end
186
+
187
+ puts if col.next == cols
188
+ end
189
+ })
190
+
191
+
192
+ end
193
+
194
+ #* Runtime library support for fOOrth constructs.
195
+ class Hash
196
+
197
+ #A helper method to extract non-stub method names from a method hash.
198
+ def extract_method_names(search_type = :no_stubs)
199
+ search_value = (search_type == :stubs)
200
+ mkeys = self.keys.select {|key| search_value == self[key].has_tag?(:stub) }
201
+ mkeys.collect {|key| XfOOrth::SymbolMap.unmap(key) || '?error?' }
202
+ end
203
+ end