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