arghing #1
@ -8,18 +8,19 @@ func _() {
|
|||||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
// Re-run the stringer command to generate them again.
|
// Re-run the stringer command to generate them again.
|
||||||
var x [1]struct{}
|
var x [1]struct{}
|
||||||
|
_ = x[OneOrMoreValue - -2]
|
||||||
|
_ = x[ZeroOrMoreValue - -1]
|
||||||
_ = x[ZeroValue-0]
|
_ = x[ZeroValue-0]
|
||||||
_ = x[OneValue-1]
|
|
||||||
_ = x[OneOrMoreValue-2]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _NValue_name = "ZeroValueOneValueOneOrMoreValue"
|
const _NValue_name = "OneOrMoreValueZeroOrMoreValueZeroValue"
|
||||||
|
|
||||||
var _NValue_index = [...]uint8{0, 9, 17, 31}
|
var _NValue_index = [...]uint8{0, 14, 29, 38}
|
||||||
|
|
||||||
func (i NValue) String() string {
|
func (i NValue) String() string {
|
||||||
|
i -= -2
|
||||||
if i < 0 || i >= NValue(len(_NValue_index)-1) {
|
if i < 0 || i >= NValue(len(_NValue_index)-1) {
|
||||||
return "NValue(" + strconv.FormatInt(int64(i), 10) + ")"
|
return "NValue(" + strconv.FormatInt(int64(i+-2), 10) + ")"
|
||||||
}
|
}
|
||||||
return _NValue_name[_NValue_index[i]:_NValue_index[i+1]]
|
return _NValue_name[_NValue_index[i]:_NValue_index[i+1]]
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ZeroValue NValue = iota
|
OneOrMoreValue NValue = -2
|
||||||
OneValue
|
ZeroOrMoreValue NValue = -1
|
||||||
OneOrMoreValue
|
ZeroValue NValue = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errSyntax = errors.New("syntax error")
|
ErrSyntax = errors.New("syntax error")
|
||||||
|
|
||||||
DefaultParserConfig = &ParserConfig{
|
DefaultParserConfig = &ParserConfig{
|
||||||
Commands: map[string]NValue{},
|
Commands: map[string]NValue{},
|
||||||
@ -57,6 +57,10 @@ type ParserConfig struct {
|
|||||||
ProgValues NValue
|
ProgValues NValue
|
||||||
Commands map[string]NValue
|
Commands map[string]NValue
|
||||||
Flags map[string]NValue
|
Flags map[string]NValue
|
||||||
|
|
||||||
|
OnUnknownFlag func(string) error
|
||||||
|
OnUnknownCommand func(string) error
|
||||||
|
|
||||||
ScannerConfig *ScannerConfig
|
ScannerConfig *ScannerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +101,7 @@ func (p *Parser) Parse() (*Argh, error) {
|
|||||||
func (p *Parser) parseArg() (bool, error) {
|
func (p *Parser) parseArg() (bool, 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 false, errors.Wrapf(ErrSyntax, "illegal value %q at pos=%v", lit, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok == EOL {
|
if tok == EOL {
|
||||||
@ -127,6 +131,10 @@ func (p *Parser) nodify() (Node, error) {
|
|||||||
tracef("nodify tok=%s lit=%q pos=%v", tok, lit, pos)
|
tracef("nodify tok=%s lit=%q pos=%v", tok, lit, pos)
|
||||||
|
|
||||||
switch tok {
|
switch tok {
|
||||||
|
case ARG_DELIMITER:
|
||||||
|
return ArgDelimiter{}, nil
|
||||||
|
case ASSIGN:
|
||||||
|
return nil, errors.Wrapf(ErrSyntax, "bare assignment operator at pos=%v", pos)
|
||||||
case IDENT:
|
case IDENT:
|
||||||
if len(p.nodes) == 0 {
|
if len(p.nodes) == 0 {
|
||||||
values, err := p.scanValues(lit, pos, p.cfg.ProgValues)
|
values, err := p.scanValues(lit, pos, p.cfg.ProgValues)
|
||||||
@ -147,8 +155,6 @@ func (p *Parser) nodify() (Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Ident{Literal: lit}, nil
|
return Ident{Literal: lit}, nil
|
||||||
case ARG_DELIMITER:
|
|
||||||
return ArgDelimiter{}, nil
|
|
||||||
case COMPOUND_SHORT_FLAG:
|
case COMPOUND_SHORT_FLAG:
|
||||||
flagNodes := []Node{}
|
flagNodes := []Node{}
|
||||||
|
|
||||||
@ -222,7 +228,7 @@ func (p *Parser) scanValues(lit string, pos int, n NValue) ([]string, error) {
|
|||||||
for {
|
for {
|
||||||
lit, err := p.scanIdent()
|
lit, err := p.scanIdent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if n == OneValue {
|
if n == NValue(1) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +239,7 @@ func (p *Parser) scanValues(lit string, pos int, n NValue) ([]string, error) {
|
|||||||
|
|
||||||
ret = append(ret, lit)
|
ret = append(ret, lit)
|
||||||
|
|
||||||
if n == OneValue && len(ret) == 1 {
|
if n == NValue(1) && len(ret) == 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,10 +261,16 @@ func (p *Parser) scanValues(lit string, pos int, n NValue) ([]string, error) {
|
|||||||
func (p *Parser) scanIdent() (string, error) {
|
func (p *Parser) scanIdent() (string, error) {
|
||||||
tok, lit, pos := p.scan()
|
tok, lit, pos := p.scan()
|
||||||
|
|
||||||
|
tracef("scanIdent scanned tok=%s lit=%q pos=%v", tok, lit, pos)
|
||||||
|
|
||||||
unscanBuf := []ScanEntry{}
|
unscanBuf := []ScanEntry{}
|
||||||
|
|
||||||
if tok == ASSIGN || tok == ARG_DELIMITER {
|
if tok == ASSIGN || tok == ARG_DELIMITER {
|
||||||
unscanBuf = append([]ScanEntry{{tok: tok, lit: lit, pos: pos}}, unscanBuf...)
|
entry := ScanEntry{tok: tok, lit: lit, pos: pos}
|
||||||
|
|
||||||
|
tracef("scanIdent tok=%s; scanning next and pushing to unscan buffer entry=%+#v", tok, entry)
|
||||||
|
|
||||||
|
unscanBuf = append([]ScanEntry{entry}, unscanBuf...)
|
||||||
|
|
||||||
tok, lit, pos = p.scan()
|
tok, lit, pos = p.scan()
|
||||||
}
|
}
|
||||||
@ -267,13 +279,17 @@ func (p *Parser) scanIdent() (string, error) {
|
|||||||
return lit, nil
|
return lit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unscanBuf = append([]ScanEntry{{tok: tok, lit: lit, pos: pos}}, unscanBuf...)
|
entry := ScanEntry{tok: tok, lit: lit, pos: pos}
|
||||||
|
|
||||||
|
tracef("scanIdent tok=%s; unscanning entry=%+#v", tok, entry)
|
||||||
|
|
||||||
|
unscanBuf = append([]ScanEntry{entry}, unscanBuf...)
|
||||||
|
|
||||||
for _, entry := range unscanBuf {
|
for _, entry := range unscanBuf {
|
||||||
p.unscan(entry.tok, entry.lit, entry.pos)
|
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) {
|
||||||
|
@ -35,7 +35,7 @@ func TestParser(t *testing.T) {
|
|||||||
name: "one positional arg",
|
name: "one positional arg",
|
||||||
args: []string{"pizzas", "excel"},
|
args: []string{"pizzas", "excel"},
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
ProgValues: argh.OneValue,
|
ProgValues: 1,
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Program{Name: "pizzas", Values: []string{"excel"}},
|
argh.Program{Name: "pizzas", Values: []string{"excel"}},
|
||||||
@ -89,7 +89,7 @@ func TestParser(t *testing.T) {
|
|||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
Commands: map[string]argh.NValue{},
|
Commands: map[string]argh.NValue{},
|
||||||
Flags: map[string]argh.NValue{
|
Flags: map[string]argh.NValue{
|
||||||
"fresh": argh.OneValue,
|
"fresh": 1,
|
||||||
"box": argh.OneOrMoreValue,
|
"box": argh.OneOrMoreValue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -173,7 +173,7 @@ func TestParser(t *testing.T) {
|
|||||||
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: map[string]argh.NValue{},
|
||||||
Flags: map[string]argh.NValue{"b": argh.OneValue},
|
Flags: map[string]argh.NValue{"b": 1},
|
||||||
},
|
},
|
||||||
expPT: []argh.Node{
|
expPT: []argh.Node{
|
||||||
argh.Program{Name: "pizzas"},
|
argh.Program{Name: "pizzas"},
|
||||||
@ -221,13 +221,13 @@ func TestParser(t *testing.T) {
|
|||||||
name: "total weirdo",
|
name: "total weirdo",
|
||||||
args: []string{"PIZZAs", "^wAT@golf", "^^hecKing", "goose", "bonk", "^^FIERCENESS@-2"},
|
args: []string{"PIZZAs", "^wAT@golf", "^^hecKing", "goose", "bonk", "^^FIERCENESS@-2"},
|
||||||
cfg: &argh.ParserConfig{
|
cfg: &argh.ParserConfig{
|
||||||
Commands: map[string]argh.NValue{"goose": argh.OneValue},
|
Commands: map[string]argh.NValue{"goose": 1},
|
||||||
Flags: map[string]argh.NValue{
|
Flags: map[string]argh.NValue{
|
||||||
"w": argh.ZeroValue,
|
"w": 0,
|
||||||
"A": argh.ZeroValue,
|
"A": 0,
|
||||||
"T": argh.OneValue,
|
"T": 1,
|
||||||
"hecking": argh.ZeroValue,
|
"hecking": 0,
|
||||||
"FIERCENESS": argh.OneValue,
|
"FIERCENESS": 1,
|
||||||
},
|
},
|
||||||
ScannerConfig: &argh.ScannerConfig{
|
ScannerConfig: &argh.ScannerConfig{
|
||||||
AssignmentOperator: '@',
|
AssignmentOperator: '@',
|
||||||
@ -253,6 +253,15 @@ func TestParser(t *testing.T) {
|
|||||||
argh.Flag{Name: "FIERCENESS", Values: []string{"-2"}},
|
argh.Flag{Name: "FIERCENESS", Values: []string{"-2"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "invalid bare assignment",
|
||||||
|
args: []string{"pizzas", "=", "--wat"},
|
||||||
|
expErr: argh.ErrSyntax,
|
||||||
|
expPT: []argh.Node{
|
||||||
|
argh.Program{Name: "pizzas"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{},
|
||||||
} {
|
} {
|
||||||
if tc.skip {
|
if tc.skip {
|
||||||
continue
|
continue
|
||||||
|
@ -167,6 +167,10 @@ func (s *Scanner) scanArg() (Token, string, int) {
|
|||||||
return STDIN_FLAG, str, pos
|
return STDIN_FLAG, str, pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.isAssignmentOperator(ch0) {
|
||||||
|
return ASSIGN, str, pos
|
||||||
|
}
|
||||||
|
|
||||||
return IDENT, str, pos
|
return IDENT, str, pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user