aboutsummaryrefslogtreecommitdiffhomepage
path: root/command/parse.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-22 23:11:17 +0900
committerOphestra <cat@gensokyo.uk>2025-02-22 23:11:17 +0900
commitdfa3217037d8c24181be24484892ecb950a2a5ba (patch)
treee2022ad6ce2e11bbb7b4d0b38731a6c67561235f /command/parse.go
parent8000a2febb546b3b68eddd9330d5709281068e9f (diff)
command: implement builder and parser
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'command/parse.go')
-rw-r--r--command/parse.go72
1 files changed, 72 insertions, 0 deletions
diff --git a/command/parse.go b/command/parse.go
new file mode 100644
index 00000000..6081ca63
--- /dev/null
+++ b/command/parse.go
@@ -0,0 +1,72 @@
+package command
+
+import (
+ "errors"
+ "log"
+)
+
+var (
+ ErrEmptyTree = errors.New("subcommand tree has no nodes")
+ ErrNoMatch = errors.New("did not match any subcommand")
+)
+
+func (n *node) Parse(arguments []string) error {
+ if n.usage == "" { // root node has zero length usage
+ if n.next != nil {
+ panic("invalid toplevel state")
+ }
+ goto match
+ }
+
+ if len(arguments) == 0 {
+ // unreachable: zero length args cause upper level to return with a help message
+ panic("attempted to parse with zero length args")
+ }
+ if arguments[0] != n.name {
+ if n.next == nil {
+ n.printf("%q is not a valid command", arguments[0])
+ return ErrNoMatch
+ }
+ n.next.prefix = n.prefix
+ return n.next.Parse(arguments)
+ }
+ arguments = arguments[1:]
+
+match:
+ if n.child != nil {
+ if n.f != nil {
+ panic("invalid subcommand tree state")
+ }
+ // propagate help prefix early: flag set usage dereferences help
+ n.child.prefix = append(n.prefix, n.name)
+ }
+
+ if n.set.Parsed() {
+ panic("invalid set state")
+ }
+ if err := n.set.Parse(arguments); err != nil {
+ return FlagError{err}
+ }
+ args := n.set.Args()
+
+ if n.child != nil {
+ if len(args) == 0 {
+ return n.writeHelp()
+ }
+ return n.child.Parse(args)
+ }
+
+ if n.f == nil {
+ n.printf("%q has no subcommands", n.name)
+ return ErrEmptyTree
+ }
+ return n.f(args)
+}
+
+func (n *node) printf(format string, a ...any) {
+ if n.logf == nil {
+ log.Printf(format, a...)
+ } else {
+ n.logf(format, a...)
+ }
+}