github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/ebnflint/ebnflint.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"flag"
    10  	"fmt"
    11  	"go/scanner"
    12  	"go/token"
    13  	"io"
    14  	"io/ioutil"
    15  	"os"
    16  	"path/filepath"
    17  
    18  	"golang.org/x/exp/ebnf"
    19  )
    20  
    21  var fset = token.NewFileSet()
    22  var start = flag.String("start", "Start", "name of start production")
    23  
    24  func usage() {
    25  	fmt.Fprintf(os.Stderr, "usage: go tool ebnflint [flags] [filename]\n")
    26  	flag.PrintDefaults()
    27  	os.Exit(1)
    28  }
    29  
    30  // Markers around EBNF sections in .html files
    31  var (
    32  	open  = []byte(`<pre class="ebnf">`)
    33  	close = []byte(`</pre>`)
    34  )
    35  
    36  func report(err error) {
    37  	scanner.PrintError(os.Stderr, err)
    38  	os.Exit(1)
    39  }
    40  
    41  func extractEBNF(src []byte) []byte {
    42  	var buf bytes.Buffer
    43  
    44  	for {
    45  		// i = beginning of EBNF text
    46  		i := bytes.Index(src, open)
    47  		if i < 0 {
    48  			break // no EBNF found - we are done
    49  		}
    50  		i += len(open)
    51  
    52  		// write as many newlines as found in the excluded text
    53  		// to maintain correct line numbers in error messages
    54  		for _, ch := range src[0:i] {
    55  			if ch == '\n' {
    56  				buf.WriteByte('\n')
    57  			}
    58  		}
    59  
    60  		// j = end of EBNF text (or end of source)
    61  		j := bytes.Index(src[i:], close) // close marker
    62  		if j < 0 {
    63  			j = len(src) - i
    64  		}
    65  		j += i
    66  
    67  		// copy EBNF text
    68  		buf.Write(src[i:j])
    69  
    70  		// advance
    71  		src = src[j:]
    72  	}
    73  
    74  	return buf.Bytes()
    75  }
    76  
    77  func main() {
    78  	flag.Parse()
    79  
    80  	var (
    81  		name string
    82  		r    io.Reader
    83  	)
    84  	switch flag.NArg() {
    85  	case 0:
    86  		name, r = "<stdin>", os.Stdin
    87  	case 1:
    88  		name = flag.Arg(0)
    89  	default:
    90  		usage()
    91  	}
    92  
    93  	if err := verify(name, *start, r); err != nil {
    94  		report(err)
    95  	}
    96  }
    97  
    98  func verify(name, start string, r io.Reader) error {
    99  	if r == nil {
   100  		f, err := os.Open(name)
   101  		if err != nil {
   102  			return err
   103  		}
   104  		defer f.Close()
   105  		r = f
   106  	}
   107  
   108  	src, err := ioutil.ReadAll(r)
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	if filepath.Ext(name) == ".html" || bytes.Index(src, open) >= 0 {
   114  		src = extractEBNF(src)
   115  	}
   116  
   117  	grammar, err := ebnf.Parse(name, bytes.NewBuffer(src))
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	return ebnf.Verify(grammar, start)
   123  }