2019-03-17 16:58:39 +00:00
|
|
|
package cmdparse
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2019-04-28 19:46:47 +00:00
|
|
|
"io"
|
2019-03-17 16:58:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
//------------------------------------------------\\
|
|
|
|
// + + + T Y P E S + + + \\
|
|
|
|
//--------------------------------------------------\\
|
|
|
|
|
|
|
|
type Parser struct {
|
2019-04-28 19:46:47 +00:00
|
|
|
s *scanner
|
|
|
|
buffer struct {
|
|
|
|
token Token
|
|
|
|
size int
|
2019-03-17 16:58:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Command struct {
|
2019-04-28 19:46:47 +00:00
|
|
|
Action string
|
|
|
|
Target string
|
|
|
|
Value []string
|
|
|
|
Type Comtype
|
2019-03-17 16:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Comtype int
|
2019-04-28 19:46:47 +00:00
|
|
|
|
2019-03-17 16:58:39 +00:00
|
|
|
const (
|
|
|
|
GOURL Comtype = iota
|
|
|
|
GOLINK
|
|
|
|
SIMPLE
|
|
|
|
DOLINK
|
|
|
|
DOLINKAS
|
|
|
|
DOAS
|
2019-05-09 04:01:54 +00:00
|
|
|
DO
|
2019-03-17 16:58:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
//------------------------------------------------\\
|
|
|
|
// + + + R E C E I V E R S + + + \\
|
|
|
|
//--------------------------------------------------\\
|
|
|
|
|
|
|
|
func (p *Parser) scan() (current Token) {
|
|
|
|
if p.buffer.size != 0 {
|
|
|
|
p.buffer.size = 0
|
|
|
|
return p.buffer.token
|
|
|
|
}
|
|
|
|
|
|
|
|
current = p.s.scan()
|
|
|
|
for {
|
|
|
|
if current.kind != Whitespace {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
current = p.s.scan()
|
|
|
|
}
|
|
|
|
|
|
|
|
p.buffer.token = current
|
2019-04-28 19:46:47 +00:00
|
|
|
return
|
2019-03-17 16:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) unscan() { p.buffer.size = 1 }
|
|
|
|
|
|
|
|
func (p *Parser) parseNonAction() (*Command, error) {
|
|
|
|
p.unscan()
|
|
|
|
t := p.scan()
|
|
|
|
cm := &Command{}
|
|
|
|
|
|
|
|
if t.kind == Value {
|
|
|
|
cm.Target = t.val
|
|
|
|
cm.Type = GOLINK
|
|
|
|
} else if t.kind == Word {
|
|
|
|
cm.Target = t.val
|
|
|
|
cm.Type = GOURL
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("Found %q, expected action, url, or link number", t.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
if u := p.scan(); u.kind != End {
|
|
|
|
return nil, fmt.Errorf("Found %q, expected EOF", u.val)
|
|
|
|
}
|
|
|
|
return cm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) parseAction() (*Command, error) {
|
|
|
|
p.unscan()
|
|
|
|
t := p.scan()
|
|
|
|
cm := &Command{}
|
|
|
|
cm.Action = t.val
|
|
|
|
t = p.scan()
|
|
|
|
switch t.kind {
|
2019-04-28 19:46:47 +00:00
|
|
|
case End:
|
|
|
|
cm.Type = SIMPLE
|
|
|
|
return cm, nil
|
|
|
|
case Value:
|
|
|
|
cm.Target = t.val
|
|
|
|
cm.Type = DOLINK
|
2020-11-01 05:05:27 +00:00
|
|
|
case Word, Action:
|
2019-04-28 19:46:47 +00:00
|
|
|
cm.Value = append(cm.Value, t.val)
|
2019-05-09 04:01:54 +00:00
|
|
|
cm.Type = DO
|
2020-11-01 05:05:27 +00:00
|
|
|
case Whitespace:
|
2019-04-28 19:46:47 +00:00
|
|
|
return nil, fmt.Errorf("Found %q (%d), expected value", t.val, t.kind)
|
2019-03-17 16:58:39 +00:00
|
|
|
}
|
|
|
|
t = p.scan()
|
|
|
|
if t.kind == End {
|
|
|
|
return cm, nil
|
|
|
|
} else {
|
|
|
|
if cm.Type == DOLINK {
|
|
|
|
cm.Type = DOLINKAS
|
|
|
|
} else {
|
|
|
|
cm.Type = DOAS
|
|
|
|
}
|
|
|
|
cm.Value = append(cm.Value, t.val)
|
|
|
|
|
|
|
|
for {
|
|
|
|
token := p.scan()
|
|
|
|
if token.kind == End {
|
|
|
|
break
|
|
|
|
} else if token.kind == Whitespace {
|
|
|
|
continue
|
|
|
|
}
|
2019-04-28 19:46:47 +00:00
|
|
|
cm.Value = append(cm.Value, token.val)
|
2019-03-17 16:58:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return cm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) Parse() (*Command, error) {
|
|
|
|
if t := p.scan(); t.kind != Action {
|
|
|
|
return p.parseNonAction()
|
|
|
|
} else {
|
|
|
|
return p.parseAction()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------\\
|
|
|
|
// + + + F U N C T I O N S + + + \\
|
|
|
|
//--------------------------------------------------\\
|
|
|
|
|
|
|
|
func NewParser(r io.Reader) *Parser {
|
|
|
|
return &Parser{s: NewScanner(r)}
|
|
|
|
}
|