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.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +13 -2
  3. data/fOOrth.gemspec +2 -2
  4. data/integration/array_lib_tests.rb +10 -0
  5. data/integration/exception_lib_tests.rb +4 -0
  6. data/integration/hash_lib_tests.rb +9 -0
  7. data/integration/numeric_lib_tests.rb +326 -321
  8. data/integration/procedure_lib_tests.rb +16 -0
  9. data/integration/queue_lib_tests.rb +2 -1
  10. data/integration/stack_lib_tests.rb +2 -1
  11. data/integration/string_lib_tests.rb +11 -0
  12. data/integration/thread_lib_tests.rb +11 -8
  13. data/lib/fOOrth/compiler/context.rb +64 -64
  14. data/lib/fOOrth/compiler/context/locals.rb +34 -34
  15. data/lib/fOOrth/compiler/context/map_name.rb +85 -85
  16. data/lib/fOOrth/compiler/context/tags.rb +60 -48
  17. data/lib/fOOrth/compiler/process/procedure.rb +40 -0
  18. data/lib/fOOrth/library.rb +1 -0
  19. data/lib/fOOrth/library/array_library.rb +41 -21
  20. data/lib/fOOrth/library/command_library.rb +1 -1
  21. data/lib/fOOrth/library/compile_library.rb +266 -266
  22. data/lib/fOOrth/library/complex_library.rb +82 -80
  23. data/lib/fOOrth/library/float_library.rb +37 -0
  24. data/lib/fOOrth/library/hash_library.rb +14 -6
  25. data/lib/fOOrth/library/mutex_library.rb +4 -2
  26. data/lib/fOOrth/library/numeric_library.rb +359 -380
  27. data/lib/fOOrth/library/procedure_library.rb +69 -65
  28. data/lib/fOOrth/library/queue_library.rb +6 -1
  29. data/lib/fOOrth/library/rational_library.rb +89 -89
  30. data/lib/fOOrth/library/stack_library.rb +6 -1
  31. data/lib/fOOrth/library/string_library.rb +18 -6
  32. data/lib/fOOrth/monkey_patch/exceptions.rb +2 -6
  33. data/lib/fOOrth/version.rb +1 -1
  34. data/tests/compiler/context_tests.rb +188 -177
  35. data/tests/compiler/file_source_tests.rb +130 -130
  36. data/tests/compiler/parser_tests.rb +4 -4
  37. data/tests/compiler/string_source_tests.rb +4 -4
  38. data/tests/core_tests.rb +138 -138
  39. data/tests/monkey_patch/complex_test.rb +24 -24
  40. data/tests/monkey_patch/object_test.rb +49 -49
  41. data/tests/monkey_patch/string_test.rb +61 -61
  42. 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
- #Validate a current data value.
30
- #<br>Parameters:
31
- #* symbol - The symbol of the value to be tested.
32
- #* expect - An array of valid values.
33
- #<br>Note:
34
- #* Throws a XfOOrthError if the value is not valid.
35
- #* To check for no value, use [nil] for expect.
36
- #* Returns true to facilitate testing only.
37
- def check_set(symbol, expect)
38
- current = self[symbol]
39
-
40
- unless expect.include?(current)
41
- error "F10: Found a #{current.inspect}, excpected #{expect}"
42
- end
43
-
44
- true
45
- end
46
-
47
- end
48
- end
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
 
@@ -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 { |val| block.call(vm, val, idx); idx += 1; vm.pop})
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
- &lambda {|vm| vm.poke(self << vm.peek); })
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
- &lambda {|vm| vm.poke(self.insert(0, vm.peek)); })
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