diff options
Diffstat (limited to 'mintage/parser.go')
-rw-r--r-- | mintage/parser.go | 207 |
1 files changed, 0 insertions, 207 deletions
diff --git a/mintage/parser.go b/mintage/parser.go deleted file mode 100644 index 4c5e6f9..0000000 --- a/mintage/parser.go +++ /dev/null @@ -1,207 +0,0 @@ -package mintage - -import ( - "bufio" - "fmt" - "io" - "strconv" - "strings" - "unicode" -) - -const ( - _ = -iota - Unknown // Unknown mintage - Invalid // All mintages <= than this are invalid -) - -type SyntaxError struct { - expected, got string - file string - linenr int -} - -func (e SyntaxError) Error() string { - return fmt.Sprintf("%s:%d: syntax error: expected %s but got %s", - e.file, e.linenr, e.expected, e.got) -} - -type Row struct { - Year int - Mintmark string - Cols [8]int -} - -type Set struct { - StartYear int - Circ, BU, Proof []Row -} - -func (r Row) Label() string { - if r.Mintmark != "" { - return fmt.Sprintf("%d %s", r.Year, r.Mintmark) - } - return strconv.Itoa(r.Year) -} - -func Parse(reader io.Reader, file string) (Set, error) { - var ( - data Set // Our data struct - slice *[]Row // Where to append mintages - ) - - scanner := bufio.NewScanner(reader) - for linenr := 1; scanner.Scan(); linenr++ { - var mintmark struct { - s string - star bool - } - - line := scanner.Text() - tokens := strings.FieldsFunc(strings.TrimSpace(line), unicode.IsSpace) - - switch { - case len(tokens) == 0: - continue - case tokens[0] == "BEGIN": - if len(tokens)-1 != 1 { - return Set{}, SyntaxError{ - expected: "single argument to ‘BEGIN’", - got: fmt.Sprintf("%d arguments", len(tokens)-1), - file: file, - linenr: linenr, - } - } - - arg := tokens[1] - - switch arg { - case "CIRC": - slice = &data.Circ - case "BU": - slice = &data.BU - case "PROOF": - slice = &data.Proof - default: - if !isNumeric(arg, false) { - return Set{}, SyntaxError{ - expected: "‘CIRC’, ‘BU’, ‘PROOF’, or a year", - got: arg, - file: file, - linenr: linenr, - } - } - data.StartYear, _ = strconv.Atoi(arg) - } - case isLabel(tokens[0]): - n := len(tokens[0]) - if n > 2 && tokens[0][n-2] == '*' { - mintmark.star = true - mintmark.s = tokens[0][:n-2] - } else { - mintmark.s = tokens[0][:n-1] - } - tokens = tokens[1:] - if !isNumeric(tokens[0], true) && tokens[0] != "?" { - return Set{}, SyntaxError{ - expected: "mintage row after label", - got: tokens[0], - file: file, - linenr: linenr, - } - } - fallthrough - case isNumeric(tokens[0], true), tokens[0] == "?": - switch { - case slice == nil: - return Set{}, SyntaxError{ - expected: "coin type declaration", - got: tokens[0], - file: file, - linenr: linenr, - } - case data.StartYear == 0: - return Set{}, SyntaxError{ - expected: "start year declaration", - got: tokens[0], - file: file, - linenr: linenr, - } - } - - numcoins := len(Row{}.Cols) - tokcnt := len(tokens) - - if tokcnt != numcoins { - word := "entries" - if tokcnt == 1 { - word = "entry" - } - return Set{}, SyntaxError{ - expected: fmt.Sprintf("%d mintage entries", numcoins), - got: fmt.Sprintf("%d %s", tokcnt, word), - file: file, - linenr: linenr, - } - } - - row := Row{Mintmark: mintmark.s} - if len(*slice) == 0 { - row.Year = data.StartYear - } else { - row.Year = (*slice)[len(*slice)-1].Year - if row.Mintmark == "" || mintmark.star { - row.Year++ - } - } - - for i, tok := range tokens { - if tok == "?" { - row.Cols[i] = Unknown - } else { - row.Cols[i] = atoiWithDots(tok) - } - } - *slice = append(*slice, row) - default: - return Set{}, SyntaxError{ - expected: "‘BEGIN’ directive or mintage row", - got: fmt.Sprintf("invalid token ‘%s’", tokens[0]), - file: file, - linenr: linenr, - } - } - } - - return data, nil -} - -func isNumeric(s string, dot bool) bool { - for _, ch := range s { - switch ch { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - if ch != '.' || !dot { - return false - } - } - } - return true -} - -func isLabel(s string) bool { - n := len(s) - return (n > 2 && s[n-1] == ':' && s[n-2] == '*') || - (n > 1 && s[n-1] == ':') -} - -func atoiWithDots(s string) int { - n := 0 - for _, ch := range s { - if ch == '.' { - continue - } - n = n*10 + int(ch) - '0' - } - return n -} |