You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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)
    }
}

问题分析

  1. Lexer规则缺失:未定义空格、逗号、等号的token规则,导致lexer无法正确分割foo = bar这类内容,会将其识别为单个非法token。
  2. String正则错误:原始正则未匹配字符串的引号边界,无法正确识别带引号的字符串,同时也无法处理bar这类标识符类型的参数值。
  3. 参数结构不兼容: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:00:55