package nodes import ( "fmt" "strconv" "strings" "github.com/noirbizarre/gonja/tokens" u "github.com/noirbizarre/gonja/utils" ) // ---------------------------------------------------------------------------- // Interfaces // // There are 3 main classes of nodes: Expressions and type nodes, // statement nodes, and declaration nodes. The node names usually // match the corresponding Go spec production names to which they // correspond. The node fields correspond to the individual parts // of the respective productions. // // All nodes contain position information marking the beginning of // the corresponding source text segment; it is accessible via the // Pos accessor method. Nodes may contain additional position info // for language constructs where comments may be found between parts // of the construct (typically any larger, parenthesized subpart). // That position information is needed to properly position comments // when printing the construct. // All node types implement the Node interface. type Node interface { fmt.Stringer Position() *tokens.Token } // Expression represents an evaluable expression part type Expression interface { Node } // Statement represents a statement block "{% %}" type Statement interface { Node } // Template is the root node of any template type Template struct { Name string Nodes []Node Blocks BlockSet Macros map[string]*Macro Parent *Template } func (t *Template) Position() *tokens.Token { return t.Nodes[0].Position() } func (t *Template) String() string { tok := t.Position() return fmt.Sprintf("Template(Name=%s Line=%d Col=%d)", t.Name, tok.Line, tok.Col) } func (tpl *Template) GetBlocks(name string) []*Wrapper { var blocks []*Wrapper if tpl.Parent != nil { blocks = tpl.Parent.GetBlocks(name) } else { blocks = []*Wrapper{} } block, exists := tpl.Blocks[name] if exists { blocks = append([]*Wrapper{block}, blocks...) } return blocks } type Trim struct { Left bool Right bool } type Data struct { Data *tokens.Token // data token } func (d *Data) Position() *tokens.Token { return d.Data } // func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) } func (c *Data) String() string { return fmt.Sprintf("Data(text=%s Line=%d Col=%d)", u.Ellipsis(c.Data.Val, 20), c.Data.Line, c.Data.Col) } // A Comment node represents a single {# #} comment. type Comment struct { Start *tokens.Token // Opening token Text string // Comment text End *tokens.Token // Closing token Trim *Trim } func (c *Comment) Position() *tokens.Token { return c.Start } // func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) } func (c *Comment) String() string { return fmt.Sprintf("Comment(text=%s Line=%d Col=%d)", u.Ellipsis(c.Text, 20), c.Start.Line, c.Start.Col) } // Ouput represents a printable expression node {{ }} type Output struct { Start *tokens.Token Expression Expression End *tokens.Token Trim *Trim } func (o *Output) Position() *tokens.Token { return o.Start } func (o *Output) String() string { return fmt.Sprintf("Output(Expression=%s Line=%d Col=%d)", o.Expression, o.Start.Line, o.End.Col) } type FilteredExpression struct { Expression Expression Filters []*FilterCall } func (expr *FilteredExpression) Position() *tokens.Token { return expr.Expression.Position() } func (expr *FilteredExpression) String() string { t := expr.Expression.Position() return fmt.Sprintf("FilteredExpression(Expression=%s Line=%d Col=%d)", expr.Expression, t.Line, t.Col) // return fmt.Sprintf("