diff options
| author | Thibaut Horel <thibaut.horel@gmail.com> | 2016-02-21 22:16:43 -0500 |
|---|---|---|
| committer | Thibaut Horel <thibaut.horel@gmail.com> | 2016-02-21 22:16:43 -0500 |
| commit | 86cddf333ee9a80a4ea0a68814face6a32ced48b (patch) | |
| tree | 5be4e3ea46bce6171740b9438bae819c7d0bf24a | |
| parent | ac7a1a413b9566e0b052248502206eb3d6f8941c (diff) | |
| download | bibtex-86cddf333ee9a80a4ea0a68814face6a32ced48b.tar.gz | |
Use panic/defer all the way through to simplify error bubbling
| -rw-r--r-- | parser.go | 192 |
1 files changed, 77 insertions, 115 deletions
@@ -31,7 +31,7 @@ type ParseError struct { file string } -func (e *ParseError) Error() string { +func (e ParseError) Error() string { return fmt.Sprintf("%s:%d:%d error: %s", e.file, e.line, e.col, e.msg) } @@ -59,7 +59,7 @@ func NewParser(f *os.File) *Parser { } func (p *Parser) NewError(msg string) error { - return &ParseError{msg: msg, line: p.lineno, col: p.colno, file: p.fname} + return ParseError{msg: msg, line: p.lineno, col: p.colno, file: p.fname} } func (p *Parser) Warning(msg string) { @@ -163,12 +163,12 @@ func (p *Parser) eatSpace() { } } -func (p *Parser) readBraceLiteral() (string, error) { +func (p *Parser) readBraceLiteral() string { var buf bytes.Buffer ch := p.read() if ch != '{' { p.unread() - return "", p.NewError("Expected '{'") + panic(p.NewError("Expected '{'")) } blevel := 1 for { @@ -183,15 +183,15 @@ func (p *Parser) readBraceLiteral() (string, error) { } buf.WriteRune(ch) } - return buf.String(), nil + return buf.String() } -func (p *Parser) readStringLiteral() (string, error) { +func (p *Parser) readStringLiteral() string { var buf bytes.Buffer ch := p.read() if ch != '"' { p.unread() - return "", p.NewError("Expected '\"'") + panic(p.NewError("Expected '\"'")) } blevel := 0 for blevel >= 0 { @@ -206,12 +206,12 @@ func (p *Parser) readStringLiteral() (string, error) { buf.WriteRune(ch) } if blevel != 0 { - return "", p.NewError("Unbalanced '{'") + panic(p.NewError("Unbalanced '{'")) } - return buf.String(), nil + return buf.String() } -func (p *Parser) readNumber() (string, error) { +func (p *Parser) readNumber() string { var buf bytes.Buffer var ch rune for { @@ -223,10 +223,10 @@ func (p *Parser) readNumber() (string, error) { buf.WriteRune(ch) } } - return buf.String(), nil + return buf.String() } -func (p *Parser) readLiteral() (string, error) { +func (p *Parser) readLiteral() string { if ch := p.peek(); ch == '{' { return p.readBraceLiteral() } else if ch == '"' { @@ -236,102 +236,80 @@ func (p *Parser) readLiteral() (string, error) { } else { id := p.readIdentifier() if id == "" { - return "", p.NewError("Expected an identifier") + panic(p.NewError("Expected an identifier")) } if str, in := p.strings[strings.ToLower(id)]; in { - return str, nil + return str } else { p.Warning(fmt.Sprintf("Unknown string %q", id)) - return "", nil + return "" } } } -func (p *Parser) readValue() (string, error) { +func (p *Parser) readValue() string { var buf bytes.Buffer var ch rune - value, err := p.readLiteral() - if err != nil { - return "", err - } + value := p.readLiteral() buf.WriteString(value) for { p.eatSpace() if ch = p.read(); ch == '#' { p.eatSpace() - value, err := p.readLiteral() - if err != nil { - return "", err - } + value := p.readLiteral() buf.WriteString(value) } else { p.unread() break } } - return buf.String(), nil + return buf.String() } -func (p *Parser) readIdValue() (string, string, error) { +func (p *Parser) readIdValue() (string, string) { p.eatSpace() id := p.readIdentifier() if id == "" { - return "", "", p.NewError("Expected an identifier") + panic(p.NewError("Expected an identifier")) } p.eatSpace() if ch := p.read(); ch != '=' { p.unread() - return "", "", p.NewError("Expected '='") + panic(p.NewError("Expected '='")) } p.eatSpace() - value, err := p.readValue() - if err != nil { - return "", "", err - } - return id, value, nil + value := p.readValue() + return id, value } -func (p *Parser) readOpen() (rune, error) { +func (p *Parser) readOpen() rune { p.eatSpace() if ch := p.read(); ch == '(' { - return ')', nil + return ')' } else if ch == '{' { - return '}', nil + return '}' } else { p.unread() - return ch, p.NewError("Expected '(' or '{'") + panic(p.NewError("Expected '(' or '{'")) } } -func (p *Parser) readPreamble() error { - close, err := p.readOpen() - if err != nil { - return err - } +func (p *Parser) readPreamble() { + close := p.readOpen() p.eatSpace() - val, err := p.readValue() - if err != nil { - return err - } + val := p.readValue() p.preamble += val p.eatSpace() if ch := p.read(); ch != close { p.unread() - return p.NewError(fmt.Sprintf("Expected %q", close)) + panic(p.NewError(fmt.Sprintf("Expected %q", close))) } - return nil } -func (p *Parser) readString() error { - close, err := p.readOpen() - if err != nil { - return err - } +func (p *Parser) readString() { + close := p.readOpen() p.eatSpace() - id, value, err := p.readIdValue() - if err != nil { - return err - } + id, value := p.readIdValue() if _, in := p.strings[strings.ToLower(id)]; in { p.Warning(fmt.Sprintf("String %q already defined, ignoring", id)) } else { @@ -340,16 +318,12 @@ func (p *Parser) readString() error { p.eatSpace() if ch := p.read(); ch != close { p.unread() - return p.NewError(fmt.Sprintf("Expected %q", close)) + panic(p.NewError(fmt.Sprintf("Expected %q", close))) } - return nil } -func (p *Parser) readEntry(entry *Entry) error { - close, err := p.readOpen() - if err != nil { - return err - } +func (p *Parser) readEntry(entry *Entry) { + close := p.readOpen() p.eatSpace() key := p.readToken("," + string(close)) entry.key = key @@ -363,17 +337,14 @@ func (p *Parser) readEntry(entry *Entry) error { for { p.eatSpace() if ch := p.read(); ch == close { - return nil + break } else if ch == ',' { p.eatSpace() if ch := p.read(); ch == close { - return nil + break } else { p.unread() - id, value, err := p.readIdValue() - if err != nil { - return err - } + id, value := p.readIdValue() if _, in := entry.fields[strings.ToLower(id)]; in { p.Warning(fmt.Sprintf("Field %q already defined, ignoring", id)) @@ -383,74 +354,65 @@ func (p *Parser) readEntry(entry *Entry) error { } } else { p.unread() - return p.NewError(fmt.Sprintf("Expected ',' or %q", close)) + panic(p.NewError(fmt.Sprintf("Expected ',' or %q", close))) } } - return nil } -func (p *Parser) readDeclaration() error { +func (p *Parser) readDeclaration() { typ := p.readIdentifier() if typ == "" { - return p.NewError("Expected entry type") + panic(p.NewError("Expected entry type")) } typ = strings.ToLower(typ) - var err error switch typ { case "string": - err = p.readString() + p.readString() case "preamble": - err = p.readPreamble() + p.readPreamble() case "comment": default: entry := NewEntry(typ) entry.line = p.lineno - err = p.readEntry(entry) + p.readEntry(entry) } - return err } -func (p *Parser) Parse(strict bool) error { - - defer func() { - if r := recover(); r != nil { - p.Warning("Reached end of file while parsing.") - } - }() - - for ch := p.readUnsafe(); ch != eof; ch = p.readUnsafe() { - if ch == '@' { - p.eatSpace() - err := p.readDeclaration() - if err != nil { - switch err.(type) { - case *ParseError: - if strict { - return err - } else { - log.Println(err.Error()) - } - default: - return err - } +func errorHandler(errp *error, strict bool, p *Parser) { + if e := recover(); e != nil { + switch e.(type) { + case ParseError: + if strict { + *errp = e.(ParseError) + } else { + log.Println(e.(ParseError).Error()) } + case error: + if e == io.EOF { + p.Warning("Reached end of file while parsing.") + *errp = e.(error) + } else { + panic(e) + } + default: + panic(e) } } - return nil } -func main() { - log.SetFlags(0) - log.SetOutput(os.Stderr) - p := NewParser(os.Stdin) - err := p.Parse(false) - if err != nil { - log.Fatal(err) - } - for key, entry := range p.entries { - fmt.Println(key, entry.typ) - for name, value := range entry.fields { - fmt.Println("\t", name, value) +func (p *Parser) Parse(strict bool) (err error) { + defer errorHandler(&err, strict, p) + + var ch rune + for { + ch = p.readUnsafe() + switch ch { + case '@': + p.eatSpace() + p.readDeclaration() + case eof: + return } } + return } |
