fOOrth 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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