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,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