fOOrth 0.6.10 → 0.6.11
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 +5 -5
- data/README.md +13 -2
- data/fOOrth.gemspec +2 -2
- data/integration/array_lib_tests.rb +10 -0
- data/integration/exception_lib_tests.rb +4 -0
- data/integration/hash_lib_tests.rb +9 -0
- data/integration/numeric_lib_tests.rb +326 -321
- data/integration/procedure_lib_tests.rb +16 -0
- data/integration/queue_lib_tests.rb +2 -1
- data/integration/stack_lib_tests.rb +2 -1
- data/integration/string_lib_tests.rb +11 -0
- data/integration/thread_lib_tests.rb +11 -8
- data/lib/fOOrth/compiler/context.rb +64 -64
- data/lib/fOOrth/compiler/context/locals.rb +34 -34
- data/lib/fOOrth/compiler/context/map_name.rb +85 -85
- data/lib/fOOrth/compiler/context/tags.rb +60 -48
- data/lib/fOOrth/compiler/process/procedure.rb +40 -0
- data/lib/fOOrth/library.rb +1 -0
- data/lib/fOOrth/library/array_library.rb +41 -21
- data/lib/fOOrth/library/command_library.rb +1 -1
- data/lib/fOOrth/library/compile_library.rb +266 -266
- data/lib/fOOrth/library/complex_library.rb +82 -80
- data/lib/fOOrth/library/float_library.rb +37 -0
- data/lib/fOOrth/library/hash_library.rb +14 -6
- data/lib/fOOrth/library/mutex_library.rb +4 -2
- data/lib/fOOrth/library/numeric_library.rb +359 -380
- data/lib/fOOrth/library/procedure_library.rb +69 -65
- data/lib/fOOrth/library/queue_library.rb +6 -1
- data/lib/fOOrth/library/rational_library.rb +89 -89
- data/lib/fOOrth/library/stack_library.rb +6 -1
- data/lib/fOOrth/library/string_library.rb +18 -6
- data/lib/fOOrth/monkey_patch/exceptions.rb +2 -6
- data/lib/fOOrth/version.rb +1 -1
- data/tests/compiler/context_tests.rb +188 -177
- data/tests/compiler/file_source_tests.rb +130 -130
- data/tests/compiler/parser_tests.rb +4 -4
- data/tests/compiler/string_source_tests.rb +4 -4
- data/tests/core_tests.rb +138 -138
- data/tests/monkey_patch/complex_test.rb +24 -24
- data/tests/monkey_patch/object_test.rb +49 -49
- data/tests/monkey_patch/string_test.rb +61 -61
- metadata +10 -10
@@ -1,48 +1,60 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
#* compiler/context/tags.rb - Support tags in context.
|
4
|
-
module XfOOrth
|
5
|
-
|
6
|
-
#* compiler/context/tags.rb - Support tags in context.
|
7
|
-
class Context
|
8
|
-
|
9
|
-
#Retrieve the data value currently in effect.
|
10
|
-
def [](index)
|
11
|
-
@data[index] || (previous && previous[index])
|
12
|
-
end
|
13
|
-
|
14
|
-
#Set a data value.
|
15
|
-
def []=(index,value)
|
16
|
-
@data[index] = value
|
17
|
-
end
|
18
|
-
|
19
|
-
#Get the compile tags in effect.
|
20
|
-
def tags
|
21
|
-
@data[:tags] || []
|
22
|
-
end
|
23
|
-
|
24
|
-
#Merge in a hash of tag data.
|
25
|
-
def merge(new_data)
|
26
|
-
@data.merge!(new_data)
|
27
|
-
end
|
28
|
-
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* compiler/context/tags.rb - Support tags in context.
|
4
|
+
module XfOOrth
|
5
|
+
|
6
|
+
#* compiler/context/tags.rb - Support tags in context.
|
7
|
+
class Context
|
8
|
+
|
9
|
+
#Retrieve the data value currently in effect.
|
10
|
+
def [](index)
|
11
|
+
@data[index] || (previous && previous[index])
|
12
|
+
end
|
13
|
+
|
14
|
+
#Set a data value.
|
15
|
+
def []=(index,value)
|
16
|
+
@data[index] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
#Get the compile tags in effect.
|
20
|
+
def tags
|
21
|
+
@data[:tags] || []
|
22
|
+
end
|
23
|
+
|
24
|
+
#Merge in a hash of tag data.
|
25
|
+
def merge(new_data)
|
26
|
+
@data.merge!(new_data)
|
27
|
+
end
|
28
|
+
|
29
|
+
#Get the context with the specified type.
|
30
|
+
def get_context_by_ctrl(ctrl_type)
|
31
|
+
result = self
|
32
|
+
|
33
|
+
while result
|
34
|
+
return result if result[:ctrl] == ctrl_type
|
35
|
+
result = result.previous
|
36
|
+
end
|
37
|
+
|
38
|
+
error "F92: Unable to locate a context for #{ctrl_type.inspect}"
|
39
|
+
end
|
40
|
+
|
41
|
+
#Validate a current data value.
|
42
|
+
#<br>Parameters:
|
43
|
+
#* symbol - The symbol of the value to be tested.
|
44
|
+
#* expect - An array of valid values.
|
45
|
+
#<br>Note:
|
46
|
+
#* Throws a XfOOrthError if the value is not valid.
|
47
|
+
#* To check for no value, use [nil] for expect.
|
48
|
+
#* Returns true to facilitate testing only.
|
49
|
+
def check_set(symbol, expect)
|
50
|
+
current = self[symbol]
|
51
|
+
|
52
|
+
unless expect.include?(current)
|
53
|
+
error "F10: Found a #{current.inspect}, expected #{expect}"
|
54
|
+
end
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -32,6 +32,42 @@ module XfOOrth
|
|
32
32
|
(_, @buffer = @buffer, save)[0]
|
33
33
|
end
|
34
34
|
|
35
|
+
#The procedure used for procedure instance values
|
36
|
+
PROC_VAL = lambda {|vm|
|
37
|
+
context = vm.context.get_context_by_ctrl(:procedure)
|
38
|
+
val_name = vm.parser.get_word()
|
39
|
+
|
40
|
+
unless /^@[a-z][a-z0-9_]*$/ =~ val_name
|
41
|
+
error "F10: Invalid val name #{val_name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
val_symbol = XfOOrth::SymbolMap.add_entry(val_name)
|
45
|
+
vm << "#{'@'+(val_symbol.to_s)} = vm.pop; "
|
46
|
+
vm << "self.create_exclusive_method(#{val_name.inspect}, InstanceVarSpec, []); "
|
47
|
+
|
48
|
+
context.create_local_method(val_name, LocalSpec, [:immediate], &lambda {|nvm|
|
49
|
+
nvm << "vm.push(#{'@'+(val_symbol.to_s)}); "
|
50
|
+
})
|
51
|
+
}
|
52
|
+
|
53
|
+
#The procedure used for procedure instance variables
|
54
|
+
PROC_VAR = lambda {|vm|
|
55
|
+
context = vm.context.get_context_by_ctrl(:procedure)
|
56
|
+
var_name = vm.parser.get_word()
|
57
|
+
|
58
|
+
unless /^@[a-z][a-z0-9_]*$/ =~ var_name
|
59
|
+
error "F10: Invalid val name #{var_name}"
|
60
|
+
end
|
61
|
+
|
62
|
+
var_symbol = XfOOrth::SymbolMap.add_entry(var_name)
|
63
|
+
vm << "#{'@'+(var_symbol.to_s)} = [vm.pop]; "
|
64
|
+
vm << "self.create_exclusive_method(#{var_name.inspect}, InstanceVarSpec, []); "
|
65
|
+
|
66
|
+
context.create_local_method(var_name, LocalSpec, [:immediate], &lambda {|nvm|
|
67
|
+
nvm << "vm.push(#{'@'+(var_symbol.to_s)}); "
|
68
|
+
})
|
69
|
+
}
|
70
|
+
|
35
71
|
#Handle the opening of a procedure literal.
|
36
72
|
def open_procedure_literal
|
37
73
|
suspend_execute_mode("vm.push(lambda {|vm, val=nil, idx=nil| ", :procedure)
|
@@ -44,6 +80,10 @@ module XfOOrth
|
|
44
80
|
context.create_local_method('var:', LocalSpec, [:immediate], &Local_Var_Action)
|
45
81
|
context.create_local_method('val:', LocalSpec, [:immediate], &Local_Val_Action)
|
46
82
|
|
83
|
+
#Support for procedure instance data.
|
84
|
+
context.create_local_method('var@:', LocalSpec, [:immediate], &PROC_VAR)
|
85
|
+
context.create_local_method('val@:', LocalSpec, [:immediate], &PROC_VAL)
|
86
|
+
|
47
87
|
context.create_local_method('}}', MacroSpec, [:macro, :end, "}); "])
|
48
88
|
end
|
49
89
|
|
data/lib/fOOrth/library.rb
CHANGED
@@ -13,6 +13,7 @@ require_relative 'library/ctrl_struct_library'
|
|
13
13
|
require_relative 'library/stdio_library'
|
14
14
|
require_relative 'library/numeric_library'
|
15
15
|
require_relative 'library/integer_library'
|
16
|
+
require_relative 'library/float_library'
|
16
17
|
require_relative 'library/rational_library'
|
17
18
|
require_relative 'library/complex_library'
|
18
19
|
require_relative 'library/string_library'
|
@@ -45,7 +45,7 @@ module XfOOrth
|
|
45
45
|
# [array] .map{{ ... }} [mapped_array]
|
46
46
|
Array.create_shared_method('.map{{', NosSpec, [], &lambda { |vm|
|
47
47
|
idx, block = 0, vm.pop
|
48
|
-
vm.push(self.map
|
48
|
+
vm.push(self.map{|val| block.call(vm, val, idx); idx += 1; vm.pop})
|
49
49
|
})
|
50
50
|
|
51
51
|
# [array] .select{{ ... }} [selected_array]
|
@@ -92,40 +92,60 @@ module XfOOrth
|
|
92
92
|
# [ v i a ] .[]! []; a[i]=v
|
93
93
|
Array.create_shared_method('.[]!', TosSpec, [], &lambda {|vm|
|
94
94
|
value, index = vm.popm(2)
|
95
|
-
self[Integer.foorth_coerce(index)] = value
|
95
|
+
self[Integer.foorth_coerce(index)] = value
|
96
96
|
})
|
97
97
|
|
98
98
|
# [ [ 1 2 3 ] ] .reverse [ [ 3 2 1 ] ]
|
99
99
|
Array.create_shared_method('.reverse', TosSpec, [],
|
100
|
-
&lambda {|vm| vm.push(self.reverse)
|
100
|
+
&lambda {|vm| vm.push(self.reverse) })
|
101
101
|
|
102
102
|
# [ [ 3 1 2 ] ] .sort [ [ 1 2 3 ] ]
|
103
103
|
Array.create_shared_method('.sort', TosSpec, [],
|
104
|
-
&lambda {|vm| vm.push(self.sort {|va,vb| va <=> va.foorth_coerce(vb)})
|
104
|
+
&lambda {|vm| vm.push(self.sort {|va,vb| va <=> va.foorth_coerce(vb)}) })
|
105
105
|
|
106
106
|
# [ [ 1 2 3 ] ] .shuffle [ [ x y z ] ]
|
107
107
|
Array.create_shared_method('.shuffle', TosSpec, [],
|
108
|
-
&lambda {|vm| vm.push(self.shuffle)
|
108
|
+
&lambda {|vm| vm.push(self.shuffle) })
|
109
109
|
|
110
110
|
# [ [ 3 1 2 ] ] .length [ 3 ]
|
111
111
|
Array.create_shared_method('.length', TosSpec, [],
|
112
|
-
&lambda {|vm| vm.push(self.length)
|
112
|
+
&lambda {|vm| vm.push(self.length) })
|
113
113
|
|
114
114
|
# [ an_array ] .empty? [ a_boolean ]
|
115
115
|
Array.create_shared_method('.empty?', TosSpec, [],
|
116
|
-
&lambda {|vm| vm.push(self.empty?)
|
116
|
+
&lambda {|vm| vm.push(self.empty?) })
|
117
|
+
|
118
|
+
# [ an_array ] .present? [ a_boolean ]
|
119
|
+
Array.create_shared_method('.present?', TosSpec, [],
|
120
|
+
&lambda {|vm| vm.push(!self.empty?) })
|
121
|
+
|
122
|
+
# [ an_array ] .clear! [ ]; The array contents are removed.
|
123
|
+
Array.create_shared_method('.clear!', TosSpec, [],
|
124
|
+
&lambda {|vm| self.clear})
|
117
125
|
|
118
126
|
# [ [ 3 1 2 ] n ] << [ [ 3 1 2 n ] ]
|
119
|
-
Array.create_shared_method('<<', NosSpec, [],
|
120
|
-
|
127
|
+
Array.create_shared_method('<<', NosSpec, [], &lambda {|vm|
|
128
|
+
begin
|
129
|
+
vm.poke(self << vm.peek)
|
130
|
+
rescue
|
131
|
+
vm.data_stack.pop
|
132
|
+
raise
|
133
|
+
end
|
134
|
+
})
|
121
135
|
|
122
136
|
# [ [ 3 1 2 ] n ] >> [ [ n 3 1 2 ] ]
|
123
|
-
Array.create_shared_method('>>', NosSpec, [],
|
124
|
-
|
137
|
+
Array.create_shared_method('>>', NosSpec, [], &lambda {|vm|
|
138
|
+
begin
|
139
|
+
vm.poke(self.insert(0, vm.peek))
|
140
|
+
rescue
|
141
|
+
vm.data_stack.pop
|
142
|
+
raise
|
143
|
+
end
|
144
|
+
})
|
125
145
|
|
126
146
|
# [[3 1 2] n] + [[3 1 2 n]]
|
127
147
|
Array.create_shared_method('+', NosSpec, [],
|
128
|
-
&lambda {|vm| vm.poke(self + vm.peek.in_array)
|
148
|
+
&lambda {|vm| vm.poke(self + vm.peek.in_array) })
|
129
149
|
|
130
150
|
|
131
151
|
# The LEFT group
|
@@ -134,7 +154,7 @@ module XfOOrth
|
|
134
154
|
begin
|
135
155
|
width = Integer.foorth_coerce(vm.peek)
|
136
156
|
error "F41: Invalid width: #{width} in .left" if width < 0
|
137
|
-
vm.poke(self.first(width))
|
157
|
+
vm.poke(self.first(width))
|
138
158
|
rescue
|
139
159
|
vm.data_stack.pop
|
140
160
|
raise
|
@@ -146,7 +166,7 @@ module XfOOrth
|
|
146
166
|
begin
|
147
167
|
width = Integer.foorth_coerce(vm.peek)
|
148
168
|
error "F41: Invalid width: #{width} in .-left" if width < 0
|
149
|
-
vm.poke(self[width..-1])
|
169
|
+
vm.poke(self[width..-1])
|
150
170
|
rescue
|
151
171
|
vm.data_stack.pop
|
152
172
|
raise
|
@@ -173,7 +193,7 @@ module XfOOrth
|
|
173
193
|
error "F41: Invalid width: #{width} in .^left" if width < 0
|
174
194
|
|
175
195
|
vm.poke(self[width..-1])
|
176
|
-
vm.push(self.first(width))
|
196
|
+
vm.push(self.first(width))
|
177
197
|
rescue
|
178
198
|
vm.data_stack.pop
|
179
199
|
raise
|
@@ -199,7 +219,7 @@ module XfOOrth
|
|
199
219
|
begin
|
200
220
|
width = Integer.foorth_coerce(vm.peek)
|
201
221
|
error "F41: Invalid width: #{width} in .-right" if width < 0
|
202
|
-
vm.poke(self[0...(0-width)])
|
222
|
+
vm.poke(self[0...(0-width)])
|
203
223
|
rescue
|
204
224
|
vm.data_stack.pop
|
205
225
|
raise
|
@@ -226,7 +246,7 @@ module XfOOrth
|
|
226
246
|
error "F41: Invalid width: #{width} in .^right" if width < 0
|
227
247
|
|
228
248
|
vm.poke(self[0...(0-width)])
|
229
|
-
vm.push(self.last(width))
|
249
|
+
vm.push(self.last(width))
|
230
250
|
rescue
|
231
251
|
vm.data_stack.pop
|
232
252
|
raise
|
@@ -358,7 +378,7 @@ module XfOOrth
|
|
358
378
|
#[ [ 1 2 3 ] ] .pop_left [ [ 2 3 ] 1 ]
|
359
379
|
Array.create_shared_method('.pop_left', TosSpec, [], &lambda{|vm|
|
360
380
|
error "F31: Array underflow error on .pop_left" if self.empty?
|
361
|
-
vm.push(self[1..-1])
|
381
|
+
vm.push(self[1..-1])
|
362
382
|
vm.push(self.first)
|
363
383
|
})
|
364
384
|
|
@@ -381,7 +401,7 @@ module XfOOrth
|
|
381
401
|
#[ [ 1 2 3 ] ] .peek_left [ [ 1 2 3 ] 1 ]
|
382
402
|
Array.create_shared_method('.peek_left', TosSpec, [], &lambda{|vm|
|
383
403
|
error "F31: Array underflow error on .peek_left" if self.empty?
|
384
|
-
vm.push(self)
|
404
|
+
vm.push(self)
|
385
405
|
vm.push(self.first)
|
386
406
|
})
|
387
407
|
|
@@ -396,7 +416,7 @@ module XfOOrth
|
|
396
416
|
#[ [ 1 2 3 ] ] .pop_right [ [ 1 2 ] 3 ]
|
397
417
|
Array.create_shared_method('.pop_right', TosSpec, [], &lambda{|vm|
|
398
418
|
error "F31: Array underflow error on .pop_right" if self.empty?
|
399
|
-
vm.push(self[0...-1])
|
419
|
+
vm.push(self[0...-1])
|
400
420
|
vm.push(self.last)
|
401
421
|
})
|
402
422
|
|
@@ -419,7 +439,7 @@ module XfOOrth
|
|
419
439
|
#[ [ 1 2 3 ] ] .peek_right [ [ 1 2 3 ] 3 ]
|
420
440
|
Array.create_shared_method('.peek_right', TosSpec, [], &lambda{|vm|
|
421
441
|
error "F31: Array underflow error on .peek_right" if self.empty?
|
422
|
-
vm.push(self)
|
442
|
+
vm.push(self)
|
423
443
|
vm.push(self.last)
|
424
444
|
})
|
425
445
|
|
@@ -9,7 +9,7 @@ module XfOOrth
|
|
9
9
|
|
10
10
|
#Execute a command to the shell.
|
11
11
|
VirtualMachine.create_shared_method(')"', MacroSpec,
|
12
|
-
[:macro, "system(vm.pop()); "])
|
12
|
+
[:macro, "system(vm.pop().to_s.chomp + \"\n\"); "])
|
13
13
|
|
14
14
|
#Enter debug mode. Warning! This is really verbose!
|
15
15
|
VirtualMachine.create_shared_method(')debug', MacroSpec,
|
@@ -1,266 +1,266 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
#* library/compile_library.rb - The compile support fOOrth library.
|
4
|
-
module XfOOrth
|
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
|
-
|
20
|
-
# COLON =======================================
|
21
|
-
|
22
|
-
#The classic colon definition that creates a word in the Virtual Machine class.
|
23
|
-
# [] : <name> <stuff omitted> ; []; creates <name> on the VirtualMachine
|
24
|
-
VirtualMachine.create_shared_method(':', VmSpec, [:immediate], &lambda {|vm|
|
25
|
-
if execute_mode?
|
26
|
-
verify_cast([VmSpec])
|
27
|
-
target = VirtualMachine
|
28
|
-
name = vm.parser.get_word()
|
29
|
-
type = VmSpec
|
30
|
-
XfOOrth.validate_type(vm, type, name)
|
31
|
-
|
32
|
-
begin_compile_mode(':', vm: vm, &lambda {|vm, src, tags|
|
33
|
-
vm.dbg_puts "#{name} => #{src}"
|
34
|
-
target.create_shared_method(name, type, tags, &eval(src))
|
35
|
-
})
|
36
|
-
|
37
|
-
XfOOrth.add_common_compiler_locals(vm, ':')
|
38
|
-
else
|
39
|
-
delayed_compile_mode(':')
|
40
|
-
end
|
41
|
-
})
|
42
|
-
|
43
|
-
# BANG COLON ==================================
|
44
|
-
|
45
|
-
#A special colon definition that creates an immediate word in the
|
46
|
-
#Virtual Machine class.
|
47
|
-
# [] !: <name> <stuff omitted> ; []; creates <name> on the VirtualMachine
|
48
|
-
VirtualMachine.create_shared_method('!:', VmSpec, [:immediate], &lambda {|vm|
|
49
|
-
if execute_mode?
|
50
|
-
verify_cast([VmSpec])
|
51
|
-
target = VirtualMachine
|
52
|
-
name = vm.parser.get_word()
|
53
|
-
type = VmSpec
|
54
|
-
XfOOrth.validate_type(vm, type, name)
|
55
|
-
|
56
|
-
begin_compile_mode('!:', vm: vm, tags: [:immediate], &lambda {|vm, src, tags|
|
57
|
-
vm.dbg_puts "(!) #{name} => #{src}"
|
58
|
-
target.create_shared_method(name, type, tags, &eval(src))
|
59
|
-
})
|
60
|
-
|
61
|
-
XfOOrth.add_common_compiler_locals(vm, '!:')
|
62
|
-
else
|
63
|
-
delayed_compile_mode('!:')
|
64
|
-
end
|
65
|
-
})
|
66
|
-
|
67
|
-
|
68
|
-
# DOT COLON ===================================
|
69
|
-
|
70
|
-
# [a_class] .: <name> <stuff omitted> ; []; creates <name> on a_class
|
71
|
-
VirtualMachine.create_shared_method('.:', VmSpec, [:immediate], &lambda {|vm|
|
72
|
-
if execute_mode?
|
73
|
-
target = vm.pop
|
74
|
-
error "F13: The target of .: must be a class" unless target.is_a?(Class)
|
75
|
-
|
76
|
-
name = vm.parser.get_word()
|
77
|
-
type = XfOOrth.name_to_type(name, self)
|
78
|
-
XfOOrth.validate_type(vm, type, name)
|
79
|
-
XfOOrth.validate_string_method(type, target, name)
|
80
|
-
|
81
|
-
begin_compile_mode('.:', cls: target, &lambda {|vm, src, tags|
|
82
|
-
vm.dbg_puts "#{target.foorth_name} #{name} => #{src}"
|
83
|
-
target.create_shared_method(name, type, tags, &eval(src))
|
84
|
-
})
|
85
|
-
|
86
|
-
XfOOrth.add_common_compiler_locals(vm, '.:')
|
87
|
-
XfOOrth.add_dot_colon_locals(vm.context)
|
88
|
-
else
|
89
|
-
delayed_compile_mode('.:')
|
90
|
-
end
|
91
|
-
})
|
92
|
-
|
93
|
-
#The procedure used for dot colon instance vars
|
94
|
-
DC_VAR = lambda {|vm|
|
95
|
-
var_name = vm.parser.get_word()
|
96
|
-
|
97
|
-
unless /^@[a-z][a-z0-9_]*$/ =~ var_name
|
98
|
-
error "F10: Invalid var name #{var_name}"
|
99
|
-
end
|
100
|
-
|
101
|
-
var_symbol = XfOOrth::SymbolMap.add_entry(var_name)
|
102
|
-
vm << "#{'@'+(var_symbol.to_s)} = [vm.pop]; "
|
103
|
-
|
104
|
-
vm.context.target_class.create_shared_method(var_name, InstanceVarSpec, [])
|
105
|
-
}
|
106
|
-
|
107
|
-
#The procedure used for dot colon instance vals
|
108
|
-
DC_VAL = lambda {|vm|
|
109
|
-
val_name = vm.parser.get_word()
|
110
|
-
|
111
|
-
unless /^@[a-z][a-z0-9_]*$/ =~ val_name
|
112
|
-
error "F10: Invalid val name #{val_name}"
|
113
|
-
end
|
114
|
-
|
115
|
-
val_symbol = XfOOrth::SymbolMap.add_entry(val_name)
|
116
|
-
vm << "#{'@'+(val_symbol.to_s)} = vm.pop; "
|
117
|
-
|
118
|
-
vm.context.target_class.create_shared_method(val_name, InstanceVarSpec, [])
|
119
|
-
}
|
120
|
-
|
121
|
-
# Add locals specific to a dot colon methods.
|
122
|
-
def self.add_dot_colon_locals(context)
|
123
|
-
context.create_local_method('var@:', LocalSpec, [:immediate], &DC_VAR)
|
124
|
-
context.create_local_method('val@:', LocalSpec, [:immediate], &DC_VAL)
|
125
|
-
end
|
126
|
-
|
127
|
-
|
128
|
-
# DOT COLON COLON =============================
|
129
|
-
|
130
|
-
# [an_object] .:: <name> <stuff omitted> ; []; creates <name> on an_object
|
131
|
-
VirtualMachine.create_shared_method('.::', VmSpec, [:immediate], &lambda {|vm|
|
132
|
-
if execute_mode?
|
133
|
-
target = vm.pop
|
134
|
-
name = vm.parser.get_word()
|
135
|
-
type = XfOOrth.name_to_type(name, self)
|
136
|
-
XfOOrth.validate_type(vm, type, name)
|
137
|
-
XfOOrth.validate_string_method(type, target.class, name)
|
138
|
-
|
139
|
-
begin_compile_mode('.::', obj: target, &lambda {|vm, src, tags|
|
140
|
-
vm.dbg_puts "#{target.foorth_name} #{name} => #{src}"
|
141
|
-
target.create_exclusive_method(name, type, tags, &eval(src))
|
142
|
-
})
|
143
|
-
|
144
|
-
XfOOrth.add_common_compiler_locals(vm, '.::')
|
145
|
-
XfOOrth.add_dot_colon_colon_locals(vm.context)
|
146
|
-
else
|
147
|
-
delayed_compile_mode('.::')
|
148
|
-
end
|
149
|
-
})
|
150
|
-
|
151
|
-
#The procedure used for dot colon colon instance vars
|
152
|
-
DCC_VAR = lambda { |vm|
|
153
|
-
var_name = vm.parser.get_word()
|
154
|
-
|
155
|
-
unless /^@[a-z][a-z0-9_]*$/ =~ var_name
|
156
|
-
error "F10: Invalid var name #{var_name}"
|
157
|
-
end
|
158
|
-
|
159
|
-
var_symbol = XfOOrth::SymbolMap.add_entry(var_name)
|
160
|
-
vm << "#{'@'+(var_symbol.to_s)} = [vm.pop]; "
|
161
|
-
|
162
|
-
vm.context.target_object.create_exclusive_method(var_name, InstanceVarSpec, [])
|
163
|
-
}
|
164
|
-
|
165
|
-
#The procedure used for dot colon colon instance vals
|
166
|
-
DCC_VAL = lambda {|vm|
|
167
|
-
val_name = vm.parser.get_word()
|
168
|
-
|
169
|
-
unless /^@[a-z][a-z0-9_]*$/ =~ val_name
|
170
|
-
error "F10: Invalid val name #{val_name}"
|
171
|
-
end
|
172
|
-
|
173
|
-
val_symbol = XfOOrth::SymbolMap.add_entry(val_name)
|
174
|
-
vm << "#{'@'+(val_symbol.to_s)} = vm.pop; "
|
175
|
-
|
176
|
-
vm.context.target_object.create_exclusive_method(val_name, InstanceVarSpec, [])
|
177
|
-
}
|
178
|
-
|
179
|
-
# Add locals specific to a dot colon colon methods.
|
180
|
-
def self.add_dot_colon_colon_locals(context)
|
181
|
-
context.create_local_method('var@:', LocalSpec, [:immediate], &DCC_VAR)
|
182
|
-
context.create_local_method('val@:', LocalSpec, [:immediate], &DCC_VAL)
|
183
|
-
end
|
184
|
-
|
185
|
-
# COMMON LOCAL DEFNS ==========================
|
186
|
-
|
187
|
-
#Set up the common local defns.
|
188
|
-
#<br>Parameters:
|
189
|
-
#* vm - The current virtual machine instance.
|
190
|
-
#* ctrl - A list of valid start controls.
|
191
|
-
#<br>Endemic Code Smells
|
192
|
-
#* :reek:TooManyStatements
|
193
|
-
def self.add_common_compiler_locals(vm, ctrl)
|
194
|
-
context = vm.context
|
195
|
-
|
196
|
-
#Support for local data.
|
197
|
-
context.create_local_method('var:', LocalSpec, [:immediate], &Local_Var_Action)
|
198
|
-
context.create_local_method('val:', LocalSpec, [:immediate], &Local_Val_Action)
|
199
|
-
|
200
|
-
#Support for super methods.
|
201
|
-
context.create_local_method('super', LocalSpec, [:immediate],
|
202
|
-
&lambda {|vm| vm << 'super(vm); ' })
|
203
|
-
|
204
|
-
#The standard end-compile adapter word: ';' semi-colon.
|
205
|
-
context.create_local_method(';', LocalSpec, [:immediate], &lambda {|vm|
|
206
|
-
vm.clear_cast
|
207
|
-
vm.end_compile_mode([ctrl])
|
208
|
-
})
|
209
|
-
end
|
210
|
-
|
211
|
-
#Determine the type of method being created. This only applies to non-vm
|
212
|
-
#methods as vm methods are all of type VmSpec.
|
213
|
-
#<br>Parameters
|
214
|
-
#*name - The name of the method to be created.
|
215
|
-
#<Returns>
|
216
|
-
#* The class of the spec to be used for this method.
|
217
|
-
def self.name_to_type(name, vm)
|
218
|
-
normal_spec = case name[0]
|
219
|
-
when '.'
|
220
|
-
TosSpec
|
221
|
-
|
222
|
-
when '~'
|
223
|
-
SelfSpec
|
224
|
-
|
225
|
-
when /[0-9A-Z$@#]/
|
226
|
-
error "F10: Invalid name for a method: #{name}"
|
227
|
-
|
228
|
-
else
|
229
|
-
NosSpec
|
230
|
-
end
|
231
|
-
|
232
|
-
vm.get_cast || normal_spec
|
233
|
-
end
|
234
|
-
|
235
|
-
#Compare the new method's spec against the specs of other methods of the
|
236
|
-
#same name. If no specs exist, create one on Object if the new spec is not
|
237
|
-
#a virtual machine spec.
|
238
|
-
#<br>Parameters
|
239
|
-
#*vm - The current virtual machine.
|
240
|
-
#*type - The class of the method to be created.
|
241
|
-
#*name - The name of the method to be created.
|
242
|
-
def self.validate_type(vm, type, name)
|
243
|
-
if (spec = vm.context.map_without_defaults(name))
|
244
|
-
if spec.class != type
|
245
|
-
error "F90: Spec type mismatch #{spec.foorth_name} vs #{type.foorth_name}"
|
246
|
-
end
|
247
|
-
else
|
248
|
-
Object.create_shared_method(name, type, [:stub]) unless type == VmSpec
|
249
|
-
end
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
#Check for the case where a string method is created on another class.
|
254
|
-
#<br>Parameters
|
255
|
-
#*type - The class of the method to be created.
|
256
|
-
#*target - The object that is to receive this method.
|
257
|
-
#*name - The name of the method to be created.
|
258
|
-
#<br>Endemic Code Smells
|
259
|
-
#* :reek:ControlParameter -- false positive
|
260
|
-
def self.validate_string_method(type, target, name)
|
261
|
-
if type == TosSpec && name[-1] == '"' && target != String
|
262
|
-
error "F13: Creating a string method #{name} on a #{target.foorth_name}"
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
end
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* library/compile_library.rb - The compile support fOOrth library.
|
4
|
+
module XfOOrth
|
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
|
+
|
20
|
+
# COLON =======================================
|
21
|
+
|
22
|
+
#The classic colon definition that creates a word in the Virtual Machine class.
|
23
|
+
# [] : <name> <stuff omitted> ; []; creates <name> on the VirtualMachine
|
24
|
+
VirtualMachine.create_shared_method(':', VmSpec, [:immediate], &lambda {|vm|
|
25
|
+
if execute_mode?
|
26
|
+
verify_cast([VmSpec])
|
27
|
+
target = VirtualMachine
|
28
|
+
name = vm.parser.get_word()
|
29
|
+
type = VmSpec
|
30
|
+
XfOOrth.validate_type(vm, type, name)
|
31
|
+
|
32
|
+
begin_compile_mode(':', vm: vm, &lambda {|vm, src, tags|
|
33
|
+
vm.dbg_puts "#{name} => #{src}"
|
34
|
+
target.create_shared_method(name, type, tags, &eval(src))
|
35
|
+
})
|
36
|
+
|
37
|
+
XfOOrth.add_common_compiler_locals(vm, ':')
|
38
|
+
else
|
39
|
+
delayed_compile_mode(':')
|
40
|
+
end
|
41
|
+
})
|
42
|
+
|
43
|
+
# BANG COLON ==================================
|
44
|
+
|
45
|
+
#A special colon definition that creates an immediate word in the
|
46
|
+
#Virtual Machine class.
|
47
|
+
# [] !: <name> <stuff omitted> ; []; creates <name> on the VirtualMachine
|
48
|
+
VirtualMachine.create_shared_method('!:', VmSpec, [:immediate], &lambda {|vm|
|
49
|
+
if execute_mode?
|
50
|
+
verify_cast([VmSpec])
|
51
|
+
target = VirtualMachine
|
52
|
+
name = vm.parser.get_word()
|
53
|
+
type = VmSpec
|
54
|
+
XfOOrth.validate_type(vm, type, name)
|
55
|
+
|
56
|
+
begin_compile_mode('!:', vm: vm, tags: [:immediate], &lambda {|vm, src, tags|
|
57
|
+
vm.dbg_puts "(!) #{name} => #{src}"
|
58
|
+
target.create_shared_method(name, type, tags, &eval(src))
|
59
|
+
})
|
60
|
+
|
61
|
+
XfOOrth.add_common_compiler_locals(vm, '!:')
|
62
|
+
else
|
63
|
+
delayed_compile_mode('!:')
|
64
|
+
end
|
65
|
+
})
|
66
|
+
|
67
|
+
|
68
|
+
# DOT COLON ===================================
|
69
|
+
|
70
|
+
# [a_class] .: <name> <stuff omitted> ; []; creates <name> on a_class
|
71
|
+
VirtualMachine.create_shared_method('.:', VmSpec, [:immediate], &lambda {|vm|
|
72
|
+
if execute_mode?
|
73
|
+
target = vm.pop
|
74
|
+
error "F13: The target of .: must be a class" unless target.is_a?(Class)
|
75
|
+
|
76
|
+
name = vm.parser.get_word()
|
77
|
+
type = XfOOrth.name_to_type(name, self)
|
78
|
+
XfOOrth.validate_type(vm, type, name)
|
79
|
+
XfOOrth.validate_string_method(type, target, name)
|
80
|
+
|
81
|
+
begin_compile_mode('.:', cls: target, &lambda {|vm, src, tags|
|
82
|
+
vm.dbg_puts "#{target.foorth_name} #{name} => #{src}"
|
83
|
+
target.create_shared_method(name, type, tags, &eval(src))
|
84
|
+
})
|
85
|
+
|
86
|
+
XfOOrth.add_common_compiler_locals(vm, '.:')
|
87
|
+
XfOOrth.add_dot_colon_locals(vm.context)
|
88
|
+
else
|
89
|
+
delayed_compile_mode('.:')
|
90
|
+
end
|
91
|
+
})
|
92
|
+
|
93
|
+
#The procedure used for dot colon instance vars
|
94
|
+
DC_VAR = lambda {|vm|
|
95
|
+
var_name = vm.parser.get_word()
|
96
|
+
|
97
|
+
unless /^@[a-z][a-z0-9_]*$/ =~ var_name
|
98
|
+
error "F10: Invalid var name #{var_name}"
|
99
|
+
end
|
100
|
+
|
101
|
+
var_symbol = XfOOrth::SymbolMap.add_entry(var_name)
|
102
|
+
vm << "#{'@'+(var_symbol.to_s)} = [vm.pop]; "
|
103
|
+
|
104
|
+
vm.context.target_class.create_shared_method(var_name, InstanceVarSpec, [])
|
105
|
+
}
|
106
|
+
|
107
|
+
#The procedure used for dot colon instance vals
|
108
|
+
DC_VAL = lambda {|vm|
|
109
|
+
val_name = vm.parser.get_word()
|
110
|
+
|
111
|
+
unless /^@[a-z][a-z0-9_]*$/ =~ val_name
|
112
|
+
error "F10: Invalid val name #{val_name}"
|
113
|
+
end
|
114
|
+
|
115
|
+
val_symbol = XfOOrth::SymbolMap.add_entry(val_name)
|
116
|
+
vm << "#{'@'+(val_symbol.to_s)} = vm.pop; "
|
117
|
+
|
118
|
+
vm.context.target_class.create_shared_method(val_name, InstanceVarSpec, [])
|
119
|
+
}
|
120
|
+
|
121
|
+
# Add locals specific to a dot colon methods.
|
122
|
+
def self.add_dot_colon_locals(context)
|
123
|
+
context.create_local_method('var@:', LocalSpec, [:immediate], &DC_VAR)
|
124
|
+
context.create_local_method('val@:', LocalSpec, [:immediate], &DC_VAL)
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# DOT COLON COLON =============================
|
129
|
+
|
130
|
+
# [an_object] .:: <name> <stuff omitted> ; []; creates <name> on an_object
|
131
|
+
VirtualMachine.create_shared_method('.::', VmSpec, [:immediate], &lambda {|vm|
|
132
|
+
if execute_mode?
|
133
|
+
target = vm.pop
|
134
|
+
name = vm.parser.get_word()
|
135
|
+
type = XfOOrth.name_to_type(name, self)
|
136
|
+
XfOOrth.validate_type(vm, type, name)
|
137
|
+
XfOOrth.validate_string_method(type, target.class, name)
|
138
|
+
|
139
|
+
begin_compile_mode('.::', obj: target, &lambda {|vm, src, tags|
|
140
|
+
vm.dbg_puts "#{target.foorth_name} #{name} => #{src}"
|
141
|
+
target.create_exclusive_method(name, type, tags, &eval(src))
|
142
|
+
})
|
143
|
+
|
144
|
+
XfOOrth.add_common_compiler_locals(vm, '.::')
|
145
|
+
XfOOrth.add_dot_colon_colon_locals(vm.context)
|
146
|
+
else
|
147
|
+
delayed_compile_mode('.::')
|
148
|
+
end
|
149
|
+
})
|
150
|
+
|
151
|
+
#The procedure used for dot colon colon instance vars
|
152
|
+
DCC_VAR = lambda { |vm|
|
153
|
+
var_name = vm.parser.get_word()
|
154
|
+
|
155
|
+
unless /^@[a-z][a-z0-9_]*$/ =~ var_name
|
156
|
+
error "F10: Invalid var name #{var_name}"
|
157
|
+
end
|
158
|
+
|
159
|
+
var_symbol = XfOOrth::SymbolMap.add_entry(var_name)
|
160
|
+
vm << "#{'@'+(var_symbol.to_s)} = [vm.pop]; "
|
161
|
+
|
162
|
+
vm.context.target_object.create_exclusive_method(var_name, InstanceVarSpec, [])
|
163
|
+
}
|
164
|
+
|
165
|
+
#The procedure used for dot colon colon instance vals
|
166
|
+
DCC_VAL = lambda {|vm|
|
167
|
+
val_name = vm.parser.get_word()
|
168
|
+
|
169
|
+
unless /^@[a-z][a-z0-9_]*$/ =~ val_name
|
170
|
+
error "F10: Invalid val name #{val_name}"
|
171
|
+
end
|
172
|
+
|
173
|
+
val_symbol = XfOOrth::SymbolMap.add_entry(val_name)
|
174
|
+
vm << "#{'@'+(val_symbol.to_s)} = vm.pop; "
|
175
|
+
|
176
|
+
vm.context.target_object.create_exclusive_method(val_name, InstanceVarSpec, [])
|
177
|
+
}
|
178
|
+
|
179
|
+
# Add locals specific to a dot colon colon methods.
|
180
|
+
def self.add_dot_colon_colon_locals(context)
|
181
|
+
context.create_local_method('var@:', LocalSpec, [:immediate], &DCC_VAR)
|
182
|
+
context.create_local_method('val@:', LocalSpec, [:immediate], &DCC_VAL)
|
183
|
+
end
|
184
|
+
|
185
|
+
# COMMON LOCAL DEFNS ==========================
|
186
|
+
|
187
|
+
#Set up the common local defns.
|
188
|
+
#<br>Parameters:
|
189
|
+
#* vm - The current virtual machine instance.
|
190
|
+
#* ctrl - A list of valid start controls.
|
191
|
+
#<br>Endemic Code Smells
|
192
|
+
#* :reek:TooManyStatements
|
193
|
+
def self.add_common_compiler_locals(vm, ctrl)
|
194
|
+
context = vm.context
|
195
|
+
|
196
|
+
#Support for local data.
|
197
|
+
context.create_local_method('var:', LocalSpec, [:immediate], &Local_Var_Action)
|
198
|
+
context.create_local_method('val:', LocalSpec, [:immediate], &Local_Val_Action)
|
199
|
+
|
200
|
+
#Support for super methods.
|
201
|
+
context.create_local_method('super', LocalSpec, [:immediate],
|
202
|
+
&lambda {|vm| vm << 'super(vm); ' })
|
203
|
+
|
204
|
+
#The standard end-compile adapter word: ';' semi-colon.
|
205
|
+
context.create_local_method(';', LocalSpec, [:immediate], &lambda {|vm|
|
206
|
+
vm.clear_cast
|
207
|
+
vm.end_compile_mode([ctrl])
|
208
|
+
})
|
209
|
+
end
|
210
|
+
|
211
|
+
#Determine the type of method being created. This only applies to non-vm
|
212
|
+
#methods as vm methods are all of type VmSpec.
|
213
|
+
#<br>Parameters
|
214
|
+
#*name - The name of the method to be created.
|
215
|
+
#<Returns>
|
216
|
+
#* The class of the spec to be used for this method.
|
217
|
+
def self.name_to_type(name, vm)
|
218
|
+
normal_spec = case name[0]
|
219
|
+
when '.'
|
220
|
+
TosSpec
|
221
|
+
|
222
|
+
when '~'
|
223
|
+
SelfSpec
|
224
|
+
|
225
|
+
when /[0-9A-Z$@#]/
|
226
|
+
error "F10: Invalid name for a method: #{name}"
|
227
|
+
|
228
|
+
else
|
229
|
+
NosSpec
|
230
|
+
end
|
231
|
+
|
232
|
+
vm.get_cast || normal_spec
|
233
|
+
end
|
234
|
+
|
235
|
+
#Compare the new method's spec against the specs of other methods of the
|
236
|
+
#same name. If no specs exist, create one on Object if the new spec is not
|
237
|
+
#a virtual machine spec.
|
238
|
+
#<br>Parameters
|
239
|
+
#*vm - The current virtual machine.
|
240
|
+
#*type - The class of the method to be created.
|
241
|
+
#*name - The name of the method to be created.
|
242
|
+
def self.validate_type(vm, type, name)
|
243
|
+
if (spec = vm.context.map_without_defaults(name))
|
244
|
+
if spec.class != type
|
245
|
+
error "F90: Spec type mismatch #{spec.foorth_name} vs #{type.foorth_name}"
|
246
|
+
end
|
247
|
+
else
|
248
|
+
Object.create_shared_method(name, type, [:stub]) unless type == VmSpec
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
#Check for the case where a string method is created on another class.
|
254
|
+
#<br>Parameters
|
255
|
+
#*type - The class of the method to be created.
|
256
|
+
#*target - The object that is to receive this method.
|
257
|
+
#*name - The name of the method to be created.
|
258
|
+
#<br>Endemic Code Smells
|
259
|
+
#* :reek:ControlParameter -- false positive
|
260
|
+
def self.validate_string_method(type, target, name)
|
261
|
+
if type == TosSpec && name[-1] == '"' && target != String
|
262
|
+
error "F13: Creating a string method #{name} on a #{target.foorth_name}"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|