HDLRuby 2.4.29 → 2.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/HDLRuby/drivers/xcd.rb +79 -0
  3. data/lib/HDLRuby/drivers/xcd/dummy.xcd +4 -0
  4. data/lib/HDLRuby/hdr_samples/adder.rb +1 -1
  5. data/lib/HDLRuby/hdr_samples/adder_bench.rb +1 -1
  6. data/lib/HDLRuby/hdr_samples/adder_gen.rb +1 -1
  7. data/lib/HDLRuby/hdr_samples/constant_in_function.rb +27 -0
  8. data/lib/HDLRuby/hdr_samples/dff_properties.rb +19 -0
  9. data/lib/HDLRuby/hdr_samples/dff_unit.rb +54 -0
  10. data/lib/HDLRuby/hdr_samples/huge_rom.rb +25 -0
  11. data/lib/HDLRuby/hdr_samples/logic_bench.rb +21 -0
  12. data/lib/HDLRuby/hdr_samples/mei8_bench.rb +1 -1
  13. data/lib/HDLRuby/hdr_samples/multi_timed_bench.rb +54 -0
  14. data/lib/HDLRuby/hdr_samples/music.rb +79 -0
  15. data/lib/HDLRuby/hdr_samples/named_sub.rb +42 -0
  16. data/lib/HDLRuby/hdr_samples/rom.rb +16 -0
  17. data/lib/HDLRuby/hdr_samples/with_function_generator.rb +25 -0
  18. data/lib/HDLRuby/hdrcc.rb +162 -26
  19. data/lib/HDLRuby/hruby_decorator.rb +250 -0
  20. data/lib/HDLRuby/hruby_high.rb +468 -91
  21. data/lib/HDLRuby/hruby_low.rb +913 -45
  22. data/lib/HDLRuby/hruby_low2c.rb +122 -168
  23. data/lib/HDLRuby/hruby_low2hdr.rb +738 -0
  24. data/lib/HDLRuby/hruby_low2high.rb +331 -549
  25. data/lib/HDLRuby/hruby_low2vhd.rb +39 -2
  26. data/lib/HDLRuby/hruby_low_bool2select.rb +29 -0
  27. data/lib/HDLRuby/hruby_low_casts_without_expression.rb +27 -0
  28. data/lib/HDLRuby/hruby_low_fix_types.rb +25 -0
  29. data/lib/HDLRuby/hruby_low_mutable.rb +70 -0
  30. data/lib/HDLRuby/hruby_low_resolve.rb +28 -0
  31. data/lib/HDLRuby/hruby_low_without_connection.rb +6 -3
  32. data/lib/HDLRuby/hruby_low_without_namespace.rb +7 -4
  33. data/lib/HDLRuby/hruby_low_without_select.rb +13 -0
  34. data/lib/HDLRuby/hruby_tools.rb +11 -1
  35. data/lib/HDLRuby/hruby_verilog.rb +1577 -1709
  36. data/lib/HDLRuby/sim/hruby_sim.h +29 -3
  37. data/lib/HDLRuby/sim/hruby_sim_calc.c +63 -6
  38. data/lib/HDLRuby/sim/hruby_sim_core.c +24 -9
  39. data/lib/HDLRuby/sim/hruby_sim_vcd.c +5 -1
  40. data/lib/HDLRuby/sim/hruby_sim_vizualize.c +22 -6
  41. data/lib/HDLRuby/std/fixpoint.rb +9 -0
  42. data/lib/HDLRuby/std/function_generator.rb +139 -0
  43. data/lib/HDLRuby/std/hruby_unit.rb +75 -0
  44. data/lib/HDLRuby/template_expander.rb +61 -0
  45. data/lib/HDLRuby/version.rb +1 -1
  46. metadata +21 -5
@@ -14,3 +14,19 @@ system :rom4_8 do
14
14
  data1 <= content1[addr]
15
15
  data2 <= content2[addr]
16
16
  end
17
+
18
+
19
+
20
+ system :test_rom do
21
+ [2..0].inner :addr
22
+ [7..0].inner :data0,:data1,:data2
23
+
24
+ rom4_8(:my_rom).(addr,data0,data1,data2)
25
+
26
+ timed do
27
+ 8.times do |i|
28
+ addr <= i
29
+ !10.ns
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ require 'std/function_generator.rb'
2
+
3
+ include HDLRuby::High::Std
4
+
5
+ # System for testing the function generator standard library.
6
+ system :with_function_generator do
7
+ # signed[8].inner :x
8
+ # signed[32].inner :y
9
+ bit[8].inner :x
10
+ signed[8].inner :y
11
+
12
+ # function_generator(Math.method(:sin).to_proc,
13
+ # signed[8],signed[32],4,-Math::PI..Math::PI,-2..2).
14
+ function_generator(Math.method(:sin).to_proc,
15
+ bit[8],signed[8],4,-Math::PI..Math::PI,-2..2).
16
+ (:my_sin).(x,y)
17
+
18
+ timed do
19
+ # (-128..127).each do |i|
20
+ (0..255).each do |i|
21
+ x <= i
22
+ !10.ns
23
+ end
24
+ end
25
+ end
data/lib/HDLRuby/hdrcc.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
3
  require 'fileutils'
4
+ require 'tempfile'
4
5
  require 'HDLRuby'
5
6
  require 'HDLRuby/hruby_check.rb'
6
7
  # require 'ripper'
7
- require 'HDLRuby/hruby_low2high'
8
+ require 'HDLRuby/hruby_low2hdr'
8
9
  require 'HDLRuby/hruby_low2c'
9
10
  require 'HDLRuby/hruby_low2vhd'
10
11
  require 'HDLRuby/hruby_low_fix_types'
@@ -50,12 +51,21 @@ module HDLRuby
50
51
  # The required files.
51
52
  attr_reader :requires
52
53
 
53
- # Creates a new loader for a +top_system+ system in file +top_file+
54
+ # Creates a new loader for a +top_system+ system in file +top_file_name+
54
55
  # from directory +dir+ with generic parameters +params+.
56
+ #
57
+ # NOTE: +top_file+ can either be a file or a file name.
55
58
  def initialize(top_system,top_file,dir,*params)
56
59
  # Sets the top and the looking directory.
57
60
  @top_system = top_system.to_s
58
- @top_file = top_file.to_s
61
+ # @top_file can either be a file or a string giving the file name.
62
+ if top_file.respond_to?(:path) then
63
+ @top_file = top_file
64
+ @top_file_name = top_file.path
65
+ else
66
+ @top_file = nil
67
+ @top_file_name = top_file.to_s
68
+ end
59
69
  @dir = dir.to_s
60
70
  @params = params
61
71
 
@@ -82,31 +92,48 @@ module HDLRuby
82
92
  end
83
93
 
84
94
  # Loads a single +file+.
95
+ #
96
+ # NOTE: +file+ can either be a file or a file name.
85
97
  def read(file)
86
98
  # Resolve the file.
87
- found = File.join(@dir,file)
88
- unless File.exist?(found) then
89
- founds = Dir.glob(@std_dirs.map {|path| File.join(path,file) })
90
- if founds.empty? then
91
- # No standard file with this name, this is an error.
92
- raise "Unknown required file: #{file}."
93
- else
94
- # A standard file is found, skip it since it does not
95
- # need to be read.
96
- # puts "Standard files: #{founds}"
97
- return false
99
+ if file.respond_to?(:read) then
100
+ found = file
101
+ else
102
+ found = File.join(@dir,file)
103
+ unless File.exist?(found) then
104
+ founds = Dir.glob(@std_dirs.map do |path|
105
+ File.join(path,file)
106
+ end)
107
+ if founds.empty? then
108
+ # No standard file with this name, this is an error.
109
+ raise "Unknown required file: #{file}."
110
+ else
111
+ # A standard file is found, skip it since it does not
112
+ # need to be read.
113
+ # puts "Standard files: #{founds}"
114
+ return false
115
+ end
98
116
  end
99
117
  end
100
118
  # Load the file.
101
- # @texts << File.read(File.join(@dir,file) )
102
119
  @texts << File.read(found)
103
- # @checks << Checker.new(@texts[-1],file)
104
- @checks << Checker.new(@texts[-1],found)
120
+ if found.respond_to?(:path) then
121
+ @checks << Checker.new(@texts[-1],found.path)
122
+ else
123
+ @checks << Checker.new(@texts[-1])
124
+ end
105
125
  return true
106
126
  end
107
127
 
108
128
  # Loads all the files from +file+.
109
- def read_all(file = @top_file)
129
+ def read_all(file = nil)
130
+ unless file then
131
+ if @top_file then
132
+ file = @top_file
133
+ else
134
+ file = @top_file_name
135
+ end
136
+ end
110
137
  # puts "read_all with file=#{file}"
111
138
  # Read the file
112
139
  # read(file)
@@ -174,7 +201,7 @@ module HDLRuby
174
201
  # Maybe it is a parse error, look for it.
175
202
  bind = TOPLEVEL_BINDING.clone
176
203
  eval("require 'HDLRuby'\n\nconfigure_high\n\n",bind)
177
- eval(@texts[0],bind,@top_file,1)
204
+ eval(@texts[0],bind,@top_file_name,1)
178
205
  # No parse error found.
179
206
  raise "Cannot find a top system." unless @top_system
180
207
  end
@@ -183,7 +210,7 @@ module HDLRuby
183
210
  bind = TOPLEVEL_BINDING.clone
184
211
  eval("require 'HDLRuby'\n\nconfigure_high\n\n",bind)
185
212
  # Process it.
186
- eval(@texts[0],bind,@top_file,1)
213
+ eval(@texts[0],bind,@top_file_name,1)
187
214
  # Get the resulting instance
188
215
  if @params.empty? then
189
216
  # There is no generic parameter
@@ -225,6 +252,20 @@ module HDLRuby
225
252
 
226
253
  end
227
254
 
255
+ # Locate an executable from cmd.
256
+ def which(cmd)
257
+ # Get the possible exetensions (for windows case).
258
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
259
+ # Look for the command within the executable paths.
260
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
261
+ exts.each do |ext|
262
+ exe = File.join(path, "#{cmd}#{ext}")
263
+ return exe if File.executable?(exe) && !File.directory?(exe)
264
+ end
265
+ end
266
+ nil
267
+ end
268
+
228
269
 
229
270
 
230
271
  if __FILE__ == $0 then
@@ -310,14 +351,24 @@ $optparse = OptionParser.new do |opts|
310
351
  opts.on("-D", "--debug","Set the HDLRuby debug mode") do |d|
311
352
  $options[:debug] = d
312
353
  end
354
+ opts.on("-T","--test t0,t1,t2","Compile the unit tests named t0,t1,...") do |t|
355
+ $options[:test] = t
356
+ end
357
+ opts.on("--testall","Compile all the available unit tests.") do |t|
358
+ $options[:testall] = t
359
+ end
313
360
  opts.on("-t", "--top system", "Specify the top system to process") do|t|
314
361
  $options[:top] = t
315
362
  end
316
363
  opts.on("-p", "--param x,y,z", "Specify the generic parameters") do |p|
317
364
  $options[:param] = p
318
365
  end
319
- opts.on("--version", "Print the version number, then exit") do
320
- puts "hdrcc: HDLRuby #{HDLRuby::VERSION} compiler"
366
+ opts.on("--dump","Dump all the properties to yaml files") do |v|
367
+ $options[:dump] = v
368
+ $options[:multiple] = v
369
+ end
370
+ opts.on("--version", "Shows the version of HDLRuby.") do |v|
371
+ puts VERSION
321
372
  exit
322
373
  end
323
374
  # opts.on_tail("-h", "--help", "Show this message") do
@@ -370,6 +421,28 @@ if $input == nil then
370
421
  exit
371
422
  end
372
423
 
424
+ if ($options[:test] || $options[:testall]) then
425
+ $top = "__test__"
426
+ tests = $options[:test]
427
+ if tests then
428
+ tests = tests.to_s.split(",")
429
+ tests.map! {|test| ":\"#{test}\"" }
430
+ tests = ", #{tests.join(",")}"
431
+ else
432
+ tests = ""
433
+ end
434
+ # Generate the unit test file.
435
+ $test_file = Tempfile.new('tester.rb',Dir.getwd)
436
+ $test_file.write("require 'std/hruby_unit.rb'\nrequire_relative '#{$input}'\n\n" +
437
+ "HDLRuby::Unit.test(:\"#{$top}\"#{tests})\n")
438
+ # $test_file.rewind
439
+ # puts $test_file.read
440
+ # exit
441
+ $test_file.rewind
442
+ # It is the new input file.
443
+ $input = $test_file
444
+ end
445
+
373
446
  # Open the output.
374
447
  if $output then
375
448
  if $options[:multiple] then
@@ -382,7 +455,7 @@ if $output then
382
455
  $output = File.open($output,"w")
383
456
  end
384
457
  else
385
- if $option[:multiple] then
458
+ if $options[:multiple] then
386
459
  raise "Need a target directory in multiple files generation mode."
387
460
  end
388
461
  $output = $stdout
@@ -394,6 +467,12 @@ $loader = HDRLoad.new($top,$input,$options[:directory].to_s,*$params)
394
467
  $loader.read_all
395
468
  $loader.check_all
396
469
 
470
+ # Remove the test file if any, it is not needed any longer.
471
+ if $test_file then
472
+ $test_file.close
473
+ $test_file.unlink
474
+ end
475
+
397
476
  if $options[:syntax] then
398
477
  if $options[:multiple] then
399
478
  raise "Multiple files generation mode not supported for syntax tree output."
@@ -414,6 +493,24 @@ end
414
493
  # Get the top systemT.
415
494
  $top_system = $top_instance.to_low.systemT
416
495
 
496
+
497
+ # Apply the pre drivers if any.
498
+ Hdecorator.each_with_property(:pre_driver) do |obj, value|
499
+ unless value.is_a?(Array) && value.size == 2 then
500
+ raise "pre_driver requires a driver file name command name."
501
+ end
502
+ # Load the driver.
503
+ require_relative(value[0].to_s)
504
+ # Ensure obj is the low version.
505
+ if obj.properties.key?(:high2low) then
506
+ # obj is high, get the corresponding low.
507
+ obj = obj.properties[:high2low][0]
508
+ end
509
+ # Execute it.
510
+ send(value[1].to_sym,obj,*value[2..-1])
511
+ end
512
+
513
+
417
514
  # Gather the non-HDLRuby code.
418
515
  $non_hdlruby = []
419
516
  $top_system.each_systemT_deep do |systemT|
@@ -455,7 +552,7 @@ elsif $options[:hdr] then
455
552
  # $output << systemT.to_high
456
553
  # end
457
554
  # $output << $top_instance.to_low.systemT.to_high
458
- $output << $top_system.to_high
555
+ $output << $top_system.to_hdr
459
556
  elsif $options[:clang] then
460
557
  # top_system = $top_instance.to_low.systemT
461
558
  # top_system = $top_system
@@ -572,8 +669,19 @@ elsif $options[:clang] then
572
669
  end
573
670
  end
574
671
  Dir.chdir($output)
575
- # Kernel.system("make -s")
576
- Kernel.system("cc -o3 -o hruby_simulator *.c -lpthread")
672
+ # Find the compiler.
673
+ cc_cmd = which('cc')
674
+ unless cc_cmd then
675
+ cc_cmd = which('gcc')
676
+ end
677
+ unless cc_cmd then
678
+ raise "Could not find any compiler, please compile by hand as follows:\n" +
679
+ " In folder #{$output} execute:\n" +
680
+ " <my compiler> -o hruby_simulator *.c -lpthread\n" +
681
+ " Then execute:\n hruby_simulator"
682
+ end
683
+ # Use it.
684
+ Kernel.system("#{cc_cmd} -o3 -o hruby_simulator *.c -lpthread")
577
685
  Kernel.system("./hruby_simulator")
578
686
  end
579
687
  elsif $options[:verilog] then
@@ -678,3 +786,31 @@ elsif $options[:vhdl] then
678
786
  end
679
787
  end
680
788
  end
789
+
790
+ # Apply the post drivers if any.
791
+ Hdecorator.each_with_property(:post_driver) do |obj, value|
792
+ # Load the driver.
793
+ require_relative(value[0].to_s)
794
+ # Execute it.
795
+ send(value[1].to_sym,obj,$output)
796
+ end
797
+
798
+ # Dump the properties
799
+ if $options[:dump] then
800
+ # Decorate with the parent ids.
801
+ Hdecorator.decorate_parent_id
802
+
803
+ # Generate the directory for the properties
804
+ property_dir = $output + "/properties"
805
+ unless File.directory?(property_dir)
806
+ FileUtils.mkdir_p(property_dir)
807
+ end
808
+
809
+ # Dump to one file per key
810
+ Properties.each_key do |key|
811
+ File.open(property_dir + "/#{key}.yaml", "w") do |f|
812
+ Hdecorator.dump(key,f)
813
+ end
814
+ end
815
+
816
+ end
@@ -0,0 +1,250 @@
1
+ require 'yaml'
2
+ require 'set'
3
+
4
+ module HDLRuby
5
+
6
+ ##
7
+ # Library for describing a decorator used for adding properties to
8
+ # HDLRuby objects that are persistent and can be used for back annotation
9
+ ########################################################################
10
+
11
+ ##
12
+ # Gives a decorator the HDLRuby object.
13
+ module Hdecorator
14
+ # The decorator requires that each HDLRuby object has a uniq
15
+ # persistent id
16
+
17
+ # The id
18
+ attr_reader :hdr_id
19
+
20
+ # The id to object table
21
+ @@id_map = {}
22
+
23
+ # Generate the ID
24
+ @@id_gen = 0
25
+
26
+ # Ensures the ID is generated when object is initialized
27
+ def self.included(base) # built-in Ruby hook for modules
28
+ base.class_eval do
29
+ original_method = instance_method(:initialize)
30
+ define_method(:initialize) do |*args, &block|
31
+ original_method.bind(self).call(*args, &block)
32
+ # Generate the id.
33
+ @hdr_id = @@id_gen
34
+ @@id_gen += 1
35
+ # Update the id to object table
36
+ @@id_map[@hdr_id] = self
37
+ end
38
+ end
39
+ end
40
+
41
+ # Get an object by id.
42
+ def self.get(id)
43
+ return @@id_map[id]
44
+ end
45
+
46
+ # Iterate over all the id with their object.
47
+ #
48
+ # Returns an enumerator if no ruby block is given.
49
+ #
50
+ # NOTE: converts the hash to an array to allow on-the-fly modification.
51
+ def self.each(&ruby_block)
52
+ # No ruby block? Return an enumerator.
53
+ return to_enum(:each) unless ruby_block
54
+ # A ruby block? Apply it on each object.
55
+ @@id_map.to_a.each(&ruby_block)
56
+ end
57
+
58
+ # The decorator also need to add properties to the HDLRuby objects.
59
+
60
+ # Access the set of properties
61
+ def properties
62
+ # Create the properties if not present.
63
+ unless @properties then
64
+ @properties = Properties.new(self)
65
+ end
66
+ return @properties
67
+ end
68
+
69
+ # Iterate over all the objects from +top+ with +prop+ property.
70
+ #
71
+ # Returns an enumerator if no ruby block is given.
72
+ # NOTE: if +top+ is not given, iterate over all the objects.
73
+ def self.each_with_property(prop, top = nil, &ruby_block)
74
+ # No ruby block? Return an enumerator.
75
+ return to_enum(:each_with_property) unless ruby_block
76
+ # A ruby block? Apply the ruby_block...
77
+ if (top) then
78
+ # A top... on each object from it.
79
+ top.each_deep do |obj|
80
+ if (obj.properties.key?(prop)) then
81
+ ruby_block.call(obj, *obj.properties[prop])
82
+ end
83
+ end
84
+ else
85
+ # No top... on all the objects.
86
+ self.each do |id,obj|
87
+ if (obj.properties.key?(prop)) then
88
+ ruby_block.call(obj, *obj.properties[prop])
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ # # Access the set of properties and the inherited properties from
95
+ # # the high objects.
96
+ # def all_properties
97
+ # high_id = self.properties[:low2high]
98
+ # if high_id && high_id >= 0 then
99
+ # return properties.merge(Hdecorator.get(high_id))
100
+ # else
101
+ # return properties.clone
102
+ # end
103
+ # end
104
+
105
+ # Saves properties +key+ of all the object associated with
106
+ # their id to +target+.
107
+ def self.dump(key, target = "")
108
+ # Build the table to dump
109
+ tbl = {}
110
+ self.each do |id,obj|
111
+ value = obj.properties[key]
112
+ if value.any? then
113
+ tbl[id] = value
114
+ end
115
+ end
116
+ # Dump the table.
117
+ target << YAML.dump(tbl)
118
+ return target
119
+ end
120
+
121
+ # Loads properties to +key+ for all objects from +source+.
122
+ def self.load(source,key)
123
+ # Load the id to property table.
124
+ tbl = YAML.load(source)
125
+ # Adds the property of each object according to tbl
126
+ tbl.each do |id,value|
127
+ @@id_map[id].properties[key] = value
128
+ end
129
+ end
130
+
131
+ # Some predefined properties to set.
132
+
133
+ def self.decorate_parent_id
134
+ @@id_map.each do |id, obj|
135
+ parent = obj.parent
136
+ if parent then
137
+ obj.properties[:parent_id] = obj.parent.hdr_id
138
+ else
139
+ obj.properties[:parent_id] = -1
140
+ end
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+
147
+ ## A HDLRuby set of properties
148
+ class Properties
149
+
150
+ # The set of all the property keys
151
+ @@property_keys = Set.new
152
+
153
+ # The HDLRuby object owning of the set of properties
154
+ attr_reader :owner
155
+
156
+ # Create a new set of properties and attach it to HDLRuby object
157
+ # +owner+.
158
+ def initialize(owner)
159
+ # Attach the owner.
160
+ @owner = owner
161
+ # Create the set.
162
+ @content = {}
163
+ end
164
+
165
+ # Clones the properties: also clone the contents.
166
+ def clone
167
+ result = Properties.new(owner)
168
+ @contents.each do |k,vals|
169
+ vals.each { |v| result[k] = v }
170
+ end
171
+ return result
172
+ end
173
+
174
+ # Create a new set of properties by merging with +prop+
175
+ def merge(prop)
176
+ result = self.clone
177
+ prop.each do |k,vals|
178
+ vals.each { |v| result[k] = v }
179
+ end
180
+ return result
181
+ end
182
+
183
+ # Tells if +key+ is present.
184
+ def key?(key)
185
+ @content.key?(key)
186
+ end
187
+
188
+ # Add a property
189
+ def []=(key,value)
190
+ @@property_keys << key
191
+ # Add an entry if not present.
192
+ @content[key] = [] unless @content.key?(key)
193
+ # Add the value to the entry.
194
+ @content[key] << value
195
+ end
196
+
197
+ # Get a property
198
+ def [](key)
199
+ return @content[key]
200
+ end
201
+
202
+ # Iterate over each value associated with +key+.
203
+ def each_with_key(key,&ruby_block)
204
+ return unless @content.key?(key)
205
+ @content[key].each(&ruby_block)
206
+ end
207
+
208
+ # Iterate over the properties of the current set.
209
+ #
210
+ # Returns an enumerator if no ruby block is given.
211
+ def each(&ruby_block)
212
+ # No ruby block? Return an enumerator.
213
+ return to_enum(:each) unless ruby_block
214
+ # A ruby block? Apply it on each input signal instance.
215
+ @content.each(&ruby_block)
216
+ end
217
+
218
+ # Iterator over all the property keys
219
+ #
220
+ # Returns an enumerator if no ruby block is given.
221
+ def self.each_key(&ruby_block)
222
+ # No ruby block? Return an enumerator.
223
+ return to_enum(:each_key) unless ruby_block
224
+ # A ruby block? Apply it on each input signal instance.
225
+ @@property_keys.each(&ruby_block)
226
+ end
227
+
228
+ # # Iterate over the property set of all the objects from current owner.
229
+ # #
230
+ # # Returns an enumerator if no ruby block is given.
231
+ # def each_properties(&ruby_block)
232
+ # # No ruby block? Return an enumerator.
233
+ # return to_enum(:each_properties) unless ruby_block
234
+ # # A ruby block? Apply it.
235
+ # # On current property set
236
+ # ruby_block.call(self)
237
+ # # And on the properties set of sub objects of the owner.
238
+ # self.owner.instance_variables.each do |var|
239
+ # obj = owner.instance_variable_get(var)
240
+ # if (obj.is_a?(Hproperties)) then
241
+ # # obj has properties, recurse on them.
242
+ # obj.properties.each_properties(&ruby_block)
243
+ # end
244
+ # end
245
+ # end
246
+
247
+ end
248
+
249
+
250
+ end