d2parser: Allow passing in ParseError for nicer error messages in imports

This commit is contained in:
Anmol Sethi 2023-06-04 22:28:18 -07:00
parent c325e94cad
commit f61409cb79
No known key found for this signature in database
GPG key ID: 8CEF1878FF10ADEB
4 changed files with 17 additions and 17 deletions

View file

@ -16,6 +16,7 @@ import (
type ParseOptions struct { type ParseOptions struct {
UTF16 bool UTF16 bool
ParseError *ParseError
} }
// Parse parses a .d2 Map in r. // Parse parses a .d2 Map in r.
@ -42,6 +43,10 @@ func Parse(path string, r io.RuneReader, opts *ParseOptions) (*d2ast.Map, error)
reader: r, reader: r,
utf16: opts.UTF16, utf16: opts.UTF16,
err: opts.ParseError,
}
if p.err == nil {
p.err = &ParseError{}
} }
m := p.parseMap(true) m := p.parseMap(true)
@ -117,17 +122,15 @@ type parser struct {
lookaheadPos d2ast.Position lookaheadPos d2ast.Position
ioerr bool ioerr bool
err ParseError err *ParseError
inEdgeGroup bool inEdgeGroup bool
depth int depth int
} }
// TODO: remove ioerr, just sort (with Append) should be fine but filter non ast errors in API
// TODO: rename to Error and make existing Error a private type errorWithRange // TODO: rename to Error and make existing Error a private type errorWithRange
type ParseError struct { type ParseError struct {
IOError *d2ast.Error `json:"ioerr"`
Errors []d2ast.Error `json:"errs"` Errors []d2ast.Error `json:"errs"`
} }
@ -140,17 +143,17 @@ func Errorf(n d2ast.Node, f string, v ...interface{}) error {
} }
} }
func (pe ParseError) Empty() bool { func (pe *ParseError) Empty() bool {
return pe.IOError == nil && len(pe.Errors) == 0 if pe == nil {
return true
}
return len(pe.Errors) == 0
} }
func (pe ParseError) Error() string { func (pe *ParseError) Error() string {
var sb strings.Builder var sb strings.Builder
if pe.IOError != nil {
sb.WriteString(pe.IOError.Error())
}
for i, err := range pe.Errors { for i, err := range pe.Errors {
if pe.IOError != nil || i > 0 { if i > 0 {
sb.WriteByte('\n') sb.WriteByte('\n')
} }
sb.WriteString(err.Error()) sb.WriteString(err.Error())
@ -191,14 +194,14 @@ func (p *parser) _readRune() (r rune, eof bool) {
if err != nil { if err != nil {
p.ioerr = true p.ioerr = true
if err != io.EOF { if err != io.EOF {
p.err.IOError = &d2ast.Error{ p.err.Errors = append(p.err.Errors, d2ast.Error{
Range: d2ast.Range{ Range: d2ast.Range{
Path: p.path, Path: p.path,
Start: p.readerPos, Start: p.readerPos,
End: p.readerPos, End: p.readerPos,
}, },
Message: fmt.Sprintf("io error: %v", err), Message: fmt.Sprintf("io error: %v", err),
} })
} }
p.rewind() p.rewind()
return 0, true return 0, true

View file

@ -4,7 +4,6 @@
"nodes": null "nodes": null
}, },
"err": { "err": {
"ioerr": null,
"errs": [ "errs": [
{ {
"range": "d2/testdata/d2parser/TestParse/bad_curly.d2,0:3:3-0:4:4", "range": "d2/testdata/d2parser/TestParse/bad_curly.d2,0:3:3-0:4:4",

View file

@ -397,7 +397,6 @@
] ]
}, },
"err": { "err": {
"ioerr": null,
"errs": [ "errs": [
{ {
"range": "d2/testdata/d2parser/TestParse/errs.d2,1:0:1-1:1:2", "range": "d2/testdata/d2parser/TestParse/errs.d2,1:0:1-1:1:2",

View file

@ -28,7 +28,6 @@
] ]
}, },
"err": { "err": {
"ioerr": null,
"errs": [ "errs": [
{ {
"range": "d2/testdata/d2parser/TestParse/missing_map_value.d2,1:1:2-1:2:3", "range": "d2/testdata/d2parser/TestParse/missing_map_value.d2,1:1:2-1:2:3",