Command parsers plan 1
This commit is contained in:
95
server/command/command.go
Normal file
95
server/command/command.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CmdSet struct {
|
||||||
|
root int32
|
||||||
|
nodes []Node
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCmdSet() *CmdSet {
|
||||||
|
return &CmdSet{
|
||||||
|
root: 0,
|
||||||
|
nodes: []Node{
|
||||||
|
{
|
||||||
|
flags: TypeRoot,
|
||||||
|
parser: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CmdSet) AddNode(n Node) int32 {
|
||||||
|
c.nodes = append(c.nodes, n)
|
||||||
|
return int32(len(c.nodes) - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CmdSet) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.Array(c.nodes),
|
||||||
|
pk.VarInt(c.root),
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CmdSet) Execute(cmd string) error {
|
||||||
|
for _, child := range c.nodes[c.root].children {
|
||||||
|
if node := c.nodes[child]; node.flags&0x03 == TypeLiteral {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
flags byte
|
||||||
|
children []int32
|
||||||
|
redirect int32
|
||||||
|
name string
|
||||||
|
parser Parser
|
||||||
|
suggestions string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.Byte(n.flags),
|
||||||
|
pk.Array(*(*[]pk.VarInt)(unsafe.Pointer(&n.children))),
|
||||||
|
pk.Opt{ // Redirect
|
||||||
|
Has: n.flags&HasRedirect != 0,
|
||||||
|
Field: pk.VarInt(n.redirect),
|
||||||
|
},
|
||||||
|
pk.Opt{ // Name
|
||||||
|
Has: n.flags&0x03 == TypeLiteral || n.flags&0x03 == TypeArgument,
|
||||||
|
Field: pk.String(n.name),
|
||||||
|
},
|
||||||
|
pk.Opt{ // Parser & Properties
|
||||||
|
Has: n.flags&0x03 == TypeArgument,
|
||||||
|
Field: n.parser,
|
||||||
|
},
|
||||||
|
pk.Opt{
|
||||||
|
Has: n.flags&HasSuggestionsType != 0,
|
||||||
|
Field: pk.Identifier(n.suggestions),
|
||||||
|
},
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parser interface {
|
||||||
|
pk.FieldEncoder
|
||||||
|
Parse(cmd string) (token string, value interface{}, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeRoot byte = iota
|
||||||
|
TypeLiteral
|
||||||
|
TypeArgument
|
||||||
|
TypeUnknown
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IsExecutable = 1 << (iota + 2)
|
||||||
|
HasRedirect
|
||||||
|
HasSuggestionsType
|
||||||
|
)
|
72
server/command/parsers.go
Normal file
72
server/command/parsers.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StringParser struct {
|
||||||
|
Format int32
|
||||||
|
V string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s StringParser) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.Identifier("brigadier:string"),
|
||||||
|
pk.VarInt(s.Format),
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s StringParser) Parse(cmd string) (token string, value interface{}, err error) {
|
||||||
|
switch s.Format {
|
||||||
|
case 2: // Greedy Phrase
|
||||||
|
return cmd, cmd, nil
|
||||||
|
case 1: // Quotable Phrase
|
||||||
|
if len(cmd) > 0 && cmd[0] == '"' {
|
||||||
|
var sb strings.Builder
|
||||||
|
var isEscaping bool
|
||||||
|
for i, v := range cmd[1:] {
|
||||||
|
if isEscaping {
|
||||||
|
isEscaping = false
|
||||||
|
switch v {
|
||||||
|
case '\\':
|
||||||
|
sb.WriteRune('\\')
|
||||||
|
case '"':
|
||||||
|
sb.WriteRune('"')
|
||||||
|
}
|
||||||
|
} else if v == '\\' {
|
||||||
|
isEscaping = true
|
||||||
|
} else if v == '"' {
|
||||||
|
return cmd[:i], sb.String(), nil
|
||||||
|
} else {
|
||||||
|
sb.WriteRune(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil, ParseErr{
|
||||||
|
Pos: len(cmd) - 1,
|
||||||
|
Err: "expected '\"'",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 0: // Single Word
|
||||||
|
i := strings.IndexAny(cmd, "\t\n\v\f\r ")
|
||||||
|
if i == -1 {
|
||||||
|
return cmd, cmd, nil
|
||||||
|
}
|
||||||
|
return cmd[:i], cmd[:i], nil
|
||||||
|
default:
|
||||||
|
panic("StringParser: unknown format 0x" + strconv.FormatInt(int64(s.Format), 16))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParseErr struct {
|
||||||
|
Pos int
|
||||||
|
Err string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p ParseErr) Error() string {
|
||||||
|
return p.Err
|
||||||
|
}
|
Reference in New Issue
Block a user