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 }