[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

DSL implementation question

tender flake

4/4/2008 3:49:00 AM

Hello,

I'm trying to write a simple DSL to define memory maps of hardware
devices.
Something like:

cfg_block "top_device", :depth => 16 do
reg "ctrl_reg", :offset => 0, :mode => "RW"
reg "status_reg", :offset => 1, :mode => "R"
end

I've implemented something but I am not satisfied with it.

The problem I have is about scoping. How can I make the reg command
in my
small DSL exemple above execute in the context of the object created
by the
cfg_block method? The way I implemented this is by passing the
created
cfg_block object as a block parameter and then passing it to every reg
command. E.g:

cfg_block "top_device", :depth => 16 do |__dev__|
reg "ctrl_reg", __dev__, :offset...
end

I consider this redundant since I'd like the context to provide the
cfg_block reference. I tried multiple things but haven't figured it
out
using blocks. Is there a way to get rid of __dev__?

Suggestions would be greatly appreciated. Thanks in advance.

My implementation follows below:

module Register_defs

class Cfg_Block < Hash

def initialize(name, params={})
self[:name] = name
self[:regs] = {}
self.merge!(params)
end

def add_reg(reg)
self[:regs][reg[:name]] = reg
end

end

class Register < Hash
def initialize(name, cfg_block, params={})
self[:name] = name
self.merge!(params)
cfg_block.add_reg(self)
end

end

def cfg_block(name, params={})
cfg_block = Cfg_Block.new(name, params)
yield(cfg_block)
cfg_block
end

def reg(name, cfg_block, params={})
reg = Register.new(name, cfg_block, params)
yield(reg)
reg
end

end

include Register_defs

modules = cfg_block "top_block" do |cb|

reg "reg1", cb, :addr => 0 do
# do something
end

reg "reg2", cb, :addr => 0 do
# do something else
end

end

p modules





2 Answers

Jeremy McAnally

4/4/2008 4:15:00 AM

0

You'd do something like this:

def cfg_block(name, params={}, &block)
# Other stuff
my_obj.instance_eval &block
end

...where my_obj is the object that you were previously yielding. :)

--Jeremy

On Thu, Apr 3, 2008 at 11:49 PM, tender flake
<tenderflake@mailinator.com> wrote:
> Hello,
>
> I'm trying to write a simple DSL to define memory maps of hardware
> devices.
> Something like:
>
> cfg_block "top_device", :depth => 16 do
> reg "ctrl_reg", :offset => 0, :mode => "RW"
> reg "status_reg", :offset => 1, :mode => "R"
> end
>
> I've implemented something but I am not satisfied with it.
>
> The problem I have is about scoping. How can I make the reg command
> in my
> small DSL exemple above execute in the context of the object created
> by the
> cfg_block method? The way I implemented this is by passing the
> created
> cfg_block object as a block parameter and then passing it to every reg
> command. E.g:
>
> cfg_block "top_device", :depth => 16 do |__dev__|
> reg "ctrl_reg", __dev__, :offset...
> end
>
> I consider this redundant since I'd like the context to provide the
> cfg_block reference. I tried multiple things but haven't figured it
> out
> using blocks. Is there a way to get rid of __dev__?
>
> Suggestions would be greatly appreciated. Thanks in advance.
>
> My implementation follows below:
>
> module Register_defs
>
> class Cfg_Block < Hash
>
> def initialize(name, params={})
> self[:name] = name
> self[:regs] = {}
> self.merge!(params)
> end
>
> def add_reg(reg)
> self[:regs][reg[:name]] = reg
> end
>
> end
>
> class Register < Hash
> def initialize(name, cfg_block, params={})
> self[:name] = name
> self.merge!(params)
> cfg_block.add_reg(self)
> end
>
> end
>
> def cfg_block(name, params={})
> cfg_block = Cfg_Block.new(name, params)
> yield(cfg_block)
> cfg_block
> end
>
> def reg(name, cfg_block, params={})
> reg = Register.new(name, cfg_block, params)
> yield(reg)
> reg
> end
>
> end
>
> include Register_defs
>
> modules = cfg_block "top_block" do |cb|
>
> reg "reg1", cb, :addr => 0 do
> # do something
> end
>
> reg "reg2", cb, :addr => 0 do
> # do something else
> end
>
> end
>
> p modules
>
>
>
>
>
>



--
http://jeremymca...
http:...

Read my books:
Ruby in Practice (http://manning.com...)
My free Ruby e-book (http://humblelittlerub...)

Or, my blogs:
http://mrneig...
http://rubyinpr...

Sean O'Halpin

4/4/2008 11:54:00 PM

0

On Fri, Apr 4, 2008 at 4:49 AM, tender flake <tenderflake@mailinator.com> wrote:
> Hello,
>
> I'm trying to write a simple DSL to define memory maps of hardware
> devices.
> Something like:
>
> cfg_block "top_device", :depth => 16 do
> reg "ctrl_reg", :offset => 0, :mode => "RW"
> reg "status_reg", :offset => 1, :mode => "R"
> end
>
> I've implemented something but I am not satisfied with it.

Hi,

I wrote Doodle to do this kind of thing (gem install doodle):

require 'doodle'
require 'pp'

class Register < Doodle::Base
has :name
has :offset
has :mode
end

class ConfigBlock < Doodle::Base
has :name
has :depth
has :registers, :init => [], :collect => { :reg => Register }
end

def cfg_block(*args, &block)
ConfigBlock(*args, &block)
end

modules = cfg_block "top_device", :depth => 16 do
reg "ctrl_reg", :offset => 0, :mode => "RW"
reg "status_reg", :offset => 1, :mode => "R"
end

pp modules

Output:

#<ConfigBlock:0xb7b9b5c4
@depth=16,
@name="top_device",
@registers=
[#<Register:0xb7b9582c @mode="RW", @name="ctrl_reg", @offset=0>,
#<Register:0xb7b8ecfc @mode="R", @name="status_reg", @offset=1>]>

If you wanted validation on the parameters, you could do something like:

require 'doodle'

class Named < Doodle::Base
has :name, :kind => String do
from Symbol do |sym|
sym.to_s
end
end
end

class Register < Named
has :offset, :kind => Integer do
must "be in range 0-15" do |offset|
(0..15).include?(offset)
end
end
has :mode, :kind => String do |mode|
valid_modes = %w[R W RW]
must "be one of #{valid_modes.join(', ')}" do |mode|
valid_modes.include?(mode)
end
end
end

class ConfigBlock < Named
has :depth, :kind => Integer
has :registers, :init => [], :collect => { :reg => Register }
end

def cfg_block(*args, &block)
ConfigBlock(*args, &block)
end

modules = cfg_block :top_device, :depth => 16 do
reg :ctrl_reg, :offset => 0, :mode => "RW"
reg :status_reg, :offset => 1, :mode => "WR"
end

#=> memory-map2.rb:35: mode must be one of R, W, RW - got String("WR")
(Doodle::ValidationError)

Regards,
Sean