2024-04-10 10:45:58 +00:00
|
|
|
package cmdlang
|
|
|
|
|
|
|
|
import (
|
2024-04-16 05:39:03 +00:00
|
|
|
"io"
|
|
|
|
|
2024-04-10 10:45:58 +00:00
|
|
|
"github.com/alecthomas/participle/v2"
|
2024-04-12 23:25:16 +00:00
|
|
|
"github.com/alecthomas/participle/v2/lexer"
|
2024-04-10 10:45:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type astLiteral struct {
|
2024-04-13 11:46:50 +00:00
|
|
|
Str *string `parser:"@String"`
|
2024-04-24 10:12:39 +00:00
|
|
|
Int *int `parser:"| @Int"`
|
2024-04-13 11:46:50 +00:00
|
|
|
}
|
|
|
|
|
2024-04-16 12:05:21 +00:00
|
|
|
type astHashKey struct {
|
|
|
|
Literal *astLiteral `parser:"@@"`
|
|
|
|
Ident *string `parser:"| @Ident"`
|
|
|
|
Var *string `parser:"| DOLLAR @Ident"`
|
|
|
|
Sub *astPipeline `parser:"| LP @@ RP"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type astElementPair struct {
|
|
|
|
Left astCmdArg `parser:"@@"`
|
|
|
|
Right *astCmdArg `parser:"( COLON @@ )? NL?"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type astListOrHash struct {
|
|
|
|
EmptyList bool `parser:"@(LS RS)"`
|
|
|
|
EmptyHash bool `parser:"| @(LS COLON RS)"`
|
|
|
|
Elements []*astElementPair `parser:"| LS NL? @@+ @@* RS"`
|
|
|
|
}
|
|
|
|
|
2024-04-13 11:46:50 +00:00
|
|
|
type astBlock struct {
|
2024-04-16 12:28:12 +00:00
|
|
|
Names []string `parser:"LC NL? (PIPE @Ident+ PIPE NL?)?"`
|
|
|
|
Statements []*astStatements `parser:"@@ NL? RC"`
|
2024-04-10 10:45:58 +00:00
|
|
|
}
|
|
|
|
|
2024-04-18 11:11:17 +00:00
|
|
|
type astMaybeSub struct {
|
|
|
|
Sub *astPipeline `parser:"@@?"`
|
|
|
|
}
|
|
|
|
|
2024-04-10 10:45:58 +00:00
|
|
|
type astCmdArg struct {
|
2024-04-16 12:05:21 +00:00
|
|
|
Literal *astLiteral `parser:"@@"`
|
|
|
|
Ident *string `parser:"| @Ident"`
|
|
|
|
Var *string `parser:"| DOLLAR @Ident"`
|
2024-04-18 11:11:17 +00:00
|
|
|
MaybeSub *astMaybeSub `parser:"| LP @@ RP"`
|
2024-04-16 12:05:21 +00:00
|
|
|
ListOrHash *astListOrHash `parser:"| @@"`
|
|
|
|
Block *astBlock `parser:"| @@"`
|
2024-04-10 10:45:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type astCmd struct {
|
2024-04-18 11:11:17 +00:00
|
|
|
Name astCmdArg `parser:"@@"`
|
2024-04-10 10:45:58 +00:00
|
|
|
Args []astCmdArg `parser:"@@*"`
|
|
|
|
}
|
|
|
|
|
2024-04-10 11:58:06 +00:00
|
|
|
type astPipeline struct {
|
|
|
|
First *astCmd `parser:"@@"`
|
2024-04-12 23:25:16 +00:00
|
|
|
Rest []*astCmd `parser:"( PIPE @@ )*"`
|
2024-04-10 11:58:06 +00:00
|
|
|
}
|
|
|
|
|
2024-04-11 12:05:05 +00:00
|
|
|
type astStatements struct {
|
|
|
|
First *astPipeline `parser:"@@"`
|
2024-04-13 11:46:50 +00:00
|
|
|
Rest []*astPipeline `parser:"( NL+ @@ )*"` // TODO: also add support for newlines
|
2024-04-11 12:05:05 +00:00
|
|
|
}
|
|
|
|
|
2024-04-13 11:46:50 +00:00
|
|
|
type astScript struct {
|
|
|
|
Statements *astStatements `parser:"NL* @@ NL*"`
|
2024-04-12 23:25:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var scanner = lexer.MustStateful(lexer.Rules{
|
|
|
|
"Root": {
|
2024-04-13 11:46:50 +00:00
|
|
|
{"Whitespace", `[ \t]+`, nil},
|
2024-04-12 23:25:16 +00:00
|
|
|
{"String", `"(\\"|[^"])*"`, nil},
|
2024-04-24 10:12:39 +00:00
|
|
|
{"Int", `[-]?[0-9][0-9]*`, nil},
|
2024-04-12 23:25:16 +00:00
|
|
|
{"DOLLAR", `\$`, nil},
|
2024-04-16 12:05:21 +00:00
|
|
|
{"COLON", `\:`, nil},
|
2024-04-12 23:25:16 +00:00
|
|
|
{"LP", `\(`, nil},
|
|
|
|
{"RP", `\)`, nil},
|
2024-04-16 12:05:21 +00:00
|
|
|
{"LS", `\[`, nil},
|
|
|
|
{"RS", `\]`, nil},
|
2024-04-13 11:46:50 +00:00
|
|
|
{"LC", `\{`, nil},
|
|
|
|
{"RC", `\}`, nil},
|
|
|
|
{"NL", `[;\n][; \n\t]*`, nil},
|
2024-04-12 23:25:16 +00:00
|
|
|
{"PIPE", `\|`, nil},
|
2024-04-24 10:12:39 +00:00
|
|
|
{"Ident", `[-]*[a-zA-Z_][\w-]*`, nil},
|
2024-04-12 23:25:16 +00:00
|
|
|
},
|
|
|
|
})
|
2024-04-13 11:46:50 +00:00
|
|
|
var parser = participle.MustBuild[astScript](participle.Lexer(scanner),
|
2024-04-12 23:25:16 +00:00
|
|
|
participle.Elide("Whitespace"))
|
2024-04-10 10:45:58 +00:00
|
|
|
|
2024-04-13 11:46:50 +00:00
|
|
|
func parse(r io.Reader) (*astScript, error) {
|
2024-04-10 10:45:58 +00:00
|
|
|
return parser.Parse("test", r)
|
|
|
|
}
|