arghing #1
21
argh/node.go
21
argh/node.go
@ -3,20 +3,20 @@ package argh
|
|||||||
type Node interface{}
|
type Node interface{}
|
||||||
|
|
||||||
type TypedNode struct {
|
type TypedNode struct {
|
||||||
Type string `json:"type"`
|
Type string
|
||||||
Node Node `json:"node"`
|
Node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type PassthroughArgs struct {
|
type PassthroughArgs struct {
|
||||||
Nodes []Node `json:"nodes"`
|
Nodes []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompoundShortFlag struct {
|
type CompoundShortFlag struct {
|
||||||
Nodes []Node `json:"nodes"`
|
Nodes []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ident struct {
|
type Ident struct {
|
||||||
Literal string `json:"literal"`
|
Literal string
|
||||||
}
|
}
|
||||||
|
|
||||||
type BadArg struct {
|
type BadArg struct {
|
||||||
@ -26,14 +26,15 @@ type BadArg struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Name string `json:"name"`
|
Name string
|
||||||
Values map[string]string `json:"values"`
|
Values map[string]string
|
||||||
Nodes []Node `json:"nodes"`
|
Nodes []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type Flag struct {
|
type Flag struct {
|
||||||
Name string `json:"name"`
|
Name string
|
||||||
Values map[string]string `json:"values"`
|
Values map[string]string
|
||||||
|
Nodes []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type StdinFlag struct{}
|
type StdinFlag struct{}
|
||||||
|
171
argh/parser2.go
171
argh/parser2.go
@ -16,6 +16,8 @@ type parser2 struct {
|
|||||||
tok Token
|
tok Token
|
||||||
lit string
|
lit string
|
||||||
pos Pos
|
pos Pos
|
||||||
|
|
||||||
|
buffered bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseArgs2(args []string, pCfg *ParserConfig) (*ParseTree, error) {
|
func ParseArgs2(args []string, pCfg *ParserConfig) (*ParseTree, error) {
|
||||||
@ -25,7 +27,7 @@ func ParseArgs2(args []string, pCfg *ParserConfig) (*ParseTree, error) {
|
|||||||
pCfg,
|
pCfg,
|
||||||
)
|
)
|
||||||
|
|
||||||
tracef("ParseArgs2 parser=%+#v", parser)
|
tracef("ParseArgs2(...) parser=%+#v", parser)
|
||||||
|
|
||||||
return parser.parseArgs()
|
return parser.parseArgs()
|
||||||
}
|
}
|
||||||
@ -46,81 +48,93 @@ func (p *parser2) init(r io.Reader, pCfg *ParserConfig) {
|
|||||||
|
|
||||||
func (p *parser2) parseArgs() (*ParseTree, error) {
|
func (p *parser2) parseArgs() (*ParseTree, error) {
|
||||||
if p.errors.Len() != 0 {
|
if p.errors.Len() != 0 {
|
||||||
tracef("parseArgs bailing due to initial error")
|
tracef("parseArgs() bailing due to initial error")
|
||||||
return nil, p.errors.Err()
|
return nil, p.errors.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracef("parseArgs() parsing %q as program command; cfg=%+#v", p.lit, p.cfg.Prog)
|
||||||
prog := p.parseCommand(&p.cfg.Prog)
|
prog := p.parseCommand(&p.cfg.Prog)
|
||||||
|
|
||||||
nodes := []Node{prog}
|
nodes := []Node{prog}
|
||||||
if v := p.parsePassthrough(); v != nil {
|
if v := p.parsePassthrough(); v != nil {
|
||||||
|
tracef("parseArgs() appending passthrough argument %v", v)
|
||||||
nodes = append(nodes, v)
|
nodes = append(nodes, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ParseTree{
|
tracef("parseArgs() returning ParseTree")
|
||||||
Nodes: nodes,
|
|
||||||
}, nil
|
return &ParseTree{Nodes: nodes}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) next() {
|
func (p *parser2) next() {
|
||||||
tracef("parser2.next() current: %v %q %v", p.tok, p.lit, p.pos)
|
tracef("next() before scan: %v %q %v", p.tok, p.lit, p.pos)
|
||||||
|
|
||||||
p.tok, p.lit, p.pos = p.s.Scan()
|
p.tok, p.lit, p.pos = p.s.Scan()
|
||||||
|
|
||||||
tracef("parser2.next() next: %v %q %v", p.tok, p.lit, p.pos)
|
tracef("next() after scan: %v %q %v", p.tok, p.lit, p.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) parseCommand(cCfg *CommandConfig) Node {
|
func (p *parser2) parseCommand(cCfg *CommandConfig) Node {
|
||||||
tracef("parseCommand cfg=%+#v", cCfg)
|
tracef("parseCommand(%+#v)", cCfg)
|
||||||
|
|
||||||
node := &Command{
|
node := &Command{
|
||||||
Name: p.lit,
|
Name: p.lit,
|
||||||
Values: map[string]string{},
|
|
||||||
Nodes: []Node{},
|
|
||||||
}
|
}
|
||||||
|
values := map[string]string{}
|
||||||
|
nodes := []Node{}
|
||||||
|
|
||||||
identIndex := 0
|
identIndex := 0
|
||||||
|
|
||||||
for i := 0; p.tok != EOL; i++ {
|
for i := 0; p.tok != EOL; i++ {
|
||||||
p.next()
|
if !p.buffered {
|
||||||
|
tracef("parseCommand(...) buffered=false; scanning next")
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
|
||||||
tracef("parseCommand for=%d node.Values=%+#v", i, node.Values)
|
p.buffered = false
|
||||||
tracef("parseCommand for=%d node.Nodes=%+#v", i, node.Values)
|
|
||||||
|
tracef("parseCommand(...) for=%d values=%+#v", i, values)
|
||||||
|
tracef("parseCommand(...) for=%d nodes=%+#v", i, nodes)
|
||||||
|
tracef("parseCommand(...) for=%d tok=%s lit=%q pos=%v", i, p.tok, p.lit, p.pos)
|
||||||
|
|
||||||
if subCfg, ok := cCfg.Commands[p.lit]; ok {
|
if subCfg, ok := cCfg.Commands[p.lit]; ok {
|
||||||
subCommand := p.lit
|
subCommand := p.lit
|
||||||
|
|
||||||
node.Nodes = append(node.Nodes, p.parseCommand(&subCfg))
|
nodes = append(nodes, p.parseCommand(&subCfg))
|
||||||
|
|
||||||
tracef("parseCommand breaking after sub-command=%v", subCommand)
|
tracef("parseCommand(...) breaking after sub-command=%v", subCommand)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case ARG_DELIMITER:
|
case ARG_DELIMITER:
|
||||||
tracef("parseCommand handling %s", p.tok)
|
tracef("parseCommand(...) handling %s", p.tok)
|
||||||
|
|
||||||
node.Nodes = append(node.Nodes, &ArgDelimiter{})
|
nodes = append(nodes, &ArgDelimiter{})
|
||||||
|
|
||||||
continue
|
continue
|
||||||
case IDENT, STDIN_FLAG:
|
case IDENT, STDIN_FLAG:
|
||||||
tracef("parseCommand handling %s", p.tok)
|
tracef("parseCommand(...) handling %s", p.tok)
|
||||||
|
|
||||||
if !cCfg.NValue.Contains(identIndex) {
|
if !cCfg.NValue.Contains(identIndex) {
|
||||||
tracef("parseCommand identIndex=%d exceeds expected=%s; breaking", identIndex, cCfg.NValue)
|
tracef("parseCommand(...) identIndex=%d exceeds expected=%s; breaking", identIndex, cCfg.NValue)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
name := fmt.Sprintf("%d", identIndex)
|
name := fmt.Sprintf("%d", identIndex)
|
||||||
|
|
||||||
tracef("parseCommand checking for name of identIndex=%d", identIndex)
|
tracef("parseCommand(...) checking for name of identIndex=%d", identIndex)
|
||||||
|
|
||||||
if len(cCfg.ValueNames) > identIndex {
|
if len(cCfg.ValueNames) > identIndex {
|
||||||
name = cCfg.ValueNames[identIndex]
|
name = cCfg.ValueNames[identIndex]
|
||||||
tracef("parseCommand setting name=%s from config value names", name)
|
tracef("parseCommand(...) setting name=%s from config value names", name)
|
||||||
} else if len(cCfg.ValueNames) == 1 && (cCfg.NValue == OneOrMoreValue || cCfg.NValue == ZeroOrMoreValue) {
|
} else if len(cCfg.ValueNames) == 1 && (cCfg.NValue == OneOrMoreValue || cCfg.NValue == ZeroOrMoreValue) {
|
||||||
name = fmt.Sprintf("%s.%d", cCfg.ValueNames[0], identIndex)
|
name = fmt.Sprintf("%s.%d", cCfg.ValueNames[0], identIndex)
|
||||||
tracef("parseCommand setting name=%s from repeating value name", name)
|
tracef("parseCommand(...) setting name=%s from repeating value name", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.Values == nil {
|
||||||
|
node.Values = map[string]string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.Values[name] = p.lit
|
node.Values[name] = p.lit
|
||||||
@ -128,61 +142,132 @@ func (p *parser2) parseCommand(cCfg *CommandConfig) Node {
|
|||||||
identIndex++
|
identIndex++
|
||||||
case LONG_FLAG, SHORT_FLAG, COMPOUND_SHORT_FLAG:
|
case LONG_FLAG, SHORT_FLAG, COMPOUND_SHORT_FLAG:
|
||||||
tok := p.tok
|
tok := p.tok
|
||||||
flagNode := p.parseFlag()
|
|
||||||
|
|
||||||
tracef("parseCommand appending %s node=%+#v", tok, flagNode)
|
flagNode := p.parseFlag(cCfg.Flags)
|
||||||
|
|
||||||
node.Nodes = append(node.Nodes, flagNode)
|
tracef("parseCommand(...) appending %s node=%+#v", tok, flagNode)
|
||||||
|
|
||||||
|
nodes = append(nodes, flagNode)
|
||||||
default:
|
default:
|
||||||
tracef("parseCommand breaking on %s", p.tok)
|
tracef("parseCommand(...) breaking on %s", p.tok)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracef("parseCommand returning node=%+#v", node)
|
if len(nodes) > 0 {
|
||||||
|
node.Nodes = nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(values) > 0 {
|
||||||
|
node.Values = values
|
||||||
|
}
|
||||||
|
|
||||||
|
tracef("parseCommand(...) returning node=%+#v", node)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) parseIdent() Node {
|
func (p *parser2) parseIdent() Node {
|
||||||
defer p.next()
|
|
||||||
|
|
||||||
node := &Ident{Literal: p.lit}
|
node := &Ident{Literal: p.lit}
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) parseFlag() Node {
|
func (p *parser2) parseFlag(flCfgMap map[string]FlagConfig) Node {
|
||||||
defer p.next()
|
|
||||||
|
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case SHORT_FLAG:
|
case SHORT_FLAG:
|
||||||
return p.parseShortFlag()
|
return p.parseShortFlag(flCfgMap)
|
||||||
case LONG_FLAG:
|
case LONG_FLAG:
|
||||||
return p.parseLongFlag()
|
return p.parseLongFlag(flCfgMap)
|
||||||
case COMPOUND_SHORT_FLAG:
|
case COMPOUND_SHORT_FLAG:
|
||||||
return p.parseCompoundShortFlag()
|
return p.parseCompoundShortFlag(flCfgMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic(fmt.Sprintf("token %v cannot be parsed as flag", p.tok))
|
panic(fmt.Sprintf("token %v cannot be parsed as flag", p.tok))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) parseShortFlag() Node {
|
func (p *parser2) parseShortFlag(flCfgMap map[string]FlagConfig) Node {
|
||||||
node := &Flag{Name: string(p.lit[1])}
|
name := string(p.lit[1])
|
||||||
// TODO: moar stuff
|
node := &Flag{Name: name}
|
||||||
|
tracef("parseShortFlag(...) TODO capture flag value(s)")
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) parseLongFlag() Node {
|
func (p *parser2) parseLongFlag(flCfgMap map[string]FlagConfig) Node {
|
||||||
node := &Flag{Name: string(p.lit[2:])}
|
node := &Flag{Name: string(p.lit[2:])}
|
||||||
// TODO: moar stuff
|
values := map[string]string{}
|
||||||
|
nodes := []Node{}
|
||||||
|
|
||||||
|
flCfg, ok := flCfgMap[node.Name]
|
||||||
|
if !ok {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
identIndex := 0
|
||||||
|
|
||||||
|
for i := 0; p.tok != EOL; i++ {
|
||||||
|
if !flCfg.NValue.Contains(identIndex) {
|
||||||
|
tracef("parseLongFlag(...) identIndex=%d exceeds expected=%s; breaking")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
p.next()
|
||||||
|
|
||||||
|
switch p.tok {
|
||||||
|
case ARG_DELIMITER:
|
||||||
|
nodes = append(nodes, &ArgDelimiter{})
|
||||||
|
|
||||||
|
continue
|
||||||
|
case IDENT, STDIN_FLAG:
|
||||||
|
name := fmt.Sprintf("%d", identIndex)
|
||||||
|
|
||||||
|
tracef("parseLongFlag(...) checking for name of identIndex=%d", identIndex)
|
||||||
|
|
||||||
|
if len(flCfg.ValueNames) > identIndex {
|
||||||
|
name = flCfg.ValueNames[identIndex]
|
||||||
|
tracef("parseLongFlag(...) setting name=%s from config value names", name)
|
||||||
|
} else if len(flCfg.ValueNames) == 1 && (flCfg.NValue == OneOrMoreValue || flCfg.NValue == ZeroOrMoreValue) {
|
||||||
|
name = fmt.Sprintf("%s.%d", flCfg.ValueNames[0], identIndex)
|
||||||
|
tracef("parseLongFlag(...) setting name=%s from repeating value name", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
values[name] = p.lit
|
||||||
|
|
||||||
|
identIndex++
|
||||||
|
default:
|
||||||
|
tracef("parseLongFlag(...) breaking on %s %q %v; setting buffered=true", p.tok, p.lit, p.pos)
|
||||||
|
p.buffered = true
|
||||||
|
|
||||||
|
if len(nodes) > 0 {
|
||||||
|
node.Nodes = nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(values) > 0 {
|
||||||
|
node.Values = values
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nodes) > 0 {
|
||||||
|
node.Nodes = nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(values) > 0 {
|
||||||
|
node.Values = values
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser2) parseCompoundShortFlag() Node {
|
func (p *parser2) parseCompoundShortFlag(flCfgMap map[string]FlagConfig) Node {
|
||||||
flagNodes := []Node{}
|
flagNodes := []Node{}
|
||||||
|
|
||||||
withoutFlagPrefix := p.lit[1:]
|
withoutFlagPrefix := p.lit[1:]
|
||||||
|
|
||||||
for _, r := range withoutFlagPrefix {
|
for i, r := range withoutFlagPrefix {
|
||||||
|
if i == len(withoutFlagPrefix)-1 {
|
||||||
|
tracef("parseCompoundShortFlag(...) TODO capture flag value(s)")
|
||||||
|
}
|
||||||
flagNodes = append(flagNodes, &Flag{Name: string(r)})
|
flagNodes = append(flagNodes, &Flag{Name: string(r)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,7 @@ func TestParser2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
&argh.Command{
|
&argh.Command{
|
||||||
Name: "pies",
|
Name: "pies",
|
||||||
Values: map[string]string{},
|
|
||||||
Nodes: []argh.Node{
|
Nodes: []argh.Node{
|
||||||
&argh.ArgDelimiter{},
|
&argh.ArgDelimiter{},
|
||||||
&argh.CompoundShortFlag{
|
&argh.CompoundShortFlag{
|
||||||
@ -46,7 +45,9 @@ func TestParser2(t *testing.T) {
|
|||||||
&argh.Flag{Name: "t"},
|
&argh.Flag{Name: "t"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
&argh.Flag{Name: "wat"},
|
&argh.Flag{Name: "wat"},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
&argh.Command{
|
&argh.Command{
|
||||||
Name: "hello",
|
Name: "hello",
|
||||||
Values: map[string]string{
|
Values: map[string]string{
|
||||||
@ -61,8 +62,7 @@ func TestParser2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
&argh.Command{
|
&argh.Command{
|
||||||
Name: "pies",
|
Name: "pies",
|
||||||
Values: map[string]string{},
|
|
||||||
Nodes: []argh.Node{
|
Nodes: []argh.Node{
|
||||||
&argh.Flag{Name: "e"},
|
&argh.Flag{Name: "e"},
|
||||||
&argh.Flag{Name: "a"},
|
&argh.Flag{Name: "a"},
|
||||||
@ -73,7 +73,6 @@ func TestParser2(t *testing.T) {
|
|||||||
Values: map[string]string{
|
Values: map[string]string{
|
||||||
"name": "mario",
|
"name": "mario",
|
||||||
},
|
},
|
||||||
Nodes: []argh.Node{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -84,37 +83,38 @@ func TestParser2(t *testing.T) {
|
|||||||
args: []string{"pizzas"},
|
args: []string{"pizzas"},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
&argh.Command{
|
&argh.Command{
|
||||||
Name: "pizzas",
|
Name: "pizzas",
|
||||||
Values: map[string]string{},
|
|
||||||
Nodes: []argh.Node{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
&argh.Command{
|
&argh.Command{
|
||||||
Name: "pizzas",
|
Name: "pizzas",
|
||||||
Values: map[string]string{},
|
|
||||||
Nodes: []argh.Node{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: true,
|
|
||||||
|
|
||||||
name: "one positional arg",
|
name: "one positional arg",
|
||||||
args: []string{"pizzas", "excel"},
|
args: []string{"pizzas", "excel"},
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
Prog: argh.CommandConfig{NValue: 1},
|
Prog: argh.CommandConfig{NValue: 1},
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Command{Name: "pizzas", Values: map[string]string{"0": "excel"}},
|
&argh.Command{
|
||||||
|
Name: "pizzas",
|
||||||
|
Values: map[string]string{"0": "excel"},
|
||||||
|
Nodes: []argh.Node{
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
argh.Command{Name: "pizzas", Values: map[string]string{"0": "excel"}},
|
&argh.Command{
|
||||||
|
Name: "pizzas",
|
||||||
|
Values: map[string]string{"0": "excel"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: true,
|
|
||||||
|
|
||||||
name: "many positional args",
|
name: "many positional args",
|
||||||
args: []string{"pizzas", "excel", "wildly", "when", "feral"},
|
args: []string{"pizzas", "excel", "wildly", "when", "feral"},
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
@ -124,7 +124,7 @@ func TestParser2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Command{
|
&argh.Command{
|
||||||
Name: "pizzas",
|
Name: "pizzas",
|
||||||
Values: map[string]string{
|
Values: map[string]string{
|
||||||
"word": "excel",
|
"word": "excel",
|
||||||
@ -132,10 +132,16 @@ func TestParser2(t *testing.T) {
|
|||||||
"word.2": "when",
|
"word.2": "when",
|
||||||
"word.3": "feral",
|
"word.3": "feral",
|
||||||
},
|
},
|
||||||
|
Nodes: []argh.Node{
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
argh.Command{
|
&argh.Command{
|
||||||
Name: "pizzas",
|
Name: "pizzas",
|
||||||
Values: map[string]string{
|
Values: map[string]string{
|
||||||
"word": "excel",
|
"word": "excel",
|
||||||
@ -147,29 +153,33 @@ func TestParser2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: true,
|
|
||||||
|
|
||||||
name: "long value-less flags",
|
name: "long value-less flags",
|
||||||
args: []string{"pizzas", "--tasty", "--fresh", "--super-hot-right-now"},
|
args: []string{"pizzas", "--tasty", "--fresh", "--super-hot-right-now"},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Command{Name: "pizzas"},
|
&argh.Command{
|
||||||
argh.ArgDelimiter{},
|
Name: "pizzas",
|
||||||
argh.Flag{Name: "tasty"},
|
Nodes: []argh.Node{
|
||||||
argh.ArgDelimiter{},
|
&argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "fresh"},
|
&argh.Flag{Name: "tasty"},
|
||||||
argh.ArgDelimiter{},
|
&argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "super-hot-right-now"},
|
&argh.Flag{Name: "fresh"},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.Flag{Name: "super-hot-right-now"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
argh.Command{Name: "pizzas"},
|
&argh.Command{
|
||||||
argh.Flag{Name: "tasty"},
|
Name: "pizzas",
|
||||||
argh.Flag{Name: "fresh"},
|
Nodes: []argh.Node{
|
||||||
argh.Flag{Name: "super-hot-right-now"},
|
&argh.Flag{Name: "tasty"},
|
||||||
|
&argh.Flag{Name: "fresh"},
|
||||||
|
&argh.Flag{Name: "super-hot-right-now"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: true,
|
|
||||||
|
|
||||||
name: "long flags mixed",
|
name: "long flags mixed",
|
||||||
args: []string{
|
args: []string{
|
||||||
"pizzas",
|
"pizzas",
|
||||||
@ -189,25 +199,47 @@ func TestParser2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Command{Name: "pizzas"},
|
&argh.Command{
|
||||||
argh.ArgDelimiter{},
|
Name: "pizzas",
|
||||||
argh.Flag{Name: "tasty"},
|
Nodes: []argh.Node{
|
||||||
argh.ArgDelimiter{},
|
&argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "fresh", Values: map[string]string{"0": "soon"}},
|
&argh.Flag{Name: "tasty"},
|
||||||
argh.ArgDelimiter{},
|
&argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "super-hot-right-now"},
|
&argh.Flag{
|
||||||
argh.ArgDelimiter{},
|
Name: "fresh",
|
||||||
argh.Flag{Name: "box", Values: map[string]string{"0": "square", "1": "shaped", "2": "hot"}},
|
Values: map[string]string{"0": "soon"},
|
||||||
argh.ArgDelimiter{},
|
Nodes: []argh.Node{
|
||||||
argh.Flag{Name: "please"},
|
&argh.ArgDelimiter{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.Flag{Name: "super-hot-right-now"},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.Flag{
|
||||||
|
Name: "box",
|
||||||
|
Values: map[string]string{"0": "square", "1": "shaped", "2": "hot"},
|
||||||
|
Nodes: []argh.Node{
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
&argh.ArgDelimiter{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&argh.Flag{Name: "please"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
argh.Command{Name: "pizzas"},
|
&argh.Command{
|
||||||
argh.Flag{Name: "tasty"},
|
Name: "pizzas",
|
||||||
argh.Flag{Name: "fresh", Values: map[string]string{"0": "soon"}},
|
Nodes: []argh.Node{
|
||||||
argh.Flag{Name: "super-hot-right-now"},
|
&argh.Flag{Name: "tasty"},
|
||||||
argh.Flag{Name: "box", Values: map[string]string{"0": "square", "1": "shaped", "2": "hot"}},
|
&argh.Flag{Name: "fresh", Values: map[string]string{"0": "soon"}},
|
||||||
argh.Flag{Name: "please"},
|
&argh.Flag{Name: "super-hot-right-now"},
|
||||||
|
&argh.Flag{Name: "box", Values: map[string]string{"0": "square", "1": "shaped", "2": "hot"}},
|
||||||
|
&argh.Flag{Name: "please"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -37,18 +37,44 @@ func (dq *defaultQuerier) AST() []Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := node.(*CompoundShortFlag); ok {
|
if v, ok := node.(*CompoundShortFlag); ok {
|
||||||
ret = append(ret, NewQuerier(v.Nodes).AST()...)
|
if v.Nodes != nil {
|
||||||
|
ret = append(ret, NewQuerier(v.Nodes).AST()...)
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := node.(*Command); ok {
|
if v, ok := node.(*Command); ok {
|
||||||
|
astNodes := NewQuerier(v.Nodes).AST()
|
||||||
|
|
||||||
|
if len(astNodes) == 0 {
|
||||||
|
astNodes = nil
|
||||||
|
}
|
||||||
|
|
||||||
ret = append(
|
ret = append(
|
||||||
ret,
|
ret,
|
||||||
&Command{
|
&Command{
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Values: v.Values,
|
Values: v.Values,
|
||||||
Nodes: NewQuerier(v.Nodes).AST(),
|
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
|
continue
|
||||||
|
Loading…
Reference in New Issue
Block a user