From 548090e67f66acf84385c4152ca464e52d3e3319 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 13 Sep 2024 13:01:48 +0200 Subject: Migrate away from templ and towards html/template --- lib/mintage/parser.go | 297 --------------------------------------------- lib/mintage/parser_test.go | 233 ----------------------------------- 2 files changed, 530 deletions(-) delete mode 100644 lib/mintage/parser.go delete mode 100644 lib/mintage/parser_test.go (limited to 'lib/mintage') diff --git a/lib/mintage/parser.go b/lib/mintage/parser.go deleted file mode 100644 index 364b6e8..0000000 --- a/lib/mintage/parser.go +++ /dev/null @@ -1,297 +0,0 @@ -package mintage - -import ( - "bufio" - "fmt" - "io" - "strconv" - "strings" - "time" -) - -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 Data struct { - Standard []SRow - Commemorative []CRow -} - -type SRow struct { - Year int - Mintmark string - Mintages [typeCount][denoms]int -} - -type CRow struct { - Year int - Mintmark string - Name string - Mintage [typeCount]int -} - -const ( - TypeCirc = iota - TypeNIFC - TypeProof - typeCount -) - -const ( - Unknown = -iota - 1 - Invalid -) - -const ( - denoms = 8 - ws = " \t" -) - -func Parse(r io.Reader, file string) (Data, error) { - yearsSince := time.Now().Year() - 1999 + 1 - data := Data{ - Standard: make([]SRow, 0, yearsSince), - Commemorative: make([]CRow, 0, yearsSince), - } - - scanner := bufio.NewScanner(r) - for linenr := 1; scanner.Scan(); linenr++ { - line := strings.Trim(scanner.Text(), ws) - if isBlankOrComment(line) { - continue - } - - if len(line) < 4 || !isNumeric(line[:4], false) { - return Data{}, SyntaxError{ - expected: "4-digit year", - got: line, - linenr: linenr, - file: file, - } - } - - var ( - commem bool - mintmark string - ) - year, _ := strconv.Atoi(line[:4]) - line = line[4:] - - if len(line) != 0 { - if strings.ContainsRune(ws, rune(line[0])) { - commem = true - goto out - } - if line[0] != '-' { - return Data{}, SyntaxError{ - expected: "end-of-line or mintmark", - got: line, - linenr: linenr, - file: file, - } - } - - if line = line[1:]; len(line) == 0 { - return Data{}, SyntaxError{ - expected: "mintmark", - got: "end-of-line", - linenr: linenr, - file: file, - } - } - - switch i := strings.IndexAny(line, ws); i { - case 0: - return Data{}, SyntaxError{ - expected: "mintmark", - got: "whitespace", - linenr: linenr, - file: file, - } - case -1: - mintmark = line - default: - mintmark, line = line[:i], line[i:] - commem = true - } - } - out: - - if !commem { - row := SRow{ - Year: year, - Mintmark: mintmark, - } - for i := range row.Mintages { - line = "" - for isBlankOrComment(line) { - if !scanner.Scan() { - return Data{}, SyntaxError{ - expected: "mintage row", - got: "end-of-file", - linenr: linenr, - file: file, - } - } - line = strings.Trim(scanner.Text(), ws) - linenr++ - } - - tokens := strings.FieldsFunc(line, func(r rune) bool { - return strings.ContainsRune(ws, r) - }) - if tokcnt := len(tokens); tokcnt != denoms { - word := "entries" - if tokcnt == 1 { - word = "entry" - } - return Data{}, SyntaxError{ - expected: fmt.Sprintf("%d mintage entries", denoms), - got: fmt.Sprintf("%d %s", tokcnt, word), - linenr: linenr, - file: file, - } - } - - for j, tok := range tokens { - if tok != "?" && !isNumeric(tok, true) { - return Data{}, SyntaxError{ - expected: "numeric mintage figure or ‘?’", - got: tok, - linenr: linenr, - file: file, - } - } - - if tok == "?" { - row.Mintages[i][j] = Unknown - } else { - row.Mintages[i][j] = atoiWithDots(tok) - } - } - } - - data.Standard = append(data.Standard, row) - } else { - row := CRow{ - Year: year, - Mintmark: mintmark, - } - line = strings.TrimLeft(line, ws) - if line[0] != '"' { - return Data{}, SyntaxError{ - expected: "string", - got: line, - linenr: linenr, - file: file, - } - } - - line = line[1:] - switch i := strings.IndexByte(line, '"'); i { - case -1: - return Data{}, SyntaxError{ - expected: "closing quote", - got: "end-of-line", - linenr: linenr, - file: file, - } - case 0: - return Data{}, SyntaxError{ - expected: "commemorated event", - got: "empty string", - linenr: linenr, - file: file, - } - default: - row.Name, line = line[:i], line[i+1:] - } - - if len(line) != 0 { - return Data{}, SyntaxError{ - expected: "end-of-line", - got: line, - linenr: linenr, - file: file, - } - } - - for isBlankOrComment(line) { - if !scanner.Scan() { - return Data{}, SyntaxError{ - expected: "mintage row", - got: "end-of-file", - linenr: linenr, - file: file, - } - } - line = strings.Trim(scanner.Text(), ws) - linenr++ - } - - tokens := strings.FieldsFunc(line, func(r rune) bool { - return strings.ContainsRune(ws, r) - }) - if tokcnt := len(tokens); tokcnt != typeCount { - word := "entries" - if tokcnt == 1 { - word = "entry" - } - return Data{}, SyntaxError{ - expected: fmt.Sprintf("%d mintage entries", typeCount), - got: fmt.Sprintf("%d %s", tokcnt, word), - linenr: linenr, - file: file, - } - } - - for i, tok := range tokens { - if tok == "?" { - row.Mintage[i] = Unknown - } else { - row.Mintage[i] = atoiWithDots(tok) - } - } - - data.Commemorative = append(data.Commemorative, row) - } - } - - 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 atoiWithDots(s string) int { - n := 0 - for _, ch := range s { - if ch == '.' { - continue - } - n = n*10 + int(ch) - '0' - } - return n -} - -func isBlankOrComment(s string) bool { - return len(s) == 0 || s[0] == '#' -} diff --git a/lib/mintage/parser_test.go b/lib/mintage/parser_test.go deleted file mode 100644 index 76e0f01..0000000 --- a/lib/mintage/parser_test.go +++ /dev/null @@ -1,233 +0,0 @@ -package mintage - -import ( - "bytes" - "errors" - "testing" -) - -func TestParserComplete(t *testing.T) { - data, err := Parse(bytes.NewBuffer([]byte(` - 2020 - 1000 1001 1002 1003 1004 1005 1006 1007 - 1100 1101 1102 1103 1104 1105 1106 1107 - 1200 1201 1202 1203 1204 1205 1206 1207 - 2021-KNM - 2.000 ? 2002 2003 2004 2005 2006 2007 - 2.100 ? 2102 2103 2104 2105 2106 2107 - 2.200 ? 2202 2203 2204 2205 2206 2207 - 2021-MdP - 3000 3001 3002 3003 3004 3005 3006 3007 - 3100 3101 3102 3103 3104 3105 3106 3107 - 3200 3201 3202 3203 3204 3205 3206 3207 - 2022 - 4000 4001 4.002 4003 4004 4005 4006 4007 - 4100 4101 4.102 4103 4104 4105 4106 4107 - 4200 4201 4.202 4203 4204 4205 4206 4207 - - 2009 "10th Anniversary of Economic and Monetary Union" - 1000 2000 3000 - 2022-⋆ "35th Anniversary of the Erasmus Programme" - 1001 ? 3001 - `)), "-") - - if err != nil { - t.Fatalf(`Expected err=nil; got "%s"`, err) - } - - for i, row := range data.Standard { - for k := TypeCirc; k <= TypeProof; k++ { - for j, col := range row.Mintages[k] { - n := 1000*(i+1) + 100*k + j - if i == 1 && j == 1 { - n = Unknown - } - if col != n { - t.Fatalf("Expected data.Standard[%d].Mintages[%d][%d]=%d; got %d", - i, k, j, col, n) - } - } - } - } - - for i, row := range data.Commemorative { - for k := TypeCirc; k <= TypeProof; k++ { - n := 1000*(k+1) + i - if i == 1 && k == 1 { - n = Unknown - } - if row.Mintage[k] != n { - t.Fatalf("Expected row.Mintage[%d]=%d; got %d", - k, n, row.Mintage[k]) - } - } - } - - if len(data.Standard) != 4 { - t.Fatalf("Expected len(data.Standard)=2; got %d", len(data.Standard)) - } - if len(data.Commemorative) != 2 { - t.Fatalf("Expected len(data.Commemorative)=2; got %d", len(data.Commemorative)) - } - - for i, x := range [...]struct { - year int - mintmark, name string - }{ - {2009, "", "10th Anniversary of Economic and Monetary Union"}, - {2022, "⋆", "35th Anniversary of the Erasmus Programme"}, - } { - if data.Commemorative[i].Year != x.year { - t.Fatalf("Expected data.Commemorative[%d].Year=%d; got %d", - i, x.year, data.Commemorative[i].Year) - } - if data.Commemorative[i].Mintmark != x.mintmark { - t.Fatalf(`Expected data.Commemorative[%d].Mintmark="%s"; got "%s"`, - i, x.mintmark, data.Commemorative[i].Mintmark) - } - if data.Commemorative[i].Name != x.name { - t.Fatalf(`Expected data.Commemorative[%d].Name="%s"; got "%s"`, - i, x.name, data.Commemorative[i].Name) - } - } -} - -func TestParserMintmarks(t *testing.T) { - data, err := Parse(bytes.NewBuffer([]byte(` - 2020 - 1000 1001 1002 1003 1004 1005 1006 1007 - 1100 1101 1102 1103 1104 1105 1106 1107 - 1200 1201 1202 1203 1204 1205 1206 1207 - 2021-KNM - 2.000 ? 2002 2003 2004 2005 2006 2007 - 2.100 ? 2102 2103 2104 2105 2106 2107 - 2.200 ? 2202 2203 2204 2205 2206 2207 - 2021-MdP - 3000 3001 3002 3003 3004 3005 3006 3007 - 3100 3101 3102 3103 3104 3105 3106 3107 - 3200 3201 3202 3203 3204 3205 3206 3207 - 2022 - 4000 4001 4.002 4003 4004 4005 4006 4007 - 4100 4101 4.102 4103 4104 4105 4106 4107 - 4200 4201 4.202 4203 4204 4205 4206 4207 - `)), "-") - - if err != nil { - t.Fatalf(`Expected err=nil; got "%s"`, err) - } - - for i, row := range data.Standard { - for j, col := range row.Mintages[TypeCirc] { - n := 1000*(i+1) + j - if i == 1 && j == 1 { - n = Unknown - } - if col != n { - t.Fatalf("Expected data.Standard[%d].Mintages[TypeCirc][%d]=%d; got %d", - i, j, col, n) - } - } - } - - for i, y := range [...]int{2020, 2021, 2021, 2022} { - if data.Standard[i].Year != y { - t.Fatalf("Expected data.Standard[%d].Year=%d; got %d", - i, y, data.Standard[i].Year) - } - } - - for i, m := range [...]string{"", "KNM", "MdP", ""} { - if data.Standard[i].Mintmark != m { - t.Fatalf(`Expected data.Standard[%d].Mintmark="%s"; got "%s"`, - i, m, data.Standard[i].Mintmark) - } - } -} - -func TestParserNoYear(t *testing.T) { - _, err := Parse(bytes.NewBuffer([]byte(` - 1.000 1001 1002 1003 1004 1005 1006 1007 - 1.100 1101 1102 1103 1104 1105 1106 1107 - 1.200 1201 1202 1203 1204 1205 1206 1207 - 2021 - 2000 ? 2002 2003 2004 2005 2006 2007 - 2100 ? 2102 2103 2104 2105 2106 2107 - 2200 ? 2202 2203 2204 2205 2206 2207 - `)), "-") - - var sErr SyntaxError - if !errors.As(err, &sErr) { - t.Fatalf("Expected err=SyntaxError; got %s", err) - } -} - -func TestParserBadToken(t *testing.T) { - _, err := Parse(bytes.NewBuffer([]byte(` - 2020 - 1.000 1001 1002 1003 1004 1005 1006 1007 - 1.100 1101 1102 1103 1104 1105 1106 1107 - 1.200 1201 1202 1203 1204 1205 1206 1207 - 2021 Naughty! - 2000 ? 2002 2003 2004 2005 2006 2007 - 2100 ? 2102 2103 2104 2105 2106 2107 - 2200 ? 2202 2203 2204 2205 2206 2207 - `)), "-") - - var sErr SyntaxError - if !errors.As(err, &sErr) { - t.Fatalf("Expected err=SyntaxError; got %s", err) - } -} - -func TestParserShortRow(t *testing.T) { - _, err := Parse(bytes.NewBuffer([]byte(` - 2020 - 1.000 1001 1002 1003 1004 1005 1006 1007 - 1.100 1101 1102 1103 1104 1105 1106 1107 - 1.200 1201 1202 1203 1204 1205 1206 1207 - 2021 - 2000 ? 2002 2003 2004 2005 2006 2007 - 2100 ? 2102 2103 2104 2105 2106 - 2200 ? 2202 2203 2204 2205 2206 2207 - `)), "-") - - var sErr SyntaxError - if !errors.As(err, &sErr) { - t.Fatalf("Expected err=SyntaxError; got %s", err) - } -} - -func TestParserLongRow(t *testing.T) { - _, err := Parse(bytes.NewBuffer([]byte(` - 2020 - 1.000 1001 1002 1003 1004 1005 1006 1007 - 1.100 1101 1102 1103 1104 1105 1106 1107 - 1.200 1201 1202 1203 1204 1205 1206 1207 - 2021 - 2000 ? 2002 2003 2004 2005 2006 2007 - 2100 ? 2102 2103 2104 2105 2106 2107 2108 - 2200 ? 2202 2203 2204 2205 2206 2207 - `)), "-") - - var sErr SyntaxError - if !errors.As(err, &sErr) { - t.Fatalf("Expected err=SyntaxError; got %s", err) - } -} - -func TestParserMissingRow(t *testing.T) { - _, err := Parse(bytes.NewBuffer([]byte(` - 2020 - 1.000 1001 1002 1003 1004 1005 1006 1007 - 1.100 1101 1102 1103 1104 1105 1106 1107 - 1.200 1201 1202 1203 1204 1205 1206 1207 - 2021 - 2000 ? 2002 2003 2004 2005 2006 2007 - 2200 ? 2202 2203 2204 2205 2206 2207 - `)), "-") - - var sErr SyntaxError - if !errors.As(err, &sErr) { - t.Fatalf("Expected err=SyntaxError; got %s", err) - } -} -- cgit v1.2.3