Eric Mahurin wrote:

> Hello everybody,
> 
> I hope I'm not intruding, but I think I found
> something you'll like.  I think I finally found the
> holy grail I was looking for in a language - the
> ability to easily write a readable grammar (BNF-like)
> directly in the target langauge.  I attached a
> syntax.rb that defines all the classes needed and
> generic expression evaluator example.

This is good stuff and I will have a deeper look at it soon as I still 
need a good parsing foundation for that Joy implementation I want to do 
in Ruby.

I have done something more or less similar as well in the past: I did an 
OOP API for regular expressions which looks like this:

> irc_re = Regexp::English.new do
>   crlf = literal("\r\n")
>   space = literal(" ")
> 
>   nospecial = outside("\x00", "\r", "\n", " ", ":")
>   middle = nospecial + (literal(":") | nospecial).zero_or_more
>   trailing = (inside(":", " ") | nospecial).zero_or_more
> 
>   shortname = (letter | digit) +
>               inside(letter, digit, "-").zero_or_more +
>               (letter | digit).zero_or_more
>   hostname = shortname + (literal(".") + shortname).zero_or_more
>   user = outside("\x00", "\r", "\n", " ", "@").multiple
>   special = inside("[]\\`_^{|}")
>   # The spec limits nick names to 9 characters. We don't.
>   nickname = (letter | special) +
>              inside(letter, digit, special, "-").zero_or_more
> 
>   prefix = hostname | (nickname +
>              ((literal("!") + user).optional +
>               literal("@") + hostname).optional)
>   command = letter.multiple | digit * 3
>   # This isn't what the spec does. It seems to enforce a maximum of 14 params.
>   trailing_param = literal(":") + trailing
>   params = trailing_param |
>            (middle + (space + middle).zero_or_more.minimal +
>             (space + trailing_param).optional)
>            
>   message = (literal(":") + prefix.capture(:prefix) + space).optional +
>             command.capture(:command) +
>             (space + params.capture(:params)).optional +
>             crlf
>   whole_string(message)
> end

It does not really solve the problems of using regular expressions as 
parsers however.

What I wonder about is how you solved the problem of recursive rules and 
ones that refer to each other. Is this possible?

> Here would be a few more niceties for this syntax
> stuff if Ruby had these:
> 
> - Ranges without a end (and/or begin?).  If
> syntactically this is a problem, nil could be used
> instead.  Of course you'd need to raise an exception
> when you did a bad thing with them (i.e. to_a).  For
> example:
>     (b..)===x  ->  x>=b
>     (b..).each {}  -> infinite loop starting with b
>     (..e)===x  ->  x<=e
>     (..) ===x  ->  true

While this is no official solution it still works (but see note):

Math::Infinity = Math::PosInfinity = (1.0 / 0.0)
Math::NegInfinity = -Math::PosInfinity

And it might be nice to add a bit of syntax sugar as well:

def Range.from(range_start)
   range_start .. Math::Infinity
end

def Range.to(range_end)
   Math::NegInfinity .. range_end
end

def Range.full() Range.from(Math::NegInfinity) end

Range.from(b) === x   # x >= b
Range.from(b).each {} # infinite loop, be careful with .to_a and so on
Range.to(e)   === x   # x <= e, can not iterate
Range.full    === x   # always true, can not iterate

Note: This is not guaranteed to work portably as there might be machines 
which don't have infinity float values or which don't yield them when 
dividing by zero. One way around this is to create custom objects which 
define <=> and (optionally) the mathematical operators correctly.

> - Allow an object to be used like a method.  This
> would require a new operator - I'll call it: ().  An
> object followed by {} or do/end would also be treated
> the same (that's the part I really want).  With this,
> I could replace the "qualify" method with this thing. 
> Here is an example:
>     class Test;
>       def ()(*args,&code); ... end
>     end
>     a = Test.new
>     a { ... }

Something like this is experimentally being introduced in the CVS builds 
of Ruby 1.9. I'm not sure if it is general enough to make your example 
work, though.

> p.s. I just learned Ruby last week!  I really love
> this language!  It's got the best of Perl, C++, and
> Java.  My main complaint is a syntactic one - the use
> of "end" instead of {}.  That's probably the influence
> of Python.

Welcome and thanks for sharing and producing Good Stuff.