1

I would like to be able to parse some Tcl code where arguments are not surrounded by strings.

Consider this tcl code:

proc foo {name} {
  puts "Foo --> $name"
}    

foo bar

For those unfamiliar with Tcl, foo is the method name and bar is the argument (quotes are optional in Tcl).

The previous code will output:

Foo --> bar

Is it possible to parse exactly the same input using ruby (bar remains unquoted)?

The equivalent ruby code is:

def foo(name)
  puts "Foo --> #{name}"
end

tcl = <<-TCL.gsub(/^\s+/, "").chop
  foo bar
TCL
instance_eval(tcl)

Of course that fails when it reaches bar since it's expected it to be quoted.

I've tried tinkering with method_missing

def method_missing(meth, *args)
    puts meth.to_s + " --> args.to_s
end

but it parses in reverse order:

to_hash --> []
bar --> []
foo --> [nil]

Does anyone have a clean solution to this type of problem. I'd like to avoid tokenizing the strings since reading the data in by calling a method requires minimal work compared to lexical analysis. But if I'm trying to do something that's not possible, I'd like to know. Thanks.

elmt
  • 1,604
  • 14
  • 24

2 Answers2

1

It's doesn't work for you because .puts method returns nil instead of string:

irb(main):003:0> puts "42"
42
=> nil

I really don't know why to_hash appears in this method_missing but it works:

def foo(name)
  puts "Foo --> #{name}"
end

def method_missing(meth, *args)
     meth.to_s unless meth.to_s  == "to_hash"
end

tcl = <<-TCL.gsub(/^\s+/, "").chop
  foo bar
TCL

instance_eval(tcl)

=> Foo --> bar
Vasiliy Ermolovich
  • 24,459
  • 5
  • 79
  • 77
  • Dang, I was so close at getting it. Thanks for input. Can anyone chime in on where `to_hash` is coming from? – elmt Apr 21 '11 at 00:38
  • Tcl doesn't use anything like `nil`; the concept is split between the empty string (the result of Tcl's `puts`) and non-existance of variables. – Donal Fellows Apr 21 '11 at 01:15
1

This is an implementation that try to make the syntax near to the TCL syntax.

class TCL
  class << self
    alias run instance_eval
    def proc(n, &b)
      self.class.__send__(:define_method, n, &b)
    end
    def method_missing(n, *a, &b)
      n.to_s
    end
  end
end

TCL.run do

  proc(:foo) { |name|
    puts "Foo --> #{name}"
  }

  foo bar

end

# prints Foo --> bar
Guilherme Bernal
  • 8,183
  • 25
  • 43
  • I had to change your braces in the block to do/end due to precedence. And then I still was getting a bug with the `define_method` which I couldn't figure out. Want to elaborate a little more? – elmt Apr 21 '11 at 00:32
  • @elmt, I made changes and now I tested. There were many things wrong. Now it works. – Guilherme Bernal Apr 21 '11 at 01:12