Understood.  My DSL is Bloom, http://bloom-lang.net  We already did a 
"plain-old-ruby" implementation via significant metaprogramming in the "bud" 
prototype. I'm trying to put a cleaner parser front-end on it to support 
program rewriting in a better way than our current Ruby AST rewrites.

Anyhow, for the time being I think it's sufficient for me to introduce a new 
pair of bracketing keywords into the DSL as a workaround.

Thanks for the help!
Joe



On May 19, 2011, at 10:51 AM, Jonathan Rochkind wrote:

> For instance, if your 'dsl' was YAML but a value could look like a 'ruby 
> block'... then you would just need to parse YAML, your parser wouldn't 
> have to care that a value happened to look like a 'ruby block', that's 
> just payload like any other.  And once parsed, you could investigate the 
> payloads with by using imperative code, or with regexps,  to see which 
> ones looked like 'a ruby block', if it mattered to pull those out.
> 
> And of course there's already a YAML parser built into ruby, you 
> wouldn't need to write one.
> 
> If your "dsl" is not YAML but is your own home-built thing, the same 
> basic approach could be tried, of structuring it so your parser doesn't 
> actually have to recognize a 'block', it's just a payload in the larger 
> structure.
> 
> One way or another, I suspect you want to re-think the nature of your 
> "dsl" to be easier to work with.
> 
> Ironically, however, Parslet itself demonstrates the utility of using 
> Plain Old Ruby for your "dsl" -- note how a parslet grammar is just ruby 
> code, it's not parsed by anything other than ruby itself.  Again, 
> there's a reason many ruby libraries take this approach, writing your 
> own parser for a 'dsl' instead can be a lot of cost for little benefit 
> compared to just structuring your API such that plain old ruby is a 
> decent "dsl".
> 
> On 5/19/2011 10:31 AM, Jonathan Rochkind wrote:
>> 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.
>>>>> 

Reply via email to