Improve makefile parser
Improve the androidmk makefile parser based on ideas from go/ast and friends: - Use type switching instead of the As* mess - Don't store endPos for every node, compute it based on the last known position in the node plus the length of the last token - Store positions as only the offset into the file, and then unpack them into Line/Column scanner.Position objects later Change-Id: I87eb6661859951e6c2ea5a85db6229fa5561d615
This commit is contained in:
110
androidmk/parser/ast.go
Normal file
110
androidmk/parser/ast.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package parser
|
||||
|
||||
type Pos int
|
||||
|
||||
const NoPos Pos = 0
|
||||
|
||||
type Node interface {
|
||||
Dump() string
|
||||
Pos() Pos
|
||||
End() Pos
|
||||
}
|
||||
|
||||
type Assignment struct {
|
||||
Target *MakeString
|
||||
Name *MakeString
|
||||
Value *MakeString
|
||||
Type string
|
||||
}
|
||||
|
||||
func (x *Assignment) Dump() string {
|
||||
target := ""
|
||||
if x.Target != nil {
|
||||
target = x.Target.Dump() + ": "
|
||||
}
|
||||
return target + x.Name.Dump() + x.Type + x.Value.Dump()
|
||||
}
|
||||
|
||||
func (x *Assignment) Pos() Pos {
|
||||
if x.Target != nil {
|
||||
return x.Target.Pos()
|
||||
}
|
||||
return x.Name.Pos()
|
||||
}
|
||||
|
||||
func (x *Assignment) End() Pos { return x.Value.End() }
|
||||
|
||||
type Comment struct {
|
||||
CommentPos Pos
|
||||
Comment string
|
||||
}
|
||||
|
||||
func (x *Comment) Dump() string {
|
||||
return "#" + x.Comment
|
||||
}
|
||||
|
||||
func (x *Comment) Pos() Pos { return x.CommentPos }
|
||||
func (x *Comment) End() Pos { return Pos(int(x.CommentPos) + len(x.Comment)) }
|
||||
|
||||
type Directive struct {
|
||||
NamePos Pos
|
||||
Name string
|
||||
Args *MakeString
|
||||
EndPos Pos
|
||||
}
|
||||
|
||||
func (x *Directive) Dump() string {
|
||||
return x.Name + " " + x.Args.Dump()
|
||||
}
|
||||
|
||||
func (x *Directive) Pos() Pos { return x.NamePos }
|
||||
func (x *Directive) End() Pos {
|
||||
if x.EndPos != NoPos {
|
||||
return x.EndPos
|
||||
}
|
||||
return x.Args.End()
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Target *MakeString
|
||||
Prerequisites *MakeString
|
||||
RecipePos Pos
|
||||
Recipe string
|
||||
}
|
||||
|
||||
func (x *Rule) Dump() string {
|
||||
recipe := ""
|
||||
if x.Recipe != "" {
|
||||
recipe = "\n" + x.Recipe
|
||||
}
|
||||
return "rule: " + x.Target.Dump() + ": " + x.Prerequisites.Dump() + recipe
|
||||
}
|
||||
|
||||
func (x *Rule) Pos() Pos { return x.Target.Pos() }
|
||||
func (x *Rule) End() Pos { return Pos(int(x.RecipePos) + len(x.Recipe)) }
|
||||
|
||||
type Variable struct {
|
||||
Name *MakeString
|
||||
}
|
||||
|
||||
func (x *Variable) Pos() Pos { return x.Name.Pos() }
|
||||
func (x *Variable) End() Pos { return x.Name.End() }
|
||||
|
||||
func (x *Variable) Dump() string {
|
||||
return "$(" + x.Name.Dump() + ")"
|
||||
}
|
||||
|
||||
// Sort interface for []Node by position
|
||||
type byPosition []Node
|
||||
|
||||
func (s byPosition) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s byPosition) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s byPosition) Less(i, j int) bool {
|
||||
return s[i].Pos() < s[j].Pos()
|
||||
}
|
Reference in New Issue
Block a user