refactor command options
This commit is contained in:
parent
f45e6bab4b
commit
19c308fa33
63
cmd/treerack/args.go
Normal file
63
cmd/treerack/args.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "flag"
|
||||||
|
|
||||||
|
type syntaxOptions struct {
|
||||||
|
usage string
|
||||||
|
example string
|
||||||
|
args []string
|
||||||
|
positional []string
|
||||||
|
syntax string
|
||||||
|
syntaxFile string
|
||||||
|
flagSet *flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func initOptions(usage, example string, args []string) *syntaxOptions {
|
||||||
|
var o syntaxOptions
|
||||||
|
o.usage = usage
|
||||||
|
o.example = example
|
||||||
|
o.args = args
|
||||||
|
o.flagSet = flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
|
o.flagSet.Usage = func() {}
|
||||||
|
o.flagSet.SetOutput(werr)
|
||||||
|
o.flagSet.StringVar(&o.syntax, "syntax-string", "", syntaxStringUsage)
|
||||||
|
o.flagSet.StringVar(&o.syntaxFile, "syntax", "", syntaxFileUsage)
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagError(fs *flag.FlagSet) {
|
||||||
|
stderr()
|
||||||
|
stderr("Options:")
|
||||||
|
fs.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *syntaxOptions) parse() (exit int) {
|
||||||
|
if err := o.flagSet.Parse(o.args); err != nil {
|
||||||
|
flagError(o.flagSet)
|
||||||
|
exit = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
o.positional = o.flagSet.Args()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *syntaxOptions) help() {
|
||||||
|
stdout(o.usage)
|
||||||
|
stdout()
|
||||||
|
stdout("Options:")
|
||||||
|
o.flagSet.SetOutput(wout)
|
||||||
|
o.flagSet.PrintDefaults()
|
||||||
|
stdout()
|
||||||
|
stdout(o.example)
|
||||||
|
stdout()
|
||||||
|
stdout(docRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *syntaxOptions) checkHelp() bool {
|
||||||
|
if len(o.args) == 0 || o.args[0] != "-help" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
o.help()
|
||||||
|
return true
|
||||||
|
}
|
@ -1,54 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
func check([]string) int {
|
||||||
"flag"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type checkOptions struct {
|
|
||||||
syntaxOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagSetCheck(o *checkOptions, output io.Writer) *flag.FlagSet {
|
|
||||||
fs := flag.NewFlagSet("", flag.ContinueOnError)
|
|
||||||
fs.Usage = func() {}
|
|
||||||
fs.SetOutput(output)
|
|
||||||
fs.StringVar(&o.syntax, "syntax-string", "", syntaxStringUsage)
|
|
||||||
fs.StringVar(&o.syntaxFile, "syntax", "", syntaxFileUsage)
|
|
||||||
return fs
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagErrorCheck(fs *flag.FlagSet) {
|
|
||||||
stderr()
|
|
||||||
stderr("Options:")
|
|
||||||
fs.PrintDefaults()
|
|
||||||
}
|
|
||||||
|
|
||||||
func helpCheck() {
|
|
||||||
stdout(checkUsage)
|
|
||||||
stdout()
|
|
||||||
stdout("Options:")
|
|
||||||
fs := flagSetCheck(&checkOptions{}, wout)
|
|
||||||
fs.PrintDefaults()
|
|
||||||
stdout()
|
|
||||||
stdout(checkExample)
|
|
||||||
stdout()
|
|
||||||
stdout(docRef)
|
|
||||||
}
|
|
||||||
|
|
||||||
func check(args []string) int {
|
|
||||||
if len(args) > 0 && args[0] == "-help" {
|
|
||||||
helpCheck()
|
|
||||||
return 0
|
return 0
|
||||||
}
|
|
||||||
|
|
||||||
var options checkOptions
|
|
||||||
fs := flagSetCheck(&options, werr)
|
|
||||||
if err := fs.Parse(args); err != nil {
|
|
||||||
flagErrorCheck(fs)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
_, code := open(options.syntaxOptions, fs)
|
|
||||||
return code
|
|
||||||
}
|
}
|
||||||
|
@ -1,103 +1 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestCheck(t *testing.T) {
|
|
||||||
runMainTest(t,
|
|
||||||
mainTest{
|
|
||||||
title: "help",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check", "-help",
|
|
||||||
},
|
|
||||||
stdout: []string{
|
|
||||||
checkUsage,
|
|
||||||
"-syntax",
|
|
||||||
"-syntax-string",
|
|
||||||
checkExample,
|
|
||||||
docRef,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "invalid flag",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check", "-foo",
|
|
||||||
},
|
|
||||||
exit: -1,
|
|
||||||
stderr: []string{
|
|
||||||
"-syntax",
|
|
||||||
"-syntax-string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "multiple inputs",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check", "-syntax", "foo.treerack", "-syntax-string", `foo = "bar"`,
|
|
||||||
},
|
|
||||||
exit: -1,
|
|
||||||
stderr: []string{
|
|
||||||
"only one",
|
|
||||||
"-syntax",
|
|
||||||
"-syntax-string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "no input",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check",
|
|
||||||
},
|
|
||||||
exit: -1,
|
|
||||||
stderr: []string{
|
|
||||||
"missing syntax input",
|
|
||||||
"-syntax",
|
|
||||||
"-syntax-string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "invalid input",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check", "-syntax-string", "foo",
|
|
||||||
},
|
|
||||||
exit: -1,
|
|
||||||
stderr: []string{
|
|
||||||
"parse failed",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "file open fails",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check", "-syntax", "noexist.treerack",
|
|
||||||
},
|
|
||||||
exit: -1,
|
|
||||||
stderr: []string{
|
|
||||||
"file",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "syntax as stdin",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "check",
|
|
||||||
},
|
|
||||||
stdin: `foo = "bar"`,
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "syntax as file",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "generate", "-syntax", "foo_test.treerack",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainTest{
|
|
||||||
title: "syntax as string",
|
|
||||||
args: []string{
|
|
||||||
"treerack", "generate", "-syntax-string", `foo = "bar"`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
15
cmd/treerack/checksyntax.go
Normal file
15
cmd/treerack/checksyntax.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func checkSyntax(args []string) int {
|
||||||
|
options := initOptions(checkSyntaxUsage, checkSyntaxExample, args)
|
||||||
|
if options.checkHelp() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if code := options.parse(); code != 0 {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
_, code := openSyntax(options)
|
||||||
|
return code
|
||||||
|
}
|
129
cmd/treerack/checksyntax_test.go
Normal file
129
cmd/treerack/checksyntax_test.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestCheckSyntax(t *testing.T) {
|
||||||
|
runMainTest(t,
|
||||||
|
mainTest{
|
||||||
|
title: "help",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "-help",
|
||||||
|
},
|
||||||
|
stdout: []string{
|
||||||
|
checkSyntaxUsage,
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
checkSyntaxExample,
|
||||||
|
docRef,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "invalid flag",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "-foo",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "multiple inputs",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "-syntax", "foo.treerack", "-syntax-string", `foo = "bar"`,
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"only one",
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "multiple inputs, positional",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "foo.treerack", "bar.treerack",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"only one",
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "multiple inputs, positional and explicit file",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "-syntax", "foo.treerack", "bar.treerack",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"only one",
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "no input",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"missing syntax input",
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "invalid input",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "-syntax-string", "foo",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"parse failed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "file open fails",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax", "-syntax", "noexist.treerack",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"file",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "syntax as stdin",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "check-syntax",
|
||||||
|
},
|
||||||
|
stdin: `foo = "bar"`,
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "syntax as file",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "generate", "-syntax", "foo_test.treerack",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "syntax as string",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "generate", "-syntax-string", `foo = "bar"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
@ -3,6 +3,9 @@ package main
|
|||||||
const summary = `treerack - parser generator - https://github.com/aryszka/treerack`
|
const summary = `treerack - parser generator - https://github.com/aryszka/treerack`
|
||||||
|
|
||||||
const commandsHelp = `Available commands:
|
const commandsHelp = `Available commands:
|
||||||
|
check validates an arbitrary input against a syntax definition
|
||||||
|
parse parses an arbitrary input with a syntax definition into an abstract syntax tree
|
||||||
|
check-syntax validates a syntax definition
|
||||||
generate generates a parser from a syntax definition
|
generate generates a parser from a syntax definition
|
||||||
help prints the current help
|
help prints the current help
|
||||||
|
|
||||||
@ -19,12 +22,17 @@ const packageNameUsage = `package name of the generated Go code`
|
|||||||
|
|
||||||
const exportUsage = `when the export flag is set, the generated code will have exported symbols to allow using it as a separate package`
|
const exportUsage = `when the export flag is set, the generated code will have exported symbols to allow using it as a separate package`
|
||||||
|
|
||||||
const generateUsage = `treerack generate takes a syntax description from the standard input, or a file, or inline string, and generates parser code implementing the described syntax. It prints the parser code to the standard output.`
|
const parseUsage = `'treerack parse' takes a syntax description from a file or inline string, an arbitrary piece of text from the standard input, or a file, or inline string, and parses the input text with the defined syntax. If it was successfully parsed, it prints the resulting abstract syntax tree (AST) in JSON format.`
|
||||||
|
|
||||||
|
const parseExample = `Example:
|
||||||
|
treerack parse -syntax example.treerack foo.example`
|
||||||
|
|
||||||
|
const checkSyntaxUsage = `'treerack check-syntax' takes a syntax description from the standard input, or a file, or inline string, and validates it to check whether it represents a valid syntax. It returns with non-zero exit code and prints the problem if the syntax is not valid.`
|
||||||
|
|
||||||
|
const checkSyntaxExample = `Example:
|
||||||
|
treerack check-syntax example.treerack`
|
||||||
|
|
||||||
|
const generateUsage = `'treerack generate' takes a syntax description from the standard input, or a file, or inline string, and generates parser code implementing the described syntax. It prints the parser code to the standard output.`
|
||||||
|
|
||||||
const generateExample = `Example:
|
const generateExample = `Example:
|
||||||
treerack generate -syntax syntax.treerack > parser.go`
|
treerack generate example.treerack > parser.go`
|
||||||
|
|
||||||
const checkUsage = `treerack check takes a syntax description from the standard input, or a file, or inline string, and validates it to check whether it represents a valid syntax. It returns with non-zero exit code and prints the problem if the syntax is not valid.`
|
|
||||||
|
|
||||||
const checkExample = `Example:
|
|
||||||
treerack check -syntax syntax.treerack`
|
|
||||||
|
@ -1,62 +1,24 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "github.com/aryszka/treerack"
|
||||||
"flag"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/aryszka/treerack"
|
|
||||||
)
|
|
||||||
|
|
||||||
type generateOptions struct {
|
type generateOptions struct {
|
||||||
syntaxOptions
|
*syntaxOptions
|
||||||
packageName string
|
packageName string
|
||||||
export bool
|
export bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func flagSetGenerate(o *generateOptions, output io.Writer) *flag.FlagSet {
|
|
||||||
fs := flag.NewFlagSet("", flag.ContinueOnError)
|
|
||||||
fs.Usage = func() {}
|
|
||||||
fs.SetOutput(output)
|
|
||||||
fs.StringVar(&o.syntax, "syntax-string", "", syntaxStringUsage)
|
|
||||||
fs.StringVar(&o.syntaxFile, "syntax", "", syntaxFileUsage)
|
|
||||||
fs.StringVar(&o.packageName, "package-name", "", packageNameUsage)
|
|
||||||
fs.BoolVar(&o.export, "export", false, exportUsage)
|
|
||||||
return fs
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagErrorGenerate(fs *flag.FlagSet) {
|
|
||||||
stderr()
|
|
||||||
stderr("Options:")
|
|
||||||
fs.PrintDefaults()
|
|
||||||
}
|
|
||||||
|
|
||||||
func helpGenerate() {
|
|
||||||
stdout(generateUsage)
|
|
||||||
stdout()
|
|
||||||
stdout("Options:")
|
|
||||||
fs := flagSetGenerate(&generateOptions{}, wout)
|
|
||||||
fs.PrintDefaults()
|
|
||||||
stdout()
|
|
||||||
stdout(generateExample)
|
|
||||||
stdout()
|
|
||||||
stdout(docRef)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generate(args []string) int {
|
func generate(args []string) int {
|
||||||
if len(args) > 0 && args[0] == "-help" {
|
var options generateOptions
|
||||||
helpGenerate()
|
options.syntaxOptions = initOptions(generateUsage, generateExample, args)
|
||||||
|
options.flagSet.BoolVar(&options.export, "export", false, exportUsage)
|
||||||
|
options.flagSet.StringVar(&options.packageName, "package-name", "", packageNameUsage)
|
||||||
|
|
||||||
|
if options.checkHelp() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var options generateOptions
|
if code := options.parse(); code != 0 {
|
||||||
fs := flagSetGenerate(&options, werr)
|
|
||||||
if err := fs.Parse(args); err != nil {
|
|
||||||
flagErrorGenerate(fs)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
s, code := open(options.syntaxOptions, fs)
|
|
||||||
if code != 0 {
|
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +26,11 @@ func generate(args []string) int {
|
|||||||
goptions.PackageName = options.packageName
|
goptions.PackageName = options.packageName
|
||||||
goptions.Export = options.export
|
goptions.Export = options.export
|
||||||
|
|
||||||
|
s, code := openSyntax(options.syntaxOptions)
|
||||||
|
if code != 0 {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.Generate(goptions, wout); err != nil {
|
if err := s.Generate(goptions, wout); err != nil {
|
||||||
stderr(err)
|
stderr(err)
|
||||||
return -1
|
return -1
|
||||||
|
@ -49,6 +49,36 @@ func TestGenerate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "multiple inputs, positional",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "generate", "foo.treerack", "bar.treerack",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"only one",
|
||||||
|
"-export",
|
||||||
|
"-package-name",
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mainTest{
|
||||||
|
title: "multiple inputs, positional and explicit file",
|
||||||
|
args: []string{
|
||||||
|
"treerack", "generate", "-syntax", "foo.treerack", "bar.treerack",
|
||||||
|
},
|
||||||
|
exit: -1,
|
||||||
|
stderr: []string{
|
||||||
|
"only one",
|
||||||
|
"-export",
|
||||||
|
"-package-name",
|
||||||
|
"-syntax",
|
||||||
|
"-syntax-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mainTest{
|
mainTest{
|
||||||
title: "no input",
|
title: "no input",
|
||||||
args: []string{
|
args: []string{
|
||||||
|
@ -21,19 +21,27 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cmd func([]string) int
|
||||||
|
|
||||||
switch os.Args[1] {
|
switch os.Args[1] {
|
||||||
case "check":
|
case "check-syntax":
|
||||||
code := check(os.Args[2:])
|
cmd = checkSyntax
|
||||||
exit(code)
|
|
||||||
case "generate":
|
case "generate":
|
||||||
code := generate(os.Args[2:])
|
cmd = generate
|
||||||
exit(code)
|
case "check":
|
||||||
|
cmd = check
|
||||||
|
case "parse":
|
||||||
|
cmd = parse
|
||||||
case "help", "-help":
|
case "help", "-help":
|
||||||
mainHelp()
|
mainHelp()
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
stderr("invalid command")
|
stderr("invalid command")
|
||||||
stderr()
|
stderr()
|
||||||
stderr(commandsHelp)
|
stderr(commandsHelp)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit(cmd(os.Args[2:]))
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,6 @@ import (
|
|||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type syntaxOptions struct {
|
|
||||||
syntax string
|
|
||||||
syntaxFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
func multipleSyntaxesError(fs *flag.FlagSet) {
|
func multipleSyntaxesError(fs *flag.FlagSet) {
|
||||||
stderr("only one of syntax file or syntax string is allowed")
|
stderr("only one of syntax file or syntax string is allowed")
|
||||||
stderr()
|
stderr()
|
||||||
@ -29,27 +24,62 @@ func missingSyntaxError(fs *flag.FlagSet) {
|
|||||||
fs.PrintDefaults()
|
fs.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
func open(options syntaxOptions, fs *flag.FlagSet) (*treerack.Syntax, int) {
|
func getSource(options *syntaxOptions) (hasInput bool, fileName string, syntax string, code int) {
|
||||||
if options.syntaxFile != "" && options.syntax != "" {
|
if len(options.positional) > 1 {
|
||||||
multipleSyntaxesError(fs)
|
multipleSyntaxesError(options.flagSet)
|
||||||
return nil, -1
|
code = -1
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasInput bool
|
hasPositional := len(options.positional) == 1
|
||||||
if options.syntaxFile == "" && options.syntax == "" {
|
hasFile := options.syntaxFile != ""
|
||||||
|
hasSyntax := options.syntax != ""
|
||||||
|
|
||||||
|
var has bool
|
||||||
|
for _, h := range []bool{hasPositional, hasFile, hasSyntax} {
|
||||||
|
if h && has {
|
||||||
|
multipleSyntaxesError(options.flagSet)
|
||||||
|
code = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
has = h
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case hasPositional:
|
||||||
|
fileName = options.positional[0]
|
||||||
|
return
|
||||||
|
case hasFile:
|
||||||
|
fileName = options.syntaxFile
|
||||||
|
return
|
||||||
|
case hasSyntax:
|
||||||
|
syntax = options.syntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check input last to allow explicit syntax in non-TTY environments:
|
||||||
hasInput = isTest && rin != nil || !isTest && !terminal.IsTerminal(0)
|
hasInput = isTest && rin != nil || !isTest && !terminal.IsTerminal(0)
|
||||||
|
if !hasInput {
|
||||||
|
missingSyntaxError(options.flagSet)
|
||||||
|
code = -1
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasInput && options.syntaxFile == "" && options.syntax == "" {
|
return
|
||||||
missingSyntaxError(fs)
|
}
|
||||||
return nil, -1
|
|
||||||
|
func openSyntax(options *syntaxOptions) (*treerack.Syntax, int) {
|
||||||
|
hasInput, fileName, syntax, code := getSource(options)
|
||||||
|
if code != 0 {
|
||||||
|
return nil, code
|
||||||
}
|
}
|
||||||
|
|
||||||
var input io.Reader
|
var input io.Reader
|
||||||
if hasInput {
|
if hasInput {
|
||||||
input = rin
|
input = rin
|
||||||
} else if options.syntaxFile != "" {
|
} else if fileName != "" {
|
||||||
f, err := os.Open(options.syntaxFile)
|
f, err := os.Open(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stderr(err)
|
stderr(err)
|
||||||
return nil, -1
|
return nil, -1
|
||||||
@ -57,8 +87,8 @@ func open(options syntaxOptions, fs *flag.FlagSet) (*treerack.Syntax, int) {
|
|||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
input = f
|
input = f
|
||||||
} else if options.syntax != "" {
|
} else {
|
||||||
input = bytes.NewBufferString(options.syntax)
|
input = bytes.NewBufferString(syntax)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &treerack.Syntax{}
|
s := &treerack.Syntax{}
|
||||||
|
45
cmd/treerack/parse.go
Normal file
45
cmd/treerack/parse.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type parseOptions struct {
|
||||||
|
syntaxOptions
|
||||||
|
input string
|
||||||
|
inputFile string
|
||||||
|
pretty bool
|
||||||
|
indent string
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagSetParse(o *parseOptions, output io.Writer) *flag.FlagSet {
|
||||||
|
fs := flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
|
fs.Usage = func() {}
|
||||||
|
fs.SetOutput(output)
|
||||||
|
fs.StringVar(&o.syntax, "syntax-string", "", syntaxStringUsage)
|
||||||
|
fs.StringVar(&o.syntaxFile, "syntax", "", syntaxFileUsage)
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagErrorParse(fs *flag.FlagSet) {
|
||||||
|
stderr()
|
||||||
|
stderr("Options:")
|
||||||
|
fs.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func helpParse() {
|
||||||
|
stdout(parseUsage)
|
||||||
|
stdout()
|
||||||
|
stdout("Options:")
|
||||||
|
fs := flagSetParse(&parseOptions{}, wout)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
stdout()
|
||||||
|
stdout(parseExample)
|
||||||
|
stdout()
|
||||||
|
stdout(docRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(args []string) int {
|
||||||
|
return 0
|
||||||
|
}
|
70
notes.txt
70
notes.txt
@ -1,59 +1,35 @@
|
|||||||
error reporting
|
|
||||||
- longest parse
|
|
||||||
- count the lines
|
|
||||||
- print the line
|
|
||||||
- print the deepest non-alias node name
|
|
||||||
- print the documentation of the node name
|
|
||||||
- make it work with custom tokens
|
|
||||||
read, with error reporting
|
|
||||||
what was the bug with the large json from eskip?
|
|
||||||
|
|
||||||
[next]
|
[next]
|
||||||
check
|
formatter
|
||||||
parse
|
report unused parsers
|
||||||
error reports
|
parse hashed, storing only the results
|
||||||
- take the last
|
linux packaging
|
||||||
simplify generator output
|
|
||||||
make generator output non-random (track parsers in a list in definition order)
|
[parser]
|
||||||
missing tests, coverage:
|
|
||||||
- validation
|
|
||||||
- error cases
|
|
||||||
- whitespace cases
|
|
||||||
error reporting
|
|
||||||
coverage
|
|
||||||
custom tokens
|
custom tokens
|
||||||
indentation
|
indentation
|
||||||
streaming
|
streaming support // ReadNode(io.Reader)
|
||||||
code generation go:
|
|
||||||
- find things that depend on the syntax input
|
[cmd]
|
||||||
- char matches can be generated into switches
|
check
|
||||||
code generation js
|
parse
|
||||||
documentation flag
|
help for positional argument
|
||||||
support custom tokenization
|
test explicit input priority
|
||||||
streaming
|
|
||||||
verify choice and sequence preference
|
[errors]
|
||||||
formatter
|
take the last
|
||||||
pretty
|
|
||||||
report unused parsers
|
|
||||||
go through the tests for docs
|
|
||||||
test all docs
|
|
||||||
warn nows usage in docs, e.g. spaces in symbol = [a-z]+
|
|
||||||
test error report on invalid flag
|
test error report on invalid flag
|
||||||
report unused definitions
|
|
||||||
simplify generated output
|
|
||||||
parse hashed, storing only the results
|
|
||||||
allchars: can have char sequence
|
|
||||||
input name: may be just dropped because completely controlled by the client
|
input name: may be just dropped because completely controlled by the client
|
||||||
|
|
||||||
|
[generator]
|
||||||
|
allchars: can have char sequence
|
||||||
|
make generator output non-random (track parsers in a list in definition order)
|
||||||
|
js
|
||||||
|
|
||||||
[optimization]
|
[optimization]
|
||||||
try preallocate larger store chunks
|
try preallocate larger store chunks
|
||||||
notes in formatting
|
|
||||||
format: test back and forth equivalence of char classes
|
|
||||||
format: test comments, first apply comments in the syntax
|
|
||||||
|
|
||||||
[problems]
|
|
||||||
can the root be an alias? check the commit mechanism
|
|
||||||
|
|
||||||
[documentation]
|
[documentation]
|
||||||
how the char classes are different from regexp
|
how the char classes are different from regexp
|
||||||
why need nows when using ws
|
why need nows when using ws
|
||||||
|
lib only useful for dynamic syntax definition
|
||||||
|
warn nows usage in docs, e.g. spaces in symbol = [a-z]+
|
||||||
|
1144
self/self.go
1144
self/self.go
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user