fOOrth 0.6.4 → 0.6.5
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 +4 -4
- data/integration/compile_lib_tests.rb +41 -0
- data/irbt.rb +0 -2
- data/lib/fOOrth/compiler.rb +4 -8
- data/lib/fOOrth/compiler/cast.rb +39 -0
- data/lib/fOOrth/compiler/context/map_name.rb +12 -31
- data/lib/fOOrth/compiler/process.rb +5 -3
- data/lib/fOOrth/core/class.rb +1 -1
- data/lib/fOOrth/debug.rb +0 -2
- data/lib/fOOrth/debug/display_abort.rb +0 -6
- data/lib/fOOrth/library.rb +1 -0
- data/lib/fOOrth/library/array_library.rb +1 -47
- data/lib/fOOrth/library/command_library.rb +35 -60
- data/lib/fOOrth/library/compile_library.rb +27 -7
- data/lib/fOOrth/library/formatting/bullets.rb +121 -0
- data/lib/fOOrth/library/formatting/columns.rb +144 -0
- data/lib/fOOrth/library/hash_library.rb +2 -1
- data/lib/fOOrth/library/introspection/class.rb +84 -0
- data/lib/fOOrth/library/introspection/context.rb +36 -0
- data/lib/fOOrth/library/introspection/object.rb +69 -0
- data/lib/fOOrth/library/introspection/string.rb +28 -0
- data/lib/fOOrth/library/introspection/symbol_map.rb +19 -0
- data/lib/fOOrth/library/introspection/vm.rb +70 -0
- data/lib/fOOrth/library/introspection/word_specs.rb +18 -0
- data/lib/fOOrth/library/introspection_library.rb +78 -0
- data/lib/fOOrth/library/stack_library.rb +2 -4
- data/lib/fOOrth/library/stdio_library.rb +68 -0
- data/lib/fOOrth/library/stubs.rb +11 -7
- data/lib/fOOrth/library/vm_library.rb +1 -5
- data/lib/fOOrth/version.rb +1 -1
- data/tests/core_tests.rb +1 -1
- metadata +13 -4
- data/lib/fOOrth/debug/context_dump.rb +0 -31
- data/lib/fOOrth/debug/vm_dump.rb +0 -27
@@ -3,12 +3,27 @@
|
|
3
3
|
#* library/compile_library.rb - The compile support fOOrth library.
|
4
4
|
module XfOOrth
|
5
5
|
|
6
|
+
# METHOD CASTING ==============================
|
7
|
+
|
8
|
+
#TosSpec method cast.
|
9
|
+
VirtualMachine.create_shared_method("'.", VmSpec, [],
|
10
|
+
&lambda {|vm| vm.set_cast(TosSpec) })
|
11
|
+
|
12
|
+
#NosSpec method cast.
|
13
|
+
VirtualMachine.create_shared_method("'*", VmSpec, [],
|
14
|
+
&lambda {|vm| vm.set_cast(NosSpec) })
|
15
|
+
|
16
|
+
#SelfSpec method cast.
|
17
|
+
VirtualMachine.create_shared_method("'~", VmSpec, [],
|
18
|
+
&lambda {|vm| vm.set_cast(SelfSpec) })
|
19
|
+
|
6
20
|
# COLON =======================================
|
7
21
|
|
8
22
|
#The classic colon definition that creates a word in the Virtual Machine class.
|
9
23
|
# [] : <name> <stuff omitted> ; []; creates <name> on the VirtualMachine
|
10
24
|
VirtualMachine.create_shared_method(':', VmSpec, [:immediate], &lambda {|vm|
|
11
25
|
if execute_mode?
|
26
|
+
verify_cast([VmSpec])
|
12
27
|
target = VirtualMachine
|
13
28
|
name = vm.parser.get_word()
|
14
29
|
type = VmSpec
|
@@ -32,6 +47,7 @@ module XfOOrth
|
|
32
47
|
# [] !: <name> <stuff omitted> ; []; creates <name> on the VirtualMachine
|
33
48
|
VirtualMachine.create_shared_method('!:', VmSpec, [:immediate], &lambda {|vm|
|
34
49
|
if execute_mode?
|
50
|
+
verify_cast([VmSpec])
|
35
51
|
target = VirtualMachine
|
36
52
|
name = vm.parser.get_word()
|
37
53
|
type = VmSpec
|
@@ -58,7 +74,7 @@ module XfOOrth
|
|
58
74
|
error "F13: The target of .: must be a class" unless target.is_a?(Class)
|
59
75
|
|
60
76
|
name = vm.parser.get_word()
|
61
|
-
type = XfOOrth.name_to_type(name)
|
77
|
+
type = XfOOrth.name_to_type(name, get_cast)
|
62
78
|
XfOOrth.validate_type(vm, type, name)
|
63
79
|
XfOOrth.validate_string_method(type, target, name)
|
64
80
|
|
@@ -116,7 +132,7 @@ module XfOOrth
|
|
116
132
|
if execute_mode?
|
117
133
|
target = vm.pop
|
118
134
|
name = vm.parser.get_word()
|
119
|
-
type = XfOOrth.name_to_type(name)
|
135
|
+
type = XfOOrth.name_to_type(name, get_cast)
|
120
136
|
XfOOrth.validate_type(vm, type, name)
|
121
137
|
XfOOrth.validate_string_method(type, target.class, name)
|
122
138
|
|
@@ -184,8 +200,10 @@ module XfOOrth
|
|
184
200
|
&lambda {|vm| vm << 'super(vm); ' })
|
185
201
|
|
186
202
|
#The standard end-compile adapter word: ';' semi-colon.
|
187
|
-
context.create_local_method(';', LocalSpec, [:immediate],
|
188
|
-
|
203
|
+
context.create_local_method(';', LocalSpec, [:immediate], &lambda {|vm|
|
204
|
+
vm.clear_cast
|
205
|
+
vm.end_compile_mode([ctrl])
|
206
|
+
})
|
189
207
|
end
|
190
208
|
|
191
209
|
#Determine the type of method being created. This only applies to non-vm
|
@@ -194,8 +212,8 @@ module XfOOrth
|
|
194
212
|
#*name - The name of the method to be created.
|
195
213
|
#<Returns>
|
196
214
|
#* The class of the spec to be used for this method.
|
197
|
-
def self.name_to_type(name)
|
198
|
-
case name[0]
|
215
|
+
def self.name_to_type(name, cast_spec=nil)
|
216
|
+
normal_spec = case name[0]
|
199
217
|
when '.'
|
200
218
|
TosSpec
|
201
219
|
|
@@ -208,6 +226,8 @@ module XfOOrth
|
|
208
226
|
else
|
209
227
|
NosSpec
|
210
228
|
end
|
229
|
+
|
230
|
+
cast_spec || normal_spec
|
211
231
|
end
|
212
232
|
|
213
233
|
#Compare the new method's spec against the specs of other methods of the
|
@@ -218,7 +238,7 @@ module XfOOrth
|
|
218
238
|
#*type - The class of the method to be created.
|
219
239
|
#*name - The name of the method to be created.
|
220
240
|
def self.validate_type(vm, type, name)
|
221
|
-
if (spec = vm.context.map(name))
|
241
|
+
if (spec = vm.context.map(name, false))
|
222
242
|
if spec.class != type
|
223
243
|
error "F90: Spec type mismatch #{spec.foorth_name} vs #{type.foorth_name}"
|
224
244
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* library/formatting/bullets.rb - Print out bullet points.
|
4
|
+
module XfOOrth
|
5
|
+
|
6
|
+
#A class to display data in bullet points.
|
7
|
+
class BulletPoints
|
8
|
+
#Prepare a blank slate.
|
9
|
+
def initialize(page_width)
|
10
|
+
@page_width, @bullet_data = page_width, []
|
11
|
+
end
|
12
|
+
|
13
|
+
#Add an item to this page.
|
14
|
+
#<br>Returns
|
15
|
+
#* The number if items that did not fit in the page.
|
16
|
+
def add(raw_bullet = "*", *raw_item)
|
17
|
+
|
18
|
+
if raw_item.empty?
|
19
|
+
bullet = ["*"]
|
20
|
+
items = raw_bullet.in_array
|
21
|
+
else
|
22
|
+
bullet = raw_bullet.in_array
|
23
|
+
items = raw_item.in_array
|
24
|
+
end
|
25
|
+
|
26
|
+
items.each_index do |index|
|
27
|
+
@bullet_data << [(bullet[index] || "").to_s, items[index].to_s]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#Render the page as an array of strings.
|
32
|
+
def render
|
33
|
+
@key_length, results = get_key_length, []
|
34
|
+
|
35
|
+
@bullet_data.each do |key, item|
|
36
|
+
results.concat(render_bullet(key, item))
|
37
|
+
end
|
38
|
+
|
39
|
+
@bullet_data = []
|
40
|
+
results
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
#How large is the largest bullet?
|
46
|
+
def get_key_length
|
47
|
+
(@bullet_data.max_by {|line| line[0].length})[0].length
|
48
|
+
end
|
49
|
+
|
50
|
+
#Render one bullet point.
|
51
|
+
def render_bullet(key, item)
|
52
|
+
result = []
|
53
|
+
input = item.split(' ').each
|
54
|
+
temp = key.ljust(len = @key_length)
|
55
|
+
pass_one = true
|
56
|
+
|
57
|
+
loop do
|
58
|
+
word = ' ' + input.next
|
59
|
+
|
60
|
+
while len >= @page_width
|
61
|
+
result << temp.slice!(0, @page_width - 1)
|
62
|
+
temp = (' ' * @key_length) + ' ' + temp
|
63
|
+
len = temp.length
|
64
|
+
end
|
65
|
+
|
66
|
+
if ((len += word.length) >= @page_width) && !pass_one
|
67
|
+
result << temp
|
68
|
+
temp = (' ' * @key_length) + word
|
69
|
+
len = temp.length
|
70
|
+
else
|
71
|
+
temp << word
|
72
|
+
pass_one = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
result << temp
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
class Array
|
84
|
+
#Print out the array as bullet points.
|
85
|
+
def puts_foorth_bullets(page_width)
|
86
|
+
puts foorth_bulletize(page_width)
|
87
|
+
end
|
88
|
+
|
89
|
+
#Convert the array to strings with bullet points.
|
90
|
+
#<br>
|
91
|
+
#* An array of arrays of strings
|
92
|
+
def foorth_bulletize(page_width)
|
93
|
+
builder = XfOOrth::BulletPoints.new(page_width)
|
94
|
+
|
95
|
+
self.each do |pair|
|
96
|
+
builder.add(*pair)
|
97
|
+
end
|
98
|
+
|
99
|
+
builder.render
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Hash
|
104
|
+
#Print out the hash as bullet points.
|
105
|
+
def puts_foorth_bullets(page_width)
|
106
|
+
puts foorth_bulletize(page_width)
|
107
|
+
end
|
108
|
+
|
109
|
+
#Convert the hash to strings with bullet points.
|
110
|
+
#<br>
|
111
|
+
#* An array of arrays of strings
|
112
|
+
def foorth_bulletize(page_width)
|
113
|
+
builder = XfOOrth::BulletPoints.new(page_width)
|
114
|
+
|
115
|
+
self.each do |key, value|
|
116
|
+
builder.add(key, *value.in_array)
|
117
|
+
end
|
118
|
+
|
119
|
+
builder.render
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* library/formatting/columns.rb - Print out data in columns.
|
4
|
+
module XfOOrth
|
5
|
+
|
6
|
+
#A class to display data in columns.
|
7
|
+
class ColumnizedPage
|
8
|
+
#Prepare a blank page.
|
9
|
+
def initialize(page_length, page_width)
|
10
|
+
@page_length, @page_width = page_length, page_width
|
11
|
+
@page_data = []
|
12
|
+
end
|
13
|
+
|
14
|
+
#Add an item to this page.
|
15
|
+
#<br>Returns
|
16
|
+
#* The number if items that did not fit in the page.
|
17
|
+
def add(raw_item)
|
18
|
+
item = raw_item.to_s
|
19
|
+
fail "Item too large to fit." unless item.length < @page_width
|
20
|
+
|
21
|
+
if (slot = find_next_column)
|
22
|
+
@page_data[slot] << item
|
23
|
+
else
|
24
|
+
@page_data << [item]
|
25
|
+
end
|
26
|
+
|
27
|
+
adjust_configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
#Render the page as an array of strings.
|
31
|
+
def render
|
32
|
+
results = []
|
33
|
+
widths = @page_data.map {|column| column.foorth_column_width}
|
34
|
+
|
35
|
+
(0...rows).each do |column_index|
|
36
|
+
results << @page_data.each_with_index.map do |column, index|
|
37
|
+
column[column_index].to_s.ljust(widths[index])
|
38
|
+
end.join(" ").freeze
|
39
|
+
end
|
40
|
+
|
41
|
+
@page_data = []
|
42
|
+
results
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
#Make sure the page fits within its boundaries.
|
48
|
+
#<br>Returns
|
49
|
+
#* The number if items that did not fit in the page.
|
50
|
+
def adjust_configuration
|
51
|
+
while total_width >= @page_width
|
52
|
+
return @page_data.pop.length if rows == @page_length
|
53
|
+
add_a_row
|
54
|
+
end
|
55
|
+
|
56
|
+
0
|
57
|
+
end
|
58
|
+
|
59
|
+
#Add a row to the page, moving items as needed.
|
60
|
+
def add_a_row
|
61
|
+
target = rows + 1
|
62
|
+
pool, @page_data = @page_data.flatten, []
|
63
|
+
|
64
|
+
until pool.empty?
|
65
|
+
@page_data << pool.shift(target)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#Compute the total width of all of the columns.
|
70
|
+
#<br>Returns
|
71
|
+
#* The sum of the widths of the widest items of each column plus a space
|
72
|
+
# between each of those columns.
|
73
|
+
def total_width
|
74
|
+
if empty?
|
75
|
+
0
|
76
|
+
else
|
77
|
+
@page_data.inject(@page_data.length-1) do |sum, column|
|
78
|
+
sum + column.foorth_column_width
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#Does the data fit on the page?
|
84
|
+
def fits?
|
85
|
+
total_width < @page_width
|
86
|
+
end
|
87
|
+
|
88
|
+
#How many rows are currently in this page?
|
89
|
+
def rows
|
90
|
+
empty? ? 0 : @page_data[0].length
|
91
|
+
end
|
92
|
+
|
93
|
+
#Is this page empty?
|
94
|
+
def empty?
|
95
|
+
@page_data.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
#Which column will receive the next item?
|
99
|
+
#<br>Returns
|
100
|
+
#* The index of the first non-filled column or nil if none found.
|
101
|
+
def find_next_column
|
102
|
+
(1...(@page_data.length)).each do |index|
|
103
|
+
if @page_data[index].length < @page_data[index-1].length
|
104
|
+
return index
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
#Support for displaying an array in neat columns.
|
115
|
+
class Array
|
116
|
+
#Print out the array with efficient columns.
|
117
|
+
def puts_foorth_columnized(page_length, page_width)
|
118
|
+
foorth_columnize(page_length, page_width).each do |page|
|
119
|
+
puts page
|
120
|
+
puts
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
#Convert the array to strings with efficient columns.
|
125
|
+
#<br>
|
126
|
+
#* An array of arrays of strings
|
127
|
+
def foorth_columnize(page_length, page_width)
|
128
|
+
index, pages, limit = 0, [], self.length
|
129
|
+
builder = XfOOrth::ColumnizedPage.new(page_length, page_width)
|
130
|
+
|
131
|
+
while index < limit
|
132
|
+
index += 1 - (left_over = builder.add(self[index]))
|
133
|
+
pages << builder.render if (left_over > 0) || (index == limit)
|
134
|
+
end
|
135
|
+
|
136
|
+
pages
|
137
|
+
end
|
138
|
+
|
139
|
+
#Get the widest element of an array.
|
140
|
+
def foorth_column_width
|
141
|
+
(self.max_by {|item| item.length}).length
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
@@ -197,7 +197,8 @@ class Hash
|
|
197
197
|
#A helper method to extract non-stub method names from a method hash.
|
198
198
|
def extract_method_names(search_type = :no_stubs)
|
199
199
|
search_value = (search_type == :stubs)
|
200
|
-
|
200
|
+
get_all = (search_type == :all)
|
201
|
+
mkeys = self.keys.select {|key| get_all || search_value == self[key].has_tag?(:stub) }
|
201
202
|
mkeys.collect {|key| XfOOrth::SymbolMap.unmap(key) || '?error?' }
|
202
203
|
end
|
203
204
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* library/introspection/class.rb - Class support for introspection.
|
4
|
+
class Class
|
5
|
+
|
6
|
+
#Get information about the mapping of the symbol.
|
7
|
+
def map_foorth_shared_info(symbol, shallow=nil)
|
8
|
+
if (spec = foorth_shared[symbol])
|
9
|
+
[spec, [["Class", foorth_class_name], ["Scope", "Shared"]]]
|
10
|
+
elsif (sc = superclass) && !shallow
|
11
|
+
sc.map_foorth_shared_info(symbol)
|
12
|
+
else
|
13
|
+
[nil, nil]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#Get the lineage of this class.
|
18
|
+
def lineage
|
19
|
+
#Ugly hack, sorry!
|
20
|
+
if [Object, Module].include?(self)
|
21
|
+
"Object"
|
22
|
+
else
|
23
|
+
foorth_class_name + " < " + superclass.lineage
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#Investigate a method of this class.
|
28
|
+
def foorth_method_info(name)
|
29
|
+
symbol, results = XfOOrth::SymbolMap.map_info(name)
|
30
|
+
found = false
|
31
|
+
|
32
|
+
if symbol
|
33
|
+
spec, info = map_foorth_shared_info(symbol)
|
34
|
+
|
35
|
+
if spec && !spec.has_tag?(:stub)
|
36
|
+
(results << ["", ""]).concat(info).concat(spec.get_info)
|
37
|
+
found = true
|
38
|
+
end
|
39
|
+
|
40
|
+
spec, info = map_foorth_exclusive_info(symbol)
|
41
|
+
|
42
|
+
if spec && !spec.has_tag?(:stub)
|
43
|
+
(results << ["", ""]).concat(info).concat(spec.get_info)
|
44
|
+
found = true
|
45
|
+
end
|
46
|
+
|
47
|
+
results << ["Scope", "not found."] unless found
|
48
|
+
end
|
49
|
+
|
50
|
+
results
|
51
|
+
end
|
52
|
+
|
53
|
+
#Get introspection info.
|
54
|
+
def get_info
|
55
|
+
results = [["Lineage", lineage]]
|
56
|
+
|
57
|
+
if foorth_has_exclusive?
|
58
|
+
results.concat([["", ""], ["Methods", "Class"]])
|
59
|
+
|
60
|
+
foorth_exclusive.extract_method_names(:all).sort.each do |name|
|
61
|
+
symbol, info = XfOOrth::SymbolMap.map_info(name)
|
62
|
+
(results << ["", ""]).concat(info)
|
63
|
+
|
64
|
+
spec, info = map_foorth_exclusive_info(symbol, :shallow)
|
65
|
+
results.concat(info).concat(spec.get_info)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
unless foorth_shared.empty?
|
70
|
+
results.concat([["", ""], ["Methods", "Shared"]])
|
71
|
+
|
72
|
+
foorth_shared.extract_method_names(:all).sort.each do |name|
|
73
|
+
symbol, info = XfOOrth::SymbolMap.map_info(name)
|
74
|
+
(results << ["", ""]).concat(info)
|
75
|
+
|
76
|
+
spec, info = map_foorth_shared_info(symbol, :shallow)
|
77
|
+
results.concat(info).concat(spec.get_info)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
results
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|