fOOrth 0.6.10 → 0.6.11

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