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,24 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'interpreter/data_stack'
4
+ require_relative 'interpreter/do_loop'
5
+ require_relative 'interpreter/squash'
6
+ require_relative 'interpreter/add_to_hash'
7
+
8
+ #* interpreter.rb - The run time interpreter portion of the fOOrth language system.
9
+ module XfOOrth
10
+
11
+ #* interpreter.rb - The run time interpreter portion of the fOOrth language system.
12
+ class VirtualMachine
13
+
14
+ #The fOOrth timer anchor point. Used to assist in benchmarking etc.
15
+ attr_accessor :start_time
16
+
17
+ #Reset the state of the fOOrth inner interpreter.
18
+ def interpreter_reset
19
+ @data_stack = Array.new
20
+ self
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ #* interpreter/add_to_hash.rb - The fOOrth language hash literal support module.
4
+ module XfOOrth
5
+
6
+ #* interpreter/add_to_hash.rb - The fOOrth language hash literal support module.
7
+ class VirtualMachine
8
+
9
+ #Add the key and value to the hash being constructed.
10
+ def add_to_hash
11
+ key, value = popm(2)
12
+ peek(1)[key] = value
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,125 @@
1
+ # coding: utf-8
2
+
3
+ #* interpreter/data_stack.rb - The fOOrth language system data stack.
4
+ module XfOOrth
5
+
6
+ #* interpreter/data_stack.rb - The fOOrth language system data stack.
7
+ class VirtualMachine
8
+ #The fOOrth data stack. This is the primary means used to hold data
9
+ #for processing.
10
+ attr_accessor :data_stack
11
+
12
+ #Add an entry to the data stack.
13
+ #<br>Parameters:
14
+ #* datum - The data to be added to the data stack.
15
+ def push(datum)
16
+ @data_stack << datum
17
+ end
18
+
19
+ #Add some entries to the data stack.
20
+ #<br>Parameters:
21
+ #* datum - An array of data to be mass added to the data stack.
22
+ def pushm(datum)
23
+ @data_stack += datum
24
+ end
25
+
26
+ #Remove the "top" entry from the data stack.
27
+ #<br>Returns:
28
+ #* The "top" element of the data stack.
29
+ #<br>Note:
30
+ #* If the stack is empty this will raise an XfOOrthError exception.
31
+ def pop
32
+ error "F30: Data Stack Underflow: pop" if @data_stack.empty?
33
+ @data_stack.pop
34
+ end
35
+
36
+ #Remove multiple entries from the "top" of the data stack.
37
+ #<br>Parameters:
38
+ #* count - the number of elements to be returned.
39
+ #<br>Returns:
40
+ #* An array containing the "top" count elements of the data stack.
41
+ #<br>Note:
42
+ #* Raises an XfOOrthError exception if the stack has too few data.
43
+ def popm(count)
44
+ begin
45
+ error "F30: Data Stack Underflow: popm" if @data_stack.length < count
46
+ @data_stack.pop(count)
47
+ rescue
48
+ @data_stack = []
49
+ raise
50
+ end
51
+ end
52
+
53
+ #Remove the "top" entry from the data stack as a boolean.
54
+ #<br>Returns:
55
+ #* The "top" element of the data stack as a boolean
56
+ #<br>Note:
57
+ #* If the stack is empty this will raise an XfOOrthError exception.
58
+ def pop?
59
+ pop.to_foorth_b
60
+ end
61
+
62
+ #Read an entry from the data stack without modify that stack.
63
+ #<br>Parameters:
64
+ #* index - The (optional) entry to be retrieved. 1 corresponds to the
65
+ # "top" of the stack, 2 the next element, etc.
66
+ # This parameter defaults to 1.
67
+ #<br>Returns:
68
+ #* The element specified from the data stack.
69
+ #<br>Note:
70
+ #* Attempting to access an element deeper than the number of elements
71
+ # on the stack will fail with an XfOOrthError exception.
72
+ def peek(index=1)
73
+ unless @data_stack.length >= index && index > 0
74
+ error "F30: Data Stack Underflow: peek"
75
+ end
76
+
77
+ @data_stack[-index]
78
+ end
79
+
80
+ #Overwrite the TOS with the supplied data.
81
+ #<br>Parameters:
82
+ #* datum - The data to be placed in the data stack.
83
+ #<br>Note:
84
+ #* Attempting to poke an empty stack will fail with an XfOOrthError exception.
85
+ def poke(datum)
86
+ error "F30: Data Stack Underflow: poke" if @data_stack.empty?
87
+ @data_stack[-1] = datum
88
+ end
89
+
90
+ #Read an entry from the data stack as a boolean without modify that stack.
91
+ #<br>Parameters:
92
+ #* index - The (optional) entry to be retrieved. 1 corresponds to the "top"
93
+ # of the stack, 2 the next element, etc. This parameter defaults to 1.
94
+ #<br>Returns:
95
+ #* The element specified from the data stack as a boolean.
96
+ #<br>Note:
97
+ #* Attempting to access an element deeper than the number of elements on
98
+ # the stack will fail with an XfOOrthError exception.
99
+ def peek?(index=1)
100
+ peek(index).to_foorth_b
101
+ end
102
+
103
+ #A special operation to support dyadic operators. Swap then pop.
104
+ #<br>Returns:
105
+ #* The second element from the data stack.
106
+ #<br>Note:
107
+ #* If the stack has less than 2 elements, this will raise an
108
+ # XfOOrthError exception.
109
+ def swap_pop
110
+ begin
111
+ unless @data_stack.length >= 2
112
+ error "F30: Data Stack Underflow: swap_pop"
113
+ end
114
+
115
+ nos, tos = @data_stack.pop(2)
116
+ @data_stack << tos
117
+ nos
118
+ rescue
119
+ @data_stack = []
120
+ raise
121
+ end
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,55 @@
1
+ # coding: utf-8
2
+
3
+ #* interpreter/do_loop.rb - The fOOrth language do loop support module.
4
+ module XfOOrth
5
+
6
+ #* interpreter/do_loop.rb - The fOOrth language do loop support module.
7
+ class VirtualMachine
8
+
9
+ #The runtime implementation of the "do" word.
10
+ #<br>Parameters:
11
+ #* jloop - An optional outer loop value.
12
+ #* block - A block of code to be executed as the do loop body.
13
+ #<br>Block Parameters:
14
+ #* iloop - The stack frame of the current loop counter. This
15
+ # corresponds to the fOOrth 'i' value.
16
+ #* jloop - The stack frame of any containing loop counter. This corresponds
17
+ # to the fOOrth 'j' value. If there is no containing loop, this
18
+ # will always be a zero frame ie: [0, 0, 0].
19
+ #<br>Note:
20
+ #* Nested loops must be in the same compiler context in order to use this
21
+ # mechanism. Otherwise, loop index counters must be passed in explicitly.
22
+ #<br>Endemic Code Smells
23
+ #* :reek:FeatureEnvy -- false positive
24
+ def vm_do(jloop = [0, 0, 0], &block)
25
+ #Pop the start and ending values from the stack.
26
+ start_index, end_index = popm(2)
27
+
28
+ #Construct the loop data frame.
29
+ iloop = [start_index, end_index - 1, start_index + end_index - 1]
30
+
31
+ #Loop until done!
32
+ while iloop[0] <= iloop[1]
33
+ #Yield to the loop.
34
+ yield iloop, jloop
35
+ end
36
+ end
37
+
38
+ #The runtime implementation of the "+loop" word.
39
+ def vm_do_increment
40
+ inc_raw = self.pop
41
+
42
+ unless (inc_value = inc_raw.to_foorth_n)
43
+ error "F40: Cannot convert a #{inc_raw.foorth_name} to a Numeric instance"
44
+ end
45
+
46
+ if inc_value > 0
47
+ inc_value
48
+ else
49
+ error "F41: Invalid loop increment value: #{inc_value}"
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+
3
+ #* interpreter/squash.rb - The fOOrth language array literal support module.
4
+ module XfOOrth
5
+
6
+ #* interpreter/squash.rb - The fOOrth language do loop support module.
7
+ class VirtualMachine
8
+
9
+ #Compress the entire data stack into a single entry.
10
+ def squash
11
+ @data_stack = [@data_stack]
12
+ end
13
+
14
+ #Compress all the added entries into a single entry and revive the previous
15
+ #contents of the data stack.
16
+ def unsquash
17
+ previous = @data_stack[0]
18
+ data = @data_stack[1..-1]
19
+ @data_stack = previous
20
+ push(data)
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'library/stubs'
4
+ require_relative 'library/object_library'
5
+ require_relative 'library/class_library'
6
+ require_relative 'library/vm_library'
7
+ require_relative 'library/data_ref_library'
8
+ require_relative 'library/clone_library'
9
+ require_relative 'library/compile_library'
10
+ require_relative 'library/ctrl_struct_library'
11
+ require_relative 'library/stdio_library'
12
+ require_relative 'library/numeric_library'
13
+ require_relative 'library/integer_library'
14
+ require_relative 'library/rational_library'
15
+ require_relative 'library/complex_library'
16
+ require_relative 'library/string_library'
17
+ require_relative 'library/duration_library'
18
+ require_relative 'library/time_library'
19
+ require_relative 'library/array_library'
20
+ require_relative 'library/hash_library'
21
+ require_relative 'library/procedure_library'
22
+ require_relative 'library/thread_library'
23
+ require_relative 'library/fiber_library'
24
+ require_relative 'library/bundle_library'
25
+ require_relative 'library/sync_bundle_library'
26
+ require_relative 'library/other_value_types_library'
27
+ require_relative 'library/command_library'
28
+ require_relative 'library/in_stream_library'
29
+ require_relative 'library/out_stream_library'
30
+ require_relative 'library/queue_library'
31
+ require_relative 'library/stack_library'
32
+ require_relative 'library/mutex_library'
33
+
34
+ #* library.rb - The word library portion of the fOOrth language system.
35
+ module XfOOrth
36
+
37
+ end
38
+
@@ -0,0 +1,577 @@
1
+ # coding: utf-8
2
+
3
+ #* library/array_library.rb - Array support for the fOOrth library.
4
+ module XfOOrth
5
+
6
+ #Connect the Array class to the fOOrth class system.
7
+ Array.create_foorth_proxy
8
+
9
+ # [] Array .new [[]]; create an empty array.
10
+ # The default implementation from Object is used for this.
11
+
12
+ # [n] Array .new_size [[0,0,...0]]; create an array of n zeros.
13
+ Array.create_exclusive_method('.new_size', TosSpec, [], &lambda {|vm|
14
+ begin
15
+ vm.poke(self.new(Integer.foorth_coerce(vm.peek), 0));
16
+ rescue
17
+ vm.data_stack.pop
18
+ raise
19
+ end
20
+ })
21
+
22
+ # [v] Array .new_value [[v]]; create an array of a single value.
23
+ Array.create_exclusive_method('.new_value', TosSpec, [],
24
+ &lambda {|vm| vm.poke(self.new(1, vm.peek)); })
25
+
26
+ # [v n] Array .new_values [[v,v,...v]]; create an array of a n values.
27
+ Array.create_exclusive_method('.new_values', TosSpec, [], &lambda {|vm|
28
+ begin
29
+ count = Integer.foorth_coerce(vm.pop)
30
+ vm.poke(self.new(count, vm.peek))
31
+ rescue
32
+ vm.data_stack.pop
33
+ raise
34
+ end
35
+ })
36
+
37
+ # [n] Array .new{{ ... }} [[array]]; create an array of a n computed values.
38
+ Array.create_exclusive_method('.new{{', NosSpec, [], &lambda {|vm|
39
+ block = vm.pop
40
+ count = Integer.foorth_coerce(vm.pop)
41
+
42
+ vm.push(Array.new(count) { |idx| block.call(vm, nil, idx); vm.pop})
43
+ })
44
+
45
+ # [array] .map{{ ... }} [mapped_array]
46
+ Array.create_shared_method('.map{{', NosSpec, [], &lambda { |vm|
47
+ idx, block = 0, vm.pop
48
+ vm.push(self.map { |val| block.call(vm, val, idx); idx += 1; vm.pop})
49
+ })
50
+
51
+ # [array] .select{{ ... }} [selected_array]
52
+ Array.create_shared_method('.select{{', NosSpec, [], &lambda { |vm|
53
+ idx, block = 0, vm.pop
54
+ vm.push(self.select { |val| block.call(vm, val, idx); idx += 1; vm.pop})
55
+ })
56
+
57
+ # [] [ v1 v2 ... vn ] [[v1,v2,...vn]]; an array literal value
58
+ VirtualMachine.create_shared_method('[', VmSpec, [:immediate], &lambda { |vm|
59
+ vm.nest_mode('vm.squash; ', :array_literal)
60
+
61
+ vm.context.create_local_method(']', LocalSpec, [:immediate],
62
+ &lambda {|vm| vm.unnest_mode('vm.unsquash; ', [:array_literal]) })
63
+ })
64
+
65
+ # [array] .each{{ ... }} [unspecified]
66
+ Array.create_shared_method('.each{{', NosSpec, [], &lambda { |vm|
67
+ block = vm.pop
68
+ self.each_with_index { |val, idx| block.call(vm, val, idx) }
69
+ })
70
+
71
+ # Some basic data access words.
72
+ # [a] @ [a[0]]
73
+ Array.create_shared_method('@', TosSpec, [], &lambda { |vm|
74
+ vm.push(self[0])
75
+ })
76
+
77
+ # [ v a ] ! [], a[0] = v
78
+ Array.create_shared_method('!', TosSpec, [], &lambda { |vm|
79
+ self[0] = vm.pop
80
+ })
81
+
82
+ # [ i a ] .[]@ [ a[i] ]
83
+ Array.create_shared_method('.[]@', TosSpec, [], &lambda {|vm|
84
+ begin
85
+ vm.poke(self[Integer.foorth_coerce(vm.peek)])
86
+ rescue
87
+ vm.data_stack.pop
88
+ raise
89
+ end
90
+ })
91
+
92
+ # [ v i a ] .[]! []; a[i]=v
93
+ Array.create_shared_method('.[]!', TosSpec, [], &lambda {|vm|
94
+ value, index = vm.popm(2)
95
+ self[Integer.foorth_coerce(index)] = value;
96
+ })
97
+
98
+ # [ [ 1 2 3 ] ] .reverse [ [ 3 2 1 ] ]
99
+ Array.create_shared_method('.reverse', TosSpec, [],
100
+ &lambda {|vm| vm.push(self.reverse); })
101
+
102
+ # [ [ 3 1 2 ] ] .sort [ [ 1 2 3 ] ]
103
+ Array.create_shared_method('.sort', TosSpec, [],
104
+ &lambda {|vm| vm.push(self.sort {|va,vb| va <=> va.foorth_coerce(vb)}); })
105
+
106
+ # [ [ 1 2 3 ] ] .shuffle [ [ x y z ] ]
107
+ Array.create_shared_method('.shuffle', TosSpec, [],
108
+ &lambda {|vm| vm.push(self.shuffle); })
109
+
110
+ # [ [ 3 1 2 ] ] .length [ 3 ]
111
+ Array.create_shared_method('.length', TosSpec, [],
112
+ &lambda {|vm| vm.push(self.length); })
113
+
114
+ # [ an_array ] .empty? [ a_boolean ]
115
+ Array.create_shared_method('.empty?', TosSpec, [],
116
+ &lambda {|vm| vm.push(self.empty?); })
117
+
118
+ # [ [ 3 1 2 ] n ] << [ [ 3 1 2 n ] ]
119
+ Array.create_shared_method('<<', NosSpec, [],
120
+ &lambda {|vm| vm.poke(self << vm.peek); })
121
+
122
+ # [[3 1 2] n] + [[3 1 2 n]]
123
+ Array.create_shared_method('+', NosSpec, [],
124
+ &lambda {|vm| vm.poke(self + vm.peek.in_array); })
125
+
126
+
127
+ # The LEFT group
128
+ # [w [ 3 1 2 ] ] .left [ [ 3 1 ] ]; assumes w = 2
129
+ Array.create_shared_method('.left', TosSpec, [], &lambda {|vm|
130
+ begin
131
+ width = Integer.foorth_coerce(vm.peek)
132
+ error "F41: Invalid width: #{width} in .left" if width < 0
133
+ vm.poke(self.first(width));
134
+ rescue
135
+ vm.data_stack.pop
136
+ raise
137
+ end
138
+ })
139
+
140
+ # [w [ 3 1 2 ] ] .-left [ 2 ] // Assumes w = 2
141
+ Array.create_shared_method('.-left', TosSpec, [], &lambda {|vm|
142
+ begin
143
+ width = Integer.foorth_coerce(vm.peek)
144
+ error "F41: Invalid width: #{width} in .-left" if width < 0
145
+ vm.poke(self[width..-1]);
146
+ rescue
147
+ vm.data_stack.pop
148
+ raise
149
+ end
150
+ })
151
+
152
+ # [w [ 0 8 9 ] [ 1 2 3 4 ] ] .+left [ [ 0 8 9 3 4 ] ] // Assumes w = 2
153
+ Array.create_shared_method('.+left', TosSpec, [], &lambda {|vm|
154
+ begin
155
+ ins = vm.pop.in_array
156
+ width = Integer.foorth_coerce(vm.peek)
157
+ error "F41: Invalid width: #{width} in .+left" if width < 0
158
+ vm.poke(ins + self[width..-1])
159
+ rescue
160
+ vm.data_stack.pop
161
+ raise
162
+ end
163
+ })
164
+
165
+ # [w [ 1 2 3 4 ] ] .^left [ [ 3 4 ] [ 1 2 ] ]; assumes w = 2
166
+ Array.create_shared_method('.^left', TosSpec, [], &lambda {|vm|
167
+ begin
168
+ width = Integer.foorth_coerce(vm.peek)
169
+ error "F41: Invalid width: #{width} in .^left" if width < 0
170
+
171
+ vm.poke(self[width..-1])
172
+ vm.push(self.first(width));
173
+ rescue
174
+ vm.data_stack.pop
175
+ raise
176
+ end
177
+ })
178
+
179
+
180
+ #The RIGHT group
181
+ # [w [ 3 1 2 ] ] .right [ [ 1 2 ] ]; assumes w = 2
182
+ Array.create_shared_method('.right', TosSpec, [], &lambda {|vm|
183
+ begin
184
+ width = Integer.foorth_coerce(vm.peek)
185
+ error "F41: Invalid width: #{width} in .right" if width < 0
186
+ vm.poke(self.last(width))
187
+ rescue
188
+ vm.data_stack.pop
189
+ raise
190
+ end
191
+ })
192
+
193
+ # [w [ 3 1 2 ] ] .-right [ [ 3 ] ] // Assumes w = 2
194
+ Array.create_shared_method('.-right', TosSpec, [], &lambda {|vm|
195
+ begin
196
+ width = Integer.foorth_coerce(vm.peek)
197
+ error "F41: Invalid width: #{width} in .-right" if width < 0
198
+ vm.poke(self[0...(0-width)]);
199
+ rescue
200
+ vm.data_stack.pop
201
+ raise
202
+ end
203
+ })
204
+
205
+ # [w [ 0 8 9 ] [ 1 2 3 4 ] ] .+right [ [ 1 2 0 8 9 ] ] // Assumes w = 2
206
+ Array.create_shared_method('.+right', TosSpec, [], &lambda {|vm|
207
+ begin
208
+ ins = vm.pop.in_array
209
+ width = Integer.foorth_coerce(vm.peek)
210
+ error "F41: Invalid width: #{width} in .+right" if width < 0
211
+ vm.poke(self[0...(0-width)] + ins)
212
+ rescue
213
+ vm.data_stack.pop
214
+ raise
215
+ end
216
+ })
217
+
218
+ # [w [ 1 2 3 4 ] ] .^right [ [ 1 2 ] [ 3 4 ] ]; assumes w = 2
219
+ Array.create_shared_method('.^right', TosSpec, [], &lambda {|vm|
220
+ begin
221
+ width = Integer.foorth_coerce(vm.peek)
222
+ error "F41: Invalid width: #{width} in .^right" if width < 0
223
+
224
+ vm.poke(self[0...(0-width)])
225
+ vm.push(self.last(width));
226
+ rescue
227
+ vm.data_stack.pop
228
+ raise
229
+ end
230
+ })
231
+
232
+
233
+ # The MID group
234
+ # [n w [ 1 2 3 4 5 6 7 8 ] ] .mid [ [ 3 4 5 6 ] ] // Assumes n = 2, w = 4
235
+ Array.create_shared_method('.mid', TosSpec, [], &lambda {|vm|
236
+ begin
237
+ width = Integer.foorth_coerce(vm.pop)
238
+ posn = Integer.foorth_coerce(vm.peek)
239
+ error "F41: Invalid index: #{posn} in .mid" if posn < 0
240
+ error "F41: Invalid width: #{width} in .mid" if width < 0
241
+ vm.poke(self[posn...(posn+width)])
242
+ rescue
243
+ vm.data_stack.pop
244
+ raise
245
+ end
246
+ })
247
+
248
+ # [n w [ 1 2 3 4 5 6 7 8 ] ] .-mid [ [ 1 2 7 8 ] ] // Assumes n = 2, w = 4
249
+ Array.create_shared_method('.-mid', TosSpec, [], &lambda {|vm|
250
+ begin
251
+ width = Integer.foorth_coerce(vm.pop)
252
+ posn = Integer.foorth_coerce(vm.peek)
253
+ error "F41: Invalid index: #{posn} in .-mid" if posn < 0
254
+ error "F41: Invalid width: #{width} in .-mid" if width < 0
255
+ vm.poke(self[0...posn] + self[(posn+width)..-1])
256
+ rescue
257
+ vm.data_stack.pop
258
+ raise
259
+ end
260
+ })
261
+
262
+ # [n w [ 0 8 9 ] [ 1 2 3 4 5 6 7 8 ] ] .+mid [ [ 1 2 0 8 9 7 8 ] ] // Assumes n=2, w=4
263
+ Array.create_shared_method('.+mid', TosSpec, [], &lambda {|vm|
264
+ begin
265
+ ins = vm.pop.in_array
266
+ width = Integer.foorth_coerce(vm.pop)
267
+ posn = Integer.foorth_coerce(vm.peek)
268
+ error "F41: Invalid index: #{posn} in .+mid" if posn < 0
269
+ error "F41: Invalid width: #{width} in .+mid" if width < 0
270
+ vm.poke(self[0...posn] + ins + self[(posn+width)..-1])
271
+ rescue
272
+ vm.data_stack.pop
273
+ raise
274
+ end
275
+ })
276
+
277
+ # [n w [ 1 2 3 4 5 6 7 8 ] ] .^mid [ [ 1 2 7 8 ] [ 3 4 5 6 ] ] // For n=2, w=4
278
+ Array.create_shared_method('.^mid', TosSpec, [], &lambda {|vm|
279
+ begin
280
+ width = Integer.foorth_coerce(vm.pop)
281
+ posn = Integer.foorth_coerce(vm.peek)
282
+ error "F41: Invalid index: #{posn} in .^mid" if posn < 0
283
+ error "F41: Invalid width: #{width} in .^mid" if width < 0
284
+ vm.poke(self[0...posn] + self[(posn+width)..-1])
285
+ vm.push(self[posn...(posn+width)])
286
+ rescue
287
+ vm.data_stack.pop
288
+ raise
289
+ end
290
+ })
291
+
292
+
293
+ # The MIDLR group
294
+ # [l r [ 1 2 3 4 5 6 7 8 ] ] .midlr [ [ 2 3 4 5 6 7 ] ] // Assumes l=1, r=1
295
+ Array.create_shared_method('.midlr', TosSpec, [], &lambda {|vm|
296
+ begin
297
+ right = Integer.foorth_coerce(vm.pop)
298
+ left = Integer.foorth_coerce(vm.peek)
299
+ error "F41: Invalid left width: #{left} in .midlr" if left < 0
300
+ error "F41: Invalid right width: #{right} in .midlr" if right < 0
301
+ vm.poke(self[left..(0-right-1)])
302
+ rescue
303
+ vm.data_stack.pop
304
+ raise
305
+ end
306
+ })
307
+
308
+ # [l r [ 1 2 3 4 5 6 7 8 ] ] .-midlr [ [ 1 8 ] ] // Assumes l = 1, r = 1
309
+ Array.create_shared_method('.-midlr', TosSpec, [], &lambda {|vm|
310
+ begin
311
+ right = Integer.foorth_coerce(vm.pop)
312
+ left = Integer.foorth_coerce(vm.peek)
313
+ error "F41: Invalid left width: #{left} in .-midlr" if left < 0
314
+ error "F41: Invalid right width: #{right} in .-midlr" if right < 0
315
+ vm.poke(self.first(left) + self.last(right))
316
+ rescue
317
+ vm.data_stack.pop
318
+ raise
319
+ end
320
+ })
321
+
322
+ # [l r [ 0 8 9 ] [ 1 2 3 4 5 6 7 8 ] ] .+midlr [ [ 1 0 8 9 8 ] ] // Assumes l = 1, r = 1
323
+ Array.create_shared_method('.+midlr', TosSpec, [], &lambda {|vm|
324
+ begin
325
+ ins = vm.pop.in_array
326
+ right = Integer.foorth_coerce(vm.pop)
327
+ left = Integer.foorth_coerce(vm.peek)
328
+ error "F41: Invalid left width: #{left} in .-midlr" if left < 0
329
+ error "F41: Invalid right width: #{right} in .-midlr" if right < 0
330
+ vm.poke(self.first(left) + ins + self.last(right))
331
+ rescue
332
+ vm.data_stack.pop
333
+ raise
334
+ end
335
+ })
336
+
337
+ # [l r [ 1 2 3 4 5 ] ] .midlr [ [ 1 5 ] [ 2 3 4 ] ] // Assumes l=1, r=1
338
+ Array.create_shared_method('.^midlr', TosSpec, [], &lambda {|vm|
339
+ begin
340
+ right = Integer.foorth_coerce(vm.pop)
341
+ left = Integer.foorth_coerce(vm.peek)
342
+ error "F41: Invalid left width: #{left} in .midlr" if left < 0
343
+ error "F41: Invalid right width: #{right} in .midlr" if right < 0
344
+ vm.poke(self.first(left) + self.last(right))
345
+ vm.push(self[left..(0-right-1)])
346
+ rescue
347
+ vm.data_stack.pop
348
+ raise
349
+ end
350
+ })
351
+
352
+
353
+ #The DEQUEUE LEFT group
354
+ #[ [ 1 2 3 ] ] .pop_left [ [ 2 3 ] 1 ]
355
+ Array.create_shared_method('.pop_left', TosSpec, [], &lambda{|vm|
356
+ error "F31: Array underflow error on .pop_left" if self.empty?
357
+ vm.push(self[1..-1]);
358
+ vm.push(self.first)
359
+ })
360
+
361
+ #[ [ 1 2 3 ] ] .pop_left! [ 1 ]; Mutates original array.
362
+ Array.create_shared_method('.pop_left!', TosSpec, [], &lambda{|vm|
363
+ error "F31: Array underflow error on .pop_left!" if self.empty?
364
+ vm.push(self.delete_at(0))
365
+ })
366
+
367
+ #[ 0 [ 1 2 3 ] ] .push_left [ [ 0 1 2 3 ] ]
368
+ Array.create_shared_method('.push_left', TosSpec, [], &lambda{|vm|
369
+ vm.poke([ vm.peek ] + self)
370
+ })
371
+
372
+ #[ 0 [ 1 2 3 ] ] .push_left! [ ]; Mutates original array.
373
+ Array.create_shared_method('.push_left!', TosSpec, [], &lambda{|vm|
374
+ self.insert(0, vm.pop)
375
+ })
376
+
377
+ #[ [ 1 2 3 ] ] .peek_left [ [ 1 2 3 ] 1 ]
378
+ Array.create_shared_method('.peek_left', TosSpec, [], &lambda{|vm|
379
+ error "F31: Array underflow error on .peek_left" if self.empty?
380
+ vm.push(self);
381
+ vm.push(self.first)
382
+ })
383
+
384
+ #[ [ 1 2 3 ] ] .peek_left! [ 1 ]
385
+ Array.create_shared_method('.peek_left!', TosSpec, [], &lambda{|vm|
386
+ error "F31: Array underflow error on .peek_left!" if self.empty?
387
+ vm.push(self.first)
388
+ })
389
+
390
+
391
+ #The DEQUEUE RIGHT group
392
+ #[ [ 1 2 3 ] ] .pop_right [ [ 1 2 ] 3 ]
393
+ Array.create_shared_method('.pop_right', TosSpec, [], &lambda{|vm|
394
+ error "F31: Array underflow error on .pop_right" if self.empty?
395
+ vm.push(self[0...-1]);
396
+ vm.push(self.last)
397
+ })
398
+
399
+ #[ [ 1 2 3 ] ] .pop_right! [ 3 ]; Mutates original array.
400
+ Array.create_shared_method('.pop_right!', TosSpec, [], &lambda{|vm|
401
+ error "F31: Array underflow error on .pop_right!" if self.empty?
402
+ vm.push(self.pop)
403
+ })
404
+
405
+ #[ 4 [ 1 2 3 ] ] .push_right [ [ 1 2 3 4 ] ]
406
+ Array.create_shared_method('.push_right', TosSpec, [], &lambda{|vm|
407
+ vm.poke(self + [ vm.peek ])
408
+ })
409
+
410
+ #[ 4 [ 1 2 3 ] ] .push_right! [ ]; Mutates original array.
411
+ Array.create_shared_method('.push_right!', TosSpec, [], &lambda{|vm|
412
+ self << vm.pop
413
+ })
414
+
415
+ #[ [ 1 2 3 ] ] .peek_right [ [ 1 2 3 ] 3 ]
416
+ Array.create_shared_method('.peek_right', TosSpec, [], &lambda{|vm|
417
+ error "F31: Array underflow error on .peek_right" if self.empty?
418
+ vm.push(self);
419
+ vm.push(self.last)
420
+ })
421
+
422
+ #[ [ 1 2 3 ] ] .peek_right! [ [ 1 2 3 ] 3 ]
423
+ Array.create_shared_method('.peek_right!', TosSpec, [], &lambda{|vm|
424
+ error "F31: Array underflow error on .peek_right!" if self.empty?
425
+ vm.push(self.last)
426
+ })
427
+
428
+
429
+ # [ a ] .min [ smallest_element ]
430
+ Array.create_shared_method('.min', TosSpec, [], &lambda {|vm|
431
+ result = self[0]
432
+
433
+ self.each do |value|
434
+ other = result.foorth_coerce(value)
435
+ result = other if result > other
436
+ end
437
+
438
+ vm.push(result)
439
+ })
440
+
441
+ # [ a ] .max [ largest_element ]
442
+ Array.create_shared_method('.max', TosSpec, [], &lambda {|vm|
443
+ result = self[0]
444
+
445
+ self.each do |value|
446
+ other = result.foorth_coerce(value)
447
+ result = other if result < other
448
+ end
449
+
450
+ vm.push(result)
451
+ })
452
+
453
+ # [ array ] .split [ a0 a1 ... aN ]
454
+ Array.create_shared_method('.split', TosSpec, [], &lambda {|vm|
455
+ vm.pushm(self)
456
+ })
457
+
458
+ # [ a1 a2 aN N ] .join [ [ a1 a2 ... aN ] ]
459
+ Integer.create_shared_method('.join', TosSpec, [], &lambda {|vm|
460
+ error "F30: Invalid array size: .join" if self < 0
461
+ vm.push(vm.popm(self))
462
+ })
463
+
464
+ # [ array ] .to_s [ string ]
465
+ Array.create_shared_method('.to_s', TosSpec, [], &lambda {|vm|
466
+ result = "[ "
467
+
468
+ self.each do |value|
469
+ if value.is_a?(String)
470
+ result << value.inspect + " "
471
+ else
472
+ value.to_foorth_s(vm)
473
+ result << (vm.pop || value.inspect) + " "
474
+ end
475
+ end
476
+
477
+ vm.push(result + "]")
478
+ })
479
+
480
+ # [ l 2 3 ... n ] .strmax [ widest ]
481
+ Array.create_shared_method('.strmax', TosSpec, [], &lambda {|vm|
482
+ result = 0
483
+
484
+ self.each {|item|
485
+ item.foorth_strlen(vm)
486
+ temp = vm.pop
487
+ result = result > temp ? result : temp
488
+ }
489
+
490
+ vm.push(result)
491
+ })
492
+
493
+ #[ array ] .scatter [ a0 a1 ... aN ]
494
+ Array.create_shared_method('.scatter', TosSpec, [], &lambda {|vm|
495
+ vm.data_stack += self
496
+ })
497
+
498
+ #[ x0 x1 ... xN] gather [ array ]
499
+ VirtualMachine.create_shared_method('gather', VmSpec, [], &lambda{|vm|
500
+ @data_stack = [@data_stack]
501
+ })
502
+
503
+ #[ x0 x1 ... xN N] .gather [ array ]
504
+ Integer.create_shared_method('.gather', TosSpec, [], &lambda {|vm|
505
+ error "F30: Invalid .gather count value." unless self > 0
506
+ error "F30: Data stack underflow." unless self <= vm.data_stack.length
507
+
508
+ temp = vm.data_stack.pop(self)
509
+ vm.data_stack << temp
510
+ })
511
+
512
+ #[ an_array ] .to_a [ an_array ]
513
+ Array.create_shared_method('.to_a', TosSpec, [],
514
+ &lambda {|vm| vm.push(self) })
515
+
516
+ #[ an_array ] .to_h [ a_hash ]
517
+ Array.create_shared_method('.to_h', TosSpec, [], &lambda {|vm|
518
+ result = {}
519
+ self.each_with_index { |val, idx| result[idx] = val }
520
+ vm.push(result)
521
+ })
522
+
523
+ #[ an_array ] .values [ an_array ]
524
+ Array.create_shared_method('.values', TosSpec, [],
525
+ &lambda {|vm| vm.push(self) })
526
+
527
+ #[ an_array ] .keys [ an_array ]
528
+ Array.create_shared_method('.keys', TosSpec, [],
529
+ &lambda {|vm| vm.push((0...self.length).to_a) })
530
+
531
+
532
+ $fcpl = 80 #fOOrth Character Per Line
533
+ $flpp = 25 #fOOrth Lines Per Page
534
+
535
+ # [ l 2 3 ... n ] .pp []; pretty print the array!
536
+ Array.create_shared_method('.pp', TosSpec, [], &lambda {|vm|
537
+ self.foorth_strmax(vm)
538
+ width = vm.pop + 1
539
+ cols = (width <= $fcpl) ? ($fcpl / width) : 1
540
+ full_rows = ((cols * width) % $fcpl) == 0
541
+ rows_left = (self.length + cols - 1) / cols
542
+ pages = (rows_left + $flpp - 1) / $flpp
543
+ page_capacity = $flpp * cols
544
+
545
+ (0...pages).each do |page|
546
+ offset = page * page_capacity
547
+ rows_this_page = (rows_left >= $flpp) ? $flpp : rows_left
548
+
549
+ (0...rows_this_page).each do |row|
550
+ (0...cols).each do |col|
551
+ self[offset + col*rows_this_page + row].to_foorth_s(vm)
552
+
553
+ if cols > 1
554
+ print vm.pop.ljust(width)
555
+ else
556
+ print vm.pop
557
+ end
558
+ end
559
+
560
+ puts unless full_rows
561
+ end
562
+
563
+ rows_left -= $flpp
564
+ puts "\n"
565
+ end
566
+ })
567
+
568
+ #Show the page length.
569
+ VirtualMachine.create_shared_method(')pl', MacroSpec,
570
+ [:macro, 'puts "Page Length = #{$flpp}"; '])
571
+
572
+
573
+ #Set/show the page length.
574
+ VirtualMachine.create_shared_method(')set_pl', MacroSpec,
575
+ [:macro, 'puts "New Page Length = #{$flpp = vm.pop.to_i}"; '])
576
+
577
+ end