Implement diag.Diagable on MuIL AST nodes

This ensures that source context information flows automatically from
MuIL AST nodes to the various diag-related functions.
This commit is contained in:
joeduffy 2017-01-17 18:01:11 -08:00
parent 3ff9e83f63
commit 2964bf6ad0
4 changed files with 36 additions and 11 deletions

View file

@ -4,8 +4,8 @@ package diag
// Pos represents a position in a file.
type Pos struct {
Ln int
Col int
Line int // a 1-based line number
Column int // a 0-based column number
}
// EmptyPos may be used when no position is needed.
@ -13,19 +13,19 @@ var EmptyPos = Pos{0, 0}
// IsEmpty returns true if the Pos information is missing.
func (pos Pos) IsEmpty() bool {
return pos.Ln == 0 && pos.Col == 0
return pos.Line == 0 && pos.Column == 0
}
// Location represents a region spanning two positions in a file.
type Location struct {
From Pos
To Pos
Start Pos // a starting position.
End *Pos // an ending position; if nil, represents a point.
}
// EmptyLocation may be used when no position information is available.
var EmptyLocation = Location{EmptyPos, EmptyPos}
var EmptyLocation = Location{EmptyPos, nil}
// IsEmpty returns true if the Location information is missing.
func (loc Location) IsEmpty() bool {
return loc.From.IsEmpty() && loc.To.IsEmpty()
return loc.Start.IsEmpty() && (loc.End == nil || loc.End.IsEmpty())
}

View file

@ -114,9 +114,9 @@ func (d *defaultSink) Stringify(diag *Diag, prefix string, args ...interface{})
if diag.Loc != nil && !diag.Loc.IsEmpty() {
buffer.WriteRune(':')
buffer.WriteString(strconv.Itoa(diag.Loc.From.Ln))
buffer.WriteString(strconv.Itoa(diag.Loc.Start.Line))
buffer.WriteRune(':')
buffer.WriteString(strconv.Itoa(diag.Loc.From.Col))
buffer.WriteString(strconv.Itoa(diag.Loc.Start.Column))
}
buffer.WriteString(": ")
}

View file

@ -11,6 +11,7 @@
package ast
import (
"github.com/marapongo/mu/pkg/diag"
"github.com/marapongo/mu/pkg/symbols"
)
@ -30,10 +31,34 @@ type node struct {
Loc *Location `json:"loc,omitempty"`
}
var _ diag.Diagable = (*node)(nil)
func (node *node) nd() {}
func (node *node) GetKind() NodeKind { return node.Kind }
func (node *node) GetLoc() *Location { return node.Loc }
func (node *node) Where() (*diag.Document, *diag.Location) {
// TODO: consider caching Document objects; allocating one per Node is wasteful.
// TODO: for development scenarios, it would be really great to recover the original source file text for purposes
// of the diag.Document part. Doing so would give nice error messages tied back to the original source code
// for any errors associated with the AST. Absent that, we will simply return nil.
if node.Loc == nil {
return nil, nil
} else {
var doc *diag.Document
if node.Loc.File != nil {
doc = diag.NewDocument(*node.Loc.File)
}
var end *diag.Pos
if node.Loc.End != nil {
end = &diag.Pos{int(node.Loc.End.Line), int(node.Loc.End.Column)}
}
return doc, &diag.Location{
diag.Pos{int(node.Loc.Start.Line), int(node.Loc.Start.Column)}, end,
}
}
}
// Identifier represents a simple string token associated with its source location context.
type Identifier struct {
node

View file

@ -11,6 +11,6 @@ type Location struct {
// Position consists of a 1-indexed `line` number and a 0-indexed `column` number.
type Position struct {
Line int64 `json:"line"` // >= 1
Column int64 `json:"column"` // >= 0
Line int64 `json:"line"` // a 1-based line number
Column int64 `json:"column"` // a 0-based column number
}