解析 0 个或多个 idents 后跟 ident 的列表

Parsing a list of 0 or more idents followed by ident

我想解析像这样形成的 DSL 的一部分:

configSignal: sticky Config

语义上是:

argument_name: 0_or_more_modifiers argument_type

我尝试实现以下解析器:

def parser = ident ~ ":" ~ rep(ident) ~ ident ^^ {
    case name ~ ":" ~ modifiers ~ returnType => Arg(name, returnType, modifiers)
}

事实是,应用 rep(ident) 部分直到没有更多标记且解析器失败,因为最后一个 ~ ident 不匹配。我应该如何正确执行此操作?

编辑

同时我意识到,修饰符将是保留字(关键字),所以现在我有:

def parser = ident ~ ":" ~ rep(modifier) ~ ident ^^ {
    case name ~ ":" ~ modifiers ~ returnType => Arg(name, returnType, modifiers)
}

def modifier = "sticky" | "control" | "count"

尽管如此,我很好奇如果没有预先定义修饰符是否可以编写解析器。

"0 or more idents followed by ident" 等同于"1 or more idents", 所以只用rep1

它的文档:

def rep1[T](p: ⇒ Parser[T]): Parser[List[T]]

A parser generator for non-empty repetitions.

rep1(p) repeatedly uses p to parse the input until p fails -- p must succeed at least once (the result is a List of the consecutive results of p)

p a Parser that is to be applied successively to the input
returns A parser that returns a list of results produced by repeatedly applying p to the input (and that only succeeds if p matches at least once).


编辑以回应 OP 的评论:

我认为没有内置方法可以执行您所描述的操作,但使用常规列表方法映射到您的自定义数据类型仍然相对容易:

def parser = ident ~ ":" ~ rep1(ident) ^^ {
  case name ~ ":" ~ idents => Arg(name, idents.last, idents.dropRight(1))
}

在这种特殊情况下,您不必担心 idents 成为 Nil,因为 rep1 解析器仅在非空列表时成功。