summaryrefslogtreecommitdiffhomepage
path: root/mintages
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-08-09 16:04:26 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-08-09 16:04:26 +0200
commit4538550638712c32087407750475e93c88fa9816 (patch)
tree9214670f118d9a789bc59809bbfce755d06c04e7 /mintages
parent5694eafaeefbb6fbd5816dfecf765179e49cdea4 (diff)
Add support for mintmarks
Diffstat (limited to 'mintages')
-rw-r--r--mintages/parser.go61
-rw-r--r--mintages/parser_test.go47
2 files changed, 94 insertions, 14 deletions
diff --git a/mintages/parser.go b/mintages/parser.go
index 18e7f33..87b9d19 100644
--- a/mintages/parser.go
+++ b/mintages/parser.go
@@ -23,15 +23,19 @@ func (e SyntaxError) Error() string {
e.file, e.linenr, e.expected, e.got)
}
-type coinset [8]int
+type Row struct {
+ Label string
+ Cols [8]int
+}
type Data struct {
StartYear int
- Circ, BU, Proof []coinset
+ Circ, BU, Proof []Row
}
func ForCountry(code string) (Data, error) {
path := filepath.Join("data", "mintages", code)
+
f, err := os.Open(path)
if err != nil {
return Data{}, err
@@ -42,12 +46,15 @@ func ForCountry(code string) (Data, error) {
func parse(reader io.Reader, file string) (Data, error) {
var (
- data Data // Our data struct
- slice *[]coinset // Where to append mintages
+ data Data // Our data struct
+ slice *[]Row // Where to append mintages
+ year int // The current year we are at
)
scanner := bufio.NewScanner(reader)
for linenr := 1; scanner.Scan(); linenr++ {
+ var mintmark string
+
line := scanner.Text()
tokens := strings.FieldsFunc(strings.TrimSpace(line), unicode.IsSpace)
@@ -84,6 +91,20 @@ func parse(reader io.Reader, file string) (Data, error) {
}
data.StartYear, _ = strconv.Atoi(arg)
}
+
+ year = data.StartYear - 1
+ case isLabel(tokens[0]):
+ mintmark = tokens[0][:len(tokens[0])-1]
+ tokens = tokens[1:]
+ if !isNumeric(tokens[0], true) && tokens[0] != "?" {
+ return Data{}, 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:
@@ -102,7 +123,7 @@ func parse(reader io.Reader, file string) (Data, error) {
}
}
- numcoins := len(coinset{})
+ numcoins := len(Row{}.Cols)
tokcnt := len(tokens)
if tokcnt != numcoins {
@@ -118,12 +139,24 @@ func parse(reader io.Reader, file string) (Data, error) {
}
}
- var row coinset
+ var row Row
+ switch {
+ case mintmark == "":
+ year += 1
+ row.Label = strconv.Itoa(year)
+ case mintmark[len(mintmark)-1] == '*':
+ year += 1
+ mintmark = mintmark[:len(mintmark)-1]
+ fallthrough
+ default:
+ row.Label = fmt.Sprintf("%d %s", year, mintmark)
+ }
+
for i, tok := range tokens {
if tok == "?" {
- row[i] = -1
+ row.Cols[i] = -1
} else {
- row[i] = atoiWithDots(tok)
+ row.Cols[i] = atoiWithDots(tok)
}
}
*slice = append(*slice, row)
@@ -141,11 +174,15 @@ func parse(reader io.Reader, file string) (Data, error) {
for each year that we haven’t filled in info for. This avoids
things accidentally breaking if the new year comes and we forget
to add extra rows. */
- for _, ms := range [...]*[]coinset{&data.Circ, &data.BU, &data.Proof} {
+ for _, ms := range [...]*[]Row{&data.Circ, &data.BU, &data.Proof} {
finalYear := len(*ms) + data.StartYear - 1
missing := time.Now().Year() - finalYear
for i := 0; i < missing; i++ {
- *ms = append(*ms, coinset{-1, -1, -1, -1, -1, -1, -1, -1})
+ label := strconv.Itoa(finalYear + i + 1)
+ *ms = append(*ms, Row{
+ Label: label,
+ Cols: [8]int{-1, -1, -1, -1, -1, -1, -1, -1},
+ })
}
}
@@ -167,6 +204,10 @@ func isNumeric(s string, dot bool) bool {
return true
}
+func isLabel(s string) bool {
+ return s[len(s)-1] == ':' && len(s) > 1
+}
+
func atoiWithDots(s string) int {
n := 0
for _, ch := range s {
diff --git a/mintages/parser_test.go b/mintages/parser_test.go
index 9ff4bc5..b2e4ef9 100644
--- a/mintages/parser_test.go
+++ b/mintages/parser_test.go
@@ -34,7 +34,7 @@ func TestParserComplete(t *testing.T) {
number of padding mintages is actually correct. */
for i, row := range data.Circ {
- for j, col := range row {
+ for j, col := range row.Cols {
var n int
switch {
case i == 1 && j == 1, i >= 2:
@@ -49,7 +49,7 @@ func TestParserComplete(t *testing.T) {
}
for i, row := range data.BU {
- for j, col := range row {
+ for j, col := range row.Cols {
var n int
switch {
case i == 1 && j == 1, i >= 2:
@@ -64,7 +64,7 @@ func TestParserComplete(t *testing.T) {
}
for i, row := range data.Proof {
- for j, col := range row {
+ for j, col := range row.Cols {
var n int
switch {
case i == 1 && j == 1, i >= 2:
@@ -106,7 +106,7 @@ func TestParserNoProof(t *testing.T) {
}
for _, row := range data.Proof {
- for _, col := range row {
+ for _, col := range row.Cols {
if col != -1 {
t.Fatalf("Expected data.Proof[i][j]=-1; got %d", col)
}
@@ -119,6 +119,45 @@ func TestParserNoProof(t *testing.T) {
}
}
+func TestParserMintmarks(t *testing.T) {
+ data, err := parse(bytes.NewBuffer([]byte(`
+ BEGIN 2020
+ BEGIN CIRC
+ 1.000 1001 1002 1003 1004 1005 1006 1007
+ KNM*: 2000 ? 2002 2003 2004 2005 2006 2007
+ MdP: 3000 ? 3002 3003 3004 3005 3006 3007
+ `)), "-")
+
+ if err != nil {
+ t.Fatalf(`Expected err=nil; got "%s"`, err)
+ }
+
+ for i, row := range data.Circ {
+ for j, col := range row.Cols {
+ var n int
+ switch {
+ case i > 0 && j == 1, i >= 3:
+ n = -1
+ default:
+ n = 1000*i + j + 1000
+ }
+ if col != n {
+ t.Fatalf("Expected data.Circ[i][j]=%d; got %d", n, col)
+ }
+ }
+ }
+
+ if data.Circ[0].Label != "2020" {
+ t.Fatalf(`Expected data.Circ[0].Label="2020"; got %s`, data.Circ[0].Label)
+ }
+ if data.Circ[1].Label != "2021\u00A0KNM" {
+ t.Fatalf(`Expected data.Circ[1].Label="2021 KNM"; got %s`, data.Circ[1].Label)
+ }
+ if data.Circ[2].Label != "2021\u00A0MdP" {
+ t.Fatalf(`Expected data.Circ[2].Label="2021 MdP"; got %s`, data.Circ[2].Label)
+ }
+}
+
func TestParserNoYear(t *testing.T) {
_, err := parse(bytes.NewBuffer([]byte(`
BEGIN CIRC