parent
c93d1cd4f0
commit
b97681c710
@ -0,0 +1,69 @@
|
|||||||
|
package argh
|
||||||
|
|
||||||
|
// ToAST accepts a slice of nodes as expected from ParseArgs and
|
||||||
|
// returns an AST with parse-time artifacts dropped and reorganized
|
||||||
|
// where applicable.
|
||||||
|
func ToAST(parseTree []Node) []Node {
|
||||||
|
ret := []Node{}
|
||||||
|
|
||||||
|
for i, node := range parseTree {
|
||||||
|
tracef("ToAST i=%d node type=%T", i, node)
|
||||||
|
|
||||||
|
if _, ok := node.(*ArgDelimiter); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := node.(*StopFlag); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := node.(*CompoundShortFlag); ok {
|
||||||
|
if v.Nodes != nil {
|
||||||
|
ret = append(ret, ToAST(v.Nodes)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := node.(*Command); ok {
|
||||||
|
astNodes := ToAST(v.Nodes)
|
||||||
|
|
||||||
|
if len(astNodes) == 0 {
|
||||||
|
astNodes = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(
|
||||||
|
ret,
|
||||||
|
&Command{
|
||||||
|
Name: v.Name,
|
||||||
|
Values: v.Values,
|
||||||
|
Nodes: astNodes,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := node.(*Flag); ok {
|
||||||
|
astNodes := ToAST(v.Nodes)
|
||||||
|
|
||||||
|
if len(astNodes) == 0 {
|
||||||
|
astNodes = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(
|
||||||
|
ret,
|
||||||
|
&Flag{
|
||||||
|
Name: v.Name,
|
||||||
|
Values: v.Values,
|
||||||
|
Nodes: astNodes,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(ret, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
@ -1,94 +0,0 @@
|
|||||||
package argh
|
|
||||||
|
|
||||||
type Querier interface {
|
|
||||||
Program() (*Command, bool)
|
|
||||||
AST() []Node
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewQuerier(nodes []Node) Querier {
|
|
||||||
return &defaultQuerier{nodes: nodes}
|
|
||||||
}
|
|
||||||
|
|
||||||
type defaultQuerier struct {
|
|
||||||
nodes []Node
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dq *defaultQuerier) Program() (*Command, bool) {
|
|
||||||
if len(dq.nodes) == 0 {
|
|
||||||
tracef("Program nodes are empty")
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
tracef("Program node[0] is %T", dq.nodes[0])
|
|
||||||
|
|
||||||
v, ok := dq.nodes[0].(*Command)
|
|
||||||
if ok && v.Name == "" {
|
|
||||||
return v, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return v, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dq *defaultQuerier) AST() []Node {
|
|
||||||
ret := []Node{}
|
|
||||||
|
|
||||||
for i, node := range dq.nodes {
|
|
||||||
tracef("AST i=%d node type=%T", i, node)
|
|
||||||
|
|
||||||
if _, ok := node.(*ArgDelimiter); ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := node.(*StopFlag); ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := node.(*CompoundShortFlag); ok {
|
|
||||||
if v.Nodes != nil {
|
|
||||||
ret = append(ret, NewQuerier(v.Nodes).AST()...)
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := node.(*Command); ok {
|
|
||||||
astNodes := NewQuerier(v.Nodes).AST()
|
|
||||||
|
|
||||||
if len(astNodes) == 0 {
|
|
||||||
astNodes = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = append(
|
|
||||||
ret,
|
|
||||||
&Command{
|
|
||||||
Name: v.Name,
|
|
||||||
Values: v.Values,
|
|
||||||
Nodes: astNodes,
|
|
||||||
})
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := node.(*Flag); ok {
|
|
||||||
astNodes := NewQuerier(v.Nodes).AST()
|
|
||||||
|
|
||||||
if len(astNodes) == 0 {
|
|
||||||
astNodes = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = append(
|
|
||||||
ret,
|
|
||||||
&Flag{
|
|
||||||
Name: v.Name,
|
|
||||||
Values: v.Values,
|
|
||||||
Nodes: astNodes,
|
|
||||||
})
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = append(ret, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
package argh_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.meatballhat.com/x/argh"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestQuerier_Program(t *testing.T) {
|
|
||||||
for _, tc := range []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
cfg *argh.ParserConfig
|
|
||||||
exp string
|
|
||||||
expOK bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "typical",
|
|
||||||
args: []string{"pizzas", "ahoy", "--treatsa", "fun"},
|
|
||||||
cfg: &argh.ParserConfig{
|
|
||||||
Prog: &argh.CommandConfig{
|
|
||||||
Commands: &argh.Commands{
|
|
||||||
Map: map[string]argh.CommandConfig{
|
|
||||||
"ahoy": argh.CommandConfig{
|
|
||||||
Flags: &argh.Flags{
|
|
||||||
Map: map[string]argh.FlagConfig{
|
|
||||||
"treatsa": argh.FlagConfig{NValue: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
exp: "pizzas",
|
|
||||||
expOK: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "minimal",
|
|
||||||
args: []string{"pizzas"},
|
|
||||||
exp: "pizzas",
|
|
||||||
expOK: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid",
|
|
||||||
args: []string{},
|
|
||||||
expOK: false,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
t.Run(tc.name, func(ct *testing.T) {
|
|
||||||
pt, err := argh.ParseArgs(tc.args, tc.cfg)
|
|
||||||
require.Nil(ct, err)
|
|
||||||
|
|
||||||
prog, ok := argh.NewQuerier(pt.Nodes).Program()
|
|
||||||
require.Equal(ct, tc.expOK, ok)
|
|
||||||
require.Equal(ct, tc.exp, prog.Name)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue