我试图为Handlebars编写一个Ruby / Parslet解析器,但是我遇到了{{ else }}
关键字。
为了解释那些不使用Handlebars的人的简要说明,if / else以这种方式编写:
{{#if my_condition}}
show something
{{else}}
show something else
{{/if}}
但它变得棘手,因为内联和帮助程序可以使用相同的语法,例如:
Name: {{ name }}
Address: {{ address }}
所以我首先制定了一条规则来识别替代品:
rule(:identifier) { match['a-zA-Z0-9_'].repeat(1) }
rule(:path) { identifier >> (dot >> identifier).repeat }
rule(:replacement) { docurly >> space? >> path.as(:item) >> space? >> dccurly}
匹配{{name}}
或{{people.name}}
之类的内容。
问题当然是也与{{ else }}
块匹配。以下是我编写规则以匹配if / else块的方法:
rule(:else_kw) {str('else')}
rule(:if_block) {
docurly >>
str('#if') >>
space >>
path.as(:condition) >>
space? >>
dccurly >>
block.as(:if_body) >>
(
docurly >>
else_kw >>
dccurly >>
block.as(:else_body)
).maybe >>
docurly >>
str('/if') >>
dccurly
}
(注意:docurly是{{
,dccurly是}}
,阻止可以是或多或少的任何东西)
所以我现在需要重写`identifier``rule,以便它匹配任何单词,但不是"否则"。
提前致谢, 文森特
答案 0 :(得分:0)
执行此操作的一种方法是使用absent?
前瞻修饰符。如果原子或规则foo.absent?
此时不匹配,foo
将匹配,并且不会消耗任何输入。
有了这个,您可以将identifier
规则写为
rule(:identifier)
{ (else_kw >> dccurly).absent? >> match['a-zA-Z0-9_'].repeat(1) }
答案 1 :(得分:0)
这取决于您尝试匹配的语法。如果您不在{{if}}
{{/if}}
对内,应将{{else}}
视为有效标识符还是语法错误?如果您有a.else.b
的路径应该有效吗?
如果a.else.b
无效,您可以执行以下操作:
rule(:identifier)
{ (else_kw).absent? >> match['a-zA-Z0-9_'].repeat(1) | else_kw >> match['a-zA-Z0-9_'].repeat(1) }
接受除" else"之外的所有字符串,通过说"任何不以else开头的字符串,或以else开头的字符串,至少还有一个字符"。
注意:这让我思考"为什么else
如此特别?"我们应该在这里排除所有关键字吗?
如果a.else.b
有效,则无法在标识符级别将其排除。然后更准确地说,path
无法"else"
。
如果你说:
rule(:path) { else_kw.absent? >> (identifier >> (dot >> identifier).repeat) }
这将排除以' else'开头的任何标识符,例如" elsewise.option"
所以.. absent?
还需要匹配一些东西来显示你的块已经结束。
rule(:path) { (else_kw >> dccurly).absent? >> (identifier >> (dot >> identifier).repeat) }
这里的问题是,我们现在正在将路径与一个dccurly
结束的想法联系起来,而else
并非严格正确(并且不会处理空格)。那么"路径"不适合放这些东西。
如果我们尝试停止匹配rule(:replacement) { docurly >> space? >> (else_kw >> space? >> dccurly).absent? >> path.as(:item) >> space? >> dccurly}
的替换,那会更容易。
else
这会阻止替换匹配elsewise.something
,但会允许else.something
或rule(:replacement) { docurly >> space? >> (else_kw >> (space | dccurly | dot)).absent? >> path.as(:item) >> space? >> dccurly}
。
如果你不想要" else.something"那么你需要这样的东西:
{{1}}
所以"否则" "其他&#34。和"否则}}"都被阻止了。