3c0dde2ae5
The "writer parser" is a parser that produces a writer AST rather than a zclsyntax AST. This can be used to produce a writer AST from existing source in order to modify it before writing it out again. It's implemented with the somewhat-unintuitive approach of running the main zclsyntax parser and then mapping the source ranges it finds back onto the token sequence to pull out the raw tokens for each object. This allows us to avoid maintaining two parsers but also keeps all of this raw-token-wrangling complexity out of the main parser.
121 lines
2.4 KiB
Go
121 lines
2.4 KiB
Go
package zclwrite
|
|
|
|
type Node interface {
|
|
walkChildNodes(w internalWalkFunc)
|
|
Tokens() *TokenSeq
|
|
}
|
|
|
|
type internalWalkFunc func(Node)
|
|
|
|
type File struct {
|
|
Name string
|
|
Bytes []byte
|
|
|
|
Body *Body
|
|
}
|
|
|
|
type Body struct {
|
|
// Items may contain Attribute, Block and Unstructured instances.
|
|
Items []Node
|
|
AllTokens *TokenSeq
|
|
|
|
// IndentLevel is the number of spaces that should appear at the start
|
|
// of lines added within this body.
|
|
IndentLevel int
|
|
}
|
|
|
|
func (n *Body) walkChildNodes(w internalWalkFunc) {
|
|
for _, item := range n.Items {
|
|
w(item)
|
|
}
|
|
}
|
|
|
|
func (n *Body) Tokens() *TokenSeq {
|
|
return n.AllTokens
|
|
}
|
|
|
|
func (n *Body) AppendItem(node Node) {
|
|
if n.AllTokens == nil {
|
|
new := make(TokenSeq, 0, 1)
|
|
n.AllTokens = &new
|
|
}
|
|
n.Items = append(n.Items, node)
|
|
*(n.AllTokens) = append(*(n.AllTokens), node.Tokens())
|
|
}
|
|
|
|
type Attribute struct {
|
|
AllTokens *TokenSeq
|
|
|
|
LeadCommentTokens *TokenSeq
|
|
NameToken *Token
|
|
EqualsToken *Token
|
|
Value *Expression
|
|
LineCommentTokens *TokenSeq
|
|
EOLToken *Token
|
|
}
|
|
|
|
func (a *Attribute) walkChildNodes(w internalWalkFunc) {
|
|
w(a.Value)
|
|
}
|
|
|
|
type Block struct {
|
|
AllTokens *TokenSeq
|
|
|
|
LeadCommentTokens *TokenSeq
|
|
TypeToken *Token
|
|
LabelTokens []*TokenSeq
|
|
LabelTokensFlat *TokenSeq
|
|
OBraceToken *Token
|
|
Body *Body
|
|
CBraceToken *Token
|
|
EOLToken *Token
|
|
}
|
|
|
|
func (n *Block) walkChildNodes(w internalWalkFunc) {
|
|
w(n.Body)
|
|
}
|
|
|
|
// Unstructured represents consecutive sets of tokens within a Body that
|
|
// aren't part of any particular construct. This includes blank lines
|
|
// and comments that aren't immediately before an attribute or nested block.
|
|
type Unstructured struct {
|
|
AllTokens *TokenSeq
|
|
}
|
|
|
|
func (n *Unstructured) Tokens() *TokenSeq {
|
|
return n.AllTokens
|
|
}
|
|
|
|
func (n *Unstructured) walkChildNodes(w internalWalkFunc) {
|
|
// no child nodes
|
|
}
|
|
|
|
type Expression struct {
|
|
AllTokens *TokenSeq
|
|
VarRefs []*VarRef
|
|
}
|
|
|
|
func (n *Expression) walkChildNodes(w internalWalkFunc) {
|
|
for _, name := range n.VarRefs {
|
|
w(name)
|
|
}
|
|
}
|
|
|
|
func (n *Expression) Tokens() *TokenSeq {
|
|
return n.AllTokens
|
|
}
|
|
|
|
type VarRef struct {
|
|
// Tokens alternate between TokenIdent and TokenDot, with the first
|
|
// and last elements always being TokenIdent.
|
|
AllTokens *TokenSeq
|
|
}
|
|
|
|
func (n *VarRef) walkChildNodes(w internalWalkFunc) {
|
|
// no child nodes of a variable name
|
|
}
|
|
|
|
func (n *VarRef) Tokens() *TokenSeq {
|
|
return n.AllTokens
|
|
}
|