我正在为带有插值的名称-值参数的字符串编写解析器,例如:'This sentence #{x: 2, y: (2 + 5) + 3} has stuff in it.'
参数值是代码,它有自己的一组解析规则。
这是我的解析器的一个版本,简化为仅允许将基本算术作为代码:
require 'parslet'
require 'ap'
class TestParser < Parslet::Parser
rule :integer do match('[0-9]').repeat(1).as :integer end
rule :space do match('[\s\\n]').repeat(1) end
rule :parens do str('(') >> code >> str(')') end
rule :operand do integer | parens end
rule :addition do (operand.as(:left) >> space >> str('+') >> space >> operand.as(:right)).as :addition end
rule :code do addition | operand end
rule :name do match('[a-z]').repeat 1 end
rule :argument do name.as(:name) >> str(':') >> space >> code.as(:value) end
rule :arguments do argument >> (str(',') >> space >> argument).repeat end
rule :interpolation do str('#{') >> arguments.as(:arguments) >> str('}') end
rule :text do (interpolation.absent? >> any).repeat(1).as(:text) end
rule :segments do (interpolation | text).repeat end
root :segments
end
string = 'This sentence #{x: 2, y: (2 + 5) + 3} has stuff in it.'
ap TestParser.new.parse(string), index: false
由于代码有自己的解析规则(以确保语法有效),参数值被解析为子树(括号等替换为子树中的嵌套):
[
{
:text => "This sentence "@0
},
{
:arguments => [
{
:name => "x"@16,
:value => {
:integer => "2"@19
}
},
{
:name => "y"@22,
:value => {
:addition => {
:left => {
:addition => {
:left => {
:integer => "2"@26
},
:right => {
:integer => "5"@30
}
}
},
:right => {
:integer => "3"@35
}
}
}
}
]
},
{
:text => " has stuff in it."@37
}
]
但是,我想将参数值存储为字符串,所以这将是理想的结果:
[
{
:text => "This sentence "@0
},
{
:arguments => [
{
:name => "x"@16,
:value => "2"
},
{
:name => "y"@22,
:value => "(2 + 5) + 3"
}
]
},
{
:text => " has stuff in it."@37
}
]
如何使用 Parslet 子树来重构参数值子字符串?我可以编写一个代码生成器,但这似乎有点过头了——Parslet 显然可以在某些时候访问子字符串的位置信息(尽管它可能会丢弃它)。
是否可以利用或破解 Parslet 来返回子字符串?