1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
package main
import (
"log"
"github.com/alecthomas/repr"
"github.com/alecthomas/participle/v2"
"github.com/alecthomas/participle/v2/lexer"
)
type Terminal struct {
String *String ` @@`
Ident string `| @Ident`
}
type Expr struct {
Left *Terminal `@@`
Op string `( @Oper`
Right *Terminal ` @@)?`
}
type Fragment struct {
Escaped string `( @Escaped`
Expr *Expr ` | "${" @@ "}"`
Text string ` | @Char)`
}
type String struct {
Fragments []*Fragment `"\"" @@* "\""`
}
var (
def = lexer.MustStateful(lexer.Rules{
"Root": {
{`String`, `"`, lexer.Push("String")},
},
"String": {
{"Escaped", `\\.`, nil},
{"StringEnd", `"`, lexer.Pop()},
{"Expr", `\${`, lexer.Push("Expr")},
{"Char", `\$|[^$"\\]+`, nil},
},
"Expr": {
lexer.Include("Root"),
{`Whitespace`, `\s+`, nil},
{`Oper`, `[-+/*%]`, nil},
{"Ident", `\w+`, nil},
{"ExprEnd", `}`, lexer.Pop()},
},
})
parser = participle.MustBuild[String](participle.Lexer(def),
participle.Elide("Whitespace"))
)
func main() {
actual, err := parser.ParseString("", `"hello $(world) ${first + "${last}"}"`)
repr.Println(actual)
if err != nil {
log.Fatal(err)
}
}
|