Compare commits
No commits in common. "9989801e620643bdbd70edaff5c80b8913856e9e" and "b2e61cd0d21caa32e2c0842ad9a1ca7f87990dd5" have entirely different histories.
9989801e62
...
b2e61cd0d2
41
argh/node.go
41
argh/node.go
@ -1,41 +0,0 @@
|
|||||||
package argh
|
|
||||||
|
|
||||||
type Node interface{}
|
|
||||||
|
|
||||||
type TypedNode struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Node Node `json:"node"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Args struct {
|
|
||||||
Nodes []Node `json:"nodes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CompoundShortFlag struct {
|
|
||||||
Nodes []Node `json:"nodes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Program struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Values []string `json:"values"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Ident struct {
|
|
||||||
Literal string `json:"literal"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Command struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Values []string `json:"values"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Flag struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Values []string `json:"values"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type StdinFlag struct{}
|
|
||||||
|
|
||||||
type StopFlag struct{}
|
|
||||||
|
|
||||||
type ArgDelimiter struct{}
|
|
@ -1,25 +0,0 @@
|
|||||||
// Code generated by "stringer -type NValue"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package argh
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
func _() {
|
|
||||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
|
||||||
// Re-run the stringer command to generate them again.
|
|
||||||
var x [1]struct{}
|
|
||||||
_ = x[ZeroValue-0]
|
|
||||||
_ = x[OneValue-1]
|
|
||||||
_ = x[OneOrMoreValue-2]
|
|
||||||
}
|
|
||||||
|
|
||||||
const _NValue_name = "ZeroValueOneValueOneOrMoreValue"
|
|
||||||
|
|
||||||
var _NValue_index = [...]uint8{0, 9, 17, 31}
|
|
||||||
|
|
||||||
func (i NValue) String() string {
|
|
||||||
if i < 0 || i >= NValue(len(_NValue_index)-1) {
|
|
||||||
return "NValue(" + strconv.FormatInt(int64(i), 10) + ")"
|
|
||||||
}
|
|
||||||
return _NValue_name[_NValue_index[i]:_NValue_index[i+1]]
|
|
||||||
}
|
|
@ -42,7 +42,7 @@ func (pt *ParseTree) ast() []Node {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := node.(CompoundShortFlag); ok {
|
if v, ok := node.(Statement); ok {
|
||||||
for _, subNode := range v.Nodes {
|
for _, subNode := range v.Nodes {
|
||||||
ret = append(ret, subNode)
|
ret = append(ret, subNode)
|
||||||
}
|
}
|
||||||
@ -55,3 +55,41 @@ func (pt *ParseTree) ast() []Node {
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Node interface{}
|
||||||
|
|
||||||
|
type TypedNode struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Node Node `json:"node"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Args struct {
|
||||||
|
Nodes []Node `json:"nodes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Statement struct {
|
||||||
|
Nodes []Node `json:"nodes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Program struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ident struct {
|
||||||
|
Literal string `json:"literal"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Flag struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value *string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StdinFlag struct{}
|
||||||
|
|
||||||
|
type StopFlag struct{}
|
||||||
|
|
||||||
|
type ArgDelimiter struct{}
|
||||||
|
193
argh/parser.go
193
argh/parser.go
@ -1,5 +1,3 @@
|
|||||||
//go:generate stringer -type NValue
|
|
||||||
|
|
||||||
package argh
|
package argh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,24 +7,16 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
ZeroValue NValue = iota
|
|
||||||
OneValue
|
|
||||||
OneOrMoreValue
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errSyntax = errors.New("syntax error")
|
errSyntax = errors.New("syntax error")
|
||||||
|
|
||||||
DefaultParserConfig = &ParserConfig{
|
DefaultParserConfig = &ParserConfig{
|
||||||
Commands: map[string]NValue{},
|
Commands: []string{},
|
||||||
Flags: map[string]NValue{},
|
ValueFlags: []string{},
|
||||||
ScannerConfig: DefaultScannerConfig,
|
ScannerConfig: DefaultScannerConfig,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type NValue int
|
|
||||||
|
|
||||||
func ParseArgs(args []string, pCfg *ParserConfig) (*Argh, error) {
|
func ParseArgs(args []string, pCfg *ParserConfig) (*Argh, error) {
|
||||||
reEncoded := strings.Join(args, string(nul))
|
reEncoded := strings.Join(args, string(nul))
|
||||||
|
|
||||||
@ -37,38 +27,50 @@ func ParseArgs(args []string, pCfg *ParserConfig) (*Argh, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Parser struct {
|
type Parser struct {
|
||||||
s *Scanner
|
s *Scanner
|
||||||
|
buf ParserBuffer
|
||||||
|
|
||||||
buf []ScanEntry
|
commands map[string]struct{}
|
||||||
|
valueFlags map[string]struct{}
|
||||||
cfg *ParserConfig
|
|
||||||
|
|
||||||
nodes []Node
|
nodes []Node
|
||||||
stopSeen bool
|
stopSeen bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScanEntry struct {
|
type ParserBuffer struct {
|
||||||
tok Token
|
tok Token
|
||||||
lit string
|
lit string
|
||||||
pos int
|
pos int
|
||||||
|
n int
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParserConfig struct {
|
type ParserConfig struct {
|
||||||
ProgValues NValue
|
Commands []string
|
||||||
Commands map[string]NValue
|
ValueFlags []string
|
||||||
Flags map[string]NValue
|
|
||||||
ScannerConfig *ScannerConfig
|
ScannerConfig *ScannerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type parseDirective struct {
|
||||||
|
Break bool
|
||||||
|
}
|
||||||
|
|
||||||
func NewParser(r io.Reader, pCfg *ParserConfig) *Parser {
|
func NewParser(r io.Reader, pCfg *ParserConfig) *Parser {
|
||||||
if pCfg == nil {
|
if pCfg == nil {
|
||||||
pCfg = DefaultParserConfig
|
pCfg = DefaultParserConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
parser := &Parser{
|
parser := &Parser{
|
||||||
buf: []ScanEntry{},
|
s: NewScanner(r, pCfg.ScannerConfig),
|
||||||
s: NewScanner(r, pCfg.ScannerConfig),
|
commands: map[string]struct{}{},
|
||||||
cfg: pCfg,
|
valueFlags: map[string]struct{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, command := range pCfg.Commands {
|
||||||
|
parser.commands[command] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, valueFlag := range pCfg.ValueFlags {
|
||||||
|
parser.valueFlags[valueFlag] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracef("NewParser parser=%+#v", parser)
|
tracef("NewParser parser=%+#v", parser)
|
||||||
@ -81,12 +83,12 @@ func (p *Parser) Parse() (*Argh, error) {
|
|||||||
p.nodes = []Node{}
|
p.nodes = []Node{}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
br, err := p.parseArg()
|
pd, err := p.parseArg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if br {
|
if pd != nil && pd.Break {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,31 +96,31 @@ func (p *Parser) Parse() (*Argh, error) {
|
|||||||
return &Argh{ParseTree: &ParseTree{Nodes: p.nodes}}, nil
|
return &Argh{ParseTree: &ParseTree{Nodes: p.nodes}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseArg() (bool, error) {
|
func (p *Parser) parseArg() (*parseDirective, error) {
|
||||||
tok, lit, pos := p.scan()
|
tok, lit, pos := p.scan()
|
||||||
if tok == ILLEGAL {
|
if tok == ILLEGAL {
|
||||||
return false, errors.Wrapf(errSyntax, "illegal value %q at pos=%v", lit, pos)
|
return nil, errors.Wrapf(errSyntax, "illegal value %q at pos=%v", lit, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok == EOL {
|
if tok == EOL {
|
||||||
return true, nil
|
return &parseDirective{Break: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.unscan(tok, lit, pos)
|
p.unscan()
|
||||||
|
|
||||||
node, err := p.nodify()
|
node, err := p.nodify()
|
||||||
|
|
||||||
tracef("parseArg node=%+#v err=%+#v", node, err)
|
tracef("parseArg node=%+#v err=%+#v", node, err)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.Wrapf(err, "value %q at pos=%v", lit, pos)
|
return nil, errors.Wrapf(err, "value %q at pos=%v", lit, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if node != nil {
|
if node != nil {
|
||||||
p.nodes = append(p.nodes, node)
|
p.nodes = append(p.nodes, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) nodify() (Node, error) {
|
func (p *Parser) nodify() (Node, error) {
|
||||||
@ -129,21 +131,11 @@ func (p *Parser) nodify() (Node, error) {
|
|||||||
switch tok {
|
switch tok {
|
||||||
case IDENT:
|
case IDENT:
|
||||||
if len(p.nodes) == 0 {
|
if len(p.nodes) == 0 {
|
||||||
values, err := p.scanValues(lit, pos, p.cfg.ProgValues)
|
return Program{Name: lit}, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Program{Name: lit, Values: values}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if n, ok := p.cfg.Commands[lit]; ok {
|
if _, ok := p.commands[lit]; ok {
|
||||||
values, err := p.scanValues(lit, pos, n)
|
return Command{Name: lit}, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Command{Name: lit, Values: values}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ident{Literal: lit}, nil
|
return Ident{Literal: lit}, nil
|
||||||
@ -152,24 +144,7 @@ func (p *Parser) nodify() (Node, error) {
|
|||||||
case COMPOUND_SHORT_FLAG:
|
case COMPOUND_SHORT_FLAG:
|
||||||
flagNodes := []Node{}
|
flagNodes := []Node{}
|
||||||
|
|
||||||
withoutFlagPrefix := lit[1:]
|
for _, r := range lit[1:] {
|
||||||
|
|
||||||
for i, r := range withoutFlagPrefix {
|
|
||||||
if i == len(withoutFlagPrefix)-1 {
|
|
||||||
flagName := string(r)
|
|
||||||
|
|
||||||
if n, ok := p.cfg.Flags[flagName]; ok {
|
|
||||||
values, err := p.scanValues(flagName, pos, n)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
flagNodes = append(flagNodes, Flag{Name: flagName, Values: values})
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flagNodes = append(
|
flagNodes = append(
|
||||||
flagNodes,
|
flagNodes,
|
||||||
Flag{
|
Flag{
|
||||||
@ -178,28 +153,18 @@ func (p *Parser) nodify() (Node, error) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return CompoundShortFlag{Nodes: flagNodes}, nil
|
return Statement{Nodes: flagNodes}, nil
|
||||||
case SHORT_FLAG:
|
case SHORT_FLAG:
|
||||||
flagName := string(lit[1:])
|
flagName := string(lit[1:])
|
||||||
if n, ok := p.cfg.Flags[flagName]; ok {
|
if _, ok := p.valueFlags[flagName]; ok {
|
||||||
values, err := p.scanValues(flagName, pos, n)
|
return p.scanValueFlag(flagName, pos)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Flag{Name: flagName, Values: values}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Flag{Name: flagName}, nil
|
return Flag{Name: flagName}, nil
|
||||||
case LONG_FLAG:
|
case LONG_FLAG:
|
||||||
flagName := string(lit[2:])
|
flagName := string(lit[2:])
|
||||||
if n, ok := p.cfg.Flags[flagName]; ok {
|
if _, ok := p.valueFlags[flagName]; ok {
|
||||||
values, err := p.scanValues(flagName, pos, n)
|
return p.scanValueFlag(flagName, pos)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Flag{Name: flagName, Values: values}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Flag{Name: flagName}, nil
|
return Flag{Name: flagName}, nil
|
||||||
@ -209,57 +174,24 @@ func (p *Parser) nodify() (Node, error) {
|
|||||||
return Ident{Literal: lit}, nil
|
return Ident{Literal: lit}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) scanValues(lit string, pos int, n NValue) ([]string, error) {
|
func (p *Parser) scanValueFlag(flagName string, pos int) (Node, error) {
|
||||||
tracef("scanValues lit=%q pos=%v n=%v", lit, pos, n)
|
tracef("scanValueFlag flagName=%q pos=%v", flagName, pos)
|
||||||
|
|
||||||
values, err := func() ([]string, error) {
|
|
||||||
if n == ZeroValue {
|
|
||||||
return []string{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := []string{}
|
|
||||||
|
|
||||||
for {
|
|
||||||
lit, err := p.scanIdent()
|
|
||||||
if err != nil {
|
|
||||||
if n == OneValue {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == OneOrMoreValue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = append(ret, lit)
|
|
||||||
|
|
||||||
if n == OneValue && len(ret) == 1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
|
lit, err := p.scanIdent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(values) == 0 {
|
return Flag{Name: flagName, Value: ptr(lit)}, nil
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return values, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) scanIdent() (string, error) {
|
func (p *Parser) scanIdent() (string, error) {
|
||||||
tok, lit, pos := p.scan()
|
tok, lit, pos := p.scan()
|
||||||
|
|
||||||
unscanBuf := []ScanEntry{}
|
nUnscan := 0
|
||||||
|
|
||||||
if tok == ASSIGN || tok == ARG_DELIMITER {
|
if tok == ASSIGN || tok == ARG_DELIMITER {
|
||||||
unscanBuf = append([]ScanEntry{{tok: tok, lit: lit, pos: pos}}, unscanBuf...)
|
nUnscan++
|
||||||
|
|
||||||
tok, lit, pos = p.scan()
|
tok, lit, pos = p.scan()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,35 +199,30 @@ func (p *Parser) scanIdent() (string, error) {
|
|||||||
return lit, nil
|
return lit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unscanBuf = append([]ScanEntry{{tok: tok, lit: lit, pos: pos}}, unscanBuf...)
|
for i := 0; i < nUnscan; i++ {
|
||||||
|
p.unscan()
|
||||||
for _, entry := range unscanBuf {
|
|
||||||
p.unscan(entry.tok, entry.lit, entry.pos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.Wrapf(errSyntax, "expected ident at pos=%v but got %s (%q)", pos, tok, lit)
|
return "", errors.Wrapf(errSyntax, "expected ident at pos=%v but got %s (%q)", pos, tok, lit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) scan() (Token, string, int) {
|
func (p *Parser) scan() (Token, string, int) {
|
||||||
if len(p.buf) != 0 {
|
if p.buf.n != 0 {
|
||||||
entry, buf := p.buf[len(p.buf)-1], p.buf[:len(p.buf)-1]
|
p.buf.n = 0
|
||||||
p.buf = buf
|
return p.buf.tok, p.buf.lit, p.buf.pos
|
||||||
|
|
||||||
tracef("scan returning buffer entry=%s %+#v", entry.tok, entry)
|
|
||||||
return entry.tok, entry.lit, entry.pos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tok, lit, pos := p.s.Scan()
|
tok, lit, pos := p.s.Scan()
|
||||||
|
|
||||||
tracef("scan returning next=%s %+#v", tok, ScanEntry{tok: tok, lit: lit, pos: pos})
|
p.buf.tok, p.buf.lit, p.buf.pos = tok, lit, pos
|
||||||
|
|
||||||
return tok, lit, pos
|
return tok, lit, pos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) unscan(tok Token, lit string, pos int) {
|
func (p *Parser) unscan() {
|
||||||
entry := ScanEntry{tok: tok, lit: lit, pos: pos}
|
p.buf.n = 1
|
||||||
|
}
|
||||||
tracef("unscan entry=%s %+#v", tok, entry)
|
|
||||||
|
func ptr[T any](v T) *T {
|
||||||
p.buf = append(p.buf, entry)
|
return &v
|
||||||
}
|
}
|
||||||
|
@ -31,32 +31,6 @@ func TestParser(t *testing.T) {
|
|||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "one positional arg",
|
|
||||||
args: []string{"pizzas", "excel"},
|
|
||||||
cfg: &argh.ParserConfig{
|
|
||||||
ProgValues: argh.OneValue,
|
|
||||||
},
|
|
||||||
expPT: []argh.Node{
|
|
||||||
argh.Program{Name: "pizzas", Values: []string{"excel"}},
|
|
||||||
},
|
|
||||||
expAST: []argh.Node{
|
|
||||||
argh.Program{Name: "pizzas", Values: []string{"excel"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "many positional args",
|
|
||||||
args: []string{"pizzas", "excel", "wildly", "when", "feral"},
|
|
||||||
cfg: &argh.ParserConfig{
|
|
||||||
ProgValues: argh.OneOrMoreValue,
|
|
||||||
},
|
|
||||||
expPT: []argh.Node{
|
|
||||||
argh.Program{Name: "pizzas", Values: []string{"excel", "wildly", "when", "feral"}},
|
|
||||||
},
|
|
||||||
expAST: []argh.Node{
|
|
||||||
argh.Program{Name: "pizzas", Values: []string{"excel", "wildly", "when", "feral"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
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"},
|
||||||
@ -78,41 +52,25 @@ func TestParser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "long flags mixed",
|
name: "long flags mixed",
|
||||||
args: []string{
|
args: []string{"pizzas", "--tasty", "--fresh", "soon", "--super-hot-right-now"},
|
||||||
"pizzas",
|
|
||||||
"--tasty",
|
|
||||||
"--fresh", "soon",
|
|
||||||
"--super-hot-right-now",
|
|
||||||
"--box", "square", "shaped", "hot",
|
|
||||||
"--please",
|
|
||||||
},
|
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
Commands: map[string]argh.NValue{},
|
Commands: []string{},
|
||||||
Flags: map[string]argh.NValue{
|
ValueFlags: []string{"fresh"},
|
||||||
"fresh": argh.OneValue,
|
|
||||||
"box": argh.OneOrMoreValue,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "tasty"},
|
argh.Flag{Name: "tasty"},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "fresh", Values: []string{"soon"}},
|
argh.Flag{Name: "fresh", Value: ptr("soon")},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "super-hot-right-now"},
|
argh.Flag{Name: "super-hot-right-now"},
|
||||||
argh.ArgDelimiter{},
|
|
||||||
argh.Flag{Name: "box", Values: []string{"square", "shaped", "hot"}},
|
|
||||||
argh.ArgDelimiter{},
|
|
||||||
argh.Flag{Name: "please"},
|
|
||||||
},
|
},
|
||||||
expAST: []argh.Node{
|
expAST: []argh.Node{
|
||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
argh.Flag{Name: "tasty"},
|
argh.Flag{Name: "tasty"},
|
||||||
argh.Flag{Name: "fresh", Values: []string{"soon"}},
|
argh.Flag{Name: "fresh", Value: ptr("soon")},
|
||||||
argh.Flag{Name: "super-hot-right-now"},
|
argh.Flag{Name: "super-hot-right-now"},
|
||||||
argh.Flag{Name: "box", Values: []string{"square", "shaped", "hot"}},
|
|
||||||
argh.Flag{Name: "please"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -140,7 +98,7 @@ func TestParser(t *testing.T) {
|
|||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.CompoundShortFlag{
|
argh.Statement{
|
||||||
Nodes: []argh.Node{
|
Nodes: []argh.Node{
|
||||||
argh.Flag{Name: "a"},
|
argh.Flag{Name: "a"},
|
||||||
argh.Flag{Name: "c"},
|
argh.Flag{Name: "c"},
|
||||||
@ -148,7 +106,7 @@ func TestParser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.CompoundShortFlag{
|
argh.Statement{
|
||||||
Nodes: []argh.Node{
|
Nodes: []argh.Node{
|
||||||
argh.Flag{Name: "b"},
|
argh.Flag{Name: "b"},
|
||||||
argh.Flag{Name: "l"},
|
argh.Flag{Name: "l"},
|
||||||
@ -172,8 +130,8 @@ func TestParser(t *testing.T) {
|
|||||||
name: "mixed long short value flags",
|
name: "mixed long short value flags",
|
||||||
args: []string{"pizzas", "-a", "--ca", "-b", "1312", "-lol"},
|
args: []string{"pizzas", "-a", "--ca", "-b", "1312", "-lol"},
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
Commands: map[string]argh.NValue{},
|
Commands: []string{},
|
||||||
Flags: map[string]argh.NValue{"b": argh.OneValue},
|
ValueFlags: []string{"b"},
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
@ -182,9 +140,9 @@ func TestParser(t *testing.T) {
|
|||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "ca"},
|
argh.Flag{Name: "ca"},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.Flag{Name: "b", Values: []string{"1312"}},
|
argh.Flag{Name: "b", Value: ptr("1312")},
|
||||||
argh.ArgDelimiter{},
|
argh.ArgDelimiter{},
|
||||||
argh.CompoundShortFlag{
|
argh.Statement{
|
||||||
Nodes: []argh.Node{
|
Nodes: []argh.Node{
|
||||||
argh.Flag{Name: "l"},
|
argh.Flag{Name: "l"},
|
||||||
argh.Flag{Name: "o"},
|
argh.Flag{Name: "o"},
|
||||||
@ -196,7 +154,7 @@ func TestParser(t *testing.T) {
|
|||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
argh.Flag{Name: "a"},
|
argh.Flag{Name: "a"},
|
||||||
argh.Flag{Name: "ca"},
|
argh.Flag{Name: "ca"},
|
||||||
argh.Flag{Name: "b", Values: []string{"1312"}},
|
argh.Flag{Name: "b", Value: ptr("1312")},
|
||||||
argh.Flag{Name: "l"},
|
argh.Flag{Name: "l"},
|
||||||
argh.Flag{Name: "o"},
|
argh.Flag{Name: "o"},
|
||||||
argh.Flag{Name: "l"},
|
argh.Flag{Name: "l"},
|
||||||
@ -206,8 +164,8 @@ func TestParser(t *testing.T) {
|
|||||||
name: "commands",
|
name: "commands",
|
||||||
args: []string{"pizzas", "fly", "fry"},
|
args: []string{"pizzas", "fly", "fry"},
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
Commands: map[string]argh.NValue{"fly": argh.ZeroValue, "fry": argh.ZeroValue},
|
Commands: []string{"fly", "fry"},
|
||||||
Flags: map[string]argh.NValue{},
|
ValueFlags: []string{},
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
@ -217,42 +175,6 @@ func TestParser(t *testing.T) {
|
|||||||
argh.Command{Name: "fry"},
|
argh.Command{Name: "fry"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "total weirdo",
|
|
||||||
args: []string{"PIZZAs", "^wAT@golf", "^^hecKing", "goose", "bonk", "^^FIERCENESS@-2"},
|
|
||||||
cfg: &argh.ParserConfig{
|
|
||||||
Commands: map[string]argh.NValue{"goose": argh.OneValue},
|
|
||||||
Flags: map[string]argh.NValue{
|
|
||||||
"w": argh.ZeroValue,
|
|
||||||
"A": argh.ZeroValue,
|
|
||||||
"T": argh.OneValue,
|
|
||||||
"hecking": argh.ZeroValue,
|
|
||||||
"FIERCENESS": argh.OneValue,
|
|
||||||
},
|
|
||||||
ScannerConfig: &argh.ScannerConfig{
|
|
||||||
AssignmentOperator: '@',
|
|
||||||
FlagPrefix: '^',
|
|
||||||
MultiValueDelim: ',',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expPT: []argh.Node{
|
|
||||||
argh.Program{Name: "PIZZAs"},
|
|
||||||
argh.ArgDelimiter{},
|
|
||||||
argh.CompoundShortFlag{
|
|
||||||
Nodes: []argh.Node{
|
|
||||||
argh.Flag{Name: "w"},
|
|
||||||
argh.Flag{Name: "A"},
|
|
||||||
argh.Flag{Name: "T", Values: []string{"golf"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
argh.ArgDelimiter{},
|
|
||||||
argh.Flag{Name: "hecKing"},
|
|
||||||
argh.ArgDelimiter{},
|
|
||||||
argh.Command{Name: "goose", Values: []string{"bonk"}},
|
|
||||||
argh.ArgDelimiter{},
|
|
||||||
argh.Flag{Name: "FIERCENESS", Values: []string{"-2"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
} {
|
||||||
if tc.skip {
|
if tc.skip {
|
||||||
continue
|
continue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user