311 lines
7.3 KiB
Go
311 lines
7.3 KiB
Go
package gluaflag
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/yuin/gopher-lua"
|
|
)
|
|
|
|
var flagFuncs = map[string]lua.LGFunction{}
|
|
|
|
type flg struct {
|
|
name string
|
|
value interface{}
|
|
usage string
|
|
required bool
|
|
compFn *lua.LFunction
|
|
}
|
|
|
|
func (f *flg) userdata(L *lua.LState) lua.LValue {
|
|
ud := L.NewUserData()
|
|
ud.Value = f
|
|
L.SetMetatable(ud, L.GetTypeMetatable(luaFlagTypeName))
|
|
return ud
|
|
}
|
|
|
|
type flgs map[string]*flg
|
|
|
|
type argument struct {
|
|
name string
|
|
times int
|
|
glob bool
|
|
optional bool
|
|
usage string
|
|
value lua.LValue
|
|
typ string
|
|
parser parser
|
|
shortUsage shortUsage
|
|
compFn *lua.LFunction
|
|
}
|
|
|
|
func (a *argument) parse(args []string, L *lua.LState) ([]string, error) {
|
|
args, value, err := a.parser(args, L)
|
|
a.value = value
|
|
return args, err
|
|
}
|
|
|
|
func (a *argument) toLValue(L *lua.LState) lua.LValue {
|
|
return a.value
|
|
}
|
|
|
|
func (a *argument) generateUsage() string {
|
|
typ := a.typ
|
|
if typ == "" {
|
|
typ = "string"
|
|
}
|
|
|
|
return fmt.Sprintf(" %v %v\n \t%v\n", a.name, typ, a.usage)
|
|
}
|
|
|
|
type arguments []*argument
|
|
|
|
type parser func([]string, *lua.LState) ([]string, lua.LValue, error)
|
|
|
|
type shortUsage func(string) string
|
|
|
|
// string parsers
|
|
func parseString(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, lua.LNil, fmt.Errorf("expected string")
|
|
}
|
|
return parseOptionalString(args, L)
|
|
}
|
|
|
|
func parseOptionalString(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, lua.LNil, nil
|
|
}
|
|
return args[1:len(args)], lua.LString(args[0]), nil
|
|
}
|
|
|
|
func parseNStrings(n int) parser {
|
|
return func(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < n {
|
|
return args, lua.LNil, fmt.Errorf("expected %v strings", n)
|
|
}
|
|
table := L.NewTable()
|
|
for i := 0; i < n; i++ {
|
|
table.Append(lua.LString(args[i]))
|
|
}
|
|
return args[n:len(args)], table, nil
|
|
}
|
|
}
|
|
|
|
func parseStrings(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, L.NewTable(), fmt.Errorf("expected at least one string")
|
|
}
|
|
|
|
return parseOptionalStrings(args, L)
|
|
}
|
|
|
|
func parseOptionalStrings(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
table := L.NewTable()
|
|
for i := 0; i < len(args); i++ {
|
|
table.Append(lua.LString(args[i]))
|
|
}
|
|
return make([]string, 0), table, nil
|
|
}
|
|
|
|
// integer parsers
|
|
func parseInt(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, lua.LNil, fmt.Errorf("expected string")
|
|
}
|
|
return parseOptionalInt(args, L)
|
|
}
|
|
|
|
func parseOptionalInt(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, lua.LNil, nil
|
|
}
|
|
i, err := strconv.Atoi(args[0])
|
|
if err != nil {
|
|
return args[1:len(args)], lua.LNumber(0), fmt.Errorf("invalid integer value: %v", args[0])
|
|
}
|
|
return args[1:len(args)], lua.LNumber(i), nil
|
|
}
|
|
|
|
func parseNInts(n int) parser {
|
|
return func(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < n {
|
|
return args, lua.LNil, fmt.Errorf("expected %v integers", n)
|
|
}
|
|
table := L.NewTable()
|
|
for i := 0; i < n; i++ {
|
|
v, err := strconv.Atoi(args[i])
|
|
if err != nil {
|
|
return args[1:len(args)], lua.LNumber(0), fmt.Errorf("invalid integer value: %v", args[i])
|
|
}
|
|
table.Append(lua.LNumber(v))
|
|
}
|
|
return args[n:len(args)], table, nil
|
|
}
|
|
}
|
|
|
|
func parseInts(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, L.NewTable(), fmt.Errorf("expected at least one integer")
|
|
}
|
|
|
|
return parseOptionalInts(args, L)
|
|
}
|
|
|
|
func parseOptionalInts(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
table := L.NewTable()
|
|
for i := 0; i < len(args); i++ {
|
|
v, err := strconv.Atoi(args[i])
|
|
if err != nil {
|
|
return args[1:len(args)], lua.LNumber(0), fmt.Errorf("invalid integer value: %v", args[i])
|
|
}
|
|
table.Append(lua.LNumber(v))
|
|
}
|
|
return make([]string, 0), table, nil
|
|
}
|
|
|
|
// number parsers
|
|
func parseNumber(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, lua.LNil, fmt.Errorf("expected string")
|
|
}
|
|
return parseOptionalNumber(args, L)
|
|
}
|
|
|
|
func parseOptionalNumber(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, lua.LNil, nil
|
|
}
|
|
i, err := strconv.ParseFloat(args[0], 64)
|
|
if err != nil {
|
|
return args[1:len(args)], lua.LNumber(0), fmt.Errorf("invalid number value: %v", args[0])
|
|
}
|
|
return args[1:len(args)], lua.LNumber(i), nil
|
|
}
|
|
|
|
func parseNNumbers(n int) parser {
|
|
return func(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < n {
|
|
return args, lua.LNil, fmt.Errorf("expected %v numbers", n)
|
|
}
|
|
table := L.NewTable()
|
|
for i := 0; i < n; i++ {
|
|
v, err := strconv.ParseFloat(args[i], 64)
|
|
if err != nil {
|
|
return args[1:len(args)], lua.LNumber(0), fmt.Errorf("invalid number value: %v", args[i])
|
|
}
|
|
table.Append(lua.LNumber(v))
|
|
}
|
|
return args[n:len(args)], table, nil
|
|
}
|
|
}
|
|
|
|
func parseNumbers(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
if len(args) < 1 {
|
|
return args, L.NewTable(), fmt.Errorf("expected at least one number")
|
|
}
|
|
|
|
return parseOptionalNumbers(args, L)
|
|
}
|
|
|
|
func parseOptionalNumbers(args []string, L *lua.LState) ([]string, lua.LValue, error) {
|
|
table := L.NewTable()
|
|
for i := 0; i < len(args); i++ {
|
|
v, err := strconv.ParseFloat(args[i], 64)
|
|
if err != nil {
|
|
return args[1:len(args)], lua.LNumber(0), fmt.Errorf("invalid number value: %v", args[i])
|
|
}
|
|
table.Append(lua.LNumber(v))
|
|
}
|
|
return make([]string, 0), table, nil
|
|
}
|
|
|
|
func getParser(typ string, option lua.LValue) (parser, error) {
|
|
parsers := map[string]map[string]parser{
|
|
"string": {
|
|
"+": parseStrings,
|
|
"*": parseOptionalStrings,
|
|
"?": parseOptionalString,
|
|
"1": parseString,
|
|
},
|
|
"int": {
|
|
"+": parseInts,
|
|
"*": parseOptionalInts,
|
|
"?": parseOptionalInt,
|
|
"1": parseInt,
|
|
},
|
|
"number": {
|
|
"+": parseNumbers,
|
|
"*": parseOptionalNumbers,
|
|
"?": parseOptionalNumber,
|
|
"1": parseNumber,
|
|
},
|
|
}
|
|
|
|
nParsers := map[string]func(int) parser{
|
|
"string": parseNStrings,
|
|
"int": parseNInts,
|
|
"number": parseNNumbers,
|
|
}
|
|
|
|
switch t := option.(type) {
|
|
case lua.LString:
|
|
if p, ok := parsers[typ][string(t)]; ok {
|
|
return p, nil
|
|
}
|
|
case lua.LNumber:
|
|
switch {
|
|
case int(t) == 1:
|
|
return parsers[typ]["1"], nil
|
|
case int(t) > 1:
|
|
return nParsers[typ](int(t)), nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("nargs should be an integer or one of '?', '*', or '+'")
|
|
}
|
|
|
|
func getShortUsageFn(option lua.LValue) (shortUsage, error) {
|
|
su := map[string]shortUsage{
|
|
"?": func(name string) string {
|
|
return fmt.Sprintf("[%v] ", name)
|
|
},
|
|
"1": func(name string) string {
|
|
return fmt.Sprintf("%v ", name)
|
|
},
|
|
|
|
"*": func(name string) string {
|
|
return fmt.Sprintf("[%v...] ", name)
|
|
},
|
|
"+": func(name string) string {
|
|
return fmt.Sprintf("%v [%v...] ", name, name)
|
|
},
|
|
}
|
|
|
|
shortNUsage := func(n int) shortUsage {
|
|
return func(name string) string {
|
|
usage := ""
|
|
for i := 0; i < n; i++ {
|
|
usage = fmt.Sprintf("%v %v ", usage, name)
|
|
}
|
|
return usage
|
|
}
|
|
}
|
|
|
|
switch t := option.(type) {
|
|
case lua.LString:
|
|
if p, ok := su[string(t)]; ok {
|
|
return p, nil
|
|
}
|
|
case lua.LNumber:
|
|
switch {
|
|
case int(t) == 1:
|
|
return su["1"], nil
|
|
case int(t) > 1:
|
|
return shortNUsage(int(t)), nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("nargs should be an integer or one of '?', '*', or '+'")
|
|
}
|