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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rdoc_options +17 -0
- data/Gemfile +4 -0
- data/README.md +67 -0
- data/bin/fOOrth +8 -0
- data/demo.rb +24 -0
- data/fOOrth.gemspec +40 -0
- data/fOOrth.reek +109 -0
- data/integration/README.md +12 -0
- data/integration/_FILE_test.foorth +5 -0
- data/integration/array_lib_tests.rb +360 -0
- data/integration/class_lib_tests.rb +116 -0
- data/integration/clone_lib_tests.rb +108 -0
- data/integration/comparison_tests.rb +132 -0
- data/integration/compile_lib_tests.rb +190 -0
- data/integration/ctrl_struct_lib_tests.rb +80 -0
- data/integration/data_ref_lib_tests.rb +43 -0
- data/integration/exception_lib_tests.rb +86 -0
- data/integration/fiber_bundle_tests.rb +380 -0
- data/integration/hash_lib_tests.rb +120 -0
- data/integration/in_stream_test_1.txt +4 -0
- data/integration/load_test_one.foorth +6 -0
- data/integration/load_test_two.foorth +4 -0
- data/integration/numeric_lib_tests.rb +321 -0
- data/integration/object_lib_tests.rb +38 -0
- data/integration/procedure_lib_tests.rb +40 -0
- data/integration/queue_lib_tests.rb +66 -0
- data/integration/stack_lib_tests.rb +70 -0
- data/integration/standard_lib_tests.rb +208 -0
- data/integration/stdio_lib_tests.rb +52 -0
- data/integration/stream_lib_tests.rb +196 -0
- data/integration/string_lib_tests.rb +217 -0
- data/integration/support/foorth_testing.rb +135 -0
- data/integration/thread_lib_tests.rb +83 -0
- data/integration/time_lib_tests.rb +791 -0
- data/integration/vm_lib_tests.rb +38 -0
- data/lib/fOOrth.rb +57 -0
- data/lib/fOOrth/compiler.rb +78 -0
- data/lib/fOOrth/compiler/context.rb +49 -0
- data/lib/fOOrth/compiler/context/locals.rb +34 -0
- data/lib/fOOrth/compiler/context/map_name.rb +92 -0
- data/lib/fOOrth/compiler/context/tags.rb +48 -0
- data/lib/fOOrth/compiler/modes.rb +32 -0
- data/lib/fOOrth/compiler/modes/compiled.rb +41 -0
- data/lib/fOOrth/compiler/modes/deferred.rb +57 -0
- data/lib/fOOrth/compiler/modes/delayed.rb +40 -0
- data/lib/fOOrth/compiler/modes/nested.rb +34 -0
- data/lib/fOOrth/compiler/modes/suspend.rb +32 -0
- data/lib/fOOrth/compiler/parser.rb +26 -0
- data/lib/fOOrth/compiler/parser/get_string.rb +71 -0
- data/lib/fOOrth/compiler/parser/normal.rb +53 -0
- data/lib/fOOrth/compiler/parser/skip.rb +50 -0
- data/lib/fOOrth/compiler/parser/special.rb +42 -0
- data/lib/fOOrth/compiler/process.rb +47 -0
- data/lib/fOOrth/compiler/process/generate.rb +24 -0
- data/lib/fOOrth/compiler/process/get_token.rb +23 -0
- data/lib/fOOrth/compiler/process/procedure.rb +55 -0
- data/lib/fOOrth/compiler/process/string.rb +20 -0
- data/lib/fOOrth/compiler/source.rb +51 -0
- data/lib/fOOrth/compiler/source/console.rb +70 -0
- data/lib/fOOrth/compiler/source/file_source.rb +37 -0
- data/lib/fOOrth/compiler/source/read_point.rb +46 -0
- data/lib/fOOrth/compiler/source/string_source.rb +28 -0
- data/lib/fOOrth/compiler/token.rb +37 -0
- data/lib/fOOrth/compiler/word_specs.rb +178 -0
- data/lib/fOOrth/core.rb +27 -0
- data/lib/fOOrth/core/class.rb +116 -0
- data/lib/fOOrth/core/object.rb +78 -0
- data/lib/fOOrth/core/virtual_machine.rb +28 -0
- data/lib/fOOrth/debug.rb +13 -0
- data/lib/fOOrth/debug/context_dump.rb +31 -0
- data/lib/fOOrth/debug/dbg_puts.rb +17 -0
- data/lib/fOOrth/debug/display_abort.rb +37 -0
- data/lib/fOOrth/debug/vm_dump.rb +27 -0
- data/lib/fOOrth/initialize.rb +83 -0
- data/lib/fOOrth/interpreter.rb +24 -0
- data/lib/fOOrth/interpreter/add_to_hash.rb +17 -0
- data/lib/fOOrth/interpreter/data_stack.rb +125 -0
- data/lib/fOOrth/interpreter/do_loop.rb +55 -0
- data/lib/fOOrth/interpreter/squash.rb +25 -0
- data/lib/fOOrth/library.rb +38 -0
- data/lib/fOOrth/library/array_library.rb +577 -0
- data/lib/fOOrth/library/bundle_library.rb +112 -0
- data/lib/fOOrth/library/class_library.rb +90 -0
- data/lib/fOOrth/library/clone_library.rb +72 -0
- data/lib/fOOrth/library/command_library.rb +205 -0
- data/lib/fOOrth/library/compile_library.rb +181 -0
- data/lib/fOOrth/library/complex_library.rb +81 -0
- data/lib/fOOrth/library/ctrl_struct_library.rb +116 -0
- data/lib/fOOrth/library/data_ref_library.rb +100 -0
- data/lib/fOOrth/library/duration/arithmetic.rb +114 -0
- data/lib/fOOrth/library/duration/formatter.rb +152 -0
- data/lib/fOOrth/library/duration/intervals.rb +233 -0
- data/lib/fOOrth/library/duration/make.rb +75 -0
- data/lib/fOOrth/library/duration_library.rb +52 -0
- data/lib/fOOrth/library/fiber_library.rb +120 -0
- data/lib/fOOrth/library/hash_library.rb +203 -0
- data/lib/fOOrth/library/in_stream_library.rb +81 -0
- data/lib/fOOrth/library/integer_library.rb +104 -0
- data/lib/fOOrth/library/mutex_library.rb +31 -0
- data/lib/fOOrth/library/numeric_library.rb +380 -0
- data/lib/fOOrth/library/object_library.rb +80 -0
- data/lib/fOOrth/library/other_value_types_library.rb +96 -0
- data/lib/fOOrth/library/out_stream_library.rb +146 -0
- data/lib/fOOrth/library/procedure_library.rb +65 -0
- data/lib/fOOrth/library/queue_library.rb +47 -0
- data/lib/fOOrth/library/rational_library.rb +90 -0
- data/lib/fOOrth/library/stack_library.rb +56 -0
- data/lib/fOOrth/library/stdio_library.rb +56 -0
- data/lib/fOOrth/library/string_library.rb +285 -0
- data/lib/fOOrth/library/stubs.rb +76 -0
- data/lib/fOOrth/library/sync_bundle_library.rb +50 -0
- data/lib/fOOrth/library/thread_library.rb +73 -0
- data/lib/fOOrth/library/time_library.rb +302 -0
- data/lib/fOOrth/library/vm_library.rb +105 -0
- data/lib/fOOrth/main.rb +125 -0
- data/lib/fOOrth/monkey_patch.rb +14 -0
- data/lib/fOOrth/monkey_patch/complex.rb +30 -0
- data/lib/fOOrth/monkey_patch/exceptions.rb +154 -0
- data/lib/fOOrth/monkey_patch/false.rb +11 -0
- data/lib/fOOrth/monkey_patch/float.rb +22 -0
- data/lib/fOOrth/monkey_patch/integer.rb +22 -0
- data/lib/fOOrth/monkey_patch/nil.rb +11 -0
- data/lib/fOOrth/monkey_patch/numeric.rb +33 -0
- data/lib/fOOrth/monkey_patch/object.rb +43 -0
- data/lib/fOOrth/monkey_patch/rational.rb +31 -0
- data/lib/fOOrth/monkey_patch/string.rb +51 -0
- data/lib/fOOrth/symbol_map.rb +82 -0
- data/lib/fOOrth/version.rb +7 -0
- data/license.txt +21 -0
- data/rakefile.rb +65 -0
- data/reek.txt +1 -0
- data/sire.rb +132 -0
- data/t.txt +3 -0
- data/test.foorth +5 -0
- data/tests/compiler/context_tests.rb +180 -0
- data/tests/compiler/file_source_test_one.txt +1 -0
- data/tests/compiler/file_source_test_three.txt +3 -0
- data/tests/compiler/file_source_test_two.txt +3 -0
- data/tests/compiler/file_source_tests.rb +130 -0
- data/tests/compiler/mode_tests.rb +45 -0
- data/tests/compiler/parser_tests.rb +116 -0
- data/tests/compiler/spec_tests.rb +113 -0
- data/tests/compiler/string_source_tests.rb +128 -0
- data/tests/core_tests.rb +138 -0
- data/tests/interpreter/data_stack_tests.rb +119 -0
- data/tests/monkey_patch/coerce_test.rb +131 -0
- data/tests/monkey_patch/complex_test.rb +25 -0
- data/tests/monkey_patch/numeric_test.rb +62 -0
- data/tests/monkey_patch/object_test.rb +49 -0
- data/tests/monkey_patch/rational_test.rb +57 -0
- data/tests/monkey_patch/string_test.rb +53 -0
- data/tests/symbol_map_tests.rb +53 -0
- 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
|