So, do you think your task ends up being basically writing a parser for
the ruby language? That's obviously a somewhat hard problem. :)
What does the "DSL" you are embedding these 'blocks' in look like?
There may be an easier way of approaching the parsing, knowing the
context. Or you may be able to alter your "DSL" to make the parsing
easier, but more unambiguously parseable things in the rest of the DSL.
But there's a reason that many ruby libraries use plain old ruby code as
a "DSL" -- you already have a ruby parser, ruby itself, and don't need
to write one.
Jonathan
On 5/18/2011 5:25 PM, Joe Hellerstein wrote:
> The plot thickens when we consider handling "do..end" blocks in Ruby.
>
> To extend our curly-brace-balancing scheme, we'd need to balance all uses of
> "end" inside a Ruby block. That is fine -- there's only a small set of Ruby
> expressions that end in "end" and I can enumerate their starting words (if,
> unless, while, until, case, for, class, module, def.)
>
> The problem is the way Ruby allows the use of "if"/"unless" at the end of a
> Ruby statement without a matching "end". To do my "end" balancing right and
> handle these cases, I'd need to recognize Ruby statements so I could figure
> out that the "if"/"unless" logic was a suffix. Blech.
>
> Any further thoughts?
>
> J
>
>
> On May 18, 2011, at 12:39 PM, Joe Hellerstein wrote:
>
>> Nicely done and thank you! As long as I don't mind enforcing
>> delimiter-balancing in the thing I'm gobbling up (and in this case I don't),
>> your trick works.
>>
>> Fixed example below for future ref.
>>
>> Joe
>>
>> require 'rubygems'
>> require 'parslet'
>>
>> class Mini< Parslet::Parser
>> rule(:lbrace) { str('{')>> space? }
>> rule(:rbrace) { str('}')>> space? }
>> rule(:word) { match['a-z'].repeat(1)>> space? }
>> rule(:space) { match('\s').repeat(1) }
>> rule(:space?) { space.maybe }
>> rule(:block) { lbrace>> (content | block).repeat(1)>> rbrace }
>> rule(:content) { match['^{}'] }
>>
>> rule(:stmt) { (block.as(:block) | word).repeat }
>> root :stmt
>> end
>>
>> def parse(str)
>> mini = Mini.new
>> print "Parsing #{str}: "
>>
>> p mini.parse(str)
>> rescue Parslet::ParseFailed => error
>> puts error, mini.root.error_tree
>> end
>>
>> parse "joe is here {hi {it's} joe}"
>>
>>
>>
>> On May 18, 2011, at 11:47 AM, Jonathan Rochkind wrote:
>>
>>> Ie, something like this maybe (just typing it into the email client, dont'
>>> know if it even compiles, let alone works, but may give you some ideas).
>>>
>>> rule :block do
>>> str('{')<< content.maybe<< block.maybe<< content.maybe<< str('}'
>>> end
>>>
>>> rule :content do
>>> match['^{}].repeat
>>> end
>>>
>>> The trick I think might work is the recursive call to block that will allow
>>> a (balanced) block to be inside a block, but otherwise we dont' allow '{'
>>> or '}'. Except I actually have no idea if this will actually work, heh,
>>> but some ideas to work with.
>>>