使用Golang Participle解析函数调用语句报错求助
函数调用解析器问题排查与修复
问题描述
需要实现一个能解析function(arg1, arg2, kw1=v1, kw2=v2)格式的函数调用解析器,基于Go的participle库编写了代码,但运行时无法解析括号内的参数,报错:
unexpected token "foo = bar" (expected "(" Property* ")")
原始代码:
var ( initLexer = lexer.MustSimple([]lexer.SimpleRule{ {`Ident`, `[a-zA-Z][a-zA-Z_\d]*`}, {`String`, `(?:\\.|[^"])+`}, }) parser = participle.MustBuild[Function]( participle.Lexer(initLexer), participle.Unquote("String"), ) ) type Function struct { Name string `@Ident` Properties []*Property `"(" @@* ")"` } type Property struct { Key string `@Ident "="` Value string `@String` } func main() { out, err := parser.ParseString("", "myfunction(foo = bar)") repr.Println(out, repr.Indent(" "), repr.OmitEmpty(true)) if err != nil { panic(err) } }
问题分析
- Lexer规则缺失:未定义空格、逗号、等号的token规则,导致lexer无法正确分割
foo = bar这类内容,会将其识别为单个非法token。 - String正则错误:原始正则未匹配字符串的引号边界,无法正确识别带引号的字符串,同时也无法处理
bar这类标识符类型的参数值。 - 参数结构不兼容:
Property结构体仅支持关键字参数(键=值),不支持位置参数(仅值);且函数参数列表未定义逗号分隔规则,无法处理多个参数的情况。
修复方案
1. 完善Lexer规则
添加空格、逗号、等号的token定义,并忽略空格:
initLexer = lexer.MustSimple([]lexer.SimpleRule{ {`Whitespace`, `\s+`}, {`Ident`, `[a-zA-Z][a-zA-Z_\d]*`}, {`String`, `"((?:\\.|[^"])*)"`}, {`Comma`, `,`}, {`Equals`, `=`}, }, lexer.Ignore("Whitespace")) // 忽略空格,解析时自动跳过
2. 调整参数结构体
支持位置参数和关键字参数两种类型:
type Property struct { Key string `(@Ident "=")?` // 关键字参数的键可选 Value string `@(Ident | String)` // 值可以是标识符或字符串 }
3. 修改函数参数列表规则
定义参数之间用逗号分隔:
type Function struct { Name string `@Ident` Properties []*Property `"(" ( @@ ("," @@)* )? ")"` // 可选的参数列表,参数间用逗号分隔 }
完整修复代码
package main import ( "github.com/alecthomas/repr" "github.com/alecthomas/participle/v2" "github.com/alecthomas/participle/v2/lexer" ) var ( initLexer = lexer.MustSimple([]lexer.SimpleRule{ {`Whitespace`, `\s+`}, {`Ident`, `[a-zA-Z][a-zA-Z_\d]*`}, {`String`, `"((?:\\.|[^"])*)"`}, {`Comma`, `,`}, {`Equals`, `=`}, }, lexer.Ignore("Whitespace")) parser = participle.MustBuild[Function]( participle.Lexer(initLexer), participle.Unquote("String"), ) ) type Function struct { Name string `@Ident` Properties []*Property `"(" ( @@ ("," @@)* )? ")"` } type Property struct { Key string `(@Ident "=")?` Value string `@(Ident | String)` } func main() { testCases := []string{ "myfunction(foo = bar)", "myfunction(arg1, arg2, kw1=\"value1\", kw2=value2)", } for _, tc := range testCases { out, err := parser.ParseString("", tc) if err != nil { panic(err) } repr.Println(out, repr.Indent(" "), repr.OmitEmpty(true)) } }
验证效果
运行后可正确解析两种参数类型:
- 对于
myfunction(foo = bar),会解析出Property{Key: "foo", Value: "bar"} - 对于
myfunction(arg1, arg2, kw1="value1", kw2=value2),会解析出四个Property,前两个Key为空(位置参数),后两个为关键字参数
内容的提问来源于stack exchange,提问作者Shiladitya Bose
相关产品推荐
相关产品推荐

