only use tracing when explicitly enabled
This commit is contained in:
parent
752e4d2275
commit
a009c1918d
@ -20,6 +20,9 @@ type checkOptions struct {
|
||||
|
||||
// InputString specifies the input content as an inline string.
|
||||
InputString *string
|
||||
|
||||
// MaxTraceLength enables tracing when set to a positive integer.
|
||||
MaxTraceLength int
|
||||
}
|
||||
|
||||
// check parses input content against the provided syntax definition and fails if the input does not match.
|
||||
@ -38,7 +41,7 @@ func check(o checkOptions, stdin io.Reader, args ...string) error {
|
||||
}
|
||||
|
||||
defer finalizeInput()
|
||||
s := &treerack.Syntax{}
|
||||
s := &treerack.Syntax{MaxTraceLength: o.MaxTraceLength}
|
||||
if err := s.ReadSyntax(syntax); err != nil {
|
||||
if terr := treerack.Trace(os.Stderr, err); terr != nil {
|
||||
err = errors.Join(err, terr)
|
||||
|
||||
@ -14,6 +14,9 @@ type checkSyntaxOptions struct {
|
||||
|
||||
// SyntaxString specifies the syntax as an inline string.
|
||||
SyntaxString *string
|
||||
|
||||
// MaxTraceLength enables tracing when set to a positive integer.
|
||||
MaxTraceLength int
|
||||
}
|
||||
|
||||
// checkSyntax validates a syntax definition. The syntax may be provided via a file path (using an option or a
|
||||
@ -25,7 +28,7 @@ func checkSyntax(o checkSyntaxOptions, stdin io.Reader, args ...string) error {
|
||||
}
|
||||
|
||||
defer finalize()
|
||||
s := &treerack.Syntax{}
|
||||
s := &treerack.Syntax{MaxTraceLength: o.MaxTraceLength}
|
||||
if err := s.ReadSyntax(syntax); err != nil {
|
||||
if terr := treerack.Trace(os.Stderr, err); terr != nil {
|
||||
err = errors.Join(err, terr)
|
||||
|
||||
@ -12,28 +12,32 @@ func init() {
|
||||
docreflect.Register("main.checkOptions", "")
|
||||
docreflect.Register("main.checkOptions.Input", "Input specifies the filename of the input content to be validated.\n")
|
||||
docreflect.Register("main.checkOptions.InputString", "InputString specifies the input content as an inline string.\n")
|
||||
docreflect.Register("main.checkOptions.MaxTraceLength", "MaxTraceLength enables tracing when set to a positive integer.\n")
|
||||
docreflect.Register("main.checkOptions.Syntax", "Syntax specifies the filename of the syntax definition file.\n")
|
||||
docreflect.Register("main.checkOptions.SyntaxString", "SyntaxString specifies the syntax as an inline string.\n")
|
||||
docreflect.Register("main.checkSyntax", "checkSyntax validates a syntax definition. The syntax may be provided via a file path (using an option or a\npositional argument), an inline string, or piped from standard input.\n\nfunc(o, stdin, args)")
|
||||
docreflect.Register("main.checkSyntaxOptions", "")
|
||||
docreflect.Register("main.checkSyntaxOptions.MaxTraceLength", "MaxTraceLength enables tracing when set to a positive integer.\n")
|
||||
docreflect.Register("main.checkSyntaxOptions.Syntax", "Syntax specifies the filename of the syntax definition file.\n")
|
||||
docreflect.Register("main.checkSyntaxOptions.SyntaxString", "SyntaxString specifies the syntax as an inline string.\n")
|
||||
docreflect.Register("main.errInvalidFilename", "")
|
||||
docreflect.Register("main.errMultipleInputs", "")
|
||||
docreflect.Register("main.errNoInput", "")
|
||||
docreflect.Register("main.format", "format input syntax. Accepts syntax from one or more files, inline syntax string or stdin. Use the --in-place\noption, when formatting files in place, or print the formatted syntax to stdout.\n\nfunc(o, stdin, stdout, syntax)")
|
||||
docreflect.Register("main.formatFile", "\nfunc(name, inPlace, out)")
|
||||
docreflect.Register("main.formatFiles", "\nfunc(files, inPlace, out)")
|
||||
docreflect.Register("main.formatInline", "\nfunc(syntax, out)")
|
||||
docreflect.Register("main.formatFile", "\nfunc(name, inPlace, maxTraceLength, out)")
|
||||
docreflect.Register("main.formatFiles", "\nfunc(files, inPlace, maxTraceLength, out)")
|
||||
docreflect.Register("main.formatInline", "\nfunc(syntax, out, maxTraceLength)")
|
||||
docreflect.Register("main.formatOptions", "")
|
||||
docreflect.Register("main.formatOptions.InPlace", "")
|
||||
docreflect.Register("main.formatOptions.Syntax", "")
|
||||
docreflect.Register("main.formatOptions.SyntaxString", "")
|
||||
docreflect.Register("main.formatStdin", "\nfunc(in, out)")
|
||||
docreflect.Register("main.formatSyntax", "\nfunc(in, out)")
|
||||
docreflect.Register("main.formatOptions.InPlace", "InPlace specifies if an input file should be formatted in-place instead of printing the formatted\nresults to the standard output.\n")
|
||||
docreflect.Register("main.formatOptions.MaxTraceLength", "MaxTraceLength enables tracing when set to a positive integer.\n")
|
||||
docreflect.Register("main.formatOptions.Syntax", "Syntax specifies the filename of the syntax definition file.\n")
|
||||
docreflect.Register("main.formatOptions.SyntaxString", "SyntaxString specifies the syntax as an inline string.\n")
|
||||
docreflect.Register("main.formatStdin", "\nfunc(in, out, maxTraceLength)")
|
||||
docreflect.Register("main.formatSyntax", "\nfunc(in, out, maxTraceLength)")
|
||||
docreflect.Register("main.generate", "generate generates Go code that can parse arbitrary input with the provided syntax, and can be used embedded\nin an application.\n\nThe syntax may be provided via a file path (using an option or a positional argument), an\ninline string, or piped from standard input.\n\nfunc(o, stdin, stdout, args)")
|
||||
docreflect.Register("main.generateOptions", "")
|
||||
docreflect.Register("main.generateOptions.Export", "Export determines whether the generated parse function is exported (visible outside its package).\n")
|
||||
docreflect.Register("main.generateOptions.MaxTraceLength", "MaxTraceLength enables tracing when set to a positive integer.\n")
|
||||
docreflect.Register("main.generateOptions.PackageName", "PackageName specifies the package name for the generated code. Defaults to main.\n")
|
||||
docreflect.Register("main.generateOptions.Syntax", "Syntax specifies the filename of the syntax definition file.\n")
|
||||
docreflect.Register("main.generateOptions.SyntaxString", "SyntaxString specifies the syntax as an inline string.\n")
|
||||
@ -53,6 +57,7 @@ func init() {
|
||||
docreflect.Register("main.showOptions.Indent", "Indent specifies a custom indentation string for the output.\n")
|
||||
docreflect.Register("main.showOptions.Input", "Input specifies the filename of the input content to be validated.\n")
|
||||
docreflect.Register("main.showOptions.InputString", "InputString specifies the input content as an inline string.\n")
|
||||
docreflect.Register("main.showOptions.MaxTraceLength", "MaxTraceLength enables tracing when set to a positive integer.\n")
|
||||
docreflect.Register("main.showOptions.Pretty", "Pretty enables indented, human-readable output.\n")
|
||||
docreflect.Register("main.showOptions.Syntax", "Syntax specifies the filename of the syntax definition file.\n")
|
||||
docreflect.Register("main.showOptions.SyntaxString", "SyntaxString specifies the syntax as an inline string.\n")
|
||||
|
||||
@ -10,13 +10,23 @@ import (
|
||||
)
|
||||
|
||||
type formatOptions struct {
|
||||
|
||||
// InPlace specifies if an input file should be formatted in-place instead of printing the formatted
|
||||
// results to the standard output.
|
||||
InPlace bool
|
||||
|
||||
// SyntaxString specifies the syntax as an inline string.
|
||||
SyntaxString *string
|
||||
|
||||
// Syntax specifies the filename of the syntax definition file.
|
||||
Syntax []string
|
||||
|
||||
// MaxTraceLength enables tracing when set to a positive integer.
|
||||
MaxTraceLength int
|
||||
}
|
||||
|
||||
func formatSyntax(in io.Reader, out io.Writer) error {
|
||||
s := new(treerack.Syntax)
|
||||
func formatSyntax(in io.Reader, out io.Writer, maxTraceLength int) error {
|
||||
s := treerack.Syntax{MaxTraceLength: maxTraceLength}
|
||||
if err := s.ReadSyntax(in); err != nil {
|
||||
if terr := treerack.Trace(os.Stderr, err); err != nil {
|
||||
err = errors.Join(err, terr)
|
||||
@ -36,7 +46,7 @@ func formatSyntax(in io.Reader, out io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatFile(name string, inPlace bool, out io.Writer) error {
|
||||
func formatFile(name string, inPlace bool, maxTraceLength int, out io.Writer) error {
|
||||
var (
|
||||
inBytes []byte
|
||||
buf *bytes.Buffer
|
||||
@ -48,7 +58,7 @@ func formatFile(name string, inPlace bool, out io.Writer) error {
|
||||
}
|
||||
|
||||
buf = bytes.NewBuffer(inBytes)
|
||||
if err = formatSyntax(buf, buf); err != nil {
|
||||
if err = formatSyntax(buf, buf, maxTraceLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -65,9 +75,9 @@ func formatFile(name string, inPlace bool, out io.Writer) error {
|
||||
return os.WriteFile(name, buf.Bytes(), 0644)
|
||||
}
|
||||
|
||||
func formatFiles(files []string, inPlace bool, out io.Writer) error {
|
||||
func formatFiles(files []string, inPlace bool, maxTraceLength int, out io.Writer) error {
|
||||
for _, f := range files {
|
||||
if err := formatFile(f, inPlace, out); err != nil {
|
||||
if err := formatFile(f, inPlace, maxTraceLength, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -75,13 +85,13 @@ func formatFiles(files []string, inPlace bool, out io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatInline(syntax string, out io.Writer) error {
|
||||
func formatInline(syntax string, out io.Writer, maxTraceLength int) error {
|
||||
buf := bytes.NewBufferString(syntax)
|
||||
return formatSyntax(buf, out)
|
||||
return formatSyntax(buf, out, maxTraceLength)
|
||||
}
|
||||
|
||||
func formatStdin(in io.Reader, out io.Writer) error {
|
||||
return formatSyntax(in, out)
|
||||
func formatStdin(in io.Reader, out io.Writer, maxTraceLength int) error {
|
||||
return formatSyntax(in, out, maxTraceLength)
|
||||
}
|
||||
|
||||
// format input syntax. Accepts syntax from one or more files, inline syntax string or stdin. Use the --in-place
|
||||
@ -109,12 +119,12 @@ func format(o formatOptions, stdin io.Reader, stdout io.Writer, syntax ...string
|
||||
}
|
||||
|
||||
if len(files) > 0 {
|
||||
return formatFiles(files, o.InPlace, stdout)
|
||||
return formatFiles(files, o.InPlace, o.MaxTraceLength, stdout)
|
||||
}
|
||||
|
||||
if o.SyntaxString != nil {
|
||||
return formatInline(*o.SyntaxString, stdout)
|
||||
return formatInline(*o.SyntaxString, stdout, o.MaxTraceLength)
|
||||
}
|
||||
|
||||
return formatSyntax(stdin, stdout)
|
||||
return formatSyntax(stdin, stdout, o.MaxTraceLength)
|
||||
}
|
||||
|
||||
@ -20,6 +20,9 @@ type generateOptions struct {
|
||||
|
||||
// Export determines whether the generated parse function is exported (visible outside its package).
|
||||
Export bool
|
||||
|
||||
// MaxTraceLength enables tracing when set to a positive integer.
|
||||
MaxTraceLength int
|
||||
}
|
||||
|
||||
// generate generates Go code that can parse arbitrary input with the provided syntax, and can be used embedded
|
||||
@ -34,7 +37,7 @@ func generate(o generateOptions, stdin io.Reader, stdout io.Writer, args ...stri
|
||||
}
|
||||
|
||||
defer finalizeSyntax()
|
||||
s := &treerack.Syntax{}
|
||||
s := &treerack.Syntax{MaxTraceLength: o.MaxTraceLength}
|
||||
if err := s.ReadSyntax(syntax); err != nil {
|
||||
if terr := treerack.Trace(os.Stderr, err); err != nil {
|
||||
err = errors.Join(err, terr)
|
||||
|
||||
@ -32,6 +32,7 @@ argument), an inline string, or piped from standard input.
|
||||
|
||||
#### Options:
|
||||
|
||||
- --max-trace-length int: enables tracing when set to a positive integer.
|
||||
- --syntax string: specifies the filename of the syntax definition file.
|
||||
- --syntax-string string: specifies the syntax as an inline string.
|
||||
- --help: Show help.
|
||||
@ -57,6 +58,7 @@ positional argument filename, an inline string option, or piped from standard in
|
||||
|
||||
- --input string: specifies the filename of the input content to be validated.
|
||||
- --input-string string: specifies the input content as an inline string.
|
||||
- --max-trace-length int: enables tracing when set to a positive integer.
|
||||
- --syntax string: specifies the filename of the syntax definition file.
|
||||
- --syntax-string string: specifies the syntax as an inline string.
|
||||
- --help: Show help.
|
||||
@ -83,6 +85,7 @@ filename option, a positional argument filename, an inline string option, or pip
|
||||
- --indent string: specifies a custom indentation string for the output.
|
||||
- --input string: specifies the filename of the input content to be validated.
|
||||
- --input-string string: specifies the input content as an inline string.
|
||||
- --max-trace-length int: enables tracing when set to a positive integer.
|
||||
- --pretty bool: enables indented, human-readable output.
|
||||
- --syntax string: specifies the filename of the syntax definition file.
|
||||
- --syntax-string string: specifies the syntax as an inline string.
|
||||
@ -110,6 +113,7 @@ piped from standard input.
|
||||
#### Options:
|
||||
|
||||
- --export bool: determines whether the generated parse function is exported (visible outside its package).
|
||||
- --max-trace-length int: enables tracing when set to a positive integer.
|
||||
- --package-name string: specifies the package name for the generated code. Defaults to main.
|
||||
- --syntax string: specifies the filename of the syntax definition file.
|
||||
- --syntax-string string: specifies the syntax as an inline string.
|
||||
@ -131,9 +135,11 @@ when formatting files in place, or print the formatted syntax to stdout.
|
||||
|
||||
#### Options:
|
||||
|
||||
- --in-place bool:
|
||||
- --syntax string \[\*\]:
|
||||
- --syntax-string string:
|
||||
- --in-place bool: specifies if an input file should be formatted in-place instead of printing the formatted
|
||||
results to the standard output.
|
||||
- --max-trace-length int: enables tracing when set to a positive integer.
|
||||
- --syntax string \[\*\]: specifies the filename of the syntax definition file.
|
||||
- --syntax-string string: specifies the syntax as an inline string.
|
||||
- --help: Show help.
|
||||
|
||||
### treerack version
|
||||
|
||||
@ -27,6 +27,9 @@ type showOptions struct {
|
||||
|
||||
// Indent specifies a custom indentation string for the output.
|
||||
Indent string
|
||||
|
||||
// MaxTraceLength enables tracing when set to a positive integer.
|
||||
MaxTraceLength int
|
||||
}
|
||||
|
||||
type node struct {
|
||||
@ -72,7 +75,7 @@ func show(o showOptions, stdin io.Reader, stdout io.Writer, args ...string) erro
|
||||
}
|
||||
|
||||
defer finalizeInput()
|
||||
s := &treerack.Syntax{}
|
||||
s := &treerack.Syntax{MaxTraceLength: o.MaxTraceLength}
|
||||
if err := s.ReadSyntax(syntax); err != nil {
|
||||
if terr := treerack.Trace(os.Stderr, err); err != nil {
|
||||
err = errors.Join(err, terr)
|
||||
|
||||
12
context.go
12
context.go
@ -7,8 +7,6 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const maxTraceEntries = 36
|
||||
|
||||
type context struct {
|
||||
reader io.RuneReader
|
||||
keywords []parser
|
||||
@ -25,15 +23,17 @@ type context struct {
|
||||
matchLast bool
|
||||
level int
|
||||
tr []TraceEntry
|
||||
maxTraceLength int
|
||||
}
|
||||
|
||||
func newContext(r io.RuneReader, keywords []parser) *context {
|
||||
func newContext(r io.RuneReader, keywords []parser, maxTraceLength int) *context {
|
||||
return &context{
|
||||
reader: r,
|
||||
keywords: keywords,
|
||||
results: &results{},
|
||||
offsetLimit: -1,
|
||||
failOffset: -1,
|
||||
maxTraceLength: maxTraceLength,
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,11 +199,15 @@ func (c *context) finalizeParse(root parser) error {
|
||||
}
|
||||
|
||||
func (c *context) trace(p parser, from, to int, event TraceEvent, reason ...string) {
|
||||
if c.maxTraceLength <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if p.commitType()&userDefined == 0 || p.commitType()&FailPass != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if len(c.tr) == maxTraceEntries {
|
||||
if len(c.tr) == c.maxTraceLength {
|
||||
c.tr = c.tr[1:]
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -603,8 +603,6 @@ func (r *results) unmarkPending(offset, id int) {
|
||||
}
|
||||
}
|
||||
|
||||
const maxTraceEntries = 36
|
||||
|
||||
type context struct {
|
||||
reader io.RuneReader
|
||||
keywords []parser
|
||||
@ -621,10 +619,11 @@ type context struct {
|
||||
matchLast bool
|
||||
level int
|
||||
tr []TraceEntry
|
||||
maxTraceLength int
|
||||
}
|
||||
|
||||
func newContext(r io.RuneReader, keywords []parser) *context {
|
||||
return &context{reader: r, keywords: keywords, results: &results{}, offsetLimit: -1, failOffset: -1}
|
||||
func newContext(r io.RuneReader, keywords []parser, maxTraceLength int) *context {
|
||||
return &context{reader: r, keywords: keywords, results: &results{}, offsetLimit: -1, failOffset: -1, maxTraceLength: maxTraceLength}
|
||||
}
|
||||
func (c *context) read() bool {
|
||||
if c.eof || c.readErr != nil {
|
||||
@ -753,10 +752,13 @@ func (c *context) finalizeParse(root parser) error {
|
||||
return c.parseError(root, false, root.nodeID())
|
||||
}
|
||||
func (c *context) trace(p parser, from, to int, event TraceEvent, reason ...string) {
|
||||
if c.maxTraceLength <= 0 {
|
||||
return
|
||||
}
|
||||
if p.commitType()&userDefined == 0 || p.commitType()&FailPass != 0 {
|
||||
return
|
||||
}
|
||||
if len(c.tr) == maxTraceEntries {
|
||||
if len(c.tr) == c.maxTraceLength {
|
||||
c.tr = c.tr[1:]
|
||||
}
|
||||
switch event {
|
||||
@ -877,8 +879,8 @@ func (pe *ParseError) Error() string {
|
||||
}
|
||||
return fmt.Sprintf("%s:%d:%d:parse failed, parsing: %s, at %d:%d", pe.Input, pe.Line+1, pe.Column+1, pe.Definition, pe.Line+1, pe.Column+1)
|
||||
}
|
||||
func parseInput(r io.Reader, p parser, b builder, kw []parser) (Node, error) {
|
||||
c := newContext(bufio.NewReader(r), kw)
|
||||
func parseInput(r io.Reader, p parser, b builder, kw []parser, maxTraceLength int) (Node, error) {
|
||||
c := newContext(bufio.NewReader(r), kw, maxTraceLength)
|
||||
p.parse(c)
|
||||
if c.readErr != nil {
|
||||
return Node{}, c.readErr
|
||||
@ -1468,5 +1470,5 @@ func Parse(r io.Reader) (Node, error) {
|
||||
|
||||
var keywords = []parser{}
|
||||
|
||||
return parseInput(r, &p183, &b183, keywords)
|
||||
return parseInput(r, &p183, &b183, keywords, 0)
|
||||
}
|
||||
|
||||
@ -776,7 +776,7 @@ func TestCharBuildNoop(t *testing.T) {
|
||||
c := newChar("foo", false, nil, nil)
|
||||
c.init(newRegistry())
|
||||
b := c.builder()
|
||||
ctx := newContext(bufio.NewReader(bytes.NewBuffer(nil)), nil)
|
||||
ctx := newContext(bufio.NewReader(bytes.NewBuffer(nil)), nil, 0)
|
||||
if n, ok := b.build(ctx); len(n) != 0 || ok {
|
||||
t.Error("char build not noop")
|
||||
}
|
||||
|
||||
@ -62,6 +62,10 @@ type Syntax struct {
|
||||
explicitRoot bool
|
||||
keywords []definition
|
||||
root definition
|
||||
|
||||
// MaxTraceLength can be used to enable tracing by setting a positive value. It should be set before
|
||||
// parsing.
|
||||
MaxTraceLength int
|
||||
}
|
||||
|
||||
// GeneratorOptions control the behavior of the Go code generator.
|
||||
@ -570,7 +574,7 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error {
|
||||
|
||||
fprintln()
|
||||
fprintln()
|
||||
fprintf(`return parseInput(r, &p%d, &b%d, keywords)`, s.root.parser().nodeID(), s.root.builder().nodeID())
|
||||
fprintf(`return parseInput(r, &p%d, &b%d, keywords, 0)`, s.root.parser().nodeID(), s.root.builder().nodeID())
|
||||
fprintln()
|
||||
fprint(`}`)
|
||||
fprintln()
|
||||
@ -584,7 +588,7 @@ func (s *Syntax) Parse(r io.Reader) (Node, error) {
|
||||
return Node{}, err
|
||||
}
|
||||
|
||||
return parseInput(r, s.root.parser(), s.root.builder(), s.keywordParsers())
|
||||
return parseInput(r, s.root.parser(), s.root.builder(), s.keywordParsers(), s.MaxTraceLength)
|
||||
}
|
||||
|
||||
// Format prints the loaded syntax definition to the output in a formatted way.
|
||||
|
||||
@ -199,8 +199,8 @@ func (pe *ParseError) Error() string {
|
||||
)
|
||||
}
|
||||
|
||||
func parseInput(r io.Reader, p parser, b builder, kw []parser) (Node, error) {
|
||||
c := newContext(bufio.NewReader(r), kw)
|
||||
func parseInput(r io.Reader, p parser, b builder, kw []parser, maxTraceLength int) (Node, error) {
|
||||
c := newContext(bufio.NewReader(r), kw, maxTraceLength)
|
||||
p.parse(c)
|
||||
if c.readErr != nil {
|
||||
return Node{}, c.readErr
|
||||
|
||||
Loading…
Reference in New Issue
Block a user