2011-12-13 95 views
1

我使用Whittle gem來解析模板語言,並希望匹配規則中未包含的任何內容。我非常瞭解其他模板引擎,但這更像是一次學術活動而不是生產案例。Whittle解析器條件規則激活

我遇到的問題是,分析器忽略的:id以上:raw的優先級,並仍在等待對{{:raw標籤。

如何判斷是否不允許在表達式中應用:raw規則,並且僅在表達式中應用:spc規則?

解析器代碼

class Parser < Whittle::Parser 
    # Skip whitespaces (should not apply in :raw) 
    rule(:spc => /\s+/).skip! 

    # Various delimiters 
    rule("{{")^4 
    rule("}}")^4 
    rule("{%")^4 
    rule("%}")^4 
    rule("|")^4 
    rule("end")^4 

    # Defines an id (very large match) 
    rule(:id => /[a-zA-Z_.$<>=!:]+(\((\w+|\s+|,|")+\))?/)^2 

    # inline tag 
    rule(:inline) do |r| 
     r["{{", :inline_head, "}}"].as { |_,id,_| Tag::Inline.new(id) } 
    end 
    # inline tag contents 
    # allows "|" chaining 
    rule(:inline_head) do |r| 
     r[:inline_head, "|", :id].as { |head, _, id| head << id } 
     r[:id].as { |id| [id] } 
     r[].as { [] } 
    end 

    # block tag 
    rule(:block) do |r| 
     r["{%", :block_head, "%}", :all, "{%", "end", "%}"].as { |_,head,_,tags,_,_,_| 
      Tag::Block.new(head, tags) 
     } 
    end 
    # block tag heading 
    # separates all the keywords 
    rule(:block_head) do |r| 
     r[:block_head, :id].as { |head, id| head << id } 
     #r[:id].as { |id| [id] } 
     r[].as { [] } 
    end 

    # one rule to match them all 
    rule(:all) do |r| 
     r[:all,:inline].as { |all, inline| all << inline } 
     r[:all, :block].as { |all, block| all << block } 
     r[:all, :raw].as { |all, raw| all << raw } 
     r[].as { [] } 
    end 

    # the everything but tags rule 
    rule(:raw => /[^\{\}%]+/).as { |text| Tag::Raw.new(text) }^1 

    # starting rule 
    start(:all) 
end 

和輸入文本將是與輸出是由對象表示的抽象語法樹(它們被簡單地散列狀物體現在)。

<html> 
    <head> 
     <title>{{ title|capitalize }}</title> 
    </head> 
    <body> 
     <div class="news"> 
      {% for news in articles %} 
       {{ news.title }} 
       {{ news.body | limit(100) }} 
       {{ tags | join(",", name) }} 
      {% end %} 
     </div> 
    </body> 
</html> 

回答

1

我不相信運營商優先支持在這裏扮演一個角色。運算符優先級僅在解決像foo = 6 + 7這樣的表達式中的歧義時發揮作用,其中表達式可以被解釋爲(foo = 6) + 7foo = (6 + 7)。給予非運營商優先權並不能達到任何目的。

也許不清楚解析器實際上做了什麼。它基本上循環重複,匹配所有終端規則針對您的輸入字符串。對於它找到的那個,它需要最長的一個,並試圖找到一個適合當前狀態的規則。所以解析器總是會找到你的空白並丟棄它,因爲這是你語法中的第一條規則。

我想你實際上不想跳過空格,因爲它在語法上很重要。你想把它包含在允許它的規則中;這將使你的語法更加冗長,但是(當前)是不可避免的。

所以:raw變成像下面這樣,吞噬了所有的空格和非語法標記成一個字符串:

rule(:raw => /[^\s\{\}%]+/) 

rule(:text) do |r| 
    r[:text, :raw].as { |text, raw| text << raw } 
    r[:text, :spc].as { |text, spc| text << spc } 
    r[:spc] 
    r[:raw] 
end 

然後在你的:all規則,把文本到您的AST的一部分(你可以實際上也是在上面的規則中做到這一點,但我對你的類定義一無所知)。

rule(:all) do |r| 
    # ... snip ... 
    r[:all, :text].as { |all, text| all << Tag::Raw.new(text) } 
    # ... snip ... 
end 

我一直在思考如何提供搭配不同狀態中的不同令牌的能力,但我寫警惕法/柔性的克隆,我覺得這是太混亂了,所以我試圖想出一種方法,它使用塊互相嵌套規則來傳達狀態如何相互關聯;儘管創建一個容易理解的DSL並不容易;)我也想提供一個可選的DSL來隱藏用於重複的算法;也許提供一種轉換成LR解析器的PEG層。這仍然是一個(非常)年輕的項目;)

+0

哇作者自己!我正在儘快嘗試。謝謝 –

+0

經過一些調整,解決了我所有的問題。偉大的項目! –