Skip to content
This repository was archived by the owner on Apr 9, 2024. It is now read-only.

Commit dbcf32e

Browse files
committed
reader - Add object field type router, refactor error to use wrap
1 parent 535a699 commit dbcf32e

File tree

3 files changed

+91
-69
lines changed

3 files changed

+91
-69
lines changed

Diff for: obj/errors.go

+5-19
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,11 @@
11
package obj
22

3-
import "fmt"
3+
import "github.com/pkg/errors"
44

5-
// ParseError represents an error in parsing
6-
type ParseError struct {
7-
LineNumber int64
8-
ItemType string
9-
Err []error
5+
func wrapLineNumber(lineNumber int64, err error) error {
6+
return errors.Wrapf(err, "error at line %d", lineNumber)
107
}
118

12-
func (err *ParseError) Error() string {
13-
return fmt.Sprintf("Parse error at line %d for %s: %s",
14-
err.LineNumber,
15-
err.ItemType,
16-
err.Err)
17-
}
18-
19-
func wrapParseErrors(lineNumber int64, itemType string, err ...error) error {
20-
return &ParseError{
21-
LineNumber: lineNumber,
22-
ItemType: itemType,
23-
Err: err,
24-
}
9+
func wrapParseErrors(itemType string, err error) error {
10+
return errors.Wrapf(err, "error parsing %s", itemType)
2511
}

Diff for: obj/reader.go

+79-43
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,24 @@ type Reader interface {
1010
Read() (*Object, error)
1111
}
1212

13-
// NewReader creates a new reader from the given io reader
13+
// NewReader creates a new reader frrouter the given io reader
1414
func NewReader(r io.Reader) Reader {
15-
return &stdReader{r}
15+
sr := &stdReader{
16+
r: r,
17+
router: make(objectRouter),
18+
}
19+
sr.router["#"] = commentHandler
20+
sr.router["o"] = objectHandler
21+
sr.router["v"] = vertexHandler
22+
sr.router["vn"] = normalHandler
23+
sr.router["vt"] = textureHandler
24+
sr.router["f"] = faceHandler
25+
return sr
1626
}
1727

1828
type stdReader struct {
19-
r io.Reader
29+
r io.Reader
30+
router objectRouter
2031
}
2132

2233
func (r *stdReader) Read() (*Object, error) {
@@ -43,54 +54,79 @@ func (r *stdReader) Read() (*Object, error) {
4354
}
4455

4556
func (r *stdReader) readLine(line []byte, lineNumber int64, o *Object) error {
46-
47-
//TODO: cyclomic complexity is 11. Would a 'router' be better here?
48-
4957
if len(line) == 0 {
5058
return nil
5159
}
5260

5361
tokens := splitByToken(line, ' ')
54-
rest := tokens[1:]
5562

56-
switch string(tokens[0]) {
57-
case "#":
58-
// skip comments
59-
return nil
60-
case "o":
61-
o.Name = string(tokens[1])
62-
case "v":
63-
v, err := parseVertex(rest)
64-
if err != nil {
65-
return wrapParseErrors(lineNumber, "vertex (v)", err)
66-
}
67-
o.Vertices = append(o.Vertices, v)
68-
return nil
69-
case "vn":
70-
vn, err := parseNormal(rest)
71-
if err != nil {
72-
return wrapParseErrors(lineNumber, "vertexNormal (vn)", err)
73-
}
74-
o.Normals = append(o.Normals, vn)
75-
return nil
76-
case "vt":
77-
vt, err := parseTextCoord(rest)
78-
if err != nil {
79-
return wrapParseErrors(lineNumber, "textureCoordinate (vt)", err)
80-
}
63+
if _, err := r.router.Route(o, tokens...); err != nil {
64+
return wrapLineNumber(lineNumber, err)
65+
}
8166

82-
o.Textures = append(o.Textures, vt)
83-
case "f":
84-
f, err := parseFace(rest, o)
85-
if err != nil {
86-
return wrapParseErrors(lineNumber, "face (f)", err)
87-
}
88-
o.Faces = append(o.Faces, f)
89-
return nil
90-
default:
91-
// fmt.Printf("ignoring token: %s\n", tokens[0])
92-
return nil
67+
return nil
68+
}
69+
70+
func commentHandler(o *Object, rest ...[]byte) error {
71+
return nil
72+
}
73+
74+
func objectHandler(o *Object, rest ...[]byte) error {
75+
o.Name = string(rest[0])
76+
return nil
77+
}
78+
79+
func vertexHandler(o *Object, rest ...[]byte) error {
80+
v, err := parseVertex(rest)
81+
if err != nil {
82+
return wrapParseErrors("vertex (v)", err)
9383
}
84+
o.Vertices = append(o.Vertices, v)
85+
return nil
86+
}
9487

88+
func normalHandler(o *Object, rest ...[]byte) error {
89+
vn, err := parseNormal(rest)
90+
if err != nil {
91+
return wrapParseErrors("vertexNormal (vn)", err)
92+
}
93+
o.Normals = append(o.Normals, vn)
9594
return nil
9695
}
96+
97+
func textureHandler(o *Object, rest ...[]byte) error {
98+
vt, err := parseTextCoord(rest)
99+
if err != nil {
100+
return wrapParseErrors("textureCoordinate (vt)", err)
101+
}
102+
103+
o.Textures = append(o.Textures, vt)
104+
return nil
105+
}
106+
107+
func faceHandler(o *Object, rest ...[]byte) error {
108+
f, err := parseFace(rest, o)
109+
if err != nil {
110+
return wrapParseErrors("face (f)", err)
111+
}
112+
o.Faces = append(o.Faces, f)
113+
return nil
114+
}
115+
116+
type objectRouter map[string]func(*Object, ...[]byte) error
117+
118+
// Route returns true if the list of tokens has been routed, false if it has been skipped
119+
func (router objectRouter) Route(o *Object, tokens ...[]byte) (bool, error) {
120+
r, ok := router[string(tokens[0])]
121+
if !ok {
122+
return false, nil
123+
}
124+
rest := tokens[1:]
125+
126+
err := r(o, rest...)
127+
if err != nil {
128+
return false, err
129+
}
130+
131+
return true, nil
132+
}

Diff for: obj/reader_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,20 @@ var readLineTests = []struct {
3333
{"#", ""},
3434
{" #", ""},
3535

36-
{"vn x", "Parse error at line 0 for vertexNormal (vn): [item length is incorrect]"},
37-
{"vt x", "Parse error at line 0 for textureCoordinate (vt): [item length is incorrect]"},
36+
{"vn x", "error at line 0: error parsing vertexNormal (vn): item length is incorrect"},
37+
{"vt x", "error at line 0: error parsing textureCoordinate (vt): item length is incorrect"},
3838
{"v 0 0 0", ""},
39-
{"v x", "Parse error at line 0 for vertex (v): [item length is incorrect]"},
40-
{"v 0 x 0", "Parse error at line 0 for vertex (v): [unable to parse Y coordinate]"},
39+
{"v x", "error at line 0: error parsing vertex (v): item length is incorrect"},
40+
{"v 0 x 0", "error at line 0: error parsing vertex (v): unable to parse Y coordinate"},
4141

4242
{"vn 0 0 0", ""},
4343

4444
{"f 1", ""},
4545

4646
//TODO: better errors
47-
{"f x", "Parse error at line 0 for face (f): [strconv.ParseInt: parsing \"x\": invalid syntax]"},
48-
{"f 1/x/1", "Parse error at line 0 for face (f): [strconv.ParseInt: parsing \"x\": invalid syntax]"},
49-
{"f 1/1/y", "Parse error at line 0 for face (f): [strconv.ParseInt: parsing \"y\": invalid syntax]"},
47+
{"f x", "error at line 0: error parsing face (f): strconv.ParseInt: parsing \"x\": invalid syntax"},
48+
{"f 1/x/1", "error at line 0: error parsing face (f): strconv.ParseInt: parsing \"x\": invalid syntax"},
49+
{"f 1/1/y", "error at line 0: error parsing face (f): strconv.ParseInt: parsing \"y\": invalid syntax"},
5050
}
5151

5252
func TestReadLine(t *testing.T) {

0 commit comments

Comments
 (0)