Skip to content

Commit

Permalink
feat(pattern): Attempt to infer pattern type from data if extension d…
Browse files Browse the repository at this point in the history
…oes not match
  • Loading branch information
gabe565 committed Jul 15, 2024
1 parent aca0290 commit 9718c91
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
27 changes: 25 additions & 2 deletions internal/pattern/pattern.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package pattern

import (
"bytes"
"errors"
"fmt"
"io"
"os"
"path/filepath"
)
Expand Down Expand Up @@ -31,9 +33,9 @@ func FormatStrings() []string {

var (
ErrInvalidHeader = errors.New("invalid header")
ErrUnknownExtension = errors.New("unknown pattern extension")
ErrPatternTooBig = errors.New("pattern too big")
ErrUnexpectedCharacter = errors.New("unexpected character")
ErrInferFailed = errors.New("unable to infer pattern file type")
)

const (
Expand All @@ -57,6 +59,27 @@ func UnmarshalFile(path string, format Format) (Pattern, error) {
case format == FormatPlaintext, ext == ExtPlaintext:
return UnmarshalPlaintext(f)
default:
return Pattern{}, fmt.Errorf("%w: %s", ErrUnknownExtension, filepath.Ext(path))
pattern, err := Unmarshal(f)
if err != nil {
err = fmt.Errorf("%w: %s", err, path)
}
return pattern, err
}
}

func Unmarshal(r io.Reader) (Pattern, error) {
buf, err := io.ReadAll(r)
if err != nil {
return Pattern{}, err
}

firstLine, _, _ := bytes.Cut(bytes.TrimSpace(buf), []byte("\n"))
switch {
case bytes.HasPrefix(firstLine, []byte("#")), RLEHeaderRegexp().Match(firstLine):
return UnmarshalRLE(bytes.NewReader(buf))
case bytes.HasPrefix(firstLine, []byte("!")), bytes.HasPrefix(firstLine, []byte(".")), bytes.HasPrefix(firstLine, []byte("O")):
return UnmarshalPlaintext(bytes.NewReader(buf))
default:
return Pattern{}, ErrInferFailed
}
}
10 changes: 7 additions & 3 deletions internal/pattern/rle.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"strconv"
)

func RLEHeaderRegexp() *regexp.Regexp {
return regexp.MustCompile(`^x *= *(?P<x>[^,]+), *y *= *(?P<y>[^,]+)(?:, *rule *= *(?P<rule>.+))?$`)
}

func UnmarshalRLE(r io.Reader) (Pattern, error) {
var pattern Pattern
scanner := bufio.NewScanner(r)
Expand All @@ -33,16 +37,16 @@ scan:
}
}
case len(pattern.Grid) == 0 && bytes.HasPrefix(line, []byte("x")):
rleHeaderRe := regexp.MustCompile(`^x *= *(?P<x>[^,]+), *y *= *(?P<y>[^,]+)(?:, *rule *= *(?P<rule>.+))?$`)
matches := rleHeaderRe.FindStringSubmatch(scanner.Text())
headerRe := RLEHeaderRegexp()
matches := headerRe.FindStringSubmatch(scanner.Text())

if len(matches) == 0 {
return pattern, fmt.Errorf("rle: %w: %s", ErrInvalidHeader, line)
}

var w, h int
var err error
for i, name := range rleHeaderRe.SubexpNames() {
for i, name := range headerRe.SubexpNames() {
switch name {
case "x":
if w, err = strconv.Atoi(matches[i]); err != nil {
Expand Down

0 comments on commit 9718c91

Please sign in to comment.