<|start_filename|>ext/django/statements/ifnotequal.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type IfNotEqualStmt struct {
	Location    *tokens.Token
	var1, var2  nodes.Expression
	thenWrapper *nodes.Wrapper
	elseWrapper *nodes.Wrapper
}

func (stmt *IfNotEqualStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *IfNotEqualStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("IfNotEqualStmt(Line=%d Col=%d)", t.Line, t.Col)
}

// func (node *IfNotEqualStmt) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
// 	r1, err := node.var1.Evaluate(ctx)
// 	if err != nil {
// 		return err
// 	}
// 	r2, err := node.var2.Evaluate(ctx)
// 	if err != nil {
// 		return err
// 	}

// 	result := !r1.EqualValueTo(r2)

// 	if result {
// 		return node.thenWrapper.Execute(ctx, writer)
// 	}
// 	if node.elseWrapper != nil {
// 		return node.elseWrapper.Execute(ctx, writer)
// 	}
// 	return nil
// }

func ifNotEqualParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	ifnotequalNode := &IfNotEqualStmt{}

	// Parse two expressions
	var1, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	var2, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	ifnotequalNode.var1 = var1
	ifnotequalNode.var2 = var2

	if !args.End() {
		return nil, args.Error("ifequal only takes 2 args.", nil)
	}

	// Wrap then/else-blocks
	wrapper, endargs, err := p.WrapUntil("else", "endifnotequal")
	if err != nil {
		return nil, err
	}
	ifnotequalNode.thenWrapper = wrapper

	if !endargs.End() {
		return nil, endargs.Error("Arguments not allowed here.", nil)
	}

	if wrapper.EndTag == "else" {
		// if there's an else in the if-statement, we need the else-Block as well
		wrapper, endargs, err = p.WrapUntil("endifnotequal")
		if err != nil {
			return nil, err
		}
		ifnotequalNode.elseWrapper = wrapper

		if !endargs.End() {
			return nil, endargs.Error("Arguments not allowed here.", nil)
		}
	}

	return ifnotequalNode, nil
}

func init() {
	All.Register("ifnotequal", ifNotEqualParser)
}


<|start_filename|>env/version.go<|end_filename|>
package env

const VERSION string = "0.1.0"


<|start_filename|>exec/context.go<|end_filename|>
package exec

type Context struct {
	data   map[string]interface{}
	parent *Context
}

func NewContext(data map[string]interface{}) *Context {
	return &Context{data: data}
}

func EmptyContext() *Context {
	return &Context{data: map[string]interface{}{}}
}

func (ctx *Context) Has(name string) bool {
	_, exists := ctx.data[name]
	if !exists && ctx.parent != nil {
		return ctx.parent.Has(name)
	}
	return exists
}

func (ctx *Context) Get(name string) interface{} {
	value, exists := ctx.data[name]
	if exists {
		return value
	} else if ctx.parent != nil {
		return ctx.parent.Get(name)
	} else {
		return nil
	}
}

func (ctx *Context) Set(name string, value interface{}) {
	ctx.data[name] = value
}

func (ctx *Context) Inherit() *Context {
	return &Context{
		data:   map[string]interface{}{},
		parent: ctx,
	}
}

// Update updates this context with the key/value pairs from a map.
func (ctx *Context) Update(other map[string]interface{}) *Context {
	for k, v := range other {
		ctx.data[k] = v
	}
	return ctx
}

// Merge updates this context with the key/value pairs from another context.
func (ctx *Context) Merge(other *Context) *Context {
	return ctx.Update(other.data)
}


<|start_filename|>parser/error.go<|end_filename|>
package parser

import (
	// "bufio"
	// "fmt"
	// "os"
	"github.com/pkg/errors"
	"github.com/goph/emperror"
	"github.com/noirbizarre/gonja/tokens"
)

// Error produces a nice error message and returns an error-object.
// The 'token'-argument is optional. If provided, it will take
// the token's position information. If not provided, it will
// automatically use the CURRENT token's position information.
func (p *Parser) Error(msg string, token *tokens.Token) error {
	// if token == nil {
	// 	// Set current token
	// 	token = p.Current()
	// 	if token == nil {
	// 		// Set to last token
	// 		if len(p.tokens) > 0 {
	// 			token = p.tokens[len(p.tokens)-1]
	// 		}
	// 	}
	// }
	// var line, col int
	// if token != nil {
	// 	line = token.Line
	// 	col = token.Col
	// }
	// return &Error{
	// 	// Template:  p.template,
	// 	// Filename:  p.name,
	// 	Sender:    "parser",
	// 	Line:      line,
	// 	Column:    col,
	// 	Token:     token,
	// 	OrigError: errors.New(msg),
	// }
	// s += fmt.Sprintf(" | Line %d Col %d", e.Line, e.Column)
	// 	if e.Token != nil {
	// 		s += fmt.Sprintf(" near '%s'", e.Token.Val)
	// 	}
	if token == nil {
		return errors.New(msg)
	} else {
		return emperror.With(
			errors.Errorf(`%s (Line: %d Col: %d, near "%s")`, msg, token.Line, token.Col, token.Val),
			"token", token,
		)
	}
}

// // The Error type is being used to address an error during lexing, parsing or
// // execution. If you want to return an error object (for example in your own
// // tag or filter) fill this object with as much information as you have.
// // Make sure "Sender" is always given (if you're returning an error within
// // a filter, make Sender equals 'filter:yourfilter'; same goes for tags: 'tag:mytag').
// // It's okay if you only fill in ErrorMsg if you don't have any other details at hand.
// type Error struct {
// 	// Template  *Template
// 	// Filename  string
// 	Line      int
// 	Column    int
// 	Token     *tokens.Token
// 	Sender    string
// 	OrigError error
// }

// // func (e *Error) updateFromTokenIfNeeded(template *Template, t *Token) *Error {
// // 	if e.Template == nil {
// // 		e.Template = template
// // 	}

// // 	if e.Token == nil {
// // 		e.Token = t
// // 		if e.Line <= 0 {
// // 			e.Line = t.Line
// // 			e.Column = t.Col
// // 		}
// // 	}

// // 	return e
// // }

// // Returns a nice formatted error string.
// func (e *Error) Error() string {
// 	s := "[Error"
// 	if e.Sender != "" {
// 		s += " (where: " + e.Sender + ")"
// 	}
// 	if e.Filename != "" {
// 		s += " in " + e.Filename
// 	}
// 	if e.Line > 0 {
// 		s += fmt.Sprintf(" | Line %d Col %d", e.Line, e.Column)
// 		if e.Token != nil {
// 			s += fmt.Sprintf(" near '%s'", e.Token.Val)
// 		}
// 	}
// 	s += "] "
// 	s += e.OrigError.Error()
// 	return s
// }

// // // RawLine returns the affected line from the original template, if available.
// // func (e *Error) RawLine() (line string, available bool, outErr error) {
// // 	if e.Line <= 0 || e.Filename == "<string>" {
// // 		return "", false, nil
// // 	}

// // 	filename := e.Filename
// // 	if e.Template != nil {
// // 		filename = e.Template.set.resolveFilename(e.Template, e.Filename)
// // 	}
// // 	file, err := os.Open(filename)
// // 	if err != nil {
// // 		return "", false, err
// // 	}
// // 	defer func() {
// // 		err := file.Close()
// // 		if err != nil && outErr == nil {
// // 			outErr = err
// // 		}
// // 	}()

// // 	scanner := bufio.NewScanner(file)
// // 	l := 0
// // 	for scanner.Scan() {
// // 		l++
// // 		if l == e.Line {
// // 			return scanner.Text(), true, nil
// // 		}
// // 	}
// // 	return "", false, nil
// // }


<|start_filename|>environment.go<|end_filename|>
package gonja

import (
	"io/ioutil"
	"sync"

	"github.com/goph/emperror"

	"github.com/noirbizarre/gonja/builtins"
	"github.com/noirbizarre/gonja/config"
	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/loaders"
)

type Environment struct {
	*exec.EvalConfig
	Loader loaders.Loader

	Cache      map[string]*exec.Template
	CacheMutex sync.Mutex
}

func NewEnvironment(cfg *config.Config, loader loaders.Loader) *Environment {
	env := &Environment{
		EvalConfig: exec.NewEvalConfig(cfg),
		Loader:     loader,
		Cache:      map[string]*exec.Template{},
	}
	env.EvalConfig.Loader = env
	env.Filters.Update(builtins.Filters)
	env.Statements.Update(builtins.Statements)
	env.Tests.Update(builtins.Tests)
	env.Globals.Merge(builtins.Globals)
	env.Globals.Set("gonja", map[string]interface{}{
		"version": VERSION,
	})
	return env
}

// CleanCache cleans the template cache. If filenames is not empty,
// it will remove the template caches of those filenames.
// Or it will empty the whole template cache. It is thread-safe.
func (env *Environment) CleanCache(filenames ...string) {
	env.CacheMutex.Lock()
	defer env.CacheMutex.Unlock()

	if len(filenames) == 0 {
		env.Cache = map[string]*exec.Template{}
	}

	for _, filename := range filenames {
		delete(env.Cache, filename)
	}
}

// FromCache is a convenient method to cache templates. It is thread-safe
// and will only compile the template associated with a filename once.
// If Environment.Debug is true (for example during development phase),
// FromCache() will not cache the template and instead recompile it on any
// call (to make changes to a template live instantaneously).
func (env *Environment) FromCache(filename string) (*exec.Template, error) {
	if env.Config.Debug {
		// Recompile on any request
		return env.FromFile(filename)
	}

	env.CacheMutex.Lock()
	defer env.CacheMutex.Unlock()

	tpl, has := env.Cache[filename]

	// Cache miss
	if !has {
		tpl, err := env.FromFile(filename)
		if err != nil {
			return nil, err
		}
		env.Cache[filename] = tpl
		return tpl, nil
	}

	// Cache hit
	return tpl, nil
}

// FromString loads a template from string and returns a Template instance.
func (env *Environment) FromString(tpl string) (*exec.Template, error) {
	return exec.NewTemplate("string", tpl, env.EvalConfig)
}

// FromBytes loads a template from bytes and returns a Template instance.
func (env *Environment) FromBytes(tpl []byte) (*exec.Template, error) {
	return exec.NewTemplate("bytes", string(tpl), env.EvalConfig)
}

// FromFile loads a template from a filename and returns a Template instance.
func (env *Environment) FromFile(filename string) (*exec.Template, error) {
	fd, err := env.Loader.Get(filename)
	if err != nil {
		return nil, emperror.With(err, "filename", filename)
	}
	buf, err := ioutil.ReadAll(fd)
	if err != nil {
		return nil, emperror.With(err, "filename", filename)
	}

	return exec.NewTemplate(filename, string(buf), env.EvalConfig)
}

func (env *Environment) GetTemplate(filename string) (*exec.Template, error) {
	return env.FromFile(filename)
}


<|start_filename|>builtins/statements/include.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type IncludeStmt struct {
	// tpl               *Template
	Location      *tokens.Token
	Filename      string
	FilenameExpr  nodes.Expression
	Template      *nodes.Template
	IgnoreMissing bool
	WithContext   bool
	IsEmpty       bool
}

func (stmt *IncludeStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *IncludeStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("IncludeStmt(Filename=%s Line=%d Col=%d)", stmt.Filename, t.Line, t.Col)
}

func (stmt *IncludeStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	if stmt.IsEmpty {
		return nil
	}
	sub := r.Inherit()

	if stmt.FilenameExpr != nil {
		filenameValue := r.Eval(stmt.FilenameExpr)
		if filenameValue.IsError() {
			return errors.Wrap(filenameValue, `Unable to evaluate filename`)
		}

		filename := filenameValue.String()
		included, err := r.Loader.GetTemplate(filename)
		if err != nil {
			if stmt.IgnoreMissing {
				return nil
			} else {
				return errors.Wrapf(err, `Unable to load template '%s'`, filename)
			}
		}
		sub.Template = included
		sub.Root = included.Root

	} else {
		sub.Root = stmt.Template
	}

	return sub.Execute()
}

type IncludeEmptyStmt struct{}

// func (node *IncludeEmptyStmt) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
// 	return nil
// }

func includeParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &IncludeStmt{
		Location: p.Current(),
	}

	if tok := args.Match(tokens.String); tok != nil {
		stmt.Filename = tok.Val
	} else {
		filename, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.FilenameExpr = filename
	}

	if args.MatchName("ignore") != nil {
		if args.MatchName("missing") != nil {
			stmt.IgnoreMissing = true
		} else {
			args.Stream.Backup()
		}
	}

	if tok := args.MatchName("with", "without"); tok != nil {
		if args.MatchName("context") != nil {
			stmt.WithContext = tok.Val == "with"
		} else {
			args.Stream.Backup()
		}
	}

	// Preload static template
	if stmt.Filename != "" {
		tpl, err := p.TemplateParser(stmt.Filename)
		if err != nil {
			if stmt.IgnoreMissing {
				stmt.IsEmpty = true
			} else {
				return nil, errors.Wrapf(err, `Unable to parse included template '%s'`, stmt.Filename)
			}
		} else {
			stmt.Template = tpl
		}
	}

	if !args.End() {
		return nil, args.Error("Malformed 'include'-tag args.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("include", includeParser)
}


<|start_filename|>ext/time/statements.go<|end_filename|>
package time

import "github.com/noirbizarre/gonja/exec"

var Statements = exec.StatementSet{}


<|start_filename|>utils/ellipsis.go<|end_filename|>
package utils

func Ellipsis(text string, length int) string {
	runes := []rune(text)
	if len(runes) <= length {
		return text
	}
	return string(runes[:length - 1]) + "…"
}


<|start_filename|>exec/evaluate.go<|end_filename|>
package exec

import (
	"math"
	"reflect"
	"strings"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
)

var (
	typeOfValuePtr   = reflect.TypeOf(new(Value))
	typeOfExecCtxPtr = reflect.TypeOf(new(Context))
)

type Evaluator struct {
	*EvalConfig
	Ctx *Context
}

func (r *Renderer) Evaluator() *Evaluator {
	return &Evaluator{
		EvalConfig: r.EvalConfig,
		Ctx:        r.Ctx,
	}
}

func (r *Renderer) Eval(node nodes.Expression) *Value {
	e := r.Evaluator()
	return e.Eval(node)
}

func (e *Evaluator) Eval(node nodes.Expression) *Value {
	switch n := node.(type) {
	case *nodes.String:
		return AsValue(n.Val)
	case *nodes.Integer:
		return AsValue(n.Val)
	case *nodes.Float:
		return AsValue(n.Val)
	case *nodes.Bool:
		return AsValue(n.Val)
	case *nodes.List:
		return e.evalList(n)
	case *nodes.Tuple:
		return e.evalTuple(n)
	case *nodes.Dict:
		return e.evalDict(n)
	case *nodes.Pair:
		return e.evalPair(n)
	case *nodes.Name:
		return e.evalName(n)
	case *nodes.Call:
		return e.evalCall(n)
	case *nodes.Getitem:
		return e.evalGetitem(n)
	case *nodes.Getattr:
		return e.evalGetattr(n)
	case *nodes.Negation:
		result := e.Eval(n.Term)
		if result.IsError() {
			return result
		}
		return result.Negate()
	case *nodes.BinaryExpression:
		return e.evalBinaryExpression(n)
	case *nodes.UnaryExpression:
		return e.evalUnaryExpression(n)
	case *nodes.FilteredExpression:
		return e.EvaluateFiltered(n)
	case *nodes.TestExpression:
		return e.EvalTest(n)
	default:
		return AsValue(errors.Errorf(`Unknown expression type "%T"`, n))
	}
}

func (e *Evaluator) evalBinaryExpression(node *nodes.BinaryExpression) *Value {
	var (
		left  *Value
		right *Value
	)
	left = e.Eval(node.Left)
	if left.IsError() {
		return AsValue(errors.Wrapf(left, `Unable to evaluate left parameter %s`, node.Left))
	}

	switch node.Operator.Token.Val {
	// These operators allow lazy right expression evluation
	case "and", "or":
	default:
		right = e.Eval(node.Right)
		if right.IsError() {
			return AsValue(errors.Wrapf(right, `Unable to evaluate right parameter %s`, node.Right))
		}
	}

	switch node.Operator.Token.Val {
	case "+":
		if left.IsList() {
			if !right.IsList() {
				return AsValue(errors.Wrapf(right, `Unable to concatenate list to %s`, node.Right))
			}

			v := &Value{Val: reflect.ValueOf([]interface{}{})}

			for ix := 0; ix < left.getResolvedValue().Len(); ix ++ {
				v.Val = reflect.Append(v.Val, left.getResolvedValue().Index(ix))
			}

			for ix := 0; ix < right.getResolvedValue().Len(); ix ++ {
				v.Val = reflect.Append(v.Val, right.getResolvedValue().Index(ix))
			}

			return v
		}
		if left.IsFloat() || right.IsFloat() {
			// Result will be a float
			return AsValue(left.Float() + right.Float())
		}
		// Result will be an integer
		return AsValue(left.Integer() + right.Integer())
	case "-":
		if left.IsFloat() || right.IsFloat() {
			// Result will be a float
			return AsValue(left.Float() - right.Float())
		}
		// Result will be an integer
		return AsValue(left.Integer() - right.Integer())
	case "*":
		if left.IsFloat() || right.IsFloat() {
			// Result will be float
			return AsValue(left.Float() * right.Float())
		}
		if left.IsString() {
			return AsValue(strings.Repeat(left.String(), right.Integer()))
		}
		// Result will be int
		return AsValue(left.Integer() * right.Integer())
	case "/":
		// Float division
		return AsValue(left.Float() / right.Float())
	case "//":
		// Int division
		return AsValue(int(left.Float() / right.Float()))
	case "%":
		// Result will be int
		return AsValue(left.Integer() % right.Integer())
	case "**":
		return AsValue(math.Pow(left.Float(), right.Float()))
	case "~":
		return AsValue(strings.Join([]string{left.String(), right.String()}, ""))
	case "and":
		if !left.IsTrue() {
			return AsValue(false)
		}
		right = e.Eval(node.Right)
		if right.IsError() {
			return AsValue(errors.Wrapf(right, `Unable to evaluate right parameter %s`, node.Right))
		}
		return AsValue(right.IsTrue())
	case "or":
		if left.IsTrue() {
			return AsValue(true)
		}
		right = e.Eval(node.Right)
		if right.IsError() {
			return AsValue(errors.Wrapf(right, `Unable to evaluate right parameter %s`, node.Right))
		}
		return AsValue(right.IsTrue())
	case "<=":
		if left.IsFloat() || right.IsFloat() {
			return AsValue(left.Float() <= right.Float())
		}
		return AsValue(left.Integer() <= right.Integer())
	case ">=":
		if left.IsFloat() || right.IsFloat() {
			return AsValue(left.Float() >= right.Float())
		}
		return AsValue(left.Integer() >= right.Integer())
	case "==":
		return AsValue(left.EqualValueTo(right))
	case ">":
		if left.IsFloat() || right.IsFloat() {
			return AsValue(left.Float() > right.Float())
		}
		return AsValue(left.Integer() > right.Integer())
	case "<":
		if left.IsFloat() || right.IsFloat() {
			return AsValue(left.Float() < right.Float())
		}
		return AsValue(left.Integer() < right.Integer())
	case "!=", "<>":
		return AsValue(!left.EqualValueTo(right))
	case "in":
		return AsValue(right.Contains(left))
	case "is":
		return nil
	default:
		return AsValue(errors.Errorf(`Unknown operator "%s"`, node.Operator.Token))
	}
}

func (e *Evaluator) evalUnaryExpression(expr *nodes.UnaryExpression) *Value {
	result := e.Eval(expr.Term)
	if result.IsError() {
		return AsValue(errors.Wrapf(result, `Unable to evaluate term %s`, expr.Term))
	}
	if expr.Negative {
		if result.IsNumber() {
			switch {
			case result.IsFloat():
				return AsValue(-1 * result.Float())
			case result.IsInteger():
				return AsValue(-1 * result.Integer())
			default:
				return AsValue(errors.New("Operation between a number and a non-(float/integer) is not possible"))
			}
		} else {
			return AsValue(errors.Errorf("Negative sign on a non-number expression %s", expr.Position()))
		}
	}
	return result
}

func (e *Evaluator) evalList(node *nodes.List) *Value {
	values := ValuesList{}
	for _, val := range node.Val {
		value := e.Eval(val)
		values = append(values, value)
	}
	return AsValue(values)
}

func (e *Evaluator) evalTuple(node *nodes.Tuple) *Value {
	values := ValuesList{}
	for _, val := range node.Val {
		value := e.Eval(val)
		values = append(values, value)
	}
	return AsValue(values)
}

func (e *Evaluator) evalDict(node *nodes.Dict) *Value {
	pairs := []*Pair{}
	for _, pair := range node.Pairs {
		p := e.evalPair(pair)
		if p.IsError() {
			return AsValue(errors.Wrapf(p, `Unable to evaluate pair "%s"`, pair))
		}
		pairs = append(pairs, p.Interface().(*Pair))
	}
	return AsValue(&Dict{pairs})
}

func (e *Evaluator) evalPair(node *nodes.Pair) *Value {
	key := e.Eval(node.Key)
	if key.IsError() {
		return AsValue(errors.Wrapf(key, `Unable to evaluate key "%s"`, node.Key))
	}
	value := e.Eval(node.Value)
	if value.IsError() {
		return AsValue(errors.Wrapf(value, `Unable to evaluate value "%s"`, node.Value))
	}
	return AsValue(&Pair{key, value})
}

func (e *Evaluator) evalName(node *nodes.Name) *Value {
	val := e.Ctx.Get(node.Name.Val)
	return ToValue(val)
}

func (e *Evaluator) evalGetitem(node *nodes.Getitem) *Value {
	value := e.Eval(node.Node)
	if value.IsError() {
		return AsValue(errors.Wrapf(value, `Unable to evaluate target %s`, node.Node))
	}

	if node.Arg != "" {
		item, found := value.Getitem(node.Arg)
		if !found {
			item, found = value.Getattr(node.Arg)
		}
		if !found {
			if item.IsError() {
				return AsValue(errors.Wrapf(item, `Unable to evaluate %s`, node))
			}
			return AsValue(nil)
			// return AsValue(errors.Errorf(`Unable to evaluate %s: item '%s' not found`, node, node.Arg))
		}
		return item
	} else {
		item, found := value.Getitem(node.Index)
		if !found {
			if item.IsError() {
				return AsValue(errors.Wrapf(item, `Unable to evaluate %s`, node))
			}
			return AsValue(nil)
			// return AsValue(errors.Errorf(`Unable to evaluate %s: item %d not found`, node, node.Index))
		}
		return item
	}
	return AsValue(errors.Errorf(`Unable to evaluate %s`, node))
}

func (e *Evaluator) evalGetattr(node *nodes.Getattr) *Value {
	value := e.Eval(node.Node)
	if value.IsError() {
		return AsValue(errors.Wrapf(value, `Unable to evaluate target %s`, node.Node))
	}

	if node.Attr != "" {
		attr, found := value.Getattr(node.Attr)
		if !found {
			attr, found = value.Getitem(node.Attr)
		}
		if !found {
			if attr.IsError() {
				return AsValue(errors.Wrapf(attr, `Unable to evaluate %s`, node))
			}
			return AsValue(nil)
			// return AsValue(errors.Errorf(`Unable to evaluate %s: attribute '%s' not found`, node, node.Attr))
		}
		return attr
	} else {
		item, found := value.Getitem(node.Index)
		if !found {
			if item.IsError() {
				return AsValue(errors.Wrapf(item, `Unable to evaluate %s`, node))
			}
			return AsValue(nil)
			// return AsValue(errors.Errorf(`Unable to evaluate %s: item %d not found`, node, node.Index))
		}
		return item
	}
	return AsValue(errors.Errorf(`Unable to evaluate %s`, node))
}

func (e *Evaluator) evalCall(node *nodes.Call) *Value {
	fn := e.Eval(node.Func)
	if fn.IsError() {
		return AsValue(errors.Wrapf(fn, `Unable to evaluate function "%s"`, node.Func))
	}

	if !fn.IsCallable() {
		return AsValue(errors.Errorf(`%s is not callable`, node.Func))
	}

	// current := reflect.ValueOf(fn) // Get the initial value

	var current reflect.Value
	var isSafe bool

	var params []reflect.Value
	var err error
	t := fn.Val.Type()

	if t.NumIn() == 1 && t.In(0) == reflect.TypeOf(&VarArgs{}) {
		params, err = e.evalVarArgs(node)
	} else {
		params, err = e.evalParams(node, fn)
	}
	if err != nil {
		return AsValue(errors.Wrapf(err, `Unable to evaluate parameters`))
	}

	// Call it and get first return parameter back
	values := fn.Val.Call(params)
	rv := values[0]
	if t.NumOut() == 2 {
		e := values[1].Interface()
		if e != nil {
			err, ok := e.(error)
			if !ok {
				return AsValue(errors.Errorf("The second return value is not an error"))
			}
			if err != nil {
				return AsValue(err)
			}
		}
	}

	if rv.Type() != typeOfValuePtr {
		current = reflect.ValueOf(rv.Interface())
	} else {
		// Return the function call value
		current = rv.Interface().(*Value).Val
		isSafe = rv.Interface().(*Value).Safe
	}

	if !current.IsValid() {
		// Value is not valid (e. g. NIL value)
		return AsValue(nil)
	}

	return &Value{Val: current, Safe: isSafe}
}

func (e *Evaluator) evalVariable(node *nodes.Variable) (*Value, error) {
	var current reflect.Value
	var isSafe bool

	for idx, part := range node.Parts {
		if idx == 0 {
			val := e.Ctx.Get(node.Parts[0].S)
			current = reflect.ValueOf(val) // Get the initial value
		} else {
			// Next parts, resolve it from current

			// Before resolving the pointer, let's see if we have a method to call
			// Problem with resolving the pointer is we're changing the receiver
			isFunc := false
			if part.Type == nodes.VarTypeIdent {
				funcValue := current.MethodByName(part.S)
				if funcValue.IsValid() {
					current = funcValue
					isFunc = true
				}
			}

			if !isFunc {
				// If current a pointer, resolve it
				if current.Kind() == reflect.Ptr {
					current = current.Elem()
					if !current.IsValid() {
						// Value is not valid (anymore)
						return AsValue(nil), nil
					}
				}

				// Look up which part must be called now
				switch part.Type {
				case nodes.VarTypeInt:
					// Calling an index is only possible for:
					// * slices/arrays/strings
					switch current.Kind() {
					case reflect.String, reflect.Array, reflect.Slice:
						if part.I >= 0 && current.Len() > part.I {
							current = current.Index(part.I)
						} else {
							// In Django, exceeding the length of a list is just empty.
							return AsValue(nil), nil
						}
					default:
						return nil, errors.Errorf("Can't access an index on type %s (variable %s)",
							current.Kind().String(), node.String())
					}
				case nodes.VarTypeIdent:
					// debugging:
					// fmt.Printf("now = %s (kind: %s)\n", part.s, current.Kind().String())

					// Calling a field or key
					switch current.Kind() {
					case reflect.Struct:
						current = current.FieldByName(part.S)
					case reflect.Map:
						current = current.MapIndex(reflect.ValueOf(part.S))
					default:
						return nil, errors.Errorf("Can't access a field by name on type %s (variable %s)",
							current.Kind().String(), node.String())
					}
				default:
					panic("unimplemented")
				}
			}
		}

		if !current.IsValid() {
			// Value is not valid (anymore)
			return AsValue(nil), nil
		}

		// If current is a reflect.ValueOf(gonja.Value), then unpack it
		// Happens in function calls (as a return value) or by injecting
		// into the execution context (e.g. in a for-loop)
		if current.Type() == typeOfValuePtr {
			tmpValue := current.Interface().(*Value)
			current = tmpValue.Val
			isSafe = tmpValue.Safe
		}

		// Check whether this is an interface and resolve it where required
		if current.Kind() == reflect.Interface {
			current = reflect.ValueOf(current.Interface())
		}

		// Check if the part is a function call
		if part.IsFunctionCall {

			var params []reflect.Value
			var err error
			t := current.Type()

			if t.NumIn() == 1 && t.In(0) == reflect.TypeOf(&VarArgs{}) {
				// params, err = e.evalVarArgs(node, t, part)
			} else {
				// params, err = e.evalParams(node, t, part)
			}
			if err != nil {
				return nil, err
			}

			// Call it and get first return parameter back
			values := current.Call(params)
			rv := values[0]
			if t.NumOut() == 2 {
				e := values[1].Interface()
				if e != nil {
					err, ok := e.(error)
					if !ok {
						return nil, errors.Errorf("The second return value is not an error")
					}
					if err != nil {
						return nil, err
					}
				}
			}

			if rv.Type() != typeOfValuePtr {
				current = reflect.ValueOf(rv.Interface())
			} else {
				// Return the function call value
				current = rv.Interface().(*Value).Val
				isSafe = rv.Interface().(*Value).Safe
			}
		}

		if !current.IsValid() {
			// Value is not valid (e. g. NIL value)
			return AsValue(nil), nil
		}
	}

	return &Value{Val: current, Safe: isSafe}, nil
}

func (e *Evaluator) evalVarArgs(node *nodes.Call) ([]reflect.Value, error) {
	params := &VarArgs{
		Args:   []*Value{},
		KwArgs: map[string]*Value{},
	}
	for _, param := range node.Args {
		value := e.Eval(param)
		if value.IsError() {
			return nil, value
		}
		params.Args = append(params.Args, value)
	}

	for key, param := range node.Kwargs {
		value := e.Eval(param)
		if value.IsError() {
			return nil, value
		}
		params.KwArgs[key] = value
	}
	// va := AsValue(VarArgs{})
	return []reflect.Value{reflect.ValueOf(params)}, nil
}

func (e *Evaluator) evalParams(node *nodes.Call, fn *Value) ([]reflect.Value, error) {
	args := node.Args
	t := fn.Val.Type()

	if len(args) != t.NumIn() && !(len(args) >= t.NumIn()-1 && t.IsVariadic()) {
		msg := "Function input argument count (%d) of '%s' must be equal to the calling argument count (%d)."
		return nil, errors.Errorf(msg, t.NumIn(), node.String(), len(args))
	}

	// Output arguments
	if t.NumOut() != 1 && t.NumOut() != 2 {
		msg := "'%s' must have exactly 1 or 2 output arguments, the second argument must be of type error"
		return nil, errors.Errorf(msg, node.String())
	}

	// Evaluate all parameters
	var parameters []reflect.Value

	numArgs := t.NumIn()
	isVariadic := t.IsVariadic()
	var fnArg reflect.Type

	for idx, arg := range args {
		pv := e.Eval(arg)
		if pv.IsError() {
			return nil, pv
		}

		if isVariadic {
			if idx >= numArgs-1 {
				fnArg = t.In(numArgs - 1).Elem()
			} else {
				fnArg = t.In(idx)
			}
		} else {
			fnArg = t.In(idx)
		}

		if fnArg != typeOfValuePtr {
			// Function's argument is not a *gonja.Value, then we have to check whether input argument is of the same type as the function's argument
			if !isVariadic {
				if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
					msg := "Function input argument %d of '%s' must be of type %s or *gonja.Value (not %T)."
					return nil, errors.Errorf(msg, idx, node.String(), fnArg.String(), pv.Interface())
				}
				// Function's argument has another type, using the interface-value
				parameters = append(parameters, reflect.ValueOf(pv.Interface()))
			} else {
				if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
					msg := "Function variadic input argument of '%s' must be of type %s or *gonja.Value (not %T)."
					return nil, errors.Errorf(msg, node.String(), fnArg.String(), pv.Interface())
				}
				// Function's argument has another type, using the interface-value
				parameters = append(parameters, reflect.ValueOf(pv.Interface()))
			}
		} else {
			// Function's argument is a *gonja.Value
			parameters = append(parameters, reflect.ValueOf(pv))
		}
	}

	// Check if any of the values are invalid
	for _, p := range parameters {
		if p.Kind() == reflect.Invalid {
			return nil, errors.Errorf("Calling a function using an invalid parameter")
		}
	}

	return parameters, nil
}


<|start_filename|>config.go<|end_filename|>
package gonja

import "github.com/noirbizarre/gonja/config"

type Config config.Config

var NewConfig = config.NewConfig


<|start_filename|>builtins/statements/filter.go<|end_filename|>
package statements

import (
	// "bytes"

	// "github.com/noirbizarre/gonja/exec"
	"fmt"
	"strings"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type FilterStmt struct {
	position    *tokens.Token
	bodyWrapper *nodes.Wrapper
	filterChain []*nodes.FilterCall
}

func (stmt *FilterStmt) Position() *tokens.Token { return stmt.position }
func (stmt *FilterStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("FilterStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (node *FilterStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	var out strings.Builder
	sub := r.Inherit()
	sub.Out = &out
	// temp := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB size

	err := sub.ExecuteWrapper(node.bodyWrapper)
	if err != nil {
		return err
	}

	value := exec.AsValue(out.String())

	for _, call := range node.filterChain {
		value = r.Evaluator().ExecuteFilter(call, value)
		if value.IsError() {
			return errors.Wrapf(value, `Unable to apply filter %s (Line: %d Col: %d, near %s`,
				call.Name, call.Token.Line, call.Token.Col, call.Token.Val)
		}
	}

	r.WriteString(value.String())

	return nil
}

func filterParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &FilterStmt{
		position: p.Current(),
	}

	wrapper, _, err := p.WrapUntil("endfilter")
	if err != nil {
		return nil, err
	}
	stmt.bodyWrapper = wrapper

	for !args.End() {
		filterCall, err := args.ParseFilter()
		if err != nil {
			return nil, err
		}

		stmt.filterChain = append(stmt.filterChain, filterCall)

		if args.Match(tokens.Pipe) == nil {
			break
		}
	}

	if !args.End() {
		return nil, p.Error("Malformed filter-tag args.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("filter", filterParser)
}


<|start_filename|>parser/variable.go<|end_filename|>
package parser

import (
	// "fmt"
	"strconv"
	"strings"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
	log "github.com/sirupsen/logrus"
)

func (p *Parser) parseNumber() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseNumber")
	t := p.Match(tokens.Integer, tokens.Float)
	if t == nil {
		return nil, p.Error("Expected a number", t)
	}

	if t.Type == tokens.Integer {
		i, err := strconv.Atoi(t.Val)
		if err != nil {
			return nil, p.Error(err.Error(), t)
		}
		nr := &nodes.Integer{
			Location: t,
			Val:      i,
		}
		return nr, nil
	} else {
		f, err := strconv.ParseFloat(t.Val, 64)
		if err != nil {
			return nil, p.Error(err.Error(), t)
		}
		fr := &nodes.Float{
			Location: t,
			Val:      f,
		}
		return fr, nil
	}
}

func (p *Parser) parseString() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseString")
	t := p.Match(tokens.String)
	if t == nil {
		return nil, p.Error("Expected a string", t)
	}
	str := strconv.Quote(t.Val)
	replaced := strings.Replace(str, `\\`, "\\", -1)
	newstr, err := strconv.Unquote(replaced)
	if err != nil {
		return nil, p.Error(err.Error(), t)
	}
	sr := &nodes.String{
		Location: t,
		Val:      newstr,
	}
	return sr, nil
}

func (p *Parser) parseCollection() (nodes.Expression, error) {
	switch p.Current().Type {
	case tokens.Lbracket:
		return p.parseList()
	case tokens.Lparen:
		return p.parseTuple()
	case tokens.Lbrace:
		return p.parseDict()
	default:
		return nil, nil
	}
}

func (p *Parser) parseList() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseList")
	t := p.Match(tokens.Lbracket)
	if t == nil {
		return nil, p.Error("Expected [", t)
	}

	if p.Match(tokens.Rbracket) != nil {
		// Empty list
		return &nodes.List{t, []nodes.Expression{}}, nil
	}

	expr, err := p.ParseExpression()
	if err != nil {
		return nil, err
	}
	list := []nodes.Expression{expr}

	for p.Match(tokens.Comma) != nil {
		if p.Peek(tokens.Rbracket) != nil {
			// Trailing coma
			break
		}
		expr, err := p.ParseExpression()
		if err != nil {
			return nil, err
		}
		if expr == nil {
			return nil, p.Error("Expected a value", p.Current())
		}
		list = append(list, expr)
	}

	if p.Match(tokens.Rbracket) == nil {
		return nil, p.Error("Expected ]", p.Current())
	}

	return &nodes.List{t, list}, nil
}

func (p *Parser) parseTuple() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseTuple")
	t := p.Match(tokens.Lparen)
	if t == nil {
		return nil, p.Error("Expected (", t)
	}
	expr, err := p.ParseExpression()
	if err != nil {
		return nil, err
	}
	list := []nodes.Expression{expr}

	trailingComa := false

	for p.Match(tokens.Comma) != nil {
		if p.Peek(tokens.Rparen) != nil {
			// Trailing coma
			trailingComa = true
			break
		}
		expr, err := p.ParseExpression()
		if err != nil {
			return nil, err
		}
		if expr == nil {
			return nil, p.Error("Expected a value", p.Current())
		}
		list = append(list, expr)
	}

	if p.Match(tokens.Rparen) == nil {
		return nil, p.Error("Unbalanced parenthesis", t)
		// return nil, p.Error("Expected )", p.Current())
	}

	if len(list) > 1 || trailingComa {
		return &nodes.Tuple{t, list}, nil
	} else {
		return expr, nil
	}
}

func (p *Parser) parsePair() (*nodes.Pair, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parsePair")
	key, err := p.ParseExpression()
	if err != nil {
		return nil, err
	}

	if p.Match(tokens.Colon) == nil {
		return nil, p.Error("Expected \":\"", p.Current())
	}
	value, err := p.ParseExpression()
	if err != nil {
		return nil, err
	}
	return &nodes.Pair{
		Key:   key,
		Value: value,
	}, nil
}

func (p *Parser) parseDict() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseDict")
	t := p.Match(tokens.Lbrace)
	if t == nil {
		return nil, p.Error("Expected {", t)
	}

	dict := &nodes.Dict{
		Token: t,
		Pairs: []*nodes.Pair{},
	}

	if p.Peek(tokens.Rbrace) == nil {
		pair, err := p.parsePair()
		if err != nil {
			return nil, err
		}
		dict.Pairs = append(dict.Pairs, pair)
	}

	for p.Match(tokens.Comma) != nil {
		pair, err := p.parsePair()
		if err != nil {
			return nil, err
		}
		dict.Pairs = append(dict.Pairs, pair)
	}

	if p.Match(tokens.Rbrace) == nil {
		return nil, p.Error("Expected }", p.Current())
	}

	return dict, nil
}

func (p *Parser) ParseVariable() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseVariable")

	t := p.Match(tokens.Name)
	if t == nil {
		return nil, p.Error("Expected an identifier.", t)
	}

	switch t.Val {
	case "true", "True":
		br := &nodes.Bool{
			Location: t,
			Val:      true,
		}
		return br, nil
	case "false", "False":
		br := &nodes.Bool{
			Location: t,
			Val:      false,
		}
		return br, nil
	}

	var variable nodes.Node = &nodes.Name{t}

	for !p.Stream.EOF() {
		if dot := p.Match(tokens.Dot); dot != nil {
			getattr := &nodes.Getattr{
				Location: dot,
				Node:     variable,
			}
			tok := p.Match(tokens.Name, tokens.Integer)
			switch tok.Type {
			case tokens.Name:
				getattr.Attr = tok.Val
			case tokens.Integer:
				i, err := strconv.Atoi(tok.Val)
				if err != nil {
					return nil, p.Error(err.Error(), tok)
				}
				getattr.Index = i
			default:
				return nil, p.Error("This token is not allowed within a variable name.", p.Current())
			}
			variable = getattr
			continue
		} else if bracket := p.Match(tokens.Lbracket); bracket != nil {
			getitem := &nodes.Getitem{
				Location: dot,
				Node:     variable,
			}
			tok := p.Match(tokens.String, tokens.Integer)
			switch tok.Type {
			case tokens.String:
				getitem.Arg = tok.Val
			case tokens.Integer:
				i, err := strconv.Atoi(tok.Val)
				if err != nil {
					return nil, p.Error(err.Error(), tok)
				}
				getitem.Index = i
			default:
				return nil, p.Error("This token is not allowed within a variable name.", p.Current())
			}
			variable = getitem
			if p.Match(tokens.Rbracket) == nil {
				return nil, p.Error("Unbalanced bracket", bracket)
			}
			continue

		} else if lparen := p.Match(tokens.Lparen); lparen != nil {
			call := &nodes.Call{
				Location: lparen,
				Func:     variable,
				Args:     []nodes.Expression{},
				Kwargs:   map[string]nodes.Expression{},
			}
			// if p.Peek(tokens.VariableEnd) != nil {
			// 	return nil, p.Error("Filter parameter required after '('.", nil)
			// }

			for p.Match(tokens.Comma) != nil || p.Match(tokens.Rparen) == nil {
				// TODO: Handle multiple args and kwargs
				v, err := p.ParseExpression()
				if err != nil {
					return nil, err
				}

				if p.Match(tokens.Assign) != nil {
					key := v.Position().Val
					value, errValue := p.ParseExpression()
					if errValue != nil {
						return nil, errValue
					}
					call.Kwargs[key] = value
				} else {
					call.Args = append(call.Args, v)
				}
			}
			variable = call
			// We're done parsing the function call, next variable part
			continue
		}

		// No dot or function call? Then we're done with the variable parsing
		break
	}

	return variable, nil
}

// IDENT | IDENT.(IDENT|NUMBER)...
func (p *Parser) ParseVariableOrLiteral() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseVariableOrLiteral")
	t := p.Current()

	if t == nil {
		return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.Current())
	}

	// Is first part a number or a string, there's nothing to resolve (because there's only to return the value then)
	switch t.Type {
	case tokens.Integer, tokens.Float:
		return p.parseNumber()

	case tokens.String:
		return p.parseString()

	case tokens.Lparen, tokens.Lbrace, tokens.Lbracket:
		return p.parseCollection()

	case tokens.Name:
		return p.ParseVariable()

	default:
		return nil, p.Error("Expected either a number, string, keyword or identifier.", t)
	}
}


<|start_filename|>ext/django/statements/widthratio.go<|end_filename|>
package statements

import (
	"fmt"
	"math"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type WidthRatioStmt struct {
	Location     *tokens.Token
	current, max nodes.Expression
	width        nodes.Expression
	ctxName      string
}

func (stmt *WidthRatioStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *WidthRatioStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("WidthRatioStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *WidthRatioStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	current := r.Eval(stmt.current)
	if current.IsError() {
		return current
	}

	max := r.Eval(stmt.max)
	if max.IsError() {
		return max
	}

	width := r.Eval(stmt.width)
	if width.IsError() {
		return width
	}

	value := int(math.Ceil(current.Float()/max.Float()*width.Float() + 0.5))

	if stmt.ctxName == "" {
		r.WriteString(fmt.Sprintf("%d", value))
	} else {
		r.Ctx.Set(stmt.ctxName, value)
	}

	return nil
}

func widthratioParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &WidthRatioStmt{
		Location: p.Current(),
	}

	current, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	stmt.current = current

	max, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	stmt.max = max

	width, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	stmt.width = width

	if args.MatchName("as") != nil {
		// Name follows
		nameToken := args.Match(tokens.Name)
		if nameToken == nil {
			return nil, args.Error("Expected name (identifier).", nil)
		}
		stmt.ctxName = nameToken.Val
	}

	if !args.End() {
		return nil, args.Error("Malformed widthratio-tag args.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("widthratio", widthratioParser)
}


<|start_filename|>utils/lorem.go<|end_filename|>
package utils

import (
	"fmt"
	"math/rand"
	"strings"

	"github.com/pkg/errors"
)

const LOREM_IPSUM = `Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.
Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.`

const LOREM_IPSUM_WORDS = `a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at
auctor augue bibendum blandit class commodo condimentum congue consectetuer
consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus
diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
penatibus per pharetra phasellus placerat platea porta porttitor posuere
potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor
tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices
ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus
viverra volutpat vulputate`

var (
	LoremParagraphs = strings.Split(LOREM_IPSUM, "\n")
	LoremWords      = strings.Fields(LOREM_IPSUM)
	WORDS           = strings.Fields(LOREM_IPSUM_WORDS)
)

func Lorem(count int, method string) (string, error) {
	var out strings.Builder
	switch method {
	case "b":
		for i := 0; i < count; i++ {
			if i > 0 {
				out.WriteString("\n")
			}
			par := LoremParagraphs[i%len(LoremParagraphs)]
			out.WriteString(par)
		}
	case "w":
		for i := 0; i < count; i++ {
			if i > 0 {
				out.WriteString(" ")
			}
			word := LoremWords[i%len(LoremWords)]
			out.WriteString(word)
		}
	case "p":
		for i := 0; i < count; i++ {
			if i > 0 {
				out.WriteString("\n")
			}
			out.WriteString("<p>")
			par := LoremParagraphs[i%len(LoremParagraphs)]
			out.WriteString(par)
			out.WriteString("</p>")

		}
	default:
		return "", errors.Errorf("unsupported method: %s", method)
	}

	return out.String(), nil
}

func Lipsum(n int, html bool, min int, max int) string {
	result := []string{}

	for i := 0; i < n; i++ {
		nextCapitalized := true
		lastComma, lastFullstop := 0, 0
		word := ""
		last := ""
		p := []string{}

		// each paragraph contains out of min to max words.
		for j := min; j < max; j++ {
			for {
				word = WORDS[rand.Intn(len(WORDS))]
				if word != last {
					last = word
					break
				}
			}

			if nextCapitalized {
				word = strings.Title(word)
				nextCapitalized = false
			}

			if j-(3+rand.Intn(5)) > lastComma {
				// Add comas
				lastComma = j
				lastFullstop += 2
				word += ","
			} else if j-(10+rand.Intn(10)) > lastFullstop {
				// Add end of sentences
				lastComma, lastFullstop = j, j
				word += "."
				nextCapitalized = true
			}

			p = append(p, word)
		}

		// # ensure that the paragraph ends with a dot.
		str := strings.Join(p, " ")
		if strings.HasSuffix(str, ",") {
			str = str[:len(str)-1] + "."
		} else if !strings.HasSuffix(str, ".") {
			str += "."
		}

		result = append(result, str)
	}

	if !html {
		return strings.Join(result, "\n\n")
	}
	htmlResult := []string{}
	for _, p := range result {
		htmlResult = append(htmlResult, fmt.Sprintf(`<p>%s<p>`, p))
	}
	return strings.Join(htmlResult, "\n")
}

// Generates some lorem ipsum for the template.
// By default, five paragraphs of HTML are generated
// with each paragraph between 20 and 100 words.
// If html is False, regular text is returned.
// func lipsum(n=5, html=True, min=20, max=100) {}
// func Lorem(count int, method string) (string, error) {
// 	var out strings.Builder
// 	switch method {
// 	case "b":
// 		if random {
// 			for i := 0; i < count; i++ {
// 				if i > 0 {
// 					out.WriteString("\n")
// 				}
// 				par := LoremParagraphs[rand.Intn(len(LoremParagraphs))]
// 				out.WriteString(par)
// 			}
// 		} else {
// 			for i := 0; i < count; i++ {
// 				if i > 0 {
// 					out.WriteString("\n")
// 				}
// 				par := LoremParagraphs[i%len(LoremParagraphs)]
// 				out.WriteString(par)
// 			}
// 		}
// 	case "w":
// 		if random {
// 			for i := 0; i < count; i++ {
// 				if i > 0 {
// 					out.WriteString(" ")
// 				}
// 				word := LoremWords[rand.Intn(len(LoremWords))]
// 				out.WriteString(word)
// 			}
// 		} else {
// 			for i := 0; i < count; i++ {
// 				if i > 0 {
// 					out.WriteString(" ")
// 				}
// 				word := LoremWords[i%len(LoremWords)]
// 				out.WriteString(word)
// 			}
// 		}
// 	case "p":
// 		if random {
// 			for i := 0; i < count; i++ {
// 				if i > 0 {
// 					out.WriteString("\n")
// 				}
// 				out.WriteString("<p>")
// 				par := LoremParagraphs[rand.Intn(len(LoremParagraphs))]
// 				out.WriteString(par)
// 				out.WriteString("</p>")
// 			}
// 		} else {
// 			for i := 0; i < count; i++ {
// 				if i > 0 {
// 					out.WriteString("\n")
// 				}
// 				out.WriteString("<p>")
// 				par := LoremParagraphs[i%len(LoremParagraphs)]
// 				out.WriteString(par)
// 				out.WriteString("</p>")

// 			}
// 		}
// 	default:
// 		return "", errors.Errorf("unsupported method: %s", method)
// 	}

// 	return out.String(), nil
// }


<|start_filename|>tokens/lexer_test.go<|end_filename|>
package tokens_test

import (
	"testing"

	"github.com/noirbizarre/gonja/tokens"
	"github.com/stretchr/testify/assert"
)

type tok struct {
	typ tokens.Type
	val string
}

func (t tok) String() string {
	return `"` + t.val + `"`
}

var (
	EOF            = tok{tokens.EOF, ""}
	varBegin       = tok{tokens.VariableBegin, "{{"}
	varEnd         = tok{tokens.VariableEnd, "}}"}
	blockBegin     = tok{tokens.BlockBegin, "{%"}
	blockBeginTrim = tok{tokens.BlockBegin, "{%-"}
	blockEnd       = tok{tokens.BlockEnd, "%}"}
	blockEndTrim   = tok{tokens.BlockEnd, "-%}"}
	lParen         = tok{tokens.Lparen, "("}
	rParen         = tok{tokens.Rparen, ")"}
	lBrace         = tok{tokens.Lbrace, "{"}
	rBrace         = tok{tokens.Rbrace, "}"}
	lBracket       = tok{tokens.Lbracket, "["}
	rBracket       = tok{tokens.Rbracket, "]"}
	space          = tok{tokens.Whitespace, " "}
)

func data(text string) tok {
	return tok{tokens.Data, text}
}

func name(text string) tok {
	return tok{tokens.Name, text}
}

func str(text string) tok {
	return tok{tokens.String, text}
}

func error(text string) tok {
	return tok{tokens.Error, text}
}

var lexerCases = []struct {
	name     string
	input    string
	expected []tok
}{
	{"empty", "", []tok{EOF}},
	{"data", "Hello World", []tok{
		data("Hello World"),
		EOF,
	}},
	{"comment", "{# a comment #}", []tok{
		tok{tokens.CommentBegin, "{#"},
		data(" a comment "),
		tok{tokens.CommentEnd, "#}"},
		EOF,
	}},
	{"mixed comment", "Hello, {# comment #}World", []tok{
		data("Hello, "),
		tok{tokens.CommentBegin, "{#"},
		data(" comment "),
		tok{tokens.CommentEnd, "#}"},
		data("World"),
		EOF,
	}},
	{"simple variable", "{{ foo }}", []tok{
		varBegin,
		space,
		name("foo"),
		space,
		varEnd,
		EOF,
	}},
	{"basic math expression", "{{ (a - b) + c }}", []tok{
		varBegin, space,
		lParen, name("a"), space, tok{tokens.Sub, "-"}, space, name("b"), rParen,
		space, tok{tokens.Add, "+"}, space, name("c"),
		space, varEnd,
		EOF,
	}},
	{"blocks", "Hello.  {% if true %}World{% else %}Nobody{% endif %}", []tok{
		data("Hello.  "),
		blockBegin, space, name("if"), space, name("true"), space, blockEnd,
		data("World"),
		blockBegin, space, name("else"), space, blockEnd,
		data("Nobody"),
		blockBegin, space, name("endif"), space, blockEnd,
		EOF,
	}},
	{"blocks with trim control", "Hello.  {%- if true -%}World{%- else -%}Nobody{%- endif -%}", []tok{
		data("Hello.  "),
		blockBeginTrim, space, name("if"), space, name("true"), space, blockEndTrim,
		data("World"),
		blockBeginTrim, space, name("else"), space, blockEndTrim,
		data("Nobody"),
		blockBeginTrim, space, name("endif"), space, blockEndTrim,
		EOF,
	}},
	{"Ignore tags in comment", "<html>{# ignore {% tags %} in comments ##}</html>", []tok{
		data("<html>"),
		tok{tokens.CommentBegin, "{#"},
		data(" ignore {% tags %} in comments #"),
		tok{tokens.CommentEnd, "#}"},
		data("</html>"),
		EOF,
	}},
	{"Mixed content", "{# comment #}{% if foo -%} bar {%- elif baz %} bing{%endif    %}", []tok{
		tok{tokens.CommentBegin, "{#"},
		data(" comment "),
		tok{tokens.CommentEnd, "#}"},
		blockBegin, space, name("if"), space, name("foo"), space, blockEndTrim,
		data(" bar "),
		blockBeginTrim, space, name("elif"), space, name("baz"), space, blockEnd,
		data(" bing"),
		blockBegin, name("endif"), tok{tokens.Whitespace, "    "}, blockEnd,
		EOF,
	}},
	{"mixed tokens with doubles", "{{ +--+ /+//,|*/**=>>=<=< == }}", []tok{
		varBegin,
		space,
		tok{tokens.Add, "+"}, tok{tokens.Sub, "-"}, tok{tokens.Sub, "-"}, tok{tokens.Add, "+"},
		space,
		tok{tokens.Div, "/"}, tok{tokens.Add, "+"}, tok{tokens.Floordiv, "//"},
		tok{tokens.Comma, ","},
		tok{tokens.Pipe, "|"},
		tok{tokens.Mul, "*"},
		tok{tokens.Div, "/"},
		tok{tokens.Pow, "**"},
		tok{tokens.Assign, "="},
		tok{tokens.Gt, ">"},
		tok{tokens.Gteq, ">="},
		tok{tokens.Lteq, "<="},
		tok{tokens.Lt, "<"},
		space,
		tok{tokens.Eq, "=="},
		space,
		varEnd,
		EOF,
	}},
	{"delimiters", "{{ ([{}]()) }}", []tok{
		varBegin, space,
		lParen, lBracket, lBrace, rBrace, rBracket, lParen, rParen, rParen,
		space, varEnd,
		EOF,
	}},
	{"Unbalanced delimiters", "{{ ([{]) }}", []tok{
		varBegin, space,
		lParen, lBracket, lBrace,
		error(`Unbalanced delimiters, expected "}", got "]"`),
	}},
	{"Unexpeced delimiter", "{{ ()) }}", []tok{
		varBegin, space,
		lParen, rParen,
		error(`Unexpected delimiter ")"`),
	}},
	{"Unbalance over end block", "{{ ({a:b, {a:b}}) }}", []tok{
		varBegin, space,
		lParen,
		lBrace, name("a"), tok{tokens.Colon, ":"}, name("b"), tok{tokens.Comma, ","},
		space,
		lBrace, name("a"), tok{tokens.Colon, ":"}, name("b"), rBrace, rBrace,
		rParen,
		space, varEnd,
		EOF,
	}},
	{"string with double quote", `{{ "Hello, " + "World" }}`, []tok{
		varBegin, space,
		str("Hello, "),
		space, tok{tokens.Add, "+"}, space,
		str("World"),
		space, varEnd,
		EOF,
	}},
	{"string with simple quote", `{{ 'Hello, ' + 'World' }}`, []tok{
		varBegin, space,
		str("Hello, "),
		space, tok{tokens.Add, "+"}, space,
		str("World"),
		space, varEnd,
		EOF,
	}},
	{"single quotes inside double quotes string", `{{ "'quoted' test" }}`, []tok{
		varBegin, space, str("'quoted' test"), space, varEnd, EOF,
	}},
	{"escaped string", `{{ "Hello, \"World\"" }}`, []tok{
		varBegin, space,
		str(`Hello, "World"`),
		space, varEnd,
		EOF,
	}},
	{"escaped string mixed", `{{ "Hello,\n \'World\'" }}`, []tok{
		varBegin, space,
		str(`Hello,\n 'World'`),
		space, varEnd,
		EOF,
	}},
	{"if statement", `{% if 5.5 == 5.500000 %}5.5 is 5.500000{% endif %}`, []tok{
		blockBegin, space, name("if"), space,
		tok{tokens.Float, "5.5"}, space, tok{tokens.Eq, "=="}, space, tok{tokens.Float, "5.500000"},
		space, blockEnd,
		data("5.5 is 5.500000"),
		blockBegin, space, name("endif"), space, blockEnd,
		EOF,
	}},
}

func tokenSlice(c chan *tokens.Token) []*tokens.Token {
	toks := []*tokens.Token{}
	for token := range c {
		toks = append(toks, token)
	}
	return toks
}

func TestLexer(t *testing.T) {
	for _, lc := range lexerCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			lexer := tokens.NewLexer(test.input)
			go lexer.Run()
			toks := tokenSlice(lexer.Tokens)

			assert := assert.New(t)
			assert.Equal(len(test.expected), len(toks))
			actual := []tok{}
			for _, token := range toks {
				actual = append(actual, tok{token.Type, token.Val})
			}
			assert.Equal(test.expected, actual)
		})
	}
}

func streamResult(s *tokens.Stream) []tok {
	out := []tok{}
	for !s.End() {
		token := s.Current()
		out = append(out, tok{token.Type, token.Val})
		s.Next()
	}
	return out
}

func asStreamResult(toks []tok) ([]tok, bool) {
	out := []tok{}
	isError := false
	for _, token := range toks {
		if token.typ == tokens.Error {
			isError = true
			break
		}
		if token.typ != tokens.Whitespace && token.typ != tokens.EOF {
			out = append(out, token)
		}
	}
	return out, isError
}

func TestLex(t *testing.T) {
	for _, lc := range lexerCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			stream := tokens.Lex(test.input)
			expected, _ := asStreamResult(test.expected)

			actual := streamResult(stream)

			assert := assert.New(t)
			assert.Equal(len(expected), len(actual))
			assert.Equal(expected, actual)
		})
	}
}

func TestStreamSlice(t *testing.T) {
	for _, lc := range lexerCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			lexer := tokens.NewLexer(test.input)
			go lexer.Run()
			toks := tokenSlice(lexer.Tokens)

			stream := tokens.NewStream(toks)
			expected, _ := asStreamResult(test.expected)

			actual := streamResult(stream)

			assert := assert.New(t)
			assert.Equal(len(expected), len(actual))
			assert.Equal(expected, actual)
		})
	}
}

const positionsCase = `Hello
{#
    Multiline comment
#}
World
`

func TestLexerPosition(t *testing.T) {
	assert := assert.New(t)

	lexer := tokens.NewLexer(positionsCase)
	go lexer.Run()
	toks := tokenSlice(lexer.Tokens)
	assert.Equal([]*tokens.Token{
		&tokens.Token{tokens.Data, "Hello\n", 0, 1, 1},
		&tokens.Token{tokens.CommentBegin, "{#", 6, 2, 1},
		&tokens.Token{tokens.Data, "\n    Multiline comment\n", 8, 2, 3},
		&tokens.Token{tokens.CommentEnd, "#}", 31, 4, 1},
		&tokens.Token{tokens.Data, "\nWorld\n", 33, 4, 3},
		&tokens.Token{tokens.EOF, "", 40, 6, 1},
	}, toks)
}


<|start_filename|>ext/django/django_test.go<|end_filename|>
package django_test

import (
	"testing"

	"github.com/noirbizarre/gonja"
	"github.com/noirbizarre/gonja/ext/django"
	tu "github.com/noirbizarre/gonja/testutils"
)

func Env(root string) *gonja.Environment {
	env := tu.TestEnv(root)
	env.Filters.Update(django.Filters)
	env.Statements.Update(django.Statements)
	return env
}

func TestDjangoTemplates(t *testing.T) {
	root := "./testData"
	env := Env(root)
	tu.GlobTemplateTests(t, root, env)
}

func TestDjangoFilters(t *testing.T) {
	root := "./testData/filters"
	env := Env(root)
	tu.GlobTemplateTests(t, root, env)
}

func TestDjangoStatements(t *testing.T) {
	root := "./testData/statements"
	env := Env(root)
	tu.GlobTemplateTests(t, root, env)
}


<|start_filename|>doc.go<|end_filename|>
// A jinja like template-engine
//
// Blog posts about gonja (including introduction and migration):
// https://www.florian-schlachter.de/?tag=gonja
//
// Complete documentation on the template language:
// https://docs.djangoproject.com/en/dev/topics/templates/
//
// Try out gonja live in the gonja playground:
// https://www.florian-schlachter.de/gonja/
//
// Make sure to read README.md in the repository as well.
//
// A tiny example with template strings:
//
// (Snippet on playground: https://www.florian-schlachter.de/gonja/?id=1206546277)
//
//     // Compile the template first (i. e. creating the AST)
//     tpl, err := gonja.FromString("Hello {{ name|capfirst }}!")
//     if err != nil {
//         panic(err)
//     }
//     // Now you can render the template with the given
//     // gonja.Context how often you want to.
//     out, err := tpl.Execute(gonja.Context{"name": "fred"})
//     if err != nil {
//         panic(err)
//     }
//     fmt.Println(out) // Output: Hello Fred!
//
package gonja


<|start_filename|>ext/django/statements/lorem.go<|end_filename|>
package statements

import (
	"fmt"
	"math/rand"
	"strings"
	"time"

	// "github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
	"github.com/noirbizarre/gonja/utils"
)

var (
	loremParagraphs = strings.Split(loremText, "\n")
	loremWords      = strings.Fields(loremText)
)

type LoremStmt struct {
	Location *tokens.Token
	count    int    // number of paragraphs
	method   string // w = words, p = HTML paragraphs, b = plain-text (default is b)
	random   bool   // does not use the default paragraph "Lorem ipsum dolor sit amet, ..."
}

func (stmt *LoremStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *LoremStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("LoremStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *LoremStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	lorem, err := utils.Lorem(stmt.count, stmt.method)
	if err != nil {
		return err
	}
	r.WriteString(lorem)

	return nil
}

func loremParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &LoremStmt{
		Location: p.Current(),
		count:    1,
		method:   "b",
	}

	if countToken := args.Match(tokens.Integer); countToken != nil {
		stmt.count = exec.AsValue(countToken.Val).Integer()
	}

	if methodToken := args.Match(tokens.Name); methodToken != nil {
		if methodToken.Val != "w" && methodToken.Val != "p" && methodToken.Val != "b" {
			return nil, args.Error("lorem-method must be either 'w', 'p' or 'b'.", nil)
		}

		stmt.method = methodToken.Val
	}

	if args.MatchName("random") != nil {
		stmt.random = true
	}

	if !args.End() {
		return nil, args.Error("Malformed lorem-tag args.", nil)
	}

	return stmt, nil
}

func init() {
	rand.Seed(time.Now().Unix())

	All.Register("lorem", loremParser)
}

const loremText = `Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.
Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.`


<|start_filename|>builtins/statements/for.go<|end_filename|>
package statements

import (
	"fmt"
	"math"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type ForStmt struct {
	key             string
	value           string // only for maps: for key, value in map
	objectEvaluator nodes.Expression
	ifCondition     nodes.Expression

	bodyWrapper  *nodes.Wrapper
	emptyWrapper *nodes.Wrapper
}

func (stmt *ForStmt) Position() *tokens.Token { return stmt.bodyWrapper.Position() }
func (stmt *ForStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("ForStmt(Line=%d Col=%d)", t.Line, t.Col)
}

type LoopInfos struct {
	index      int
	index0     int
	revindex   int
	revindex0  int
	first      bool
	last       bool
	length     int
	depth      int
	depth0     int
	PrevItem   *exec.Value
	NextItem   *exec.Value
	_lastValue *exec.Value
}

func (li *LoopInfos) Cycle(va *exec.VarArgs) *exec.Value {
	return va.Args[int(math.Mod(float64(li.index0), float64(len(va.Args))))]
}

func (li *LoopInfos) Changed(value *exec.Value) bool {
	same := li._lastValue != nil && value.EqualValueTo(li._lastValue)
	li._lastValue = value
	return !same
}

func (node *ForStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) (forError error) {
	obj := r.Eval(node.objectEvaluator)
	if obj.IsError() {
		return obj
	}

	// Create loop struct
	items := exec.NewDict()

	// First iteration: filter values to ensure proper LoopInfos
	obj.Iterate(func(idx, count int, key, value *exec.Value) bool {
		sub := r.Inherit()
		ctx := sub.Ctx
		pair := &exec.Pair{}

		// There's something to iterate over (correct type and at least 1 item)
		// Update loop infos and public context
		if node.value != "" && !key.IsString() && key.Len() == 2 {
			key.Iterate(func(idx, count int, key, value *exec.Value) bool {
				switch idx {
				case 0:
					ctx.Set(node.key, key)
					pair.Key = key
				case 1:
					ctx.Set(node.value, key)
					pair.Value = key
				}
				return true
			}, func() {})
		} else {
			ctx.Set(node.key, key)
			pair.Key = key
			if value != nil {
				ctx.Set(node.value, value)
				pair.Value = value
			}
		}

		if node.ifCondition != nil {
			if !sub.Eval(node.ifCondition).IsTrue() {
				return true
			}
		}
		items.Pairs = append(items.Pairs, pair)
		return true
	}, func() {
		// Nothing to iterate over (maybe wrong type or no items)
		if node.emptyWrapper != nil {
			sub := r.Inherit()
			err := sub.ExecuteWrapper(node.emptyWrapper)
			if err != nil {
				forError = err
			}
		}
	})

	// 2nd pass: all values are defined, render
	length := len(items.Pairs)
	loop := &LoopInfos{
		first:  true,
		index0: -1,
	}
	for idx, pair := range items.Pairs {
		r.EndTag(tag.Trim)
		sub := r.Inherit()
		ctx := sub.Ctx

		ctx.Set(node.key, pair.Key)
		if pair.Value != nil {
			ctx.Set(node.value, pair.Value)
		}

		ctx.Set("loop", loop)
		loop.index0 = idx
		loop.index = loop.index0 + 1
		if idx == 1 {
			loop.first = false
		}
		if idx+1 == length {
			loop.last = true
		}
		loop.revindex = length - idx
		loop.revindex0 = length - (idx + 1)

		if idx == 0 {
			loop.PrevItem = exec.AsValue(nil)
		} else {
			pp := items.Pairs[idx-1]
			if pp.Value != nil {
				loop.PrevItem = exec.AsValue([2]*exec.Value{pp.Key, pp.Value})
			} else {
				loop.PrevItem = pp.Key
			}
		}

		if idx == length-1 {
			loop.NextItem = exec.AsValue(nil)
		} else {
			np := items.Pairs[idx+1]
			if np.Value != nil {
				loop.NextItem = exec.AsValue([2]*exec.Value{np.Key, np.Value})
			} else {
				loop.NextItem = np.Key
			}
		}

		// Render elements with updated context
		err := sub.ExecuteWrapper(node.bodyWrapper)
		if err != nil {
			return err
		}
	}

	return forError
}

func forParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &ForStmt{}

	// Arguments parsing
	var valueToken *tokens.Token
	keyToken := args.Match(tokens.Name)
	if keyToken == nil {
		return nil, args.Error("Expected an key identifier as first argument for 'for'-tag", nil)
	}

	if args.Match(tokens.Comma) != nil {
		// Value name is provided
		valueToken = args.Match(tokens.Name)
		if valueToken == nil {
			return nil, args.Error("Value name must be an identifier.", nil)
		}
	}

	if args.MatchName("in") == nil {
		return nil, args.Error("Expected keyword 'in'.", nil)
	}

	objectEvaluator, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	stmt.objectEvaluator = objectEvaluator
	stmt.key = keyToken.Val
	if valueToken != nil {
		stmt.value = valueToken.Val
	}

	if args.MatchName("if") != nil {
		ifCondition, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.ifCondition = ifCondition
	}

	if !args.End() {
		return nil, args.Error("Malformed for-loop args.", nil)
	}

	// Body wrapping
	wrapper, endargs, err := p.WrapUntil("else", "endfor")
	if err != nil {
		return nil, err
	}
	stmt.bodyWrapper = wrapper

	if !endargs.End() {
		return nil, endargs.Error("Arguments not allowed here.", nil)
	}

	if wrapper.EndTag == "else" {
		// if there's an else in the if-statement, we need the else-Block as well
		wrapper, endargs, err = p.WrapUntil("endfor")
		if err != nil {
			return nil, err
		}
		stmt.emptyWrapper = wrapper

		if !endargs.End() {
			return nil, endargs.Error("Arguments not allowed here.", nil)
		}
	}

	return stmt, nil
}

func init() {
	All.Register("for", forParser)
}


<|start_filename|>gonja_test.go<|end_filename|>
package gonja_test

import (
	"flag"
	"os"
	"testing"

	. "github.com/go-check/check"
	log "github.com/sirupsen/logrus"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

var (
	logLevel = flag.String("log.level", "", "Log Level")
)

func TestMain(m *testing.M) {
	flag.Parse()

	log.SetFormatter(&prefixed.TextFormatter{
		ForceColors:      true,
		DisableTimestamp: true,
		ForceFormatting:  true,
	})

	switch *logLevel {
	case "error":
		log.SetLevel(log.ErrorLevel)
	case "warning", "warn":
		log.SetLevel(log.WarnLevel)
	case "info":
		log.SetLevel(log.InfoLevel)
	case "debug":
		log.SetLevel(log.DebugLevel)
	case "trace":
		log.SetLevel(log.TraceLevel)
	default:
		log.SetLevel(log.PanicLevel)
	}
	code := m.Run()
	os.Exit(code)
}


<|start_filename|>ext/django/statements/templatetag.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type TemplateTagStmt struct {
	Location *tokens.Token
	content  string
}

func (stmt *TemplateTagStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *TemplateTagStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("TemplateTagStmt(Line=%d Col=%d)", t.Line, t.Col)
}

var templateTagMapping = map[string]string{
	"openblock":     "{%",
	"closeblock":    "%}",
	"openvariable":  "{{",
	"closevariable": "}}",
	"openbrace":     "{",
	"closebrace":    "}",
	"opencomment":   "{#",
	"closecomment":  "#}",
}

func (node *TemplateTagStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	r.WriteString(node.content)
	return nil
}

func templateTagParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &TemplateTagStmt{}

	if argToken := args.Match(tokens.Name); argToken != nil {
		output, found := templateTagMapping[argToken.Val]
		if !found {
			return nil, args.Error("Argument not found", argToken)
		}
		stmt.content = output
	} else {
		return nil, args.Error("Identifier expected.", nil)
	}

	if !args.End() {
		return nil, args.Error("Malformed templatetag-tag argument.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("templatetag", templateTagParser)
}


<|start_filename|>exec/config.go<|end_filename|>
package exec

import (
	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/config"
	"github.com/noirbizarre/gonja/nodes"
)

type EvalConfig struct {
	*config.Config
	Filters    *FilterSet
	Globals    *Context
	Statements *StatementSet
	Tests      *TestSet
	Loader     TemplateLoader
}

func NewEvalConfig(cfg *config.Config) *EvalConfig {
	return &EvalConfig{
		Config:     cfg,
		Globals:    EmptyContext(),
		Filters:    &FilterSet{},
		Statements: &StatementSet{},
		Tests:      &TestSet{},
	}
}

func (cfg *EvalConfig) Inherit() *EvalConfig {
	return &EvalConfig{
		Config:     cfg.Config.Inherit(),
		Globals:    cfg.Globals,
		Filters:    cfg.Filters,
		Statements: cfg.Statements,
		Tests:      cfg.Tests,
		Loader:     cfg.Loader,
	}
}

func (cfg *EvalConfig) GetTemplate(filename string) (*nodes.Template, error) {
	tpl, err := cfg.Loader.GetTemplate(filename)
	if err != nil {
		return nil, errors.Wrapf(err, `Unable to parse template "%s"`, filename)
	}
	return tpl.Root, nil
}


<|start_filename|>tokens/lexer.go<|end_filename|>
package tokens

import (
	"fmt"
	// "encoding/json"
	"regexp"
	// "strconv"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/noirbizarre/gonja/config"
)

// EOF is an arbitraty value for End Of File
const rEOF = -1
const re_ENDRAW = `%s\s*%s`

var escapedStrings = map[string]string{
	`\"`: `"`,
	`\'`: `'`,
}

// var pattern = regexp.MustCompile(`(?m)(?P<key>\w+):\s+(?P<value>\w+)$`)

// lexFn represents the state of the scanner
// as a function that returns the next state.
type lexFn func() lexFn

// Lexer holds the state of the scanner.
type Lexer struct {
	Input string // the string being scanned.
	Start int    // start position of this item.
	Pos   int    // current position in the input.
	Width int    // width of last rune read from input.
	Line  int    // Current line in the input
	Col   int    // Current position in the line
	// Position Position // Current lexing position in the input
	Config        *config.Config // The lexer configuration
	Tokens        chan *Token    // channel of scanned tokens.
	delimiters    []rune
	RawStatements rawStmt
	rawEnd        *regexp.Regexp
}

// TODO: set from env
type rawStmt map[string]*regexp.Regexp

// NewLexer creates a new scanner for the input string.
func NewLexer(input string) *Lexer {
	cfg := config.DefaultConfig
	return &Lexer{
		Input:  input,
		Tokens: make(chan *Token),
		Config: cfg,
		RawStatements: rawStmt{
			"raw":     regexp.MustCompile(fmt.Sprintf(`%s\s*endraw`, cfg.BlockStartString)),
			"comment": regexp.MustCompile(fmt.Sprintf(`%s\s*endcomment`, cfg.BlockStartString)),
		},
	}
}

func Lex(input string) *Stream {
	l := NewLexer(input)
	go l.Run()
	return NewStream(l.Tokens)
}

// errorf returns an error token and terminates the scan
// by passing back a nil pointer that will be the next
// state, terminating Lexer.Run.
func (l *Lexer) errorf(format string, args ...interface{}) lexFn {
	l.Tokens <- &Token{
		Type: Error,
		Val:  fmt.Sprintf(format, args...),
		Pos:  l.Pos,
	}
	return nil
}

// Position return the current position in the input
func (l *Lexer) Position() *Position {
	return &Position{
		Offset: l.Pos,
		Line:   l.Line,
		Column: l.Col,
	}
}

func (l *Lexer) Current() string {
	return l.Input[l.Start:l.Pos]
}

// Run lexes the input by executing state functions until
// the state is nil.
func (l *Lexer) Run() {
	for state := l.lexData; state != nil; {
		state = state()
	}
	close(l.Tokens) // No more tokens will be delivered.
}

// next returns the next rune in the input.
func (l *Lexer) next() (rune rune) {
	if l.Pos >= len(l.Input) {
		l.Width = 0
		return rEOF
	}
	rune, l.Width = utf8.DecodeRuneInString(l.Input[l.Pos:])
	l.Pos += l.Width
	if rune == '\n' {
		l.Line++
		l.Col = 1
	}
	return rune
}

// emit passes a Token back to the client.
func (l *Lexer) emit(t Type) {
	l.processAndEmit(t, nil)
}

func (l *Lexer) processAndEmit(t Type, fn func(string) string) {
	line, col := ReadablePosition(l.Start, l.Input)
	val := l.Input[l.Start:l.Pos]
	if fn != nil {
		val = fn(val)
	}
	l.Tokens <- &Token{
		Type: t,
		Val:  val,
		Pos:  l.Start,
		Line: line,
		Col:  col,
	}
	l.Start = l.Pos
}

// ignore skips over the pending input before this point.
func (l *Lexer) ignore() {
	l.Start = l.Pos
}

// backup steps back one rune.
// Can be called only once per call of next.
func (l *Lexer) backup() {
	l.Pos -= l.Width
}

// peek returns but does not consume
// the next rune in the input.
func (l *Lexer) peek() rune {
	rune := l.next()
	l.backup()
	return rune
}

// accept consumes the next rune
// if it's from the valid set.
func (l *Lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *Lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *Lexer) pushDelimiter(r rune) {
	l.delimiters = append(l.delimiters, r)
}

func (l *Lexer) hasPrefix(prefix string) bool {
	return strings.HasPrefix(l.Input[l.Pos:], prefix)
}

func (l *Lexer) popDelimiter(r rune) bool {
	if len(l.delimiters) == 0 {
		l.errorf(`Unexpected delimiter "%c"`, r)
		return false
	}
	last := len(l.delimiters) - 1
	expected := l.delimiters[last]
	if r != expected {
		l.errorf(`Unbalanced delimiters, expected "%c", got "%c"`, expected, r)
		return false
	}
	// l.delimiters[last] = nil // Erase element (write zero value)
	l.delimiters = l.delimiters[:last]
	return true
}

// return whether or not we are expecting r as the next delimiter
func (l *Lexer) expectDelimiter(r rune) bool {
	if len(l.delimiters) == 0 {
		return false
	}
	expected := l.delimiters[len(l.delimiters)-1]
	return r == expected
}

func (l *Lexer) lexData() lexFn {
	for {
		if l.hasPrefix(l.Config.CommentStartString) {
			if l.Pos > l.Start {
				l.emit(Data)
			}
			return l.lexComment
		}

		if l.hasPrefix(l.Config.VariableStartString) {
			if l.Pos > l.Start {
				l.emit(Data)
			}
			return l.lexVariable
		}

		if l.hasPrefix(l.Config.BlockStartString) {
			if l.Pos > l.Start {
				l.emit(Data)
			}
			return l.lexBlock
		}

		if l.next() == rEOF {
			break
		}
	}
	// Correctly reached EOF.
	if l.Pos > l.Start {
		l.emit(Data)
	}
	l.emit(EOF) // Useful to make EOF a token.
	return nil  // Stop the run loop.
}

func (l *Lexer) remaining() string {
	return l.Input[l.Pos:]
}

func (l *Lexer) lexRaw() lexFn {
	loc := l.rawEnd.FindStringIndex(l.remaining())
	if loc == nil {
		return l.errorf(`Unable to find raw closing statement`)
	}
	l.Pos += loc[0]
	l.emit(Data)
	l.rawEnd = nil
	return l.lexBlock
	// regexp.MustCompile(`(?m)(?P<key>\w+):\s+(?P<value>\w+)$`)
	// idx := pattern
}

func (l *Lexer) lexComment() lexFn {
	l.Pos += len(l.Config.CommentStartString)
	l.emit(CommentBegin)
	i := strings.Index(l.Input[l.Pos:], l.Config.CommentEndString)
	if i < 0 {
		return l.errorf("unclosed comment")
	}
	l.Pos += i
	l.emit(Data)
	l.Pos += len(l.Config.CommentEndString)
	l.emit(CommentEnd)
	return l.lexData
}

func (l *Lexer) lexVariable() lexFn {
	l.Pos += len(l.Config.VariableStartString)
	l.accept("-")
	l.emit(VariableBegin)
	return l.lexExpression
}

func (l *Lexer) lexVariableEnd() lexFn {
	l.accept("-")
	l.Pos += len(l.Config.VariableEndString)
	l.emit(VariableEnd)
	return l.lexData
}

func (l *Lexer) lexBlock() lexFn {
	l.Pos += len(l.Config.BlockStartString)
	l.accept("+-")
	l.emit(BlockBegin)
	for isSpace(l.peek()) {
		l.next()
	}
	if len(l.Current()) > 0 {
		l.emit(Whitespace)
	}
	stmt := l.nextIdentifier()
	l.emit(Name)
	re, exists := l.RawStatements[stmt]
	if exists {
		l.rawEnd = re
	}
	return l.lexExpression
}

func (l *Lexer) lexBlockEnd() lexFn {
	l.accept("-")
	l.Pos += len(l.Config.BlockEndString)
	l.emit(BlockEnd)
	if l.rawEnd != nil {
		return l.lexRaw
	} else {
		return l.lexData
	}
}

func (l *Lexer) lexExpression() lexFn {
	for {
		if !l.expectDelimiter(l.peek()) {
			if l.hasPrefix(l.Config.VariableEndString) { // && l.expectDelimiter(l.peek()) {
				return l.lexVariableEnd
			}

			// if this is the rightDelim, but we are expecting the next char as a delimiter
			// then skip marking this as rightDelim.  This allows us to have, eg, '}}' as
			// part of a literal inside a var block.
			// if strings.HasPrefix(l.input[l.pos:], l.rightDelim) && !l.shouldExpectDelim(l.peek()) {
			// 	l.pos += Pos(len(l.rightDelim))
			// 	l.emitRight()
			// 	return lexText
			// }

			if l.hasPrefix(l.Config.BlockEndString) {
				return l.lexBlockEnd
			}
		}

		r := l.next()
		// remaining := l.Input[l.Pos:]
		switch {
		case isSpace(r):
			return l.lexSpace
		case isNumeric(r):
			return l.lexNumber
		case isAlphaNumeric(r):
			return l.lexIdentifier
		}

		switch r {
		case '"', '\'':
			l.backup()
			return l.lexString
		case ',':
			l.emit(Comma)
		case '|':
			l.emit(Pipe)
			// if l.accept("|") {
			// 	l.emit(Or)
			// } else {
			// }
		case '+':
			l.emit(Add)
		case '-':
			if l.hasPrefix(l.Config.BlockEndString) {
				l.backup()
				return l.lexBlockEnd
			} else if l.hasPrefix(l.Config.VariableEndString) {
				l.backup()
				return l.lexVariableEnd
			} else {
				l.emit(Sub)
			}
		case '~':
			l.emit(Tilde)
		case ':':
			l.emit(Colon)
		case '.':
			l.emit(Dot)
		case '%':
			l.emit(Mod)
		case '/':
			if l.accept("/") {
				l.emit(Floordiv)
			} else {
				l.emit(Div)
			}
		case '<':
			if l.accept("=") {
				l.emit(Lteq)
			} else {
				l.emit(Lt)
			}
		case '>':
			if l.accept("=") {
				l.emit(Gteq)
			} else {
				l.emit(Gt)
			}
		case '*':
			if l.accept("*") {
				l.emit(Pow)
			} else {
				l.emit(Mul)
			}
		case '!':
			if l.accept("=") {
				l.emit(Ne)
			} else {
				// l.emit(Not)
				l.errorf(`Unexpected "!"`)
			}
		// case '&':
		// 	if l.accept("&") {
		// 		l.emit(And)
		// 	} else {
		// 		return nil
		// 	}
		case '=':
			if l.accept("=") {
				l.emit(Eq)
			} else {
				l.emit(Assign)
			}
		case '(':
			l.emit(Lparen)
			l.pushDelimiter(')')
		case '{':
			l.emit(Lbrace)
			l.pushDelimiter('}')
		case '[':
			l.emit(Lbracket)
			l.pushDelimiter(']')
		case ')':
			if !l.popDelimiter(')') {
				return nil
			}
			l.emit(Rparen)
		case '}':
			if !l.popDelimiter('}') {
				return nil
			}
			l.emit(Rbrace)
		case ']':
			if !l.popDelimiter(']') {
				return nil
			}
			l.emit(Rbracket)
		}
	}
	return l.lexData
}

func (l *Lexer) lexSpace() lexFn {
	for isSpace(l.peek()) {
		l.next()
	}
	l.emit(Whitespace)
	return l.lexExpression
}

func (l *Lexer) nextIdentifier() string {
	for {
		switch r := l.next(); {
		case isAlphaNumeric(r):
			// absorb.
		default:
			l.backup()
			// l.emit(Name)
			return l.Current()
		}
	}
}

func (l *Lexer) lexIdentifier() lexFn {
	l.nextIdentifier()
	l.emit(Name)
	return l.lexExpression
}

func (l *Lexer) lexNumber() lexFn {
	tokType := Integer
	for {
		switch r := l.next(); {
		case isNumeric(r):
			// abosrb
		case r == '.':
			if tokType != Float {
				tokType = Float
			} else {
				l.errorf("two dots in numeric token")
			}
		case isAlphaNumeric(r) && tokType == Integer:
			return l.lexIdentifier
		default:
			l.backup()
			l.emit(tokType)
			return l.lexExpression
		}
	}
}

func unescape(str string) string {
	str = str[1 : len(str)-1]
	for escaped, unescaped := range escapedStrings {
		str = strings.ReplaceAll(str, escaped, unescaped)
	}
	return str
}

func (l *Lexer) lexString() lexFn {
	quote := l.next() // should be either ' or "
	var prev rune
	for r := l.next(); r != quote || prev == '\\'; r, prev = l.next(), r {
	}
	l.processAndEmit(String, unescape)
	return l.lexExpression
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t'
}

// isEndOfLine reports whether r is an end-of-line character.
func isEndOfLine(r rune) bool {
	return r == '\r' || r == '\n'
}

// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
func isAlphaNumeric(r rune) bool {
	return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
}

func isNumeric(r rune) bool {
	return unicode.IsDigit(r)
}


<|start_filename|>builtins/statements/autoescape.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type AutoescapeStmt struct {
	Wrapper    *nodes.Wrapper
	Autoescape bool
}

func (stmt *AutoescapeStmt) Position() *tokens.Token { return stmt.Wrapper.Position() }
func (stmt *AutoescapeStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("AutoescapeStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *AutoescapeStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	sub := r.Inherit()
	sub.Autoescape = stmt.Autoescape

	err := sub.ExecuteWrapper(stmt.Wrapper)
	if err != nil {
		return err
	}

	return nil
}

func autoescapeParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &AutoescapeStmt{}

	wrapper, _, err := p.WrapUntil("endautoescape")
	if err != nil {
		return nil, err
	}
	stmt.Wrapper = wrapper

	modeToken := args.Match(tokens.Name)
	if modeToken == nil {
		return nil, args.Error("A mode is required for autoescape statement.", nil)
	}
	if modeToken.Val == "true" {
		stmt.Autoescape = true
	} else if modeToken.Val == "false" {
		stmt.Autoescape = false
	} else {
		return nil, args.Error("Only 'true' or 'false' is valid as an autoescape statement.", nil)
	}

	if !args.Stream.End() {
		return nil, args.Error("Malformed autoescape statement args.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("autoescape", autoescapeParser)
}


<|start_filename|>ext/django/statements/ifchanged.go<|end_filename|>
package statements

import (
	// "bytes"

	"fmt"
	"strings"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type IfChangedStmt struct {
	Location    *tokens.Token
	watchedExpr []nodes.Expression
	lastValues  []*exec.Value
	lastContent string
	thenWrapper *nodes.Wrapper
	elseWrapper *nodes.Wrapper
}

func (stmt *IfChangedStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *IfChangedStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("IfChangedStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *IfChangedStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	if len(stmt.watchedExpr) == 0 {
		// Check against own rendered body
		var out strings.Builder
		sub := r.Inherit()
		sub.Out = &out
		err := sub.ExecuteWrapper(stmt.thenWrapper)
		if err != nil {
			return err
		}

		str := out.String()
		if stmt.lastContent != str {
			// Rendered content changed, output it
			r.WriteString(str)
			stmt.lastContent = str
		}
	} else {
		nowValues := make([]*exec.Value, 0, len(stmt.watchedExpr))
		for _, expr := range stmt.watchedExpr {
			val := r.Eval(expr)
			if val.IsError() {
				return val
			}
			nowValues = append(nowValues, val)
		}

		// Compare old to new values now
		changed := len(stmt.lastValues) == 0

		for idx, oldVal := range stmt.lastValues {
			if !oldVal.EqualValueTo(nowValues[idx]) {
				changed = true
				break // we can stop here because ONE value changed
			}
		}

		stmt.lastValues = nowValues

		if changed {
			// Render thenWrapper
			err := r.ExecuteWrapper(stmt.thenWrapper)
			if err != nil {
				return err
			}
		} else {
			// Render elseWrapper
			err := r.ExecuteWrapper(stmt.elseWrapper)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func ifchangedParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &IfChangedStmt{
		Location: p.Current(),
	}

	for !args.End() {
		// Parse condition
		expr, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.watchedExpr = append(stmt.watchedExpr, expr)
	}

	if !args.End() {
		return nil, args.Error("Ifchanged-arguments are malformed.", nil)
	}

	// Wrap then/else-blocks
	wrapper, endargs, err := p.WrapUntil("else", "endifchanged")
	if err != nil {
		return nil, err
	}
	stmt.thenWrapper = wrapper

	if !endargs.End() {
		return nil, endargs.Error("Arguments not allowed here.", nil)
	}

	if wrapper.EndTag == "else" {
		// if there's an else in the if-statement, we need the else-Block as well
		wrapper, endargs, err = p.WrapUntil("endifchanged")
		if err != nil {
			return nil, err
		}
		stmt.elseWrapper = wrapper

		if !endargs.End() {
			return nil, endargs.Error("Arguments not allowed here.", nil)
		}
	}

	return stmt, nil
}

func init() {
	All.Register("ifchanged", ifchangedParser)
}


<|start_filename|>builtins/statements.go<|end_filename|>
package builtins

import "github.com/noirbizarre/gonja/builtins/statements"

// Statements exports all builtins statements
var Statements = statements.All


<|start_filename|>ext/django/statements/comment.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type CommentStmt struct {
	Location *tokens.Token
}

func (stmt *CommentStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *CommentStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("Block(Line=%d Col=%d)", t.Line, t.Col)
}

func commentParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	commentNode := &CommentStmt{p.Current()}

	err := p.SkipUntil("endcomment")
	if err != nil {
		return nil, err
	}

	if !args.End() {
		return nil, args.Error("Tag 'comment' does not take any argument.", nil)
	}

	return commentNode, nil
}

func init() {
	All.Register("comment", commentParser)
}


<|start_filename|>ext/time/time_test.go<|end_filename|>
package time_test

import (
	"testing"

	arrow "github.com/bmuller/arrow/lib"

	"github.com/noirbizarre/gonja"
	"github.com/noirbizarre/gonja/ext/time"
	tu "github.com/noirbizarre/gonja/testutils"
)

func Env(root string) *gonja.Environment {
	env := tu.TestEnv(root)
	env.Statements.Update(time.Statements)
	cfg := time.NewConfig()
	parsed, _ := arrow.CParse("%Y-%m-%d %H:%M:%S", "1984-06-07 16:40:00")
	cfg.Now = &parsed
	env.Config.Ext["time"] = cfg
	return env
}

func TestTimeStatement(t *testing.T) {
	root := "./testData"
	env := Env(root)
	tu.GlobTemplateTests(t, root, env)
}


<|start_filename|>testutils/fixtures.go<|end_filename|>
package testutils

import (
	"fmt"
	"sort"

	"strings"
	"time"

	"github.com/noirbizarre/gonja"
	"github.com/noirbizarre/gonja/exec"
)

var adminList = []string{"user2"}

var time1 = time.Date(2014, 06, 10, 15, 30, 15, 0, time.UTC)
var time2 = time.Date(2011, 03, 21, 8, 37, 56, 12, time.UTC)

type post struct {
	Text    string
	Created time.Time
}

type user struct {
	Name      string
	Validated bool
}

func (u *user) String() string {
	return u.Name
}

type comment struct {
	Author *user
	Date   time.Time
	Text   string
}

type person struct {
	FirstName string
	LastName  string
	Gender    string
}

func isAdmin(u *user) bool {
	for _, a := range adminList {
		if a == u.Name {
			return true
		}
	}
	return false
}

func (u *user) IsAdmin() *exec.Value {
	return exec.AsValue(isAdmin(u))
}

func (u *user) IsAdmin2() bool {
	return isAdmin(u)
}

func (p *post) String() string {
	return ":-)"
}

/*
 * End setup sandbox
 */

var Fixtures = gonja.Context{
	"number": 11,
	"simple": map[string]interface{}{
		"number":                   42,
		"name":                     "<NAME>",
		"included_file":            "INCLUDES.helper",
		"included_file_not_exists": "INCLUDES.helper.not_exists",
		"nil":                      nil,
		"uint":                     uint(8),
		"float":                    float64(3.1415),
		"str":                      "string",
		"chinese_hello_world":      "你好世界",
		"bool_true":                true,
		"bool_false":               false,
		"newline_text": `this is a text
with a new line in it`,
		"long_text": `This is a simple text.

This too, as a paragraph.
Right?

Yep!`,
		"escape_js_test":     `escape sequences \r\n\'\" special chars "?!=$<>`,
		"one_item_list":      []int{99},
		"multiple_item_list": []int{1, 1, 2, 3, 5, 8, 13, 21, 34, 55},
		"unsorted_int_list":  []int{192, 581, 22, 1, 249, 9999, 1828591, 8271},
		"fixed_item_list":    [...]int{1, 2, 3, 4},
		"misc_list":          []interface{}{"Hello", 99, 3.14, "good"},
		"escape_text":        "This is \\a Test. \"Yep\". 'Yep'.",
		"xss":                "<script>alert(\"uh oh\");</script>",
		"intmap": map[int]string{
			1: "one",
			5: "five",
			2: "two",
		},
		"strmap": map[string]string{
			"abc": "def",
			"bcd": "efg",
			"zab": "cde",
			"gh":  "kqm",
			"ukq": "qqa",
			"aab": "aba",
		},
		"casedStrmap": map[string]string{
			"a": "a",
			"B": "B",
			"c": "c",
			"D": "D",
			"e": "e",
			"F": "F",
		},
		"func_add": func(a, b int) int {
			return a + b
		},
		"func_add_iface": func(a, b interface{}) interface{} {
			return a.(int) + b.(int)
		},
		"func_variadic": func(msg string, args ...interface{}) string {
			return fmt.Sprintf(msg, args...)
		},
		"func_variadic_sum_int": func(args ...int) int {
			// Create a sum
			s := 0
			for _, i := range args {
				s += i
			}
			return s
		},
		"func_variadic_sum_int2": func(args ...*exec.Value) *exec.Value {
			// Create a sum
			s := 0
			for _, i := range args {
				s += i.Integer()
			}
			return exec.AsValue(s)
		},
		"func_with_varargs": func(params *exec.VarArgs) *exec.Value {
			// arg := params.args[0]
			argsAsStr := []string{}
			for _, arg := range params.Args {
				argsAsStr = append(argsAsStr, arg.String())
			}
			kwargsAsStr := []string{}
			for key, value := range params.KwArgs {
				v := value.String()
				if value.IsString() {
					v = "\"" + v + "\""
				}
				pair := []string{key, v}
				kwargsAsStr = append(kwargsAsStr, strings.Join(pair, "="))
			}
			sort.Strings(kwargsAsStr)
			args := strings.Join(argsAsStr, ", ")
			kwargs := strings.Join(kwargsAsStr, ", ")

			str := fmt.Sprintf("VarArgs(args=[%s], kwargs={%s})", args, kwargs)
			return exec.AsSafeValue(str)
		},
	},
	"complex": map[string]interface{}{
		"user": &user{
			Name:      "<NAME>",
			Validated: true,
		},
		"is_admin": isAdmin,
		"post": post{
			Text:    "<h2>Hello!</h2><p>Welcome to my new blog page. I'm using gonja which supports {{ variables }} and {% tags %}.</p>",
			Created: time2,
		},
		"comments": []*comment{
			&comment{
				Author: &user{
					Name:      "user1",
					Validated: true,
				},
				Date: time1,
				Text: "\"gonja is nice!\"",
			},
			&comment{
				Author: &user{
					Name:      "user2",
					Validated: true,
				},
				Date: time2,
				Text: "comment2 with <script>unsafe</script> tags in it",
			},
			&comment{
				Author: &user{
					Name:      "user3",
					Validated: false,
				},
				Date: time1,
				Text: "<b>hello!</b> there",
			},
		},
		"comments2": []*comment{
			&comment{
				Author: &user{
					Name:      "user1",
					Validated: true,
				},
				Date: time2,
				Text: "\"gonja is nice!\"",
			},
			&comment{
				Author: &user{
					Name:      "user1",
					Validated: true,
				},
				Date: time1,
				Text: "comment2 with <script>unsafe</script> tags in it",
			},
			&comment{
				Author: &user{
					Name:      "user3",
					Validated: false,
				},
				Date: time1,
				Text: "<b>hello!</b> there",
			},
		},
	},
	"persons": []*person{
		{"John", "Doe", "male"},
		{"Jane", "Doe", "female"},
		{"Akira", "Toriyama", "male"},
		{"Selina", "Kyle", "female"},
		{"Axel", "Haustant", "male"},
	},
	"groupable": []map[string]string{
		{"grouper": "group 1", "value": "value 1-1"},
		{"grouper": "group 2", "value": "value 2-1"},
		{"grouper": "group 3", "value": "value 3-1"},
		{"grouper": "group 1", "value": "value 1-2"},
		{"grouper": "group 2", "value": "value 2-2"},
		{"grouper": "group 3", "value": "value 3-2"},
		{"grouper": "group 1", "value": "value 1-3"},
		{"grouper": "group 2", "value": "value 2-3"},
		{"grouper": "group 3", "value": "value 3-3"},
	},
}


<|start_filename|>exec/value_test.go<|end_filename|>
package exec_test

import (
	// "fmt"

	"reflect"
	"testing"

	"github.com/noirbizarre/gonja/exec"
	"github.com/stretchr/testify/assert"
)

type flags struct {
	IsString   bool
	IsCallable bool
	IsBool     bool
	IsFloat    bool
	IsInteger  bool
	IsNumber   bool
	IsList     bool
	IsDict     bool
	IsIterable bool
	IsNil      bool
	IsTrue     bool
	IsError    bool
}

func (f *flags) assert(t *testing.T, value *exec.Value) {
	assert := assert.New(t)

	val := reflect.ValueOf(value)
	fval := reflect.ValueOf(f).Elem()

	for i := 0; i < fval.NumField(); i++ {
		name := fval.Type().Field(i).Name
		method := val.MethodByName(name)
		bVal := fval.Field(i).Interface().(bool)
		result := method.Call([]reflect.Value{})
		bResult := result[0].Interface().(bool)
		if bVal {
			assert.Truef(bResult, `%s() should be true`, name)
		} else {
			assert.Falsef(bResult, `%s() should be false`, name)
		}
	}
}

var valueCases = []struct {
	name     string
	value    interface{}
	asString string
	flags    flags
}{
	{"nil", nil, "", flags{IsNil: true}},
	{"string", "Hello World", "Hello World", flags{IsString: true, IsTrue: true, IsIterable: true}},
	{"int", 42, "42", flags{IsInteger: true, IsNumber: true, IsTrue: true}},
	{"int 0", 0, "0", flags{IsInteger: true, IsNumber: true}},
	{"float", 42., "42.0", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
	{"float with trailing zeros", 42.04200, "42.042", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
	{"float max precision", 42.5556700089099, "42.55567000891", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
	{"float max precision rounded up", 42.555670008999999, "42.555670009", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
	{"float 0.0", 0., "0.0", flags{IsFloat: true, IsNumber: true}},
	{"true", true, "True", flags{IsBool: true, IsTrue: true}},
	{"false", false, "False", flags{IsBool: true}},
	{"slice", []int{1, 2, 3}, "[1, 2, 3]", flags{IsTrue: true, IsIterable: true, IsList: true}},
	{"strings slice", []string{"a", "b", "c"}, "['a', 'b', 'c']", flags{IsTrue: true, IsIterable: true, IsList: true}},
	{
		"values slice",
		[]*exec.Value{exec.AsValue(1), exec.AsValue(2), exec.AsValue(3)},
		"[1, 2, 3]",
		flags{IsTrue: true, IsIterable: true, IsList: true},
	},
	{"string values slice",
		[]*exec.Value{exec.AsValue("a"), exec.AsValue("b"), exec.AsValue("c")},
		"['a', 'b', 'c']",
		flags{IsTrue: true, IsIterable: true, IsList: true},
	},
	{"array", [3]int{1, 2, 3}, "[1, 2, 3]", flags{IsTrue: true, IsIterable: true, IsList: true}},
	{"strings array", [3]string{"a", "b", "c"}, "['a', 'b', 'c']", flags{IsTrue: true, IsIterable: true, IsList: true}},
	{
		"dict as map",
		map[string]string{"a": "a", "b": "b"},
		"{'a': 'a', 'b': 'b'}",
		flags{IsTrue: true, IsIterable: true, IsDict: true},
	},
	{
		"dict as Dict/Pairs",
		&exec.Dict{[]*exec.Pair{
			{exec.AsValue("a"), exec.AsValue("a")},
			{exec.AsValue("b"), exec.AsValue("b")},
		}},
		"{'a': 'a', 'b': 'b'}",
		flags{IsTrue: true, IsIterable: true, IsDict: true},
	},
	{"func", func() {}, "<func() Value>", flags{IsCallable: true}},
}

func TestValue(t *testing.T) {
	for _, lc := range valueCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			value := exec.AsValue(test.value)

			assert.Equal(test.asString, value.String())
			test.flags.assert(t, value)
		})
	}
}

func TestValueFromMap(t *testing.T) {
	for _, lc := range valueCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			data := map[string]interface{}{"value": test.value}
			value := exec.AsValue(data["value"])

			assert.Equal(test.asString, value.String())
			test.flags.assert(t, value)
		})
	}
}

type testStruct struct {
	Attr string
}

func (t testStruct) String() string {
	return t.Attr
}

var getattrCases = []struct {
	name     string
	value    interface{}
	attr     string
	found    bool
	asString string
	flags    flags
}{
	{"nil", nil, "missing", false, "", flags{IsError: true}},
	{"attr found", testStruct{"test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true, IsIterable: true}},
	{"attr not found", testStruct{"test"}, "Missing", false, "", flags{IsNil: true}},
	{"item", map[string]interface{}{"Attr": "test"}, "Attr", false, "", flags{IsNil: true}},
}

func TestValueGetAttr(t *testing.T) {
	for _, lc := range getattrCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			value := exec.AsValue(test.value)
			out, found := value.Getattr(test.attr)

			if !test.flags.IsError && out.IsError() {
				t.Fatalf(`Unexpected error: %s`, out.Error())
			}

			if test.found {
				assert.Truef(found, `Attribute '%s' should be found on %s`, test.attr, value)
				assert.Equal(test.asString, out.String())
			} else {
				assert.Falsef(found, `Attribute '%s' should not be found on %s`, test.attr, value)
			}

			test.flags.assert(t, out)
		})
	}
}

var getitemCases = []struct {
	name     string
	value    interface{}
	key      interface{}
	found    bool
	asString string
	flags    flags
}{
	{"nil", nil, "missing", false, "", flags{IsError: true}},
	{"item found", map[string]interface{}{"Attr": "test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true, IsIterable: true}},
	{"item not found", map[string]interface{}{"Attr": "test"}, "Missing", false, "test", flags{IsNil: true}},
	{"attr", testStruct{"test"}, "Attr", false, "", flags{IsNil: true}},
	{"dict found", &exec.Dict{[]*exec.Pair{
		{exec.AsValue("key"), exec.AsValue("value")},
		{exec.AsValue("otherKey"), exec.AsValue("otherValue")},
	}}, "key", true, "value", flags{IsTrue: true, IsString: true, IsIterable: true}},
}

func TestValueGetitem(t *testing.T) {
	for _, lc := range getitemCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			value := exec.AsValue(test.value)
			out, found := value.Getitem(test.key)

			if !test.flags.IsError && out.IsError() {
				t.Fatalf(`Unexpected error: %s`, out.Error())
			}

			if test.found {
				assert.Truef(found, `Key '%s' should be found on %s`, test.key, value)
				assert.Equal(test.asString, out.String())
			} else {
				assert.Falsef(found, `Key '%s' should not be found on %s`, test.key, value)
			}

			test.flags.assert(t, out)
		})
	}
}

var setCases = []struct {
	name     string
	value    interface{}
	attr     string
	set      interface{}
	error    bool
	asString string
}{
	{"nil", nil, "missing", "whatever", true, ""},
	{"existing attr on struct by ref", &testStruct{"test"}, "Attr", "value", false, "value"},
	{"existing attr on struct by value", testStruct{"test"}, "Attr", "value", true, `Can't write field "Attr"`},
	{"missing attr on struct by ref", &testStruct{"test"}, "Missing", "value", true, "test"},
	{"missing attr on struct by value", testStruct{"test"}, "Missing", "value", true, "test"},
	{
		"existing key on map",
		map[string]interface{}{"Attr": "test"},
		"Attr",
		"value",
		false,
		"{'Attr': 'value'}",
	},
	{
		"new key on map",
		map[string]interface{}{"Attr": "test"},
		"New",
		"value",
		false,
		"{'Attr': 'test', 'New': 'value'}",
	},
}

func TestValueSet(t *testing.T) {
	for _, lc := range setCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			value := exec.AsValue(test.value)
			err := value.Set(test.attr, test.set)

			if test.error {
				assert.NotNil(err)
			} else {
				assert.Nil(err)
				assert.Equal(test.asString, value.String())
			}
		})
	}
}

var valueKeysCases = []struct {
	name     string
	value    interface{}
	asString string
	isError  bool
}{
	{"nil", nil, "", true},
	{"string", "Hello World", "", true},
	{"int", 42, "", true},
	{"float", 42., "", true},
	{"true", true, "", true},
	{"false", false, "", true},
	{"slice", []int{1, 2, 3}, "", true},
	// Map keys are sorted alphabetically, case insensitive
	{"dict as map", map[string]string{"c": "c", "a": "a", "B": "B"}, "['a', 'B', 'c']", false},
	// Dict as Pairs keys are kept in order
	{
		"dict as Dict/Pairs",
		&exec.Dict{[]*exec.Pair{
			{exec.AsValue("c"), exec.AsValue("c")},
			{exec.AsValue("A"), exec.AsValue("A")},
			{exec.AsValue("b"), exec.AsValue("b")},
		}},
		"['c', 'A', 'b']",
		false,
	},
	{"func", func() {}, "", true},
}

func TestValueKeys(t *testing.T) {
	for _, lc := range valueKeysCases {
		test := lc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			value := exec.AsValue(test.value)
			keys := value.Keys()
			if test.isError {
				assert.Len(keys, 0)
			} else {
				assert.Equal(test.asString, keys.String())
			}
		})
	}
}


<|start_filename|>nodes/sets.go<|end_filename|>
package nodes

import (
	"github.com/pkg/errors"
)

type BlockSet map[string]*Wrapper

// Exists returns true if the given block is already registered
func (bs BlockSet) Exists(name string) bool {
	_, existing := bs[name]
	return existing
}

// Register registers a new block. If there's already a filter with the same
// name, Register will panic. You usually want to call this
// function in the filter's init() function:
// http://golang.org/doc/effective_go.html#init
//
// See http://www.florian-schlachter.de/post/gonja/ for more about
// writing filters and tags.
func (bs *BlockSet) Register(name string, w *Wrapper) error {
	if bs.Exists(name) {
		return errors.Errorf("Block with name '%s' is already registered", name)
	}
	(*bs)[name] = w
	return nil
}

// Replace replaces an already registered filter with a new implementation. Use this
// function with caution since it allobs you to change existing filter behaviour.
func (bs *BlockSet) Replace(name string, w *Wrapper) error {
	if !bs.Exists(name) {
		return errors.Errorf("Block with name '%s' does not exist (therefore cannot be overridden)", name)
	}
	(*bs)[name] = w
	return nil
}


<|start_filename|>whitespace_control_test.go<|end_filename|>
package gonja_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/noirbizarre/gonja"
	"github.com/noirbizarre/gonja/config"
	"github.com/pmezard/go-difflib/difflib"

	tu "github.com/noirbizarre/gonja/testutils"
)

var testCases = []struct {
	name                  string
	trim_blocks           bool
	lstrip_blocks         bool
	keep_trailing_newline bool
}{
	{"default", false, false, false},
	{"trim_blocks", true, false, false},
	{"lstrip_blocks", false, true, false},
	{"keep_trailing_newline", false, false, true},
	{"all", true, true, true},
}

const source = "testData/whitespaces/source.tpl"
const result = "testData/whitespaces/%s.out"

func TestWhiteSpace(t *testing.T) {
	for _, tc := range testCases {
		test := tc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			cfg := config.NewConfig()
			env := gonja.NewEnvironment(cfg, gonja.DefaultLoader)
			env.TrimBlocks = test.trim_blocks
			env.LstripBlocks = test.lstrip_blocks
			env.KeepTrailingNewline = test.keep_trailing_newline

			tpl, err := env.FromFile(source)
			if err != nil {
				t.Fatalf("Error on FromFile('%s'): %s", source, err.Error())
			}
			output := fmt.Sprintf(result, test.name)
			expected, rerr := ioutil.ReadFile(output)
			if rerr != nil {
				t.Fatalf("Error on ReadFile('%s'): %s", output, rerr.Error())
			}
			rendered, err := tpl.ExecuteBytes(tu.Fixtures)
			if err != nil {
				t.Fatalf("Error on Execute('%s'): %s", source, err.Error())
			}
			// rendered = testTemplateFixes.fixIfNeeded(match, rendered)
			if bytes.Compare(expected, rendered) != 0 {
				diff := difflib.UnifiedDiff{
					A:        difflib.SplitLines(string(expected)),
					B:        difflib.SplitLines(string(rendered)),
					FromFile: "Expected",
					ToFile:   "Rendered",
					Context:  2,
					Eol:      "\n",
				}
				result, _ := difflib.GetUnifiedDiffString(diff)
				t.Errorf("%s rendered with diff:\n%v", source, result)
			}
		})
	}
}


<|start_filename|>tokens/position_test.go<|end_filename|>
package tokens_test

import (
	"testing"

	"github.com/noirbizarre/gonja/tokens"
	"github.com/stretchr/testify/assert"
)

const multilineSample = `Hello
{# 
    Multiline comment
#}
World
`

var readablePositionsCases = []struct {
	name string
	pos  int
	line int
	col  int
	char byte
}{
	{"First char", 0, 1, 1, 'H'},
	{"Last char", len(multilineSample) - 1, 5, 6, '\n'},
	{"Anywhere", 14, 3, 5, 'M'},
}

func TestReadablePosition(t *testing.T) {
	for _, rp := range readablePositionsCases {
		test := rp
		t.Run(test.name, func(t *testing.T) {
			assert := assert.New(t)
			assert.Equalf(test.char, multilineSample[test.pos],
				`Invalid test, expected "%#U" rune at pos %d, got "%#U"`,
				test.char, test.pos, multilineSample[test.pos])
			line, col := tokens.ReadablePosition(test.pos, multilineSample)
			assert.Equalf(test.line, line, "Expected line %d, got %d", test.line, line)
			assert.Equalf(test.col, col, "Expected col %d, got %d", test.col, col)
		})
	}
}


<|start_filename|>exec/tests.go<|end_filename|>
package exec

import (
	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
)

// TestFunction is the type test functions must fulfil
type TestFunction func(*Context, *Value, *VarArgs) (bool, error)

// TestSet maps test names to their TestFunction handler
type TestSet map[string]TestFunction

// Exists returns true if the given test is already registered
func (ts TestSet) Exists(name string) bool {
	_, existing := ts[name]
	return existing
}

// Register registers a new test. If there's already a test with the same
// name, RegisterTest will panic. You usually want to call this
// function in the test's init() function:
// http://golang.org/doc/effective_go.html#init
//
// See http://www.florian-schlachter.de/post/gonja/ for more about
// writing tests and tags.
func (ts *TestSet) Register(name string, fn TestFunction) error {
	if ts.Exists(name) {
		return errors.Errorf("test with name '%s' is already registered", name)
	}
	(*ts)[name] = fn
	return nil
}

// Replace replaces an already registered test with a new implementation. Use this
// function with caution since it allows you to change existing test behaviour.
func (ts *TestSet) Replace(name string, fn TestFunction) error {
	if !ts.Exists(name) {
		return errors.Errorf("test with name '%s' does not exist (therefore cannot be overridden)", name)
	}
	(*ts)[name] = fn
	return nil
}

func (ts *TestSet) Update(other TestSet) TestSet {
	for name, test := range other {
		(*ts)[name] = test
	}
	return *ts
}

func (e *Evaluator) EvalTest(expr *nodes.TestExpression) *Value {
	value := e.Eval(expr.Expression)
	// if value.IsError() {
	// 	return AsValue(errors.Wrapf(value, `Unable to evaluate expresion %s`, expr.Expression))
	// }

	return e.ExecuteTest(expr.Test, value)
}

func (e *Evaluator) ExecuteTest(tc *nodes.TestCall, v *Value) *Value {
	params := &VarArgs{
		Args:   []*Value{},
		KwArgs: map[string]*Value{},
	}

	for _, param := range tc.Args {
		value := e.Eval(param)
		if value.IsError() {
			return AsValue(errors.Wrapf(value, `Unable to evaluate parameter %s`, param))
		}
		params.Args = append(params.Args, value)
	}

	for key, param := range tc.Kwargs {
		value := e.Eval(param)
		if value.IsError() {
			return AsValue(errors.Wrapf(value, `Unable to evaluate parameter %s`, param))
		}
		params.KwArgs[key] = value
	}

	return e.ExecuteTestByName(tc.Name, v, params)
}

func (e *Evaluator) ExecuteTestByName(name string, in *Value, params *VarArgs) *Value {
	if !e.Tests.Exists(name) {
		return AsValue(errors.Errorf(`Test "%s" not found`, name))
	}
	test, _ := (*e.Tests)[name]

	result, err := test(e.Ctx, in, params)
	if err != nil {
		return AsValue(errors.Wrapf(err, `Unable to execute test %s`, name))
	} else {
		return AsValue(result)
	}
}


<|start_filename|>tokens/tokens.go<|end_filename|>
package tokens

import "fmt"

// TokenType identifies the type of a token
type Type int

// Known tokens
const (
	Error Type = iota
	Add
	Assign
	Colon
	Comma
	Div
	Dot
	Eq
	// EqEq
	Floordiv
	Gt
	Gteq
	Lbrace
	Lbracket
	Lparen
	Lt
	Lteq
	// Not
	// And
	// Or
	// Neq
	Mod
	Mul
	Ne
	Pipe
	Pow
	Rbrace
	Rbracket
	Rparen
	Semicolon
	Sub
	Tilde
	Whitespace
	Float
	Integer
	Name
	String
	Operator
	BlockBegin
	BlockEnd
	VariableBegin
	VariableEnd
	RawBegin
	RawEnd
	CommentBegin
	CommentEnd
	Comment
	LinestatementBegin
	LinestatementEnd
	LinecommentBegin
	LinecommentEnd
	Linecomment
	Data
	Initial
	EOF
)

// TokenNames maps token types to their human readable name
var Names = map[Type]string{
	Error:  "Error",
	Add:    "Add",
	Assign: "Assign",
	Colon:  "Colon",
	Comma:  "Comma",
	Div:    "Div",
	Dot:    "Dot",
	Eq:     "Eq",
	// EqEq:     "EqEq",
	Floordiv: "Floordiv",
	Gt:       "Gt",
	Gteq:     "Gteq",
	Lbrace:   "Lbrace",
	Lbracket: "Lbracket",
	Lparen:   "Lparen",
	Lt:       "Lt",
	Lteq:     "Lteq",
	// Not:                "Not",
	// And:                "And",
	// Or:                 "Or",
	// Neq:                "Neq",
	Mod:                "Mod",
	Mul:                "Mul",
	Ne:                 "Ne",
	Pipe:               "Pipe",
	Pow:                "Pow",
	Rbrace:             "Rbrace",
	Rbracket:           "Rbracket",
	Rparen:             "Rparen",
	Semicolon:          "Semicolon",
	Sub:                "Sub",
	Tilde:              "Tilde",
	Whitespace:         "Whitespace",
	Float:              "Float",
	Integer:            "Integer",
	Name:               "Name",
	String:             "String",
	Operator:           "Operator",
	BlockBegin:         "BlockBegin",
	BlockEnd:           "BlockEnd",
	VariableBegin:      "VariableBegin",
	VariableEnd:        "VariableEnd",
	RawBegin:           "RawBegin",
	RawEnd:             "RawEnd",
	CommentBegin:       "CommentBegin",
	CommentEnd:         "CommentEnd",
	Comment:            "Comment",
	LinestatementBegin: "LinestatementBegin",
	LinestatementEnd:   "LinestatementEnd",
	LinecommentBegin:   "LinecommentBegin",
	LinecommentEnd:     "LinecommentEnd",
	Linecomment:        "Linecomment",
	Data:               "Data",
	Initial:            "Initial",
	EOF:                "EOF",
}

// var SymbolTokens = map[TokenType]bool {

// }

// var KeywordTokens = map[TokenType]bool {

// }

// var NumberTokens = map[TokenType]bool {

// }

// Token represents a unit of lexing
type Token struct {
	Type Type
	Val  string
	Pos  int
	Line int
	Col  int
}

func (t Token) String() string {
	val := t.Val
	if len(val) > 1000 {
		val = fmt.Sprintf("%s...%s", val[:10], val[len(val)-5:len(val)])
	}

	return fmt.Sprintf("<Token[%s] Val='%s' Pos=%d Line=%d Col=%d>",
		Names[t.Type], val, t.Pos, t.Line, t.Col)
}


<|start_filename|>parser/math.go<|end_filename|>
package parser

import (
	// "fmt"

	"fmt"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
	log "github.com/sirupsen/logrus"
)

// type unary struct {
// 	negative bool
// 	term     nodes.Expression
// 	operator *Token
// }

// func (expr *unary) String() string {
// 	t := expr.GetPositionToken()

// 	return fmt.Sprintf("<Unary sign=%s term=%s Line=%d Col=%d>",
// 		expr.operator.Val, expr.term, t.Line, t.Col)
// }

// func (expr *unary) FilterApplied(name string) bool {
// 	return expr.term.FilterApplied(name)
// }

// func (expr *unary) GetPositionToken() *Token {
// 	return expr.operator
// }

// func (expr *unary) Execute(ctx *ExecutionContext, writer TemplateWriter) error {
// 	value, err := expr.Evaluate(ctx)
// 	if err != nil {
// 		return err
// 	}
// 	writer.WriteString(value.String())
// 	return nil
// }

// func (expr *unary) Evaluate(ctx *ExecutionContext) (*Value, error) {
// 	result, err := expr.term.Evaluate(ctx)
// 	if err != nil {
// 		return nil, err
// 	}
// 	if expr.negative {
// 		if result.IsNumber() {
// 			switch {
// 			case result.IsFloat():
// 				result = AsValue(-1 * result.Float())
// 			case result.IsInteger():
// 				result = AsValue(-1 * result.Integer())
// 			default:
// 				return nil, ctx.Error("Operation between a number and a non-(float/integer) is not possible", nil)
// 			}
// 		} else {
// 			return nil, ctx.Error("Negative sign on a non-number expression", expr.GetPositionToken())
// 		}
// 	}

// 	return result, nil
// }

func (p *Parser) ParseMath() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseMath")

	expr, err := p.parseConcat()
	if err != nil {
		return nil, err
	}

	for p.Peek(tokens.Add, tokens.Sub) != nil {
		op := BinOp(p.Pop())
		right, err := p.parseConcat()
		if err != nil {
			return nil, err
		}
		expr = &nodes.BinaryExpression{
			Left:     expr,
			Right:    right,
			Operator: op,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("ParseMath return")
	return expr, nil
}

func (p *Parser) parseConcat() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseConcat")

	expr, err := p.ParseMathPrioritary()
	if err != nil {
		return nil, err
	}

	for p.Peek(tokens.Tilde) != nil {
		op := BinOp(p.Pop())
		right, err := p.ParseMathPrioritary()
		if err != nil {
			return nil, err
		}
		expr = &nodes.BinaryExpression{
			Left:     expr,
			Right:    right,
			Operator: op,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseConcat return")
	return expr, nil
}

func (p *Parser) ParseMathPrioritary() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseMathPrioritary")

	expr, err := p.parseUnary()
	if err != nil {
		return nil, err
	}

	for p.Peek(tokens.Mul, tokens.Div, tokens.Floordiv, tokens.Mod) != nil {
		op := BinOp(p.Pop())
		right, err := p.parseUnary()
		if err != nil {
			return nil, err
		}
		expr = &nodes.BinaryExpression{
			Left:     expr,
			Right:    right,
			Operator: op,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("ParseMathPrioritary return")
	return expr, nil
}

func (p *Parser) parseUnary() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseUnary")

	sign := p.Match(tokens.Add, tokens.Sub)

	expr, err := p.ParsePower()
	if err != nil {
		return nil, err
	}

	if sign != nil {
		expr = &nodes.UnaryExpression{
			Operator: sign,
			Negative: sign.Val == "-",
			Term:     expr,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseUnary return")
	return expr, nil
}

func (p *Parser) ParsePower() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParsePower")

	expr, err := p.ParseVariableOrLiteral()
	if err != nil {
		return nil, err
	}

	for p.Peek(tokens.Pow) != nil {
		op := BinOp(p.Pop())
		right, err := p.ParseVariableOrLiteral()
		if err != nil {
			return nil, err
		}
		expr = &nodes.BinaryExpression{
			Left:     expr,
			Right:    right,
			Operator: op,
		}
	}

	log.WithFields(log.Fields{
		"type": fmt.Sprintf("%T", expr),
		"expr": expr,
	}).Trace("ParsePower return")
	return expr, nil
}


<|start_filename|>parser/tests.go<|end_filename|>
package parser

import (
	log "github.com/sirupsen/logrus"

	"github.com/noirbizarre/gonja/nodes"
)

func (p *Parser) ParseTest(expr nodes.Expression) (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseTest")

	expr, err := p.ParseFilterExpression(expr)
	if err != nil {
		return nil, err
	}

	if p.MatchName("is") != nil {
		not := p.MatchName("not")
		ident := p.Next()

		test := &nodes.TestCall{
			Token:  ident,
			Name:   ident.Val,
			Args:   []nodes.Expression{},
			Kwargs: map[string]nodes.Expression{},
		}

		arg, err := p.ParseExpression()
		if err == nil && arg != nil {
			test.Args = append(test.Args, arg)
		}

		

		// // Check for test-argument (2 tokens needed: ':' ARG)
		// if p.Match(tokens.Lparen) != nil {
		// 	if p.Peek(tokens.VariableEnd) != nil {
		// 		return nil, p.Error("Filter parameter required after '('.", nil)
		// 	}

		// 	for p.Match(tokens.Comma) != nil || p.Match(tokens.Rparen) == nil {
		// 		// TODO: Handle multiple args and kwargs
		// 		v, err := p.ParseExpression()
		// 		if err != nil {
		// 			return nil, err
		// 		}

		// 		if p.Match(tokens.Assign) != nil {
		// 			key := v.Position().Val
		// 			value, errValue := p.ParseExpression()
		// 			if errValue != nil {
		// 				return nil, errValue
		// 			}
		// 			test.Kwargs[key] = value
		// 		} else {
		// 			test.Args = append(test.Args, v)
		// 		}
		// 	}
		// } else {
		// 	arg, err := p.ParseExpression()
		// 	if err == nil && arg != nil {
		// 		test.Args = append(test.Args, arg)
		// 	}
		// }

		expr = &nodes.TestExpression{
			Expression: expr,
			Test:       test,
		}

		if not != nil {
			expr = &nodes.Negation{expr, not}
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseTest return")
	return expr, nil
}


<|start_filename|>exec/varargs.go<|end_filename|>
package exec

import (
	"sort"
	"strings"

	"github.com/pkg/errors"
)

// VarArgs represents pythonic variadic args/kwargs
type VarArgs struct {
	Args   []*Value
	KwArgs map[string]*Value
}

func NewVarArgs() *VarArgs {
	return &VarArgs{
		Args:   []*Value{},
		KwArgs: map[string]*Value{},
	}
}

// First returns the first argument or nil AsValue
func (va *VarArgs) First() *Value {
	if len(va.Args) > 0 {
		return va.Args[0]
	}
	return AsValue(nil)
}

// GetKwarg gets a keyword arguments with fallback on default value
func (va *VarArgs) GetKwarg(key string, fallback interface{}) *Value {
	value, ok := va.KwArgs[key]
	if ok {
		return value
	}
	return AsValue(fallback)
}

type KwArg struct {
	Name    string
	Default interface{}
}

// Expect validates VarArgs against an expected signature
func (va *VarArgs) Expect(args int, kwargs []*KwArg) *ReducedVarArgs {
	rva := &ReducedVarArgs{VarArgs: va}
	reduced := &VarArgs{
		Args:   va.Args,
		KwArgs: map[string]*Value{},
	}
	reduceIdx := -1
	unexpectedArgs := []string{}
	if len(va.Args) < args {
		// Priority on missing arguments
		if args > 1 {
			rva.error = errors.Errorf(`Expected %d arguments, got %d`, args, len(va.Args))
		} else {
			rva.error = errors.Errorf(`Expected an argument, got %d`, len(va.Args))
		}
		return rva
	} else if len(va.Args) > args {
		reduced.Args = va.Args[:args]
		for idx, arg := range va.Args[args:] {
			if len(kwargs) > idx {
				reduced.KwArgs[kwargs[idx].Name] = arg
				reduceIdx = idx + 1
			} else {
				unexpectedArgs = append(unexpectedArgs, arg.String())
			}
		}
	}

	unexpectedKwArgs := []string{}
Loop:
	for key, value := range va.KwArgs {
		for idx, kwarg := range kwargs {
			if key == kwarg.Name {
				if reduceIdx < 0 || idx >= reduceIdx {
					reduced.KwArgs[key] = value
					continue Loop
				} else {
					rva.error = errors.Errorf(`Keyword '%s' has been submitted twice`, key)
					break Loop
				}
			}
		}
		kv := strings.Join([]string{key, value.String()}, "=")
		unexpectedKwArgs = append(unexpectedKwArgs, kv)
	}
	sort.Strings(unexpectedKwArgs)

	if rva.error != nil {
		return rva
	}

	switch {
	case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) == 0:
	case len(unexpectedArgs) == 1 && len(unexpectedKwArgs) == 0:
		rva.error = errors.Errorf(`Unexpected argument '%s'`, unexpectedArgs[0])
	case len(unexpectedArgs) > 1 && len(unexpectedKwArgs) == 0:
		rva.error = errors.Errorf(`Unexpected arguments '%s'`, strings.Join(unexpectedArgs, ", "))
	case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) == 1:
		rva.error = errors.Errorf(`Unexpected keyword argument '%s'`, unexpectedKwArgs[0])
	case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) > 0:
		rva.error = errors.Errorf(`Unexpected keyword arguments '%s'`, strings.Join(unexpectedKwArgs, ", "))
	default:
		rva.error = errors.Errorf(`Unexpected arguments '%s, %s'`,
			strings.Join(unexpectedArgs, ", "),
			strings.Join(unexpectedKwArgs, ", "),
		)
	}

	if rva.error != nil {
		return rva
	}
	// fill defaults
	for _, kwarg := range kwargs {
		_, exists := reduced.KwArgs[kwarg.Name]
		if !exists {
			reduced.KwArgs[kwarg.Name] = AsValue(kwarg.Default)
		}
	}
	rva.VarArgs = reduced
	return rva
}

// ExpectArgs ensures VarArgs receive only arguments
func (va *VarArgs) ExpectArgs(args int) *ReducedVarArgs {
	return va.Expect(args, []*KwArg{})
}

// ExpectNothing ensures VarArgs does not receive any argument
func (va *VarArgs) ExpectNothing() *ReducedVarArgs {
	return va.ExpectArgs(0)
}

// ExpectKwArgs allow to specify optionnaly expected KwArgs
func (va *VarArgs) ExpectKwArgs(kwargs []*KwArg) *ReducedVarArgs {
	return va.Expect(0, kwargs)
}

// ReducedVarArgs represents pythonic variadic args/kwargs
// but values are reduced (ie. kwargs given as args are accessible by name)
type ReducedVarArgs struct {
	*VarArgs
	error error
}

// IsError returns true if there was an error on Expect call
func (rva *ReducedVarArgs) IsError() bool {
	return rva.error != nil
}

func (rva *ReducedVarArgs) Error() string {
	if rva.IsError() {
		return rva.error.Error()
	}
	return ""
}


<|start_filename|>parser/template.go<|end_filename|>
package parser

import (
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
)

type TemplateParser func(string) (*nodes.Template, error)

// Doc = { ( Filter | Tag | HTML ) }
func (p *Parser) parseDocElement() (nodes.Node, error) {
	t := p.Current()

	switch t.Type {
	case tokens.Data:
		n := &nodes.Data{Data: t}
		p.Consume() // consume HTML element
		return n, nil
	case tokens.EOF:
		p.Consume()
		return nil, nil
	case tokens.CommentBegin:
		return p.ParseComment()
	case tokens.VariableBegin:
		return p.ParseExpressionNode()
	case tokens.BlockBegin:
		return p.ParseStatementBlock()
	}
	return nil, p.Error("Unexpected token (only HTML/tags/filters in templates allowed)", t)
}

func (p *Parser) ParseTemplate() (*nodes.Template, error) {
	tpl := &nodes.Template{
		Name:   p.Name,
		Blocks: nodes.BlockSet{},
		Macros: map[string]*nodes.Macro{},
	}
	p.Template = tpl

	for !p.Stream.End() {
		node, err := p.parseDocElement()
		if err != nil {
			return nil, err
		}
		if node != nil {
			tpl.Nodes = append(tpl.Nodes, node)
		}
	}
	return tpl, nil
}


<|start_filename|>exec/template.go<|end_filename|>
package exec

import (
	"bytes"
	"io"
	"strings"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type TemplateLoader interface {
	GetTemplate(string) (*Template, error)
}

type Template struct {
	Name   string
	Reader io.Reader
	Source string

	Env    *EvalConfig
	Loader TemplateLoader

	Tokens *tokens.Stream
	Parser *parser.Parser

	Root   *nodes.Template
	Macros MacroSet
}

func NewTemplate(name string, source string, cfg *EvalConfig) (*Template, error) {
	// Create the template
	t := &Template{
		Env:    cfg,
		Name:   name,
		Source: source,
		Tokens: tokens.Lex(source),
	}

	// Parse it
	t.Parser = parser.NewParser(name, cfg.Config, t.Tokens)
	t.Parser.Statements = *t.Env.Statements
	t.Parser.TemplateParser = t.Env.GetTemplate
	root, err := t.Parser.Parse()
	if err != nil {
		return nil, err
	}
	t.Root = root

	return t, nil
}

func (tpl *Template) execute(ctx map[string]interface{}, out io.StringWriter) error {
	exCtx := tpl.Env.Globals.Inherit()
	exCtx.Update(ctx)

	var builder strings.Builder
	renderer := NewRenderer(exCtx, &builder, tpl.Env, tpl)

	err := renderer.Execute()
	if err != nil {
		return errors.Wrap(err, `Unable to Execute template`)
	}
	out.WriteString(renderer.String())

	return nil
}

func (tpl *Template) newBufferAndExecute(ctx map[string]interface{}) (*bytes.Buffer, error) {
	var buffer bytes.Buffer
	// Create output buffer
	// We assume that the rendered template will be 30% larger
	// buffer := bytes.NewBuffer(make([]byte, 0, int(float64(tpl.size)*1.3)))
	if err := tpl.execute(ctx, &buffer); err != nil {
		return nil, err
	}
	return &buffer, nil
}

// // Executes the template with the given context and writes to writer (io.Writer)
// // on success. Context can be nil. Nothing is written on error; instead the error
// // is being returned.
// func (tpl *Template) ExecuteWriter(ctx *Context, writer io.Writer) error {
// 	buf, err := tpl.newBufferAndExecute(ctx)
// 	if err != nil {
// 		return err
// 	}
// 	_, err = buf.WriteTo(writer)
// 	if err != nil {
// 		return err
// 	}
// 	return nil
// }

// // // Same as ExecuteWriter. The only difference between both functions is that
// // // this function might already have written parts of the generated template in the
// // // case of an execution error because there's no intermediate buffer involved for
// // // performance reasons. This is handy if you need high performance template
// // // generation or if you want to manage your own pool of buffers.
// // func (tpl *Template) ExecuteWriterUnbuffered(ctx *Context, writer io.Writer) error {
// // 	return tpl.newTemplateWriterAndExecute(ctx, writer)
// // }

// Executes the template and returns the rendered template as a []byte
func (tpl *Template) ExecuteBytes(ctx map[string]interface{}) ([]byte, error) {
	buffer, err := tpl.newBufferAndExecute(ctx)
	if err != nil {
		return nil, err
	}
	return buffer.Bytes(), nil
}

// Executes the template and returns the rendered template as a string
func (tpl *Template) Execute(ctx map[string]interface{}) (string, error) {
	var b strings.Builder
	err := tpl.execute(ctx, &b)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}


<|start_filename|>builtins/globals.go<|end_filename|>
package builtins

import (
	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/utils"
)

var Globals = exec.NewContext(map[string]interface{}{
	"cycler":    Cycler,
	"dict":      Dict,
	"joiner":    Joiner,
	"lipsum":    Lipsum,
	"namespace": Namespace,
	"range":     Range,
})

func Range(va *exec.VarArgs) <-chan int {
	var (
		start = 0
		stop  = -1
		step  = 1
	)
	switch len(va.Args) {
	case 1:
		stop = va.Args[0].Integer()
	case 2:
		start = va.Args[0].Integer()
		stop = va.Args[1].Integer()
	case 3:
		start = va.Args[0].Integer()
		stop = va.Args[1].Integer()
		step = va.Args[2].Integer()
		// default:
		// 	return nil, errors.New("range expect signature range([start, ]stop[, step])")
	}
	chnl := make(chan int)
	go func() {
		for i := start; i < stop; i += step {
			chnl <- i
		}

		// Ensure that at the end of the loop we close the channel!
		close(chnl)
	}()
	return chnl
}

func Dict(va *exec.VarArgs) *exec.Value {
	dict := exec.NewDict()
	for key, value := range va.KwArgs {
		dict.Pairs = append(dict.Pairs, &exec.Pair{
			Key:   exec.AsValue(key),
			Value: value,
		})
	}
	return exec.AsValue(dict)
}

type cycler struct {
	values  []string
	idx     int
	getters map[string]interface{}
}

func (c *cycler) Reset() {
	c.idx = 0
	c.getters["current"] = c.values[c.idx]
}

func (c *cycler) Next() string {
	c.idx++
	value := c.getters["current"].(string)
	if c.idx >= len(c.values) {
		c.idx = 0
	}
	c.getters["current"] = c.values[c.idx]
	return value
}

func Cycler(va *exec.VarArgs) *exec.Value {
	c := &cycler{}
	for _, arg := range va.Args {
		c.values = append(c.values, arg.String())
	}
	c.getters = map[string]interface{}{
		"next":  c.Next,
		"reset": c.Reset,
	}
	c.Reset()
	return exec.AsValue(c.getters)
}

type joiner struct {
	sep   string
	first bool
}

func (j *joiner) String() string {
	if !j.first {
		j.first = true
		return ""
	}
	return j.sep
}

func Joiner(va *exec.VarArgs) *exec.Value {
	p := va.ExpectKwArgs([]*exec.KwArg{{"sep", ","}})
	if p.IsError() {
		return exec.AsValue(errors.Wrapf(p, `wrong signature for 'joiner'`))
	}
	sep := p.KwArgs["sep"].String()
	j := &joiner{sep: sep}
	return exec.AsValue(j.String)
}

// type namespace map[string]interface{}

func Namespace(va *exec.VarArgs) map[string]interface{} {
	ns := map[string]interface{}{}
	for key, value := range va.KwArgs {
		ns[key] = value
	}
	return ns
}

func Lipsum(va *exec.VarArgs) *exec.Value {
	p := va.ExpectKwArgs([]*exec.KwArg{
		{"n", 5},
		{"html", true},
		{"min", 20},
		{"max", 100},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrapf(p, `wrong signature for 'lipsum'`))
	}
	n := p.KwArgs["n"].Integer()
	html := p.KwArgs["html"].Bool()
	min := p.KwArgs["min"].Integer()
	max := p.KwArgs["max"].Integer()
	return exec.AsSafeValue(utils.Lipsum(n, html, min, max))
}


<|start_filename|>ext/django/filters.go<|end_filename|>
package django

import (
	"bytes"
	"fmt"
	"math/rand"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	u "github.com/noirbizarre/gonja/utils"
)

func init() {
	rand.Seed(time.Now().Unix())
}

var Filters = exec.FilterSet{
	"escapejs":           filterEscapejs,
	"add":                filterAdd,
	"addslashes":         filterAddslashes,
	"capfirst":           filterCapfirst,
	"cut":                filterCut,
	"date":               filterDate,
	"default_if_none":    filterDefaultIfNone,
	"floatformat":        filterFloatformat,
	"get_digit":          filterGetdigit,
	"iriencode":          filterIriencode,
	"length_is":          filterLengthis,
	"linebreaks":         filterLinebreaks,
	"linebreaksbr":       filterLinebreaksbr,
	"linenumbers":        filterLinenumbers,
	"ljust":              filterLjust,
	"make_list":          filterMakelist,
	"phone2numeric":      filterPhone2numeric,
	"pluralize":          filterPluralize,
	"removetags":         filterRemovetags,
	"rjust":              filterRjust,
	"split":              filterSplit,
	"stringformat":       filterStringformat,
	"time":               filterDate, // time uses filterDate (same golang-format,
	"truncatechars":      filterTruncatechars,
	"truncatechars_html": filterTruncatecharsHTML,
	"truncatewords":      filterTruncatewords,
	"truncatewords_html": filterTruncatewordsHTML,
	"yesno":              filterYesno,
}

func filterTruncatecharsHelper(s string, newLen int) string {
	runes := []rune(s)
	if newLen < len(runes) {
		if newLen >= 3 {
			return fmt.Sprintf("%s...", string(runes[:newLen-3]))
		}
		// Not enough space for the ellipsis
		return string(runes[:newLen])
	}
	return string(runes)
}

func filterTruncateHTMLHelper(value string, newOutput *bytes.Buffer, cond func() bool, fn func(c rune, s int, idx int) int, finalize func()) {
	vLen := len(value)
	var tagStack []string
	idx := 0

	for idx < vLen && !cond() {
		c, s := utf8.DecodeRuneInString(value[idx:])
		if c == utf8.RuneError {
			idx += s
			continue
		}

		if c == '<' {
			newOutput.WriteRune(c)
			idx += s // consume "<"

			if idx+1 < vLen {
				if value[idx] == '/' {
					// Close tag

					newOutput.WriteString("/")

					tag := ""
					idx++ // consume "/"

					for idx < vLen {
						c2, size2 := utf8.DecodeRuneInString(value[idx:])
						if c2 == utf8.RuneError {
							idx += size2
							continue
						}

						// End of tag found
						if c2 == '>' {
							idx++ // consume ">"
							break
						}
						tag += string(c2)
						idx += size2
					}

					if len(tagStack) > 0 {
						// Ideally, the close tag is TOP of tag stack
						// In malformed HTML, it must not be, so iterate through the stack and remove the tag
						for i := len(tagStack) - 1; i >= 0; i-- {
							if tagStack[i] == tag {
								// Found the tag
								tagStack[i] = tagStack[len(tagStack)-1]
								tagStack = tagStack[:len(tagStack)-1]
								break
							}
						}
					}

					newOutput.WriteString(tag)
					newOutput.WriteString(">")
				} else {
					// Open tag

					tag := ""

					params := false
					for idx < vLen {
						c2, size2 := utf8.DecodeRuneInString(value[idx:])
						if c2 == utf8.RuneError {
							idx += size2
							continue
						}

						newOutput.WriteRune(c2)

						// End of tag found
						if c2 == '>' {
							idx++ // consume ">"
							break
						}

						if !params {
							if c2 == ' ' {
								params = true
							} else {
								tag += string(c2)
							}
						}

						idx += size2
					}

					// Add tag to stack
					tagStack = append(tagStack, tag)
				}
			}
		} else {
			idx = fn(c, s, idx)
		}
	}

	finalize()

	for i := len(tagStack) - 1; i >= 0; i-- {
		tag := tagStack[i]
		// Close everything from the regular tag stack
		newOutput.WriteString(fmt.Sprintf("</%s>", tag))
	}
}

func filterTruncatechars(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	s := in.String()
	newLen := params.Args[0].Integer()
	return exec.AsValue(filterTruncatecharsHelper(s, newLen))
}

func filterTruncatecharsHTML(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	value := in.String()
	newLen := u.Max(params.Args[0].Integer()-3, 0)

	newOutput := bytes.NewBuffer(nil)

	textcounter := 0

	filterTruncateHTMLHelper(value, newOutput, func() bool {
		return textcounter >= newLen
	}, func(c rune, s int, idx int) int {
		textcounter++
		newOutput.WriteRune(c)

		return idx + s
	}, func() {
		if textcounter >= newLen && textcounter < len(value) {
			newOutput.WriteString("...")
		}
	})

	return exec.AsSafeValue(newOutput.String())
}

func filterTruncatewords(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	words := strings.Fields(in.String())
	n := params.Args[0].Integer()
	if n <= 0 {
		return exec.AsValue("")
	}
	nlen := u.Min(len(words), n)
	out := make([]string, 0, nlen)
	for i := 0; i < nlen; i++ {
		out = append(out, words[i])
	}

	if n < len(words) {
		out = append(out, "...")
	}

	return exec.AsValue(strings.Join(out, " "))
}

func filterTruncatewordsHTML(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	value := in.String()
	newLen := u.Max(params.Args[0].Integer(), 0)

	newOutput := bytes.NewBuffer(nil)

	wordcounter := 0

	filterTruncateHTMLHelper(value, newOutput, func() bool {
		return wordcounter >= newLen
	}, func(_ rune, _ int, idx int) int {
		// Get next word
		wordFound := false

		for idx < len(value) {
			c2, size2 := utf8.DecodeRuneInString(value[idx:])
			if c2 == utf8.RuneError {
				idx += size2
				continue
			}

			if c2 == '<' {
				// HTML tag start, don't consume it
				return idx
			}

			newOutput.WriteRune(c2)
			idx += size2

			if c2 == ' ' || c2 == '.' || c2 == ',' || c2 == ';' {
				// Word ends here, stop capturing it now
				break
			} else {
				wordFound = true
			}
		}

		if wordFound {
			wordcounter++
		}

		return idx
	}, func() {
		if wordcounter >= newLen {
			newOutput.WriteString("...")
		}
	})

	return exec.AsSafeValue(newOutput.String())
}

func filterEscapejs(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	sin := in.String()

	var b bytes.Buffer

	idx := 0
	for idx < len(sin) {
		c, size := utf8.DecodeRuneInString(sin[idx:])
		if c == utf8.RuneError {
			idx += size
			continue
		}

		if c == '\\' {
			// Escape seq?
			if idx+1 < len(sin) {
				switch sin[idx+1] {
				case 'r':
					b.WriteString(fmt.Sprintf(`\u%04X`, '\r'))
					idx += 2
					continue
				case 'n':
					b.WriteString(fmt.Sprintf(`\u%04X`, '\n'))
					idx += 2
					continue
					/*case '\'':
						b.WriteString(fmt.Sprintf(`\u%04X`, '\''))
						idx += 2
						continue
					case '"':
						b.WriteString(fmt.Sprintf(`\u%04X`, '"'))
						idx += 2
						continue*/
				}
			}
		}

		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == ' ' || c == '/' {
			b.WriteRune(c)
		} else {
			b.WriteString(fmt.Sprintf(`\u%04X`, c))
		}

		idx += size
	}

	return exec.AsValue(b.String())
}

func filterAdd(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	param := params.Args[0]
	if in.IsNumber() && param.IsNumber() {
		if in.IsFloat() || param.IsFloat() {
			return exec.AsValue(in.Float() + param.Float())
		}
		return exec.AsValue(in.Integer() + param.Integer())
	}
	// If in/param is not a number, we're relying on the
	// Value's String() conversion and just add them both together
	return exec.AsValue(in.String() + param.String())
}

func filterAddslashes(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	output := strings.Replace(in.String(), "\\", "\\\\", -1)
	output = strings.Replace(output, "\"", "\\\"", -1)
	output = strings.Replace(output, "'", "\\'", -1)
	return exec.AsValue(output)
}

func filterCut(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	return exec.AsValue(strings.Replace(in.String(), params.Args[0].String(), "", -1))
}

func filterLengthis(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	return exec.AsValue(in.Len() == params.Args[0].Integer())
}

func filterDefaultIfNone(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if in.IsError() || in.IsNil() {
		return params.Args[0]
	}
	return in
}

func filterFloatformat(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	val := in.Float()
	param := params.First()

	decimals := -1
	if !param.IsNil() {
		// Any argument provided?
		decimals = param.Integer()
	}

	// if the argument is not a number (e. g. empty), the default
	// behaviour is trim the result
	trim := !param.IsNumber()

	if decimals <= 0 {
		// argument is negative or zero, so we
		// want the output being trimmed
		decimals = -decimals
		trim = true
	}

	if trim {
		// Remove zeroes
		if float64(int(val)) == val {
			return exec.AsValue(in.Integer())
		}
	}

	return exec.AsValue(strconv.FormatFloat(val, 'f', decimals, 64))
}

func filterGetdigit(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if len(params.Args) > 1 {
		return exec.AsValue(errors.New("'getdigit' filter expect one and only one argument"))
		// return nil, &Error{
		// 	Sender:    "filter:getdigit",
		// 	OrigError: errors.New("'getdigit' filter expect one and only one argument"),
		// }
	}
	param := params.First()
	i := param.Integer()
	l := len(in.String()) // do NOT use in.Len() here!
	if i <= 0 || i > l {
		return in
	}
	return exec.AsValue(in.String()[l-i] - 48)
}

func filterIriencode(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	return exec.AsValue(u.IRIEncode(in.String()))
}

func filterMakelist(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	s := in.String()
	result := make([]string, 0, len(s))
	for _, c := range s {
		result = append(result, string(c))
	}
	return exec.AsValue(result)
}

func filterCapfirst(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if in.Len() <= 0 {
		return exec.AsValue("")
	}
	t := in.String()
	r, size := utf8.DecodeRuneInString(t)
	return exec.AsValue(strings.ToUpper(string(r)) + t[size:])
}

func filterDate(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	t, isTime := in.Interface().(time.Time)
	if !isTime {
		return exec.AsValue(errors.New("filter input argument must be of type 'time.Time'"))
		// return nil, &Error{
		// 	Sender:    "filter:date",
		// 	OrigError: errors.New("filter input argument must be of type 'time.Time'"),
		// }
	}
	return exec.AsValue(t.Format(params.Args[0].String()))
}

func filterLinebreaks(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if in.Len() == 0 {
		return in
	}

	var b bytes.Buffer

	// Newline = <br />
	// Double newline = <p>...</p>
	lines := strings.Split(in.String(), "\n")
	lenlines := len(lines)

	opened := false

	for idx, line := range lines {

		if !opened {
			b.WriteString("<p>")
			opened = true
		}

		b.WriteString(line)

		if idx < lenlines-1 && strings.TrimSpace(lines[idx]) != "" {
			// We've not reached the end
			if strings.TrimSpace(lines[idx+1]) == "" {
				// Next line is empty
				if opened {
					b.WriteString("</p>")
					opened = false
				}
			} else {
				b.WriteString("<br />")
			}
		}
	}

	if opened {
		b.WriteString("</p>")
	}

	return exec.AsValue(b.String())
}

func filterSplit(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	chunks := strings.Split(in.String(), params.Args[0].String())

	return exec.AsValue(chunks)
}

func filterLinebreaksbr(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	return exec.AsValue(strings.Replace(in.String(), "\n", "<br />", -1))
}

func filterLinenumbers(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	lines := strings.Split(in.String(), "\n")
	output := make([]string, 0, len(lines))
	for idx, line := range lines {
		output = append(output, fmt.Sprintf("%d. %s", idx+1, line))
	}
	return exec.AsValue(strings.Join(output, "\n"))
}

func filterLjust(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	times := params.Args[0].Integer() - in.Len()
	if times < 0 {
		times = 0
	}
	return exec.AsValue(fmt.Sprintf("%s%s", in.String(), strings.Repeat(" ", times)))
}

func filterStringformat(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	return exec.AsValue(fmt.Sprintf(params.Args[0].String(), in.Interface()))
}

// https://en.wikipedia.org/wiki/Phoneword
var filterPhone2numericMap = map[string]string{
	"a": "2", "b": "2", "c": "2", "d": "3", "e": "3", "f": "3", "g": "4", "h": "4", "i": "4", "j": "5", "k": "5",
	"l": "5", "m": "6", "n": "6", "o": "6", "p": "7", "q": "7", "r": "7", "s": "7", "t": "8", "u": "8", "v": "8",
	"w": "9", "x": "9", "y": "9", "z": "9",
}

func filterPhone2numeric(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	sin := in.String()
	for k, v := range filterPhone2numericMap {
		sin = strings.Replace(sin, k, v, -1)
		sin = strings.Replace(sin, strings.ToUpper(k), v, -1)
	}
	return exec.AsValue(sin)
}

func filterPluralize(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	param := params.First()
	if in.IsNumber() {
		// Works only on numbers
		if param.Len() > 0 {
			endings := strings.Split(param.String(), ",")
			if len(endings) > 2 {
				return exec.AsValue(errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"))
				// return nil, &Error{
				// 	Sender:    "filter:pluralize",
				// 	OrigError: errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"),
				// }
			}
			if len(endings) == 1 {
				// 1 argument
				if in.Integer() != 1 {
					return exec.AsValue(endings[0])
				}
			} else {
				if in.Integer() != 1 {
					// 2 arguments
					return exec.AsValue(endings[1])
				}
				return exec.AsValue(endings[0])
			}
		} else {
			if in.Integer() != 1 {
				// return default 's'
				return exec.AsValue("s")
			}
		}

		return exec.AsValue("")
	}
	// return nil, &Error{
	// 	Sender:    "filter:pluralize",
	// 	OrigError: errors.New("filter 'pluralize' does only work on numbers"),
	// }
	return exec.AsValue(errors.New("filter 'pluralize' does only work on numbers"))
}

func filterRemovetags(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	s := in.String()
	tags := strings.Split(params.Args[0].String(), ",")

	// Strip only specific tags
	for _, tag := range tags {
		re := regexp.MustCompile(fmt.Sprintf("</?%s/?>", tag))
		s = re.ReplaceAllString(s, "")
	}

	return exec.AsValue(strings.TrimSpace(s))
}

func filterRjust(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	return exec.AsValue(fmt.Sprintf(fmt.Sprintf("%%%ds", params.Args[0].Integer()), in.String()))
}

func filterYesno(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if len(params.Args) > 1 {
		// return nil, &Error{
		// 	Sender:    "filter:getdigit",
		// 	OrigError: errors.New("'getdigit' filter expect one and only one argument"),
		// }
		return exec.AsValue(errors.New("'getdigit' filter expect one and only one argument"))
	}
	choices := map[int]string{
		0: "yes",
		1: "no",
		2: "maybe",
	}
	param := params.First()
	paramString := param.String()
	customChoices := strings.Split(paramString, ",")
	if len(paramString) > 0 {
		if len(customChoices) > 3 {
			return exec.AsValue(errors.Errorf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", paramString))
			// return nil, &Error{
			// 	Sender:    "filter:yesno",
			// 	OrigError: errors.Errorf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", paramString),
			// }
		}
		if len(customChoices) < 2 {
			// return nil, &Error{
			// 	Sender:    "filter:yesno",
			// 	OrigError: errors.Errorf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", paramString),
			// }
			return exec.AsValue(errors.Errorf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", paramString))
		}

		// Map to the options now
		choices[0] = customChoices[0]
		choices[1] = customChoices[1]
		if len(customChoices) == 3 {
			choices[2] = customChoices[2]
		}
	}

	// maybe
	if in.IsNil() {
		return exec.AsValue(choices[2])
	}

	// yes
	if in.IsTrue() {
		return exec.AsValue(choices[0])
	}

	// no
	return exec.AsValue(choices[1])
}


<|start_filename|>utils/escape.go<|end_filename|>
package utils

import "strings"

func Escape(in string) string {
	output := strings.Replace(in, "&", "&amp;", -1)
	output = strings.Replace(output, ">", "&gt;", -1)
	output = strings.Replace(output, "<", "&lt;", -1)
	output = strings.Replace(output, "\"", "&quot;", -1)
	output = strings.Replace(output, "'", "&#39;", -1)
	return output
}


<|start_filename|>ext/django/statements/all.go<|end_filename|>
package statements

import "github.com/noirbizarre/gonja/exec"

// All holds all builtins statements for easier registeration
var All = exec.StatementSet{}


<|start_filename|>parser/comment.go<|end_filename|>
package parser

import (
	"fmt"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
	log "github.com/sirupsen/logrus"
)

func (p *Parser) ParseComment() (*nodes.Comment, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseComment")

	tok := p.Match(tokens.CommentBegin)
	if tok == nil {
		msg := fmt.Sprintf(`Expected '%s' , got %s`, p.Config.CommentStartString, p.Current())
		return nil, p.Error(msg, p.Current())
	}

	comment := &nodes.Comment{
		Start: tok,
		Trim:  &nodes.Trim{},
	}

	tok = p.Match(tokens.Data)
	if tok == nil {
		comment.Text = ""
	} else {
		comment.Text = tok.Val
	}

	tok = p.Match(tokens.CommentEnd)
	if tok == nil {
		msg := fmt.Sprintf(`Expected '%s' , got %s`, p.Config.CommentEndString, p.Current())
		return nil, p.Error(msg, p.Current())
	}
	comment.End = tok

	log.WithFields(log.Fields{
		"node": comment,
	}).Trace("ParseComment return")
	return comment, nil
}


<|start_filename|>builtins/statements/raw.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type RawStmt struct {
	Data *nodes.Data
	// Content string
}

func (stmt *RawStmt) Position() *tokens.Token { return stmt.Data.Position() }
func (stmt *RawStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("RawStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *RawStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	r.WriteString(stmt.Data.Data.Val)
	// sub := r.Inherit()
	// sub.Autoescape = stmt.Autoescape

	// err := sub.ExecuteWrapper(stmt.Wrapper)
	// if err != nil {
	// 	return err
	// }

	return nil
}

func rawParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &RawStmt{}

	wrapper, _, err := p.WrapUntil("endraw")
	if err != nil {
		return nil, err
	}
	node := wrapper.Nodes[0]
	data, ok := node.(*nodes.Data)
	if ok {
		stmt.Data = data
	} else {
		return nil, p.Error("raw statement can only contains a single data node", node.Position())
	}

	if !args.End() {
		return nil, args.Error("raw statement doesn't accept parameters.", args.Current())
	}

	return stmt, nil
}

func init() {
	All.Register("raw", rawParser)
}


<|start_filename|>parser/logic.go<|end_filename|>
package parser

import (
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
	log "github.com/sirupsen/logrus"
)

var compareOps = []tokens.Type{
	tokens.Eq, tokens.Ne,
	tokens.Gt, tokens.Gteq,
	tokens.Lt, tokens.Lteq,
	// "in", "not in") != nil || p.PeekOne(TokenSymbol, "==", "<=", ">=", "!=", "<>", ">", "<"
}

func BinOp(token *tokens.Token) *nodes.BinOperator {
	return &nodes.BinOperator{token}
}

// type negation struct {
// 	term     Expression
// 	operator *Token
// }

// func (expr *negation) String() string {
// 	t := expr.GetPositionToken()

// 	return fmt.Sprintf("<Negation term=%s Line=%d Col=%d>", expr.term, t.Line, t.Col)
// }

// func (expr *negation) FilterApplied(name string) bool {
// 	return expr.term.FilterApplied(name)
// }

// func (expr *negation) GetPositionToken() *Token {
// 	return expr.operator
// }

// func (expr *negation) Evaluate(ctx *ExecutionContext) (*Value, error) {
// 	result, err := expr.term.Evaluate(ctx)
// 	if err != nil {
// 		return nil, err
// 	}

// 	return result.Negate(), nil
// }

func (p *Parser) ParseLogicalExpression() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseLogicalExpression")
	return p.parseOr()
}

func (p *Parser) parseOr() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseOr")

	var expr nodes.Expression

	expr, err := p.parseAnd()
	if err != nil {
		return nil, err
	}

	for p.PeekName("or") != nil {
		op := BinOp(p.Pop())
		right, err := p.parseAnd()
		if err != nil {
			return nil, err
		}
		expr = &nodes.BinaryExpression{
			Left:     expr,
			Right:    right,
			Operator: op,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseOr return")
	return expr, nil
}

func (p *Parser) parseAnd() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseAnd")

	var expr nodes.Expression

	expr, err := p.parseNot()
	if err != nil {
		return nil, err
	}

	for p.PeekName("and") != nil {
		op := BinOp(p.Pop())
		// binExpr :=

		right, err := p.parseNot()
		if err != nil {
			return nil, err
		}
		// binExpr.right = right
		expr = &nodes.BinaryExpression{
			Left:     expr,
			Right:    right,
			Operator: op,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseAnd return")
	return expr, nil
}

func (p *Parser) parseNot() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseNot")

	op := p.MatchName("not")
	expr, err := p.parseCompare()
	if err != nil {
		return nil, err
	}

	if op != nil {
		expr = &nodes.Negation{
			Operator: op,
			Term:     expr,
		}
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseNot return")
	return expr, nil
}

func (p *Parser) parseCompare() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("parseCompare")

	var expr nodes.Expression

	expr, err := p.ParseMath()
	if err != nil {
		return nil, err
	}

	// for p.PeekOne(TokenKeyword, "in", "not in") != nil || p.PeekOne(TokenSymbol, "==", "<=", ">=", "!=", "<>", ">", "<") != nil {
	for p.Peek(compareOps...) != nil || p.PeekName("in", "not") != nil {

		op := p.Pop()
		// if op = p.MatchOne(TokenKeyword, "in", "not in"); op == nil {
		// 	if op = p.MatchOne(TokenSymbol, "==", "<=", ">=", "!=", "<>", ">", "<"); op == nil {
		// 		return nil, p.Error("Unexpected operator %s", p.Current())
		// 	}
		// }

		right, err := p.ParseMath()
		if err != nil {
			return nil, err
		}

		if right != nil {
			expr = &nodes.BinaryExpression{
				Left:     expr,
				Operator: BinOp(op),
				Right:    right,
			}
		}
	}

	expr, err = p.ParseTest(expr)
	if err != nil {
		return nil, err
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("parseCompare return")
	return expr, nil
}


<|start_filename|>builtins/statements/block.go<|end_filename|>
package statements

import (
	"fmt"
	"strings"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type BlockStmt struct {
	Location *tokens.Token
	Name     string
}

func (stmt *BlockStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *BlockStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("BlockStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *BlockStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	// root, block := r.Root.GetBlock(stmt.Name)
	blocks := r.Root.GetBlocks(stmt.Name)
	block, blocks := blocks[0], blocks[1:]

	if block == nil {
		return errors.Errorf(`Unable to find block "%s"`, stmt.Name)
	}

	sub := r.Inherit()
	infos := &BlockInfos{Block: stmt, Renderer: sub, Blocks: blocks}

	sub.Ctx.Set("super", infos.super)
	sub.Ctx.Set("self", exec.Self(sub))

	err := sub.ExecuteWrapper(block)
	if err != nil {
		return err
	}

	return nil
}

type BlockInfos struct {
	Block    *BlockStmt
	Renderer *exec.Renderer
	Blocks   []*nodes.Wrapper
	Root     *nodes.Template
}

func (bi *BlockInfos) super() string {
	if len(bi.Blocks) <= 0 {
		return ""
	}
	r := bi.Renderer
	block, blocks := bi.Blocks[0], bi.Blocks[1:]
	sub := r.Inherit()
	var out strings.Builder
	sub.Out = &out
	infos := &BlockInfos{
		Block:    bi.Block,
		Renderer: sub,
		Blocks:   blocks,
	}
	sub.Ctx.Set("self", exec.Self(sub))
	sub.Ctx.Set("super", infos.super)
	sub.ExecuteWrapper(block)
	return out.String()
}

func blockParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	block := &BlockStmt{
		Location: p.Current(),
	}
	if args.End() {
		return nil, errors.New("Tag 'block' requires an identifier.")
	}

	name := args.Match(tokens.Name)
	if name == nil {
		return nil, errors.New("First argument for tag 'block' must be an identifier.")
	}

	if !args.End() {
		return nil, errors.New("Tag 'block' takes exactly 1 argument (an identifier).")
	}

	wrapper, endargs, err := p.WrapUntil("endblock")
	if err != nil {
		return nil, err
	}
	if !endargs.End() {
		endName := endargs.Match(tokens.Name)
		if endName != nil {
			if endName.Val != endName.Val {
				return nil, errors.Errorf(`Name for 'endblock' must equal to 'block'-tag's name ('%s' != '%s').`,
					name.Val, endName.Val)
			}
		}

		if endName == nil || !endargs.End() {
			return nil, errors.New("Either no or only one argument (identifier) allowed for 'endblock'.")
		}
	}

	if !p.Template.Blocks.Exists(name.Val) {
		p.Template.Blocks.Register(name.Val, wrapper)
	} else {
		return nil, args.Error(fmt.Sprintf("Block named '%s' already defined", name.Val), nil)
	}

	block.Name = name.Val
	return block, nil
}

func init() {
	All.Register("block", blockParser)
}


<|start_filename|>benchmark_test.go<|end_filename|>
// +build bench

package gonja_test

import (
	"io/ioutil"
	"testing"

	"github.com/noirbizarre/gonja"

	tu "github.com/noirbizarre/gonja/testutils"
)

func BenchmarkFromCache(b *testing.B) {
	for i := 0; i < b.N; i++ {
		tpl, err := gonja.FromCache("testData/complex.tpl")
		if err != nil {
			b.Fatal(err)
		}
		_, err = tpl.Execute(tu.Fixtures)
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkFromFile(b *testing.B) {
	for i := 0; i < b.N; i++ {
		tpl, err := gonja.FromFile("testData/complex.tpl")
		if err != nil {
			b.Fatal(err)
		}
		_, err = tpl.Execute(tu.Fixtures)
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkExecute(b *testing.B) {
	tpl, err := gonja.FromFile("testData/complex.tpl")
	if err != nil {
		b.Fatal(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err = tpl.Execute(tu.Fixtures)
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkCompileAndExecute(b *testing.B) {
	buf, err := ioutil.ReadFile("testData/complex.tpl")
	if err != nil {
		b.Fatal(err)
	}
	preloadedTpl := string(buf)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		tpl, err := gonja.FromString(preloadedTpl)
		if err != nil {
			b.Fatal(err)
		}

		_, err = tpl.Execute(tu.Fixtures)
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkParallelExecute(b *testing.B) {
	tpl, err := gonja.FromFile("testData/complex.tpl")
	if err != nil {
		b.Fatal(err)
	}
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			_, err := tpl.Execute(tu.Fixtures)
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}


<|start_filename|>ext/django/statements.go<|end_filename|>
package django

import "github.com/noirbizarre/gonja/ext/django/statements"

var Statements = statements.All


<|start_filename|>exec/self.go<|end_filename|>
package exec

import (
	"strings"

	"github.com/noirbizarre/gonja/nodes"
)

func getBlocks(tpl *nodes.Template) map[string]*nodes.Wrapper {
	if tpl == nil {
		return map[string]*nodes.Wrapper{}
	}
	blocks := getBlocks(tpl.Parent)
	for name, wrapper := range tpl.Blocks {
		blocks[name] = wrapper
	}
	return blocks
}

func Self(r *Renderer) map[string]func() string {
	blocks := map[string]func() string{}
	for name, block := range getBlocks(r.Root) {
		blocks[name] = func() string {
			sub := r.Inherit()
			var out strings.Builder
			sub.Out = &out
			sub.ExecuteWrapper(block)
			return out.String()
		}
	}
	return blocks
}


<|start_filename|>parser/filters.go<|end_filename|>
package parser

import (
	// "fmt"

	// "github.com/juju/errors"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
)

// FilterFunction is the type filter functions must fulfil
// type FilterFunction func(in *Value, params *VarArgs) (out *Value, err *Error)

// MustApplyFilter behaves like ApplyFilter, but panics on an error.
// func MustApplyFilter(name string, value *Value, params *VarArgs) *Value {
// 	val, err := ApplyFilter(name, value, params)
// 	if err != nil {
// 		panic(err)
// 	}
// 	return val
// }

// // ApplyFilter applies a filter to a given value using the given parameters.
// // Returns a *gonja.Value or an error.
// func ApplyFilter(name string, value *Value, params *VarArgs) (*Value, *Error) {
// 	fn, existing := filters[name]
// 	if !existing {
// 		return nil, &Error{
// 			Sender:    "applyfilter",
// 			OrigError: errors.Errorf("Filter with name '%s' not found.", name),
// 		}
// 	}

// 	// // Make sure param is a *Value
// 	// if param == nil {
// 	// 	param = AsValue(nil)
// 	// }

// 	return fn(value, params)
// }

// type filterCall struct {
// 	token *Token

// 	name   string
// 	args   []Expression
// 	kwargs map[string]Expression

// 	filterFunc FilterFunction
// }

// func (fc *filterCall) Execute(v *Value, ctx *ExecutionContext) (*Value, *Error) {
// 	params := &VarArgs{
// 		Args:   []*Value{},
// 		KwArgs: map[string]*Value{},
// 	}
// 	var err *Error

// 	for _, param := range fc.args {
// 		value, err := param.Evaluate(ctx)
// 		if err != nil {
// 			return nil, err
// 		}
// 		params.Args = append(params.Args, value)
// 	}

// 	for key, param := range fc.kwargs {
// 		value, err := param.Evaluate(ctx)
// 		if err != nil {
// 			return nil, err
// 		}
// 		params.KwArgs[key] = value
// 	}

// 	filteredValue, err := fc.filterFunc(v, params)
// 	if err != nil {
// 		return nil, err.updateFromTokenIfNeeded(ctx.template, fc.token)
// 	}
// 	return filteredValue, nil
// }

// Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
func (p *Parser) ParseFilter() (*nodes.FilterCall, error) {
	identToken := p.Match(tokens.Name)

	// Check filter ident
	if identToken == nil {
		return nil, p.Error("Filter name must be an identifier.", p.Current())
	}

	filter := &nodes.FilterCall{
		Token:  identToken,
		Name:   identToken.Val,
		Args:   []nodes.Expression{},
		Kwargs: map[string]nodes.Expression{},
	}

	// // Get the appropriate filter function and bind it
	// filterFn, exists := filters[identToken.Val]
	// if !exists {
	// 	return nil, p.Error(fmt.Sprintf("Filter '%s' does not exist.", identToken.Val), identToken)
	// }

	// filter.filterFunc = filterFn

	// Check for filter-argument (2 tokens needed: ':' ARG)
	if p.Match(tokens.Lparen) != nil {
		if p.Peek(tokens.VariableEnd) != nil {
			return nil, p.Error("Filter parameter required after '('.", nil)
		}

		for p.Match(tokens.Comma) != nil || p.Match(tokens.Rparen) == nil {
			// TODO: Handle multiple args and kwargs
			v, err := p.ParseExpression()
			if err != nil {
				return nil, err
			}

			if p.Match(tokens.Assign) != nil {
				key := v.Position().Val
				value, errValue := p.ParseExpression()
				if errValue != nil {
					return nil, errValue
				}
				filter.Kwargs[key] = value
			} else {
				filter.Args = append(filter.Args, v)
			}
		}
	}

	return filter, nil
}


<|start_filename|>ext/django/statements/spaceless.go<|end_filename|>
package statements

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type SpacelessStmt struct {
	Location *tokens.Token
	wrapper  *nodes.Wrapper
}

func (stmt *SpacelessStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *SpacelessStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("SpacelessStmt(Line=%d Col=%d)", t.Line, t.Col)
}

var spacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)

func (stmt *SpacelessStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	var out strings.Builder

	sub := r.Inherit()
	sub.Out = &out
	err := sub.ExecuteWrapper(stmt.wrapper)
	if err != nil {
		return err
	}

	s := out.String()
	// Repeat this recursively
	changed := true
	for changed {
		s2 := spacelessRegexp.ReplaceAllString(s, "$1$3")
		changed = s != s2
		s = s2
	}

	r.WriteString(s)

	return nil
}

func spacelessParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &SpacelessStmt{
		Location: p.Current(),
	}

	wrapper, _, err := p.WrapUntil("endspaceless")
	if err != nil {
		return nil, err
	}
	stmt.wrapper = wrapper

	if !args.End() {
		return nil, args.Error("Malformed spaceless-tag args.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("spaceless", spacelessParser)
}


<|start_filename|>version.go<|end_filename|>
package gonja

const VERSION = "0.1.0"


<|start_filename|>builtins/tests.go<|end_filename|>
package builtins

import (
	"reflect"
	"strings"

	"github.com/noirbizarre/gonja/exec"
)

var Tests = exec.TestSet{
	"callable":    testCallable,
	"defined":     testDefined,
	"divisibleby": testDivisibleby,
	"eq":          testEqual,
	"equalto":     testEqual,
	"==":          testEqual,
	// TODO: "escaped": testEscaped,
	"even":        testEven,
	"ge":          testGreaterEqual,
	">=":          testGreaterEqual,
	"gt":          testGreaterThan,
	"greaterthan": testGreaterThan,
	">":           testGreaterThan,
	"in":          testIn,
	"iterable":    testIterable,
	"le":          testLessEqual,
	"<=":          testLessEqual,
	"lower":       testLower,
	"lt":          testLessThan,
	"lessthan":    testLessThan,
	"<":           testLessThan,
	"mapping":     testMapping,
	"ne":          testNotEqual,
	"!=":          testNotEqual,
	"none":        testNone,
	"number":      testNumber,
	"odd":         testOdd,
	"sameas":      testSameas,
	"sequence":    testIterable,
	"string":      testString,
	"undefined":   testUndefined,
	"upper":       testUpper,
}

func testCallable(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return in.IsCallable(), nil
}

func testDefined(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return !(in.IsError() || in.IsNil()), nil
}

func testDivisibleby(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.First()
	if param.Integer() == 0 {
		return false, nil
	}
	return in.Integer()%param.Integer() == 0, nil
}

func testEqual(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.First()
	return in.Interface() == param.Interface(), nil
}

func testEven(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	if !in.IsInteger() {
		return false, nil
	}
	return in.Integer()%2 == 0, nil
}

func testGreaterEqual(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.Args[0]
	if !in.IsNumber() || !param.IsNumber() {
		return false, nil
	}
	return in.Float() >= param.Float(), nil
}

func testGreaterThan(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.Args[0]
	if !in.IsNumber() || !param.IsNumber() {
		return false, nil
	}
	return in.Float() > param.Float(), nil
}

func testIn(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	seq := params.First()
	return seq.Contains(in), nil
}

func testIterable(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return in.CanSlice(), nil
}

func testLessEqual(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.Args[0]
	if !in.IsNumber() || !param.IsNumber() {
		return false, nil
	}
	return in.Float() <= param.Float(), nil
}

func testLower(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	if !in.IsString() {
		return false, nil
	}
	return strings.ToLower(in.String()) == in.String(), nil
}

func testLessThan(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.Args[0]
	if !in.IsNumber() || !param.IsNumber() {
		return false, nil
	}
	return in.Float() < param.Float(), nil
}

func testMapping(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return in.IsDict(), nil
}

func testNotEqual(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.Args[0]
	return in.Interface() != param.Interface(), nil
}

func testNone(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return in.IsNil(), nil
}

func testNumber(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return in.IsNumber(), nil
}

func testOdd(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	if !in.IsInteger() {
		return false, nil
	}
	return in.Integer()%2 == 1, nil
}

func testSameas(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	param := params.Args[0]
	if in.IsNil() && param.IsNil() {
		return true, nil
	} else if param.Val.CanAddr() && in.Val.CanAddr() {
		return param.Val.Addr() == in.Val.Addr(), nil
	}
	return reflect.Indirect(param.Val) == reflect.Indirect(in.Val), nil
}

func testString(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	return in.IsString(), nil
}

func testUndefined(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	defined, err := testDefined(ctx, in, params)
	return !defined, err
}

func testUpper(ctx *exec.Context, in *exec.Value, params *exec.VarArgs) (bool, error) {
	if !in.IsString() {
		return false, nil
	}
	return strings.ToUpper(in.String()) == in.String(), nil
}


<|start_filename|>loaders/filesystem.go<|end_filename|>
package loaders

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
)

// FilesystemLoader represents a local filesystem loader with basic
// BaseDirectory capabilities. The access to the local filesystem is unrestricted.
type FilesystemLoader struct {
	root string
}

// MustNewFileSystemLoader creates a new FilesystemLoader instance
// and panics if there's any error during instantiation. The parameters
// are the same like NewFileSystemLoader.
func MustNewFileSystemLoader(root string) *FilesystemLoader {
	fs, err := NewFileSystemLoader(root)
	if err != nil {
		log.Panic(err)
	}
	return fs
}

// NewFileSystemLoader creates a new FilesystemLoader and allows
// templatesto be loaded from disk (unrestricted). If any base directory
// is given (or being set using SetBaseDir), this base directory is being used
// for path calculation in template inclusions/imports. Otherwise the path
// is calculated based relatively to the including template's path.
func NewFileSystemLoader(root string) (*FilesystemLoader, error) {
	fs := &FilesystemLoader{}
	if root != "" {
		if err := fs.SetBaseDir(root); err != nil {
			return nil, err
		}
	}
	return fs, nil
}

// SetBaseDir sets the template's base directory. This directory will
// be used for any relative path in filters, tags and From*-functions to determine
// your template. See the comment for NewFileSystemLoader as well.
func (fs *FilesystemLoader) SetBaseDir(path string) error {
	// Make the path absolute
	if !filepath.IsAbs(path) {
		abs, err := filepath.Abs(path)
		if err != nil {
			return err
		}
		path = abs
	}

	// Check for existence
	fi, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !fi.IsDir() {
		return errors.Errorf("The given path '%s' is not a directory.", path)
	}

	fs.root = path
	return nil
}

// Get reads the path's content from your local filesystem.
func (fs *FilesystemLoader) Get(path string) (io.Reader, error) {
	realPath, err := fs.Path(path)
	if err != nil {
		return nil, err
	}
	buf, err := ioutil.ReadFile(realPath)
	if err != nil {
		return nil, err
	}
	return bytes.NewReader(buf), nil
}

// Path resolves a filename relative to the base directory. Absolute paths are allowed.
// When there's no base dir set, the absolute path to the filename
// will be calculated based on either the provided base directory (which
// might be a path of a template which includes another template) or
// the current working directory.
func (fs *FilesystemLoader) Path(name string) (string, error) {
	if filepath.IsAbs(name) {
		return name, nil
	}

	// root := fs.root
	if fs.root == "" {
		root, err := os.Getwd()
		if err != nil {
			return "", err
		}
		return filepath.Join(root, name), nil
	} else {
		return filepath.Join(fs.root, name), nil
	}

	// // Our own base dir has always priority; if there's none
	// // we use the path provided in base.
	// var err error
	// if fs.root == "" {
	// 	if base == "" {
	// 		base, err = os.Getwd()
	// 		if err != nil {
	// 			panic(err)
	// 		}
	// 		return filepath.Join(base, name)
	// 	}

	// 	return filepath.Join(filepath.Dir(base), name)
	// }

	// return filepath.Join(fs.root, name)
}

// SandboxedFilesystemLoader is still WIP.
type SandboxedFilesystemLoader struct {
	*FilesystemLoader
}

// NewSandboxedFilesystemLoader creates a new sandboxed local file system instance.
func NewSandboxedFilesystemLoader(root string) (*SandboxedFilesystemLoader, error) {
	fs, err := NewFileSystemLoader(root)
	if err != nil {
		return nil, err
	}
	return &SandboxedFilesystemLoader{
		FilesystemLoader: fs,
	}, nil
}

// Move sandbox to a virtual fs

/*
if len(set.SandboxDirectories) > 0 {
    defer func() {
        // Remove any ".." or other crap
        resolvedPath = filepath.Clean(resolvedPath)

        // Make the path absolute
        absPath, err := filepath.Abs(resolvedPath)
        if err != nil {
            panic(err)
        }
        resolvedPath = absPath

        // Check against the sandbox directories (once one pattern matches, we're done and can allow it)
        for _, pattern := range set.SandboxDirectories {
            matched, err := filepath.Match(pattern, resolvedPath)
            if err != nil {
                panic("Wrong sandbox directory match pattern (see http://golang.org/pkg/path/filepath/#Match).")
            }
            if matched {
                // OK!
                return
            }
        }

        // No pattern matched, we have to log+deny the request
        set.logf("Access attempt outside of the sandbox directories (blocked): '%s'", resolvedPath)
        resolvedPath = ""
    }()
}
*/


<|start_filename|>ext/django/statements/cycle.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type cycleValue struct {
	node  *CycleStatement
	value *exec.Value
}

type CycleStatement struct {
	position *tokens.Token
	args     []nodes.Expression
	idx      int
	asName   string
	silent   bool
}

func (stmt *CycleStatement) Position() *tokens.Token { return stmt.position }
func (stmt *CycleStatement) String() string {
	t := stmt.Position()
	return fmt.Sprintf("CycleStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (cv *cycleValue) String() string {
	return cv.value.String()
}

func (stmt *CycleStatement) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	item := stmt.args[stmt.idx%len(stmt.args)]
	stmt.idx++

	val := r.Eval(item)
	if val.IsError() {
		return val
	}

	if t, ok := val.Interface().(*cycleValue); ok {
		// {% cycle "test1" "test2"
		// {% cycle cycleitem %}

		// Update the cycle value with next value
		item := t.node.args[t.node.idx%len(t.node.args)]
		t.node.idx++

		val := r.Eval(item)
		if val.IsError() {
			return val
		}

		t.value = val

		if !t.node.silent {
			r.WriteString(val.String())
		}
	} else {
		// Regular call

		cycleValue := &cycleValue{
			node:  stmt,
			value: val,
		}

		if stmt.asName != "" {
			r.Ctx.Set(stmt.asName, cycleValue)
		}
		if !stmt.silent {
			r.WriteString(val.String())
		}
	}

	return nil
}

// HINT: We're not supporting the old comma-separated list of expressions argument-style
func cycleParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	cycleNode := &CycleStatement{
		position: p.Current(),
	}

	for !args.End() {
		node, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		cycleNode.args = append(cycleNode.args, node)

		if args.MatchName("as") != nil {
			// as

			name := args.Match(tokens.Name)
			if name == nil {
				return nil, args.Error("Name (identifier) expected after 'as'.", nil)
			}
			cycleNode.asName = name.Val

			if args.MatchName("silent") != nil {
				cycleNode.silent = true
			}

			// Now we're finished
			break
		}
	}

	if !args.End() {
		return nil, args.Error("Malformed cycle-tag.", nil)
	}

	return cycleNode, nil
}

func init() {
	All.Register("cycle", cycleParser)
}


<|start_filename|>context.go<|end_filename|>
package gonja

// import (
// 	"github.com/noirbizarre/gonja/exec"
// )

type Context map[string]interface{}

// func (c Context) Get(name string) interface{} {
// 	return nil
// }

// // Update updates this context with the key/value-pairs from another context.
// func (c Context) Update(other exec.Context) Context {
// 	for k, v := range other.AsMap() {
// 		c[k] = v
// 	}
// 	return c
// }


<|start_filename|>utils/sets.go<|end_filename|>
package utils

// // Create a set
// set := make(map[int]struct{})

// // Add some values
// set[1] = struct{}{}
// set[5] = struct{}{}

// // Check if some values are in the set
// if _, ok := set[1]; ok {
// 	fmt.Println("1 is in the set")
// }
// if _, ok := set[2]; ok {
// 	fmt.Println("2 is in the set")
// }


<|start_filename|>exec/context_test.go<|end_filename|>
package exec_test

import (
	// "fmt"

	"testing"

	"github.com/noirbizarre/gonja/exec"
	"github.com/stretchr/testify/assert"
)

var ctxData = map[string]interface{}{
	"nil":    nil,
	"string": "Hello World",
	"int":    42,
	"float":  42.,
	"true":   true,
	"false":  false,
	"func":   func() {},
}

var ctxCases = []struct {
	name     string
	value    interface{}
	asString string
	flags    flags
}{
	{"nil", nil, "", flags{IsNil: true}},
	{"string", "Hello World", "Hello World", flags{IsString: true, IsTrue: true}},
	{"int", 42, "42", flags{IsInteger: true, IsNumber: true, IsTrue: true}},
	{"int 0", 0, "0", flags{IsInteger: true, IsNumber: true}},
	{"float", 42., "42.000000", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
	{"float 0.0", 0., "0.000000", flags{IsFloat: true, IsNumber: true}},
	{"true", true, "True", flags{IsBool: true, IsTrue: true}},
	{"false", false, "False", flags{IsBool: true}},
}

func TestContext(t *testing.T) {
	for _, cc := range ctxCases {
		test := cc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			ctx := exec.EmptyContext()
			ctx.Set(test.name, test.value)
			value := ctx.Get(test.name)

			// value := exec.AsValue(test.value)
			assert.Equal(test.value, value)

			// assert.Equal(test.asString, value.String())
			// test.flags.assert(t, value)
		})
	}
}

func TestSubContext(t *testing.T) {
	for _, cc := range ctxCases {
		test := cc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			ctx := exec.EmptyContext()
			ctx.Set(test.name, test.value)
			sub := ctx.Inherit()
			value := sub.Get(test.name)

			// value := exec.AsValue(test.value)
			assert.Equal(test.value, value)

			// assert.Equal(test.asString, value.String())
			// test.flags.assert(t, value)
		})
	}
}

func TestFuncContext(t *testing.T) {
	ctx := exec.EmptyContext()
	ctx.Set("func", func() {})

	cases := []struct {
		name string
		ctx  *exec.Context
	}{
		{"top context", ctx},
		{"sub context", ctx.Inherit()},
	}

	for _, c := range cases {
		test := c
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			assert := assert.New(t)

			value := test.ctx.Get("func")
			_, ok := value.(func())
			assert.True(ok)
		})
	}
}

// func TestValueFromMap(t *testing.T) {
// 	for _, lc := range valueCases {
// 		test := lc
// 		t.Run(test.name, func(t *testing.T) {
// 			defer func() {
// 				if err := recover(); err != nil {
// 					t.Error(err)
// 				}
// 			}()
// 			assert := assert.New(t)

// 			data := map[string]interface{}{"value": test.value}
// 			value := exec.AsValue(data["value"])

// 			assert.Equal(test.asString, value.String())
// 			test.flags.assert(t, value)
// 		})
// 	}
// }

// type testStruct struct {
// 	Attr string
// }

// var getattrCases = []struct {
// 	name     string
// 	value    interface{}
// 	attr     string
// 	found    bool
// 	asString string
// 	flags    flags
// }{
// 	{"nil", nil, "missing", false, "", flags{IsError: true}},
// 	{"attr found", testStruct{"test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true}},
// 	{"item", map[string]interface{}{"Attr": "test"}, "Attr", false, "", flags{IsError: true}},
// }

// func TestValueGetAttr(t *testing.T) {
// 	for _, lc := range getattrCases {
// 		test := lc
// 		t.Run(test.name, func(t *testing.T) {
// 			defer func() {
// 				if err := recover(); err != nil {
// 					t.Error(err)
// 				}
// 			}()
// 			assert := assert.New(t)

// 			value := exec.AsValue(test.value)
// 			out, found := value.Getattr(test.attr)

// 			if !test.flags.IsError && out.IsError() {
// 				t.Fatalf(`Unexpected error: %s`, out.Error())
// 			}

// 			if test.found {
// 				assert.Truef(found, `Attribute '%s' should be found on %s`, test.attr, value)
// 				assert.Equal(test.asString, out.String())
// 			} else {
// 				assert.Falsef(found, `Attribute '%s' should not be found on %s`, test.attr, value)
// 			}

// 			test.flags.assert(t, out)
// 		})
// 	}
// }

// var getitemCases = []struct {
// 	name     string
// 	value    interface{}
// 	key      interface{}
// 	found    bool
// 	asString string
// 	flags    flags
// }{
// 	{"nil", nil, "missing", false, "", flags{IsError: true}},
// 	{"item found", map[string]interface{}{"Attr": "test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true}},
// 	{"attr", testStruct{"test"}, "Attr", false, "", flags{IsError: true}},
// }

// func TestValueGetitem(t *testing.T) {
// 	for _, lc := range getitemCases {
// 		test := lc
// 		t.Run(test.name, func(t *testing.T) {
// 			defer func() {
// 				if err := recover(); err != nil {
// 					t.Error(err)
// 				}
// 			}()
// 			assert := assert.New(t)

// 			value := exec.AsValue(test.value)
// 			out, found := value.Getitem(test.key)

// 			if !test.flags.IsError && out.IsError() {
// 				t.Fatalf(`Unexpected error: %s`, out.Error())
// 			}

// 			if test.found {
// 				assert.Truef(found, `Key '%s' should be found on %s`, test.key, value)
// 				assert.Equal(test.asString, out.String())
// 			} else {
// 				assert.Falsef(found, `Key '%s' should not be found on %s`, test.key, value)
// 			}

// 			test.flags.assert(t, out)
// 		})
// 	}
// }


<|start_filename|>integration_test.go<|end_filename|>
// +build integration

package gonja_test

import (
	"testing"

	tu "github.com/noirbizarre/gonja/testutils"
)

func TestTemplates(t *testing.T) {
	// Add a global to the default set
	root := "./testData"
	env := tu.TestEnv(root)
	env.Globals.Set("this_is_a_global_variable", "this is a global text")
	tu.GlobTemplateTests(t, root, env)
}

func TestExpressions(t *testing.T) {
	root := "./testData/expressions"
	env := tu.TestEnv(root)
	tu.GlobTemplateTests(t, root, env)
}

func TestFilters(t *testing.T) {
	root := "./testData/filters"
	env := tu.TestEnv(root)
	tu.GlobTemplateTests(t, root, env)
}

func TestFunctions(t *testing.T) {
	root := "./testData/functions"
	env := tu.TestEnv(root)
	tu.GlobTemplateTests(t, root, env)
}

func TestTests(t *testing.T) {
	root := "./testData/tests"
	env := tu.TestEnv(root)
	tu.GlobTemplateTests(t, root, env)
}

func TestStatements(t *testing.T) {
	root := "./testData/statements"
	env := tu.TestEnv(root)
	tu.GlobTemplateTests(t, root, env)
}

// func TestCompilationErrors(t *testing.T) {
// 	tu.GlobErrorTests(t, "./testData/errors/compilation")
// }

// func TestExecutionErrors(t *testing.T) {
// 	tu.GlobErrorTests(t, "./testData/errors/execution")
// }


<|start_filename|>exec/value.go<|end_filename|>
package exec

import (
	"fmt"
	"reflect"
	"sort"
	"strconv"
	"strings"

	"github.com/pkg/errors"

	log "github.com/sirupsen/logrus"

	u "github.com/noirbizarre/gonja/utils"
)

type Value struct {
	Val  reflect.Value
	Safe bool // used to indicate whether a Value needs explicit escaping in the template
}

// AsValue converts any given Value to a gonja.Value
// Usually being used within oSn functions passed to a template
// through a Context or within filter functions.
//
// Example:
//     AsValue("my string")
func AsValue(i interface{}) *Value {
	return &Value{
		Val: reflect.ValueOf(i),
	}
}

// AsSafeValue works like AsValue, but does not apply the 'escape' filter.
func AsSafeValue(i interface{}) *Value {
	return &Value{
		Val:  reflect.ValueOf(i),
		Safe: true,
	}
}

func ValueError(err error) *Value {
	return &Value{Val: reflect.ValueOf(err)}
}

func (v *Value) getResolvedValue() reflect.Value {
	if v.Val.IsValid() && v.Val.Kind() == reflect.Ptr {
		return v.Val.Elem()
	}
	return v.Val
}

// IsString checks whether the underlying value is a string
func (v *Value) IsString() bool {
	return v.getResolvedValue().Kind() == reflect.String
}

// IsBool checks whether the underlying value is a bool
func (v *Value) IsBool() bool {
	return v.getResolvedValue().Kind() == reflect.Bool
}

// IsFloat checks whether the underlying value is a float
func (v *Value) IsFloat() bool {
	return v.getResolvedValue().Kind() == reflect.Float32 ||
		v.getResolvedValue().Kind() == reflect.Float64
}

// IsInteger checks whether the underlying value is an integer
func (v *Value) IsInteger() bool {
	kind := v.getResolvedValue().Kind()
	return kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 ||
		kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.Uint ||
		kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 ||
		kind == reflect.Uint64
}

// IsNumber checks whether the underlying value is either an integer
// or a float.
func (v *Value) IsNumber() bool {
	return v.IsInteger() || v.IsFloat()
}

func (v *Value) IsCallable() bool {
	return v.getResolvedValue().Kind() == reflect.Func
}

func (v *Value) IsList() bool {
	kind := v.getResolvedValue().Kind()
	return kind == reflect.Array || kind == reflect.Slice
}

func (v *Value) IsDict() bool {
	resolved := v.getResolvedValue()
	return resolved.Kind() == reflect.Map || resolved.Kind() == reflect.Struct && resolved.Type() == TypeDict
}

func (v *Value) IsIterable() bool {
	return v.IsString() || v.IsList() || v.IsDict()
}

// IsNil checks whether the underlying value is NIL
func (v *Value) IsNil() bool {
	return !v.getResolvedValue().IsValid()
}

func (v *Value) IsError() bool {
	if v.IsNil() || !v.getResolvedValue().CanInterface() {
		return false
	}
	_, ok := v.Interface().(error)
	return ok
}

func (v *Value) Error() string {
	if v.IsError() {
		return v.Interface().(error).Error()
	}
	return ""
}

// String returns a string for the underlying value. If this value is not
// of type string, gonja tries to convert it. Currently the following
// types for underlying values are supported:
//
//     1. string
//     2. int/uint (any size)
//     3. float (any precision)
//     4. bool
//     5. time.Time
//     6. String() will be called on the underlying value if provided
//
// NIL values will lead to an empty string. Unsupported types are leading
// to their respective type name.
func (v *Value) String() string {
	if v.IsNil() {
		return ""
	}
	resolved := v.getResolvedValue()

	switch resolved.Kind() {
	case reflect.String:
		return resolved.String()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(resolved.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(resolved.Uint(), 10)
	case reflect.Float32, reflect.Float64:
		formated := strconv.FormatFloat(resolved.Float(), 'f', 11, 64)
		if !strings.Contains(formated, ".") {
			formated = formated + "."
		}
		formated = strings.TrimRight(formated, "0")
		if formated[len(formated)-1] == '.' {
			formated += "0"
		}
		return formated
	case reflect.Bool:
		if v.Bool() {
			return "True"
		}
		return "False"
	case reflect.Struct:
		if t, ok := v.Interface().(fmt.Stringer); ok {
			return t.String()
		}
	case reflect.Slice, reflect.Array:
		var out strings.Builder
		length := v.Len()
		out.WriteByte('[')
		for i := 0; i < length; i++ {
			if i > 0 {
				out.WriteString(", ")
			}
			item := ToValue(v.Index(i).Val)
			if item.IsString() {
				out.WriteString(fmt.Sprintf(`'%s'`, item.String()))
			} else {
				out.WriteString(item.String())
			}
		}
		out.WriteByte(']')
		return out.String()
	case reflect.Map:
		pairs := []string{}
		for _, key := range resolved.MapKeys() {
			keyLabel := key.String()
			if key.Kind() == reflect.String {
				keyLabel = fmt.Sprintf(`'%s'`, keyLabel)
			}

			value := resolved.MapIndex(key)
			// Check whether this is an interface and resolve it where required
			for value.Kind() == reflect.Interface {
				value = reflect.ValueOf(value.Interface())
			}
			valueLabel := value.String()
			if value.Kind() == reflect.String {
				valueLabel = fmt.Sprintf(`'%s'`, valueLabel)
			}
			pair := fmt.Sprintf(`%s: %s`, keyLabel, valueLabel)
			pairs = append(pairs, pair)
		}
		sort.Strings(pairs)
		return fmt.Sprintf("{%s}", strings.Join(pairs, ", "))
	}

	log.Errorf("Value.String() not implemented for type: %s\n", resolved.Kind().String())
	return resolved.String()
}

// Escaped returns the escaped version of String()
func (v *Value) Escaped() string {
	return u.Escape(v.String())
}

// Integer returns the underlying value as an integer (converts the underlying
// value, if necessary). If it's not possible to convert the underlying value,
// it will return 0.
func (v *Value) Integer() int {
	switch v.getResolvedValue().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return int(v.getResolvedValue().Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return int(v.getResolvedValue().Uint())
	case reflect.Float32, reflect.Float64:
		return int(v.getResolvedValue().Float())
	case reflect.String:
		// Try to convert from string to int (base 10)
		f, err := strconv.ParseFloat(v.getResolvedValue().String(), 64)
		if err != nil {
			return 0
		}
		return int(f)
	default:
		log.Errorf("Value.Integer() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return 0
	}
}

// Float returns the underlying value as a float (converts the underlying
// value, if necessary). If it's not possible to convert the underlying value,
// it will return 0.0.
func (v *Value) Float() float64 {
	switch v.getResolvedValue().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(v.getResolvedValue().Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return float64(v.getResolvedValue().Uint())
	case reflect.Float32, reflect.Float64:
		return v.getResolvedValue().Float()
	case reflect.String:
		// Try to convert from string to float64 (base 10)
		f, err := strconv.ParseFloat(v.getResolvedValue().String(), 64)
		if err != nil {
			return 0.0
		}
		return f
	default:
		log.Errorf("Value.Float() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return 0.0
	}
}

// Bool returns the underlying value as bool. If the value is not bool, false
// will always be returned. If you're looking for true/false-evaluation of the
// underlying value, have a look on the IsTrue()-function.
func (v *Value) Bool() bool {
	switch v.getResolvedValue().Kind() {
	case reflect.Bool:
		return v.getResolvedValue().Bool()
	default:
		log.Errorf("Value.Bool() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return false
	}
}

// IsTrue tries to evaluate the underlying value the Pythonic-way:
//
// Returns TRUE in one the following cases:
//
//     * int != 0
//     * uint != 0
//     * float != 0.0
//     * len(array/chan/map/slice/string) > 0
//     * bool == true
//     * underlying value is a struct
//
// Otherwise returns always FALSE.
func (v *Value) IsTrue() bool {
	if v.IsNil() || v.IsError() {
		return false
	}
	switch v.getResolvedValue().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.getResolvedValue().Int() != 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return v.getResolvedValue().Uint() != 0
	case reflect.Float32, reflect.Float64:
		return v.getResolvedValue().Float() != 0
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
		return v.getResolvedValue().Len() > 0
	case reflect.Bool:
		return v.getResolvedValue().Bool()
	case reflect.Struct:
		return true // struct instance is always true
	default:
		log.Errorf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return false
	}
}

// Negate tries to negate the underlying value. It's mainly used for
// the NOT-operator and in conjunction with a call to
// return_value.IsTrue() afterwards.
//
// Example:
//     AsValue(1).Negate().IsTrue() == false
func (v *Value) Negate() *Value {
	switch v.getResolvedValue().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if v.Integer() != 0 {
			return AsValue(0)
		}
		return AsValue(1)
	case reflect.Float32, reflect.Float64:
		if v.Float() != 0.0 {
			return AsValue(float64(0.0))
		}
		return AsValue(float64(1.1))
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
		return AsValue(v.getResolvedValue().Len() == 0)
	case reflect.Bool:
		return AsValue(!v.getResolvedValue().Bool())
	case reflect.Struct:
		return AsValue(false)
	default:
		log.Errorf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return AsValue(true)
	}
}

// Len returns the length for an array, chan, map, slice or string.
// Otherwise it will return 0.
func (v *Value) Len() int {
	switch v.getResolvedValue().Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
		return v.getResolvedValue().Len()
	case reflect.String:
		runes := []rune(v.getResolvedValue().String())
		return len(runes)
	default:
		log.Errorf("Value.Len() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return 0
	}
}

// Slice slices an array, slice or string. Otherwise it will
// return an empty []int.
func (v *Value) Slice(i, j int) *Value {
	switch v.getResolvedValue().Kind() {
	case reflect.Array, reflect.Slice:
		return AsValue(v.getResolvedValue().Slice(i, j).Interface())
	case reflect.String:
		runes := []rune(v.getResolvedValue().String())
		return AsValue(string(runes[i:j]))
	default:
		log.Errorf("Value.Slice() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return AsValue([]int{})
	}
}

// Index gets the i-th item of an array, slice or string. Otherwise
// it will return NIL.
func (v *Value) Index(i int) *Value {
	switch v.getResolvedValue().Kind() {
	case reflect.Array, reflect.Slice:
		if i >= v.Len() {
			return AsValue(nil)
		}
		return AsValue(v.getResolvedValue().Index(i).Interface())
	case reflect.String:
		//return AsValue(v.getResolvedValue().Slice(i, i+1).Interface())
		s := v.getResolvedValue().String()
		runes := []rune(s)
		if i < len(runes) {
			return AsValue(string(runes[i]))
		}
		return AsValue("")
	default:
		log.Errorf("Value.Slice() not available for type: %s\n", v.getResolvedValue().Kind().String())
		return AsValue([]int{})
	}
}

// Contains checks whether the underlying value (which must be of type struct, map,
// string, array or slice) contains of another Value (e. g. used to check
// whether a struct contains of a specific field or a map contains a specific key).
//
// Example:
//     AsValue("Hello, World!").Contains(AsValue("World")) == true
func (v *Value) Contains(other *Value) bool {
	resolved := v.getResolvedValue()
	switch resolved.Kind() {
	case reflect.Struct:
		if dict, ok := resolved.Interface().(Dict); ok {
			return dict.Keys().Contains(other)
		}
		fieldValue := resolved.FieldByName(other.String())
		return fieldValue.IsValid()
	case reflect.Map:
		var mapValue reflect.Value
		switch other.Interface().(type) {
		case int:
			mapValue = resolved.MapIndex(other.getResolvedValue())
		case string:
			mapValue = resolved.MapIndex(other.getResolvedValue())
		default:
			log.Errorf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
			return false
		}

		return mapValue.IsValid()
	case reflect.String:
		return strings.Contains(resolved.String(), other.String())

	case reflect.Slice, reflect.Array:
		if vl, ok := resolved.Interface().(ValuesList); ok {
			return vl.Contains(other)
		}
		for i := 0; i < resolved.Len(); i++ {
			item := resolved.Index(i)
			if other.Interface() == item.Interface() {
				return true
			}
		}
		return false

	default:
		fmt.Println("default")
		log.Errorf("Value.Contains() not available for type: %s\n", resolved.Kind().String())
		return false
	}
}

// CanSlice checks whether the underlying value is of type array, slice or string.
// You normally would use CanSlice() before using the Slice() operation.
func (v *Value) CanSlice() bool {
	switch v.getResolvedValue().Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		return true
	}
	return false
}

// Iterate iterates over a map, array, slice or a string. It calls the
// function's first argument for every value with the following arguments:
//
//     idx      current 0-index
//     count    total amount of items
//     key      *Value for the key or item
//     value    *Value (only for maps, the respective value for a specific key)
//
// If the underlying value has no items or is not one of the types above,
// the empty function (function's second argument) will be called.
func (v *Value) Iterate(fn func(idx, count int, key, value *Value) bool, empty func()) {
	v.IterateOrder(fn, empty, false, false, false)
}

// IterateOrder behaves like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
// not affect the iteration through a map because maps don't have any particular order.
// However, you can force an order using the `sorted` keyword (and even use `reversed sorted`).
func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool, sorted bool, caseSensitive bool) {
	resolved := v.getResolvedValue()
	switch resolved.Kind() {
	case reflect.Map:
		keys := v.Keys()
		if sorted {
			if reverse {
				if !caseSensitive {
					sort.Sort(sort.Reverse(CaseInsensitive(keys)))
				} else {
					sort.Sort(sort.Reverse(keys))
				}
			} else {
				if !caseSensitive {
					sort.Sort(CaseInsensitive(keys))
				} else {
					sort.Sort(keys)
				}
			}
		}
		keyLen := len(keys)
		for idx, key := range keys {
			value, _ := v.Getitem(key.Interface())
			if !fn(idx, keyLen, key, value) {
				return
			}
		}
		if keyLen == 0 {
			empty()
		}
		return // done
	case reflect.Array, reflect.Slice:
		var items ValuesList

		itemCount := resolved.Len()
		for i := 0; i < itemCount; i++ {
			// value := resolved.Index(i)

			items = append(items, ToValue(resolved.Index(i)))
		}

		if sorted {
			if reverse {
				if !caseSensitive && items[0].IsString() {
					sort.Slice(items, func(i, j int) bool {
						return strings.ToLower(items[i].String()) > strings.ToLower(items[j].String())
					})
				} else {
					sort.Sort(sort.Reverse(items))
				}
			} else {
				if !caseSensitive && items[0].IsString() {
					sort.Slice(items, func(i, j int) bool {
						return strings.ToLower(items[i].String()) < strings.ToLower(items[j].String())
					})
				} else {
					sort.Sort(items)
				}
			}
		} else {
			if reverse {
				for i := 0; i < itemCount/2; i++ {
					items[i], items[itemCount-1-i] = items[itemCount-1-i], items[i]
				}
			}
		}

		if len(items) > 0 {
			for idx, item := range items {
				if !fn(idx, itemCount, item, nil) {
					return
				}
			}
		} else {
			empty()
		}
		return // done
	case reflect.String:
		if sorted {
			r := []rune(resolved.String())
			if caseSensitive {
				sort.Sort(sortRunes(r))
			} else {
				sort.Sort(CaseInsensitive(sortRunes(r)))
			}
			resolved = reflect.ValueOf(string(r))
		}

		// TODO(flosch): Not utf8-compatible (utf8-decoding necessary)
		charCount := resolved.Len()
		if charCount > 0 {
			if reverse {
				for i := charCount - 1; i >= 0; i-- {
					if !fn(i, charCount, &Value{Val: resolved.Slice(i, i+1)}, nil) {
						return
					}
				}
			} else {
				for i := 0; i < charCount; i++ {
					if !fn(i, charCount, &Value{Val: resolved.Slice(i, i+1)}, nil) {
						return
					}
				}
			}
		} else {
			empty()
		}
		return // done
	case reflect.Chan:
		items := []reflect.Value{}
		for {
			value, ok := resolved.Recv()
			if !ok {
				break
			}
			items = append(items, value)
		}
		count := len(items)
		if count > 0 {
			for idx, value := range items {
				fn(idx, count, &Value{Val: value}, nil)
			}
		} else {
			empty()
		}
		return
	case reflect.Struct:
		if resolved.Type() != TypeDict {
			log.Errorf("Value.Iterate() not available for type: %s\n", resolved.Kind().String())
		}
		dict := resolved.Interface().(Dict)
		keys := dict.Keys()
		length := len(dict.Pairs)
		if sorted {
			if reverse {
				if !caseSensitive {
					sort.Sort(sort.Reverse(CaseInsensitive(keys)))
				} else {
					sort.Sort(sort.Reverse(keys))
				}
			} else {
				if !caseSensitive {
					sort.Sort(CaseInsensitive(keys))
				} else {
					sort.Sort(keys)
				}
			}
		}
		if len(keys) > 0 {
			for idx, key := range keys {
				if !fn(idx, length, key, dict.Get(key)) {
					return
				}
			}
		} else {
			empty()
		}

	default:
		log.Errorf("Value.Iterate() not available for type: %s\n", resolved.Kind().String())
	}
	empty()
}

// Interface gives you access to the underlying value.
func (v *Value) Interface() interface{} {
	if v.Val.IsValid() {
		return v.Val.Interface()
	}
	return nil
}

// EqualValueTo checks whether two values are containing the same value or object.
func (v *Value) EqualValueTo(other *Value) bool {
	// comparison of uint with int fails using .Interface()-comparison (see issue #64)
	if v.IsInteger() && other.IsInteger() {
		return v.Integer() == other.Integer()
	}
	return v.Interface() == other.Interface()
}

func (v *Value) Keys() ValuesList {
	keys := ValuesList{}
	if v.IsNil() {
		return keys
	}
	resolved := v.getResolvedValue()
	if resolved.Type() == TypeDict {
		for _, pair := range resolved.Interface().(Dict).Pairs {
			keys = append(keys, pair.Key)
		}
		return keys
	} else if resolved.Kind() != reflect.Map {
		return keys
	}
	for _, key := range resolved.MapKeys() {
		keys = append(keys, &Value{Val: key})
	}
	sort.Sort(CaseInsensitive(keys))
	return keys
}

func (v *Value) Items() []*Pair {
	out := []*Pair{}
	resolved := v.getResolvedValue()
	if resolved.Kind() != reflect.Map {
		return out
	}
	iter := resolved.MapRange()
	for iter.Next() {
		out = append(out, &Pair{
			Key:   &Value{Val: iter.Key()},
			Value: &Value{Val: iter.Value()},
		})
	}
	return out
}

func ToValue(data interface{}) *Value {
	var isSafe bool
	// if data == nil {
	// 	return AsValue(nil), nil
	// }
	value, ok := data.(*Value)
	if ok {
		return value
	}

	val, ok := data.(reflect.Value)
	if !ok {
		val = reflect.ValueOf(data) // Get the initial value
	}

	if !val.IsValid() {
		// Value is not valid (anymore)
		return AsValue(nil)
	}

	if val.Type() == reflect.TypeOf(reflect.Value{}) {
		val = val.Interface().(reflect.Value)
	} else if val.Type() == reflect.TypeOf(&reflect.Value{}) {
		val = *(val.Interface().(*reflect.Value))
	}

	if !val.IsValid() {
		// Value is not valid (anymore)
		return AsValue(nil)
	}

	// Check whether this is an interface and resolve it where required
	for val.Kind() == reflect.Interface {
		val = reflect.ValueOf(val.Interface())
	}

	if !val.IsValid() {
		// Value is not valid (anymore)
		return AsValue(nil)
	}

	// If val is a reflect.ValueOf(gonja.Value), then unpack it
	// Happens in function calls (as a return value) or by injecting
	// into the execution context (e.g. in a for-loop)
	if val.Type() == typeOfValuePtr {
		tmpValue := val.Interface().(*Value)
		val = tmpValue.Val
		isSafe = tmpValue.Safe
	}

	if !val.IsValid() {
		// Value is not valid (e. g. NIL value)
		return AsValue(nil)
	}
	return &Value{Val: val, Safe: isSafe}
}

func (v *Value) Getattr(name string) (*Value, bool) {
	if v.IsNil() {
		return AsValue(errors.New(`Can't use getattr on None`)), false
	}
	var val reflect.Value
	val = v.Val.MethodByName(name)
	if val.IsValid() {
		return ToValue(val), true
	}
	if v.Val.Kind() == reflect.Ptr {
		val = v.Val.Elem()
		if !val.IsValid() {
			// Value is not valid (anymore)
			return AsValue(nil), false
		}
	} else {
		val = v.Val
	}

	if val.Kind() == reflect.Struct {
		field := val.FieldByName(name)
		if field.IsValid() {
			return ToValue(field), true
		}
	}

	return AsValue(nil), false // Attr not found
}

func (v *Value) Getitem(key interface{}) (*Value, bool) {
	if v.IsNil() {
		return AsValue(errors.New(`Can't use Getitem on None`)), false
	}
	var val reflect.Value
	if v.Val.Kind() == reflect.Ptr {
		val = v.Val.Elem()
		if !val.IsValid() {
			// Value is not valid (anymore)
			return AsValue(nil), false
		}
	} else {
		val = v.Val
	}

	switch t := key.(type) {
	case string:
		if val.Kind() == reflect.Map {
			atKey := val.MapIndex(reflect.ValueOf(t))
			if atKey.IsValid() {
				return ToValue(atKey), true
			}
		} else if val.Kind() == reflect.Struct && val.Type() == TypeDict {
			for _, pair := range val.Interface().(Dict).Pairs {
				if pair.Key.String() == t {
					return pair.Value, true
				}
			}
		}

	case int:
		switch val.Kind() {
		case reflect.String, reflect.Array, reflect.Slice:
			if t >= 0 && val.Len() > t {
				atIndex := val.Index(t)
				if atIndex.IsValid() {
					return ToValue(atIndex), true
				}
			} else {
				// In Django, exceeding the length of a list is just empty.
				return AsValue(nil), false
			}
		default:
			return AsValue(errors.Errorf("Can't access an index on type %s (variable %s)", val.Kind().String(), v)), false
		}
	default:
		return AsValue(nil), false
	}

	return AsValue(nil), false // Item not found
}

func (v *Value) Get(key string) (*Value, bool) {
	value, found := v.Getattr(key)
	if !found {
		value, found = v.Getitem(key)
	}
	return value, found
}

func (v *Value) Set(key string, value interface{}) error {
	if v.IsNil() {
		return errors.New(`Can't set attribute or item on None`)
	}
	val := v.Val
	for val.Kind() == reflect.Ptr {
		val = val.Elem()
		if !val.IsValid() {
			// Value is not valid (anymore)
			return errors.Errorf(`Invalid value "%s"`, val)
		}
	}

	switch val.Kind() {
	case reflect.Struct:
		field := val.FieldByName(key)
		if field.IsValid() && field.CanSet() {
			field.Set(reflect.ValueOf(value))
		} else {
			return errors.Errorf(`Can't write field "%s"`, key)
		}
	case reflect.Map:
		val.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value))
	default:
		return errors.Errorf(`Unkown type "%s", can't set value on "%s"`, val.Kind(), key)
	}

	return nil
}

type ValuesList []*Value

func (vl ValuesList) Len() int {
	return len(vl)
}

func (vl ValuesList) Less(i, j int) bool {
	vi := vl[i]
	vj := vl[j]
	switch {
	case vi.IsInteger() && vj.IsInteger():
		return vi.Integer() < vj.Integer()
	case vi.IsFloat() && vj.IsFloat():
		return vi.Float() < vj.Float()
	default:
		return vi.String() < vj.String()
	}
}

func (vl ValuesList) Swap(i, j int) {
	vl[i], vl[j] = vl[j], vl[i]
}

func (vl ValuesList) String() string {
	var out strings.Builder
	out.WriteByte('[')
	for idx, key := range vl {
		if idx > 0 {
			out.WriteString(", ")
		}
		if key.IsString() {
			out.WriteString("'")
		}
		out.WriteString(key.String())
		if key.IsString() {
			out.WriteString("'")
		}
	}
	out.WriteByte(']')
	return out.String()
}

func (vl ValuesList) Contains(value *Value) bool {
	for _, val := range vl {
		if value.EqualValueTo(val) {
			return true
		}
	}
	return false
}

type Pair struct {
	Key   *Value
	Value *Value
}

func (p *Pair) String() string {
	var key, value string
	if p.Key.IsString() {
		key = fmt.Sprintf(`'%s'`, p.Key.String())
	} else {
		key = p.Key.String()
	}
	if p.Value.IsString() {
		value = fmt.Sprintf(`'%s'`, p.Value.String())
	} else {
		value = p.Value.String()
	}
	return fmt.Sprintf(`%s: %s`, key, value)
}

type Dict struct {
	Pairs []*Pair
}

func NewDict() *Dict {
	return &Dict{Pairs: []*Pair{}}
}

func (d *Dict) String() string {
	pairs := []string{}
	for _, pair := range d.Pairs {
		pairs = append(pairs, pair.String())
	}
	return fmt.Sprintf(`{%s}`, strings.Join(pairs, ", "))
}

func (d *Dict) Keys() ValuesList {
	keys := ValuesList{}
	for _, pair := range d.Pairs {
		keys = append(keys, pair.Key)
	}
	return keys
}

func (d *Dict) Get(key *Value) *Value {
	for _, pair := range d.Pairs {
		if pair.Key.EqualValueTo(key) {
			return pair.Value
		}
	}
	return AsValue(nil)
}

var TypeDict = reflect.TypeOf(Dict{})

type sortRunes []rune

func (s sortRunes) Less(i, j int) bool {
	return s[i] < s[j]
}

func (s sortRunes) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s sortRunes) Len() int {
	return len(s)
}

type caseInsensitiveSortedRunes struct {
	sortRunes
}

func (ci caseInsensitiveSortedRunes) Less(i, j int) bool {
	return strings.ToLower(string(ci.sortRunes[i])) < strings.ToLower(string(ci.sortRunes[j]))
}

type caseInsensitiveValueList struct {
	ValuesList
}

func (ci caseInsensitiveValueList) Less(i, j int) bool {
	vi := ci.ValuesList[i]
	vj := ci.ValuesList[j]
	switch {
	case vi.IsInteger() && vj.IsInteger():
		return vi.Integer() < vj.Integer()
	case vi.IsFloat() && vj.IsFloat():
		return vi.Float() < vj.Float()
	default:
		return strings.ToLower(vi.String()) < strings.ToLower(vj.String())
	}
}

// CaseInsensitive returns the the data sorted in a case insensitive way (if string).
func CaseInsensitive(data sort.Interface) sort.Interface {
	if vl, ok := data.(ValuesList); ok {
		return &caseInsensitiveValueList{vl}
	} else if sr, ok := data.(sortRunes); ok {
		return &caseInsensitiveSortedRunes{sr}
	}
	return data
}


<|start_filename|>nodes/nodes.go<|end_filename|>
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("<FilteredExpression Expression=%s", expr.Expression)
}

type FilterCall struct {
	Token *tokens.Token

	Name   string
	Args   []Expression
	Kwargs map[string]Expression

	// filterFunc FilterFunction
}

type TestExpression struct {
	Expression Expression
	Test       *TestCall
}

func (expr *TestExpression) String() string {
	t := expr.Position()

	return fmt.Sprintf("TestExpression(Expression=%s Test=%s Line=%d Col=%d)",
		expr.Expression, expr.Test, t.Line, t.Col)
	// return fmt.Sprintf("TestExpression(Expression=%s Test=%s)",
	// 	expr.Expression, expr.Test)
}
func (expr *TestExpression) Position() *tokens.Token {
	return expr.Expression.Position()
}

type TestCall struct {
	Token *tokens.Token

	Name   string
	Args   []Expression
	Kwargs map[string]Expression

	// testFunc TestFunction
}

func (tc *TestCall) String() string {
	return fmt.Sprintf("TestCall(name=%s Line=%d Col=%d)",
		tc.Name, tc.Token.Line, tc.Token.Col)
}

type String struct {
	Location *tokens.Token
	Val      string
}

func (s *String) Position() *tokens.Token { return s.Location }
func (s *String) String() string          { return s.Location.Val }

type Integer struct {
	Location *tokens.Token
	Val      int
}

func (i *Integer) Position() *tokens.Token { return i.Location }
func (i *Integer) String() string          { return i.Location.Val }

type Float struct {
	Location *tokens.Token
	Val      float64
}

func (f *Float) Position() *tokens.Token { return f.Location }
func (f *Float) String() string          { return f.Location.Val }

type Bool struct {
	Location *tokens.Token
	Val      bool
}

func (b *Bool) Position() *tokens.Token { return b.Location }
func (b *Bool) String() string          { return b.Location.Val }

type Name struct {
	Name *tokens.Token
}

func (n *Name) Position() *tokens.Token { return n.Name }
func (n *Name) String() string {
	t := n.Position()
	return fmt.Sprintf("Name(Val=%s Line=%d Col=%d)", t.Val, t.Line, t.Col)
}

type List struct {
	Location *tokens.Token
	Val      []Expression
}

func (l *List) Position() *tokens.Token { return l.Location }
func (l *List) String() string          { return l.Location.Val }

type Tuple struct {
	Location *tokens.Token
	Val      []Expression
}

func (t *Tuple) Position() *tokens.Token { return t.Location }
func (t *Tuple) String() string          { return t.Location.Val }

type Dict struct {
	Token *tokens.Token
	Pairs []*Pair
}

func (d *Dict) Position() *tokens.Token { return d.Token }
func (d *Dict) String() string          { return d.Token.Val }

type Pair struct {
	Key   Expression
	Value Expression
}

func (p *Pair) Position() *tokens.Token { return p.Key.Position() }
func (p *Pair) String() string {
	t := p.Position()
	return fmt.Sprintf("Pair(Key=%s Value=%s Line=%d Col=%d)", p.Key, p.Value, t.Line, t.Col)
}

type Variable struct {
	Location *tokens.Token

	Parts []*VariablePart
}

func (v *Variable) Position() *tokens.Token { return v.Location }
func (v *Variable) String() string {
	parts := make([]string, 0, len(v.Parts))
	for _, p := range v.Parts {
		switch p.Type {
		case VarTypeInt:
			parts = append(parts, strconv.Itoa(p.I))
		case VarTypeIdent:
			parts = append(parts, p.S)
		default:
			panic("unimplemented")
		}
	}
	return strings.Join(parts, ".")
}

const (
	VarTypeInt = iota
	VarTypeIdent
)

type VariablePart struct {
	Type int
	S    string
	I    int

	IsFunctionCall bool
	// callingArgs    []functionCallArgument // needed for a function call, represents all argument nodes (Node supports nested function calls)
	Args   []Expression
	Kwargs map[string]Expression
}

func (vp *VariablePart) String() string {
	return fmt.Sprintf("VariablePart(S=%s I=%d)", vp.S, vp.I)
}

type Call struct {
	Location *tokens.Token
	Func     Node
	Args     []Expression
	Kwargs   map[string]Expression
}

func (c *Call) Position() *tokens.Token { return c.Location }
func (c *Call) String() string {
	t := c.Position()
	return fmt.Sprintf("Call(Args=%s Kwargs=%s Line=%d Col=%d)", c.Args, c.Kwargs, t.Line, t.Col)
}

type Getitem struct {
	Location *tokens.Token
	Node     Node
	Arg      string
	Index    int
}

func (g *Getitem) Position() *tokens.Token { return g.Location }
func (g *Getitem) String() string {
	t := g.Position()
	var param string
	if g.Arg != "" {
		param = fmt.Sprintf(`Arg=%s`, g.Arg)
	} else {
		param = fmt.Sprintf(`Index=%s`, strconv.Itoa(g.Index))
	}
	return fmt.Sprintf("Getitem(Node=%s %s Line=%d Col=%d)", g.Node, param, t.Line, t.Col)
}

type Getattr struct {
	Location *tokens.Token
	Node     Node
	Attr     string
	Index    int
}

func (g *Getattr) Position() *tokens.Token { return g.Location }
func (g *Getattr) String() string {
	t := g.Position()
	var param string
	if g.Attr != "" {
		param = fmt.Sprintf(`Attr=%s`, g.Attr)
	} else {
		param = fmt.Sprintf(`Index=%s`, strconv.Itoa(g.Index))
	}
	return fmt.Sprintf("Getattr(Node=%s %s Line=%d Col=%d)", g.Node, param, t.Line, t.Col)
}

type Negation struct {
	Term     Expression
	Operator *tokens.Token
}

func (n *Negation) Position() *tokens.Token { return n.Operator }
func (n *Negation) String() string {
	t := n.Operator
	return fmt.Sprintf("Negation(term=%s Line=%d Col=%d)", n.Term, t.Line, t.Col)
}

type UnaryExpression struct {
	Negative bool
	Term     Expression
	Operator *tokens.Token
}

func (u *UnaryExpression) Position() *tokens.Token { return u.Operator }
func (u *UnaryExpression) String() string {
	t := u.Operator

	return fmt.Sprintf("UnaryExpression(sign=%s term=%s Line=%d Col=%d)",
		t.Val, u.Term, t.Line, t.Col)
}

type BinaryExpression struct {
	Left     Expression
	Right    Expression
	Operator *BinOperator
}

func (b *BinaryExpression) Position() *tokens.Token { return b.Left.Position() }
func (expr *BinaryExpression) String() string {
	t := expr.Position()

	return fmt.Sprintf("BinaryExpression(operator=%s left=%s right=%s Line=%d Col=%d)",
		expr.Operator.Token.Val, expr.Left, expr.Right, t.Line, t.Col)
}

type BinOperator struct {
	Token *tokens.Token
}

func (op BinOperator) Position() *tokens.Token { return op.Token }
func (op BinOperator) String() string          { return op.Token.String() }

type StatementBlock struct {
	Location *tokens.Token
	Name     string
	Stmt     Statement
	Trim     *Trim
	LStrip   bool
}

func (s StatementBlock) Position() *tokens.Token { return s.Location }
func (s StatementBlock) String() string {
	t := s.Position()

	return fmt.Sprintf("StatementBlock(Name=%s Impl=%s Line=%d Col=%d)",
		s.Name, s.Stmt, t.Line, t.Col)
}

type Wrapper struct {
	Location *tokens.Token
	Nodes    []Node
	EndTag   string
	Trim     *Trim
	LStrip   bool
}

func (w Wrapper) Position() *tokens.Token { return w.Location }
func (w Wrapper) String() string {
	t := w.Position()

	return fmt.Sprintf("Wrapper(Nodes=%s EndTag=%s Line=%d Col=%d)",
		w.Nodes, w.EndTag, t.Line, t.Col)
}

type Macro struct {
	Location *tokens.Token
	Name     string
	Args     []string
	Kwargs   []*Pair
	Wrapper  *Wrapper
}

func (m *Macro) Position() *tokens.Token { return m.Location }
func (m *Macro) String() string {
	t := m.Position()
	return fmt.Sprintf("Macro(Name=%s Args=%s Kwargs=%s Line=%d Col=%d)", m.Name, m.Args, m.Kwargs, t.Line, t.Col)
}


<|start_filename|>exec/varargs_test.go<|end_filename|>
package exec_test

import (
	// "fmt"

	"testing"

	"github.com/noirbizarre/gonja/exec"
	"github.com/stretchr/testify/assert"
)

func failsafe(t *testing.T) {
	if err := recover(); err != nil {
		t.Error(err)
	}
}

func TestVarArgs(t *testing.T) {
	t.Run("first", testVAFirst)
	t.Run("GetKwarg", testVAGetKwarg)
	t.Run("Expect", testVAExpect)
}

func testVAFirst(t *testing.T) {
	t.Run("nil if empty", func(t *testing.T) {
		defer failsafe(t)
		assert := assert.New(t)

		va := exec.VarArgs{}
		first := va.First()
		assert.True(first.IsNil())
	})
	t.Run("first value", func(t *testing.T) {
		defer failsafe(t)
		assert := assert.New(t)

		va := exec.VarArgs{Args: []*exec.Value{exec.AsValue(42)}}
		first := va.First()
		assert.Equal(42, first.Integer())
	})
}

func testVAGetKwarg(t *testing.T) {
	t.Run("value if found", func(t *testing.T) {
		defer failsafe(t)
		assert := assert.New(t)

		va := exec.VarArgs{KwArgs: map[string]*exec.Value{
			"key": exec.AsValue(42),
		}}
		kwarg := va.GetKwarg("key", "not found")
		assert.Equal(42, kwarg.Integer())
	})
	t.Run("defaut if missing", func(t *testing.T) {
		defer failsafe(t)
		assert := assert.New(t)

		va := exec.VarArgs{}
		kwarg := va.GetKwarg("missing", "not found")
		assert.Equal("not found", kwarg.String())
	})
}

var nothingCases = []struct {
	name  string
	va    *exec.VarArgs
	error string
}{
	{"got nothing", &exec.VarArgs{}, ""}, {
		"got an argument",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42)}},
		`Unexpected argument '42'`,
	}, {
		"got multiples arguments",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42), exec.AsValue(7)}},
		`Unexpected arguments '42, 7'`,
	}, {
		"got a keyword argument",
		&exec.VarArgs{KwArgs: map[string]*exec.Value{
			"key": exec.AsValue(42),
		}},
		`Unexpected keyword argument 'key=42'`,
	}, {
		"got multiple keyword arguments",
		&exec.VarArgs{KwArgs: map[string]*exec.Value{
			"key":   exec.AsValue(42),
			"other": exec.AsValue(7),
		}},
		`Unexpected keyword arguments 'key=42, other=7'`,
	}, {
		"got one of each",
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"key": exec.AsValue(42),
			},
		},
		`Unexpected arguments '42, key=42'`,
	},
}

var argsCases = []struct {
	name  string
	va    *exec.VarArgs
	args  int
	error string
}{
	{
		"got expected",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42), exec.AsValue(7)}},
		2, "",
	}, {
		"got less arguments",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42)}},
		2, `Expected 2 arguments, got 1`,
	}, {
		"got less arguments (singular)",
		&exec.VarArgs{},
		1, `Expected an argument, got 0`,
	}, {
		"got more arguments",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42), exec.AsValue(7)}},
		1, `Unexpected argument '7'`,
	}, {
		"got a keyword argument",
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"key": exec.AsValue(42),
			},
		},
		1, `Unexpected keyword argument 'key=42'`,
	},
}

var kwargsCases = []struct {
	name   string
	va     *exec.VarArgs
	kwargs []*exec.KwArg
	error  string
}{
	{
		"got expected",
		&exec.VarArgs{KwArgs: map[string]*exec.Value{
			"key":   exec.AsValue(42),
			"other": exec.AsValue(7),
		}},
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		"",
	}, {
		"got unexpected arguments",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42), exec.AsValue(7), exec.AsValue("unexpected")}},
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		`Unexpected argument 'unexpected'`,
	}, {
		"got an unexpected keyword argument",
		&exec.VarArgs{KwArgs: map[string]*exec.Value{
			"unknown": exec.AsValue(42),
		}},
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		`Unexpected keyword argument 'unknown=42'`,
	}, {
		"got multiple keyword arguments",
		&exec.VarArgs{KwArgs: map[string]*exec.Value{
			"unknown": exec.AsValue(42),
			"seven":   exec.AsValue(7),
		}},
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		`Unexpected keyword arguments 'seven=7, unknown=42'`,
	},
}

var mixedArgsKwargsCases = []struct {
	name     string
	va       *exec.VarArgs
	args     int
	kwargs   []*exec.KwArg
	expected *exec.VarArgs
	error    string
}{
	{
		"got expected",
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"key":   exec.AsValue(42),
				"other": exec.AsValue(7),
			},
		},
		1,
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"key":   exec.AsValue(42),
				"other": exec.AsValue(7),
			},
		},
		"",
	},
	{
		"fill with default",
		&exec.VarArgs{Args: []*exec.Value{exec.AsValue(42)}},
		1,
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"key":   exec.AsValue("default key"),
				"other": exec.AsValue("default other"),
			},
		},
		"",
	},
	{
		"keyword as argument",
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42), exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"other": exec.AsValue(7),
			},
		},
		1,
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42)},
			KwArgs: map[string]*exec.Value{
				"key":   exec.AsValue(42),
				"other": exec.AsValue(7),
			},
		},
		"",
	},
	{
		"keyword submitted twice",
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42), exec.AsValue(5)},
			KwArgs: map[string]*exec.Value{
				"key":   exec.AsValue(42),
				"other": exec.AsValue(7),
			},
		},
		1,
		[]*exec.KwArg{
			{"key", "default key"},
			{"other", "default other"},
		},
		&exec.VarArgs{
			Args: []*exec.Value{exec.AsValue(42), exec.AsValue(5)},
			KwArgs: map[string]*exec.Value{
				"key":   exec.AsValue(42),
				"other": exec.AsValue(7),
			},
		},
		`Keyword 'key' has been submitted twice`,
	},
}

func assertError(t *testing.T, rva *exec.ReducedVarArgs, expected string) {
	assert := assert.New(t)
	if len(expected) > 0 {
		if assert.True(rva.IsError(), "Should have returned an error") {
			assert.Equal(expected, rva.Error())
		}
	} else {
		assert.Falsef(rva.IsError(), "Unexpected error: %s", rva.Error())
	}
}

func testVAExpect(t *testing.T) {
	t.Run("nothing", func(t *testing.T) {
		for _, tc := range nothingCases {
			test := tc
			t.Run(test.name, func(t *testing.T) {
				defer failsafe(t)
				rva := test.va.ExpectNothing()
				assertError(t, rva, test.error)
			})
		}
	})
	t.Run("arguments", func(t *testing.T) {
		for _, tc := range argsCases {
			test := tc
			t.Run(test.name, func(t *testing.T) {
				defer failsafe(t)
				rva := test.va.ExpectArgs(test.args)
				assertError(t, rva, test.error)
			})
		}
	})
	t.Run("keyword arguments", func(t *testing.T) {
		for _, tc := range kwargsCases {
			test := tc
			t.Run(test.name, func(t *testing.T) {
				defer failsafe(t)
				rva := test.va.Expect(0, test.kwargs)
				assertError(t, rva, test.error)
			})
		}
	})
	t.Run("mixed argmuents", func(t *testing.T) {
		for _, tc := range mixedArgsKwargsCases {
			test := tc
			t.Run(test.name, func(t *testing.T) {
				defer failsafe(t)
				assert := assert.New(t)
				rva := test.va.Expect(test.args, test.kwargs)
				assertError(t, rva, test.error)
				if assert.Equal(len(test.expected.Args), len(rva.Args)) {
					for idx, expected := range test.expected.Args {
						arg := rva.Args[idx]
						assert.Equalf(expected.Interface(), arg.Interface(),
							`Argument %d mismatch: expected '%s' got '%s'`,
							idx, expected.String(), arg.String(),
						)
					}
				}
				if assert.Equal(len(test.expected.KwArgs), len(rva.KwArgs)) {
					for key, expected := range test.expected.KwArgs {
						if assert.Contains(rva.KwArgs, key) {
							value := rva.KwArgs[key]
							assert.Equalf(expected.Interface(), value.Interface(),
								`Keyword argument %s mismatch: expected '%s' got '%s'`,
								key, expected.String(), value.String(),
							)

						}
					}
				}
			})
		}
	})
}


<|start_filename|>nodes/walk.go<|end_filename|>
package nodes

import (
	"github.com/pkg/errors"
)

type Visitor interface {
	Visit(node Node) (Visitor, error)
}

// type Visitor interface {
// 	Template(node *Template) error
// 	Comment(node *Template) error
// 	Data(node *Data) error
// 	Output(node *Output) error
// 	Statement(node *Statement) error
// }

func Walk(v Visitor, node Node) error {
	v, err := v.Visit(node)
	if err != nil {
		return err
	}
	if v == nil {
		return nil
	}

	switch n := node.(type) {
	case *Template:
		for _, node := range n.Nodes {
			if err := Walk(v, node); err != nil {
				return err
			}
		}
	case *Wrapper:
		for _, node := range n.Nodes {
			if err := Walk(v, node); err != nil {
				return err
			}
		}
	// case *Data:
	// 	return visitor.Data(t)
	// case *Output:
	// 	return visitor.Output(t)
	default:
		return errors.Errorf("Unkown type %T", n)
	}
	return nil
}

type Inspector func(Node) bool

func (f Inspector) Visit(node Node) (Visitor, error) {
	if f(node) {
		return f, nil
	}
	return nil, nil
}

// Inspect traverses an AST in depth-first order: It starts by calling
// f(node); node must not be nil. If f returns true, Inspect invokes f
// recursively for each of the non-nil children of node, followed by a
// call of f(nil).
//
func Inspect(node Node, f func(Node) bool) {
	Walk(Inspector(f), node)
}

// type NoOpVisitor struct {}

// func (v *NoOpVisitor) Template(node *Template) error {
// 	return nil
// }
// func (v *NoOpVisitor) Comment(node *Template) error {
// 	return nil
// }
// func (v *NoOpVisitor) Data(node *Data) error {
// 	return nil
// }
// func (v *NoOpVisitor) Output(node *Output) error {
// 	return nil
// }
// func (v *NoOpVisitor) Statement(node *Statement) error {
// 	return nil
// }


<|start_filename|>exec/statement.go<|end_filename|>
package exec

/* Incomplete:
   -----------

   verbatim (only the "name" argument is missing for verbatim)

   Reconsideration:
   ----------------

   debug (reason: not sure what to output yet)
   regroup / Grouping on other properties (reason: maybe too python-specific; not sure how useful this would be in Go)

   Following built-in tags wont be added:
   --------------------------------------

   csrf_token (reason: web-framework specific)
   load (reason: python-specific)
   url (reason: web-framework specific)
*/

import (
	// "fmt"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	// "github.com/noirbizarre/gonja/tokens"
)

// type NodeStatement interface {
// 	astNode
// }

// This is the function signature of the tag's parser you will have
// to implement in order to create a new tag.
//
// 'doc' is providing access to the whole document while 'arguments'
// is providing access to the user's arguments to the tag:
//
//     {% your_tag_name some "arguments" 123 %}
//
// start_token will be the *Token with the tag's name in it (here: your_tag_name).
//
// Please see the Parser documentation on how to use the parser.
// See RegisterTag()'s documentation for more information about
// writing a tag as well.

// type StatementExecutor func(*nodes.Node, *ExecutionContext) *Value

type Statement interface {
	nodes.Statement
	Execute(*Renderer, *nodes.StatementBlock) error
}

type StatementSet map[string]parser.StatementParser

// Exists returns true if the given test is already registered
func (ss StatementSet) Exists(name string) bool {
	_, existing := ss[name]
	return existing
}

// Registers a new tag. You usually want to call this
// function in the tag's init() function:
// http://golang.org/doc/effective_go.html#init
//
// See http://www.florian-schlachter.de/post/gonja/ for more about
// writing filters and tags.
func (ss *StatementSet) Register(name string, parser parser.StatementParser) error {
	if ss.Exists(name) {
		return errors.Errorf("Statement '%s' is already registered", name)
	}
	(*ss)[name] = parser
	// &statement{
	// 	name:   name,
	// 	parser: parserFn,
	// }
	return nil
}

// Replaces an already registered tag with a new implementation. Use this
// function with caution since it allows you to change existing tag behaviour.
func (ss *StatementSet) Replace(name string, parser parser.StatementParser) error {
	if !ss.Exists(name) {
		return errors.Errorf("Statement '%s' does not exist (therefore cannot be overridden)", name)
	}
	(*ss)[name] = parser
	// statements[name] = &statement{
	// 	name:   name,
	// 	parser: parserFn,
	// }
	return nil
}

func (ss *StatementSet) Update(other StatementSet) StatementSet {
	for name, parser := range other {
		(*ss)[name] = parser
	}
	return *ss
}

// func (ss StatementSet) Parsers() map[string]parser.StatementParser {
// 	parsers := map[string]parser.StatementParser{}
// 	for key, specs := range ss {
// 		parsers[key] = specs.Parse
// 	}
// 	return parsers
// }

// // Tag = "{%" IDENT ARGS "%}"
// func (p *Parser) ParseStatement() (ast.Statement, *Error) {
// 	p.Consume() // consume "{%"
// 	tokenName := p.MatchType(TokenIdentifier)

// 	// Check for identifier
// 	if tokenName == nil {
// 		return nil, p.Error("Statement name must be an identifier.", nil)
// 	}

// 	// Check for the existing statement
// 	stmt, exists := statements[tokenName.Val]
// 	if !exists {
// 		// Does not exists
// 		return nil, p.Error(fmt.Sprintf("Statement '%s' not found (or beginning not provided)", tokenName.Val), tokenName)
// 	}

// 	// Check sandbox tag restriction
// 	if _, isBanned := p.bannedStmts[tokenName.Val]; isBanned {
// 		return nil, p.Error(fmt.Sprintf("Usage of statement '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
// 	}

// 	var argsToken []*Token
// 	for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
// 		// Add token to args
// 		argsToken = append(argsToken, p.Current())
// 		p.Consume() // next token
// 	}

// 	// EOF?
// 	if p.Remaining() == 0 {
// 		return nil, p.Error("Unexpectedly reached EOF, no statement end found.", p.lastToken)
// 	}

// 	p.Match(TokenSymbol, "%}")

// 	argParser := newParser(p.name, argsToken, p.template)
// 	if len(argsToken) == 0 {
// 		// This is done to have nice EOF error messages
// 		argParser.lastToken = tokenName
// 	}

// 	p.template.level++
// 	defer func() { p.template.level-- }()
// 	return stmt.parser(p, tokenName, argParser)
// }


<|start_filename|>builtins/statements/extends.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type ExtendsStmt struct {
	Location    *tokens.Token
	Filename    string
	WithContext bool
}

func (stmt *ExtendsStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *ExtendsStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("ExtendsStmt(Filename=%s Line=%d Col=%d)", stmt.Filename, t.Line, t.Col)
}

func (node *ExtendsStmt) Execute(r *exec.Renderer) error {
	return nil
}

func extendsParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &ExtendsStmt{
		Location: p.Current(),
	}

	if p.Level > 1 {
		return nil, args.Error(`The 'extends' statement can only be defined at root level`, p.Current())
	}

	if p.Template.Parent != nil {
		return nil, args.Error("This template has already one parent.", args.Current())
	}

	// var filename nodes.Node
	if filename := args.Match(tokens.String); filename != nil {
		stmt.Filename = filename.Val
		tpl, err := p.TemplateParser(stmt.Filename)
		if err != nil {
			return nil, errors.Wrapf(err, `Unable to parse parent template '%s'`, stmt.Filename)
		}
		p.Template.Parent = tpl
	} else {
		return nil, args.Error("Tag 'extends' requires a template filename as string.", args.Current())
	}

	if tok := args.MatchName("with", "without"); tok != nil {
		if args.MatchName("context") != nil {
			stmt.WithContext = tok.Val == "with"
		} else {
			args.Stream.Backup()
		}
	}

	if !args.End() {
		return nil, args.Error("Tag 'extends' does only take 1 argument.", nil)
	}

	return stmt, nil
}

func init() {
	All.Register("extends", extendsParser)
}


<|start_filename|>ext/django/statements/firstof.go<|end_filename|>
package statements

import (
	// "github.com/noirbizarre/gonja/exec"
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type FirstofStmt struct {
	Location *tokens.Token
	Args     []nodes.Expression
}

func (stmt *FirstofStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *FirstofStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("FirstofStmt(Args=%s, Line=%d Col=%d)", stmt.Args, t.Line, t.Col)
}

func (stmt *FirstofStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	for _, arg := range stmt.Args {
		val := r.Eval(arg)
		if val.IsError() {
			return val
		}

		if val.IsTrue() {
			r.RenderValue(val)
			return nil
		}
	}

	return nil
}

func firstofParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &FirstofStmt{
		Location: p.Current(),
	}

	for !args.End() {
		node, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Args = append(stmt.Args, node)
	}

	return stmt, nil
}

func init() {
	All.Register("firstof", firstofParser)
}


<|start_filename|>gonja.go<|end_filename|>
package gonja

import (
	"github.com/noirbizarre/gonja/config"
	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/loaders"
)

var (
	// DefaultLoader is being used by the DefaultSet.
	DefaultLoader = loaders.MustNewFileSystemLoader("")

	// DefaultEnv is an environment created for quick/standalone template rendering.
	DefaultEnv = NewEnvironment(config.DefaultConfig, DefaultLoader)

	// Methods on the default set
	FromString = DefaultEnv.FromString
	FromBytes  = DefaultEnv.FromBytes
	FromFile   = DefaultEnv.FromFile
	FromCache  = DefaultEnv.FromCache

	// Globals for the default set
	Globals = DefaultEnv.Globals
)

// Must panics, if a Template couldn't successfully parsed. This is how you
// would use it:
//     var baseTemplate = gonja.Must(gonja.FromFile("templates/base.html"))
func Must(tpl *exec.Template, err error) *exec.Template {
	if err != nil {
		panic(err)
	}
	return tpl
}


<|start_filename|>builtins/statements/set.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
	"github.com/pkg/errors"
)

type SetStmt struct {
	Location   *tokens.Token
	Target     nodes.Expression
	Expression nodes.Expression
}

func (stmt *SetStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *SetStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("SetStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *SetStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	// Evaluate expression
	value := r.Eval(stmt.Expression)
	if value.IsError() {
		return value
	}

	switch n := stmt.Target.(type) {
	case *nodes.Name:
		r.Ctx.Set(n.Name.Val, value.Interface())
	case *nodes.Getattr:
		target := r.Eval(n.Node)
		if target.IsError() {
			return errors.Wrapf(target, `Unable to evaluate target %s`, n)
		}
		if err := target.Set(n.Attr, value.Interface()); err != nil {
			return errors.Wrapf(err, `Unable to set value on "%s"`, n.Attr)
		}
	case *nodes.Getitem:
		target := r.Eval(n.Node)
		if target.IsError() {
			return errors.Wrapf(target, `Unable to evaluate target %s`, n)
		}
		if err := target.Set(n.Arg, value.Interface()); err != nil {
			return errors.Wrapf(err, `Unable to set value on "%s"`, n.Arg)
		}
	default:
		return errors.Errorf(`Illegal set target node %s`, n)
	}

	return nil
}

func setParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &SetStmt{
		Location: p.Current(),
	}

	// Parse variable name
	ident, err := args.ParseVariable()
	if err != nil {
		return nil, errors.Wrap(err, `Unable to parse identifier`)
	}
	switch n := ident.(type) {
	case *nodes.Name, *nodes.Call, *nodes.Getitem, *nodes.Getattr:
		stmt.Target = n
	default:
		return nil, errors.Errorf(`Unexpected set target %s`, n)
	}

	if args.Match(tokens.Assign) == nil {
		return nil, args.Error("Expected '='.", args.Current())
	}

	// Variable expression
	expr, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	stmt.Expression = expr

	// Remaining arguments
	if !args.End() {
		return nil, args.Error("Malformed 'set'-tag args.", args.Current())
	}

	return stmt, nil
}

func init() {
	All.Register("set", setParser)
}


<|start_filename|>exec/renderer.go<|end_filename|>
package exec

import (
	"strings"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
)

// TrimState stores and apply trim policy
type TrimState struct {
	Should      bool
	ShouldBlock bool
	Buffer      *strings.Builder
}

func (ts *TrimState) TrimBlocks(r rune) bool {
	if ts.ShouldBlock {
		switch r {
		case '\n':
			ts.ShouldBlock = false
			return true
		case ' ', '\t':
			return true
		default:
			return false
		}
	}
	return false
}

// Renderer is a node visitor in charge of rendering
type Renderer struct {
	*EvalConfig
	Ctx      *Context
	Template *Template
	Root     *nodes.Template
	Out      *strings.Builder
	Trim     *TrimState
}

// NewRenderer initialize a new renderer
func NewRenderer(ctx *Context, out *strings.Builder, cfg *EvalConfig, tpl *Template) *Renderer {
	var buffer strings.Builder
	r := &Renderer{
		EvalConfig: cfg,
		Ctx:        ctx,
		Template:   tpl,
		Root:       tpl.Root,
		Out:        out,
		Trim:       &TrimState{Buffer: &buffer},
	}
	r.Ctx.Set("self", Self(r))
	return r
}

// Inherit creates a new sub renderer
func (r *Renderer) Inherit() *Renderer {
	sub := &Renderer{
		EvalConfig: r.EvalConfig.Inherit(),
		Ctx:        r.Ctx.Inherit(),
		Template:   r.Template,
		Root:       r.Root,
		Out:        r.Out,
		Trim:       r.Trim,
	}
	return sub
}

func (r *Renderer) Flush(lstrip bool) {
	r.FlushAndTrim(false, lstrip)
}

func (r *Renderer) FlushAndTrim(trim, lstrip bool) {
	txt := r.Trim.Buffer.String()
	if r.Config.LstripBlocks && !lstrip {
		lines := strings.Split(txt, "\n")
		last := lines[len(lines)-1]
		lines[len(lines)-1] = strings.TrimLeft(last, " \t")
		txt = strings.Join(lines, "\n")
	}
	if trim {
		txt = strings.TrimRight(txt, " \t\n")
	}
	r.Out.WriteString(txt)
	r.Trim.Buffer.Reset()
}

// WriteString wraps the triming policy
func (r *Renderer) WriteString(txt string) (int, error) {
	if r.Config.TrimBlocks {
		txt = strings.TrimLeftFunc(txt, r.Trim.TrimBlocks)
	}
	if r.Trim.Should {
		txt = strings.TrimLeft(txt, " \t\n")
		if len(txt) > 0 {
			r.Trim.Should = false
		}
	}
	return r.Trim.Buffer.WriteString(txt)
}

// RenderValue properly render a value
func (r *Renderer) RenderValue(value *Value) {
	if r.Autoescape && value.IsString() && !value.Safe {
		r.WriteString(value.Escaped())
	} else {
		r.WriteString(value.String())
	}
}

func (r *Renderer) StartTag(trim *nodes.Trim, lstrip bool) {
	if trim == nil {
		r.Flush(lstrip)
	} else {
		r.FlushAndTrim(trim.Left, lstrip)
	}
	r.Trim.Should = false
}

func (r *Renderer) EndTag(trim *nodes.Trim) {
	if trim == nil {
		return
	}
	r.Trim.Should = trim.Right
}

func (r *Renderer) Tag(trim *nodes.Trim, lstrip bool) {
	r.StartTag(trim, lstrip)
	r.EndTag(trim)
}

// Visit implements the nodes.Visitor interface
func (r *Renderer) Visit(node nodes.Node) (nodes.Visitor, error) {
	switch n := node.(type) {
	case *nodes.Comment:
		r.Tag(n.Trim, false)
		return nil, nil
	case *nodes.Data:
		r.WriteString(n.Data.Val)
		return nil, nil
	case *nodes.Output:
		r.StartTag(n.Trim, false)
		value := r.Eval(n.Expression)
		if value.IsError() {
			return nil, errors.Wrapf(value, `Unable to render expression '%s'`, n.Expression)
		}
		r.RenderValue(value)
		r.EndTag(n.Trim)
		return nil, nil
	case *nodes.StatementBlock:
		r.Tag(n.Trim, n.LStrip)
		r.Trim.ShouldBlock = r.Config.TrimBlocks
		stmt, ok := n.Stmt.(Statement)
		if ok {
			// Silently ignore non executable statements
			// return nil, nil
			// return nil, errors.Errorf(`Unable to execute statement '%s'`, n.Stmt)
			if err := stmt.Execute(r, n); err != nil {
				return nil, errors.Wrapf(err, `Unable to execute statement '%s'`, n.Stmt)
			}
		}
		return nil, nil
	default:
		return r, nil
	}
}

// ExecuteWrapper wraps the nodes.Wrapper execution logic
func (r *Renderer) ExecuteWrapper(wrapper *nodes.Wrapper) error {
	sub := r.Inherit()
	err := nodes.Walk(sub, wrapper)
	sub.Tag(wrapper.Trim, wrapper.LStrip)
	r.Trim.ShouldBlock = r.Config.TrimBlocks
	return err
}

func (r *Renderer) LStrip() {
}

func (r *Renderer) Execute() error {
	// Determine the parent to be executed (for template inheritance)
	root := r.Root
	for root.Parent != nil {
		root = root.Parent
	}

	err := nodes.Walk(r, root)
	if err == nil {
		r.Flush(false)
	}
	return err
}

func (r *Renderer) String() string {
	r.Flush(false)
	out := r.Out.String()
	if !r.Config.KeepTrailingNewline {
		out = strings.TrimSuffix(out, "\n")
	}
	return out
}


<|start_filename|>testutils/helpers.go<|end_filename|>
package testutils

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"math/rand"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"testing"

	"github.com/pmezard/go-difflib/difflib"

	"github.com/noirbizarre/gonja"
	"github.com/noirbizarre/gonja/loaders"

	u "github.com/noirbizarre/gonja/utils"
)

func TestEnv(root string) *gonja.Environment {
	cfg := gonja.NewConfig()
	cfg.KeepTrailingNewline = true
	loader := loaders.MustNewFileSystemLoader(root)
	env := gonja.NewEnvironment(cfg, loader)
	env.Autoescape = true
	env.Globals.Set("lorem", u.Lorem) // Predictable random content
	return env
}

func GlobTemplateTests(t *testing.T, root string, env *gonja.Environment) {
	pattern := filepath.Join(root, `*.tpl`)
	matches, err := filepath.Glob(pattern)
	// env := TestEnv(root)
	if err != nil {
		t.Fatal(err)
	}
	for _, match := range matches {
		filename, err := filepath.Rel(root, match)
		if err != nil {
			t.Fatalf("Unable to compute path from `%s`:\n%s", match, err.Error())
		}
		testName := strings.Replace(path.Base(match), ".tpl", "", 1)
		t.Run(testName, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()

			rand.Seed(42) // Make tests deterministics

			tpl, err := env.FromFile(filename)
			if err != nil {
				t.Fatalf("Error on FromFile('%s'):\n%s", filename, err.Error())
			}
			testFilename := fmt.Sprintf("%s.out", match)
			expected, rerr := ioutil.ReadFile(testFilename)
			if rerr != nil {
				t.Fatalf("Error on ReadFile('%s'):\n%s", testFilename, rerr.Error())
			}
			rendered, err := tpl.ExecuteBytes(Fixtures)
			if err != nil {
				t.Fatalf("Error on Execute('%s'):\n%s", filename, err.Error())
			}
			// rendered = testTemplateFixes.fixIfNeeded(filename, rendered)
			if bytes.Compare(expected, rendered) != 0 {
				diff := difflib.UnifiedDiff{
					A:        difflib.SplitLines(string(expected)),
					B:        difflib.SplitLines(string(rendered)),
					FromFile: "Expected",
					ToFile:   "Rendered",
					Context:  2,
					Eol:      "\n",
				}
				result, _ := difflib.GetUnifiedDiffString(diff)
				t.Errorf("%s rendered with diff:\n%v", testFilename, result)
			}
		})
	}
}

func GlobErrorTests(t *testing.T, root string) {
	pattern := filepath.Join(root, `*.err`)
	matches, err := filepath.Glob(pattern)
	env := TestEnv(root)
	if err != nil {
		t.Fatal(err)
	}
	for _, match := range matches {
		testName := strings.Replace(path.Base(match), ".err", "", 1)
		t.Run(testName, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()

			testData, err := ioutil.ReadFile(match)
			tests := strings.Split(string(testData), "\n")

			checkFilename := fmt.Sprintf("%s.out", match)
			checkData, err := ioutil.ReadFile(checkFilename)
			if err != nil {
				t.Fatalf("Error on ReadFile('%s'):\n%s", checkFilename, err.Error())
			}
			checks := strings.Split(string(checkData), "\n")

			if len(checks) != len(tests) {
				t.Fatal("Template lines != Checks lines")
			}

			for idx, test := range tests {
				if strings.TrimSpace(test) == "" {
					continue
				}
				if strings.TrimSpace(checks[idx]) == "" {
					t.Fatalf("[%s Line %d] Check is empty (must contain an regular expression).",
						match, idx+1)
				}

				tpl, err := env.FromString(test)
				if err != nil {
					t.Fatalf("Error on FromString('%s'):\n%s", test, err.Error())
				}

				tpl, err = env.FromBytes([]byte(test))
				if err != nil {
					t.Fatalf("Error on FromBytes('%s'):\n%s", test, err.Error())
				}

				_, err = tpl.ExecuteBytes(Fixtures)
				if err == nil {
					t.Fatalf("[%s Line %d] Expected error for (got none): %s",
						match, idx+1, tests[idx])
				}

				re := regexp.MustCompile(fmt.Sprintf("^%s$", checks[idx]))
				if !re.MatchString(err.Error()) {
					t.Fatalf("[%s Line %d] Error for '%s' (err = '%s') does not match the (regexp-)check: %s",
						match, idx+1, test, err.Error(), checks[idx])
				}
			}
		})
	}
}


<|start_filename|>config/config.go<|end_filename|>
package config

type Inheritable interface {
	Inherit() Inheritable
}

// Config holds plexer and parser parameters
type Config struct {
	Debug bool
	// The string marking the beginning of a block. Defaults to '{%'
	BlockStartString string
	// The string marking the end of a block. Defaults to '%}'.
	BlockEndString string
	// The string marking the beginning of a print statement. Defaults to '{{'.
	VariableStartString string
	// The string marking the end of a print statement. Defaults to '}}'.
	VariableEndString string
	// The string marking the beginning of a comment. Defaults to '{#'.
	CommentStartString string
	// The string marking the end of a comment. Defaults to '#}'.
	CommentEndString string
	// If given and a string, this will be used as prefix for line based statements.
	// See also Line Statements.
	LineStatementPrefix string
	// If given and a string, this will be used as prefix for line based comments.
	// See also Line Statements.
	LineCommentPrefix string
	// If this is set to True the first newline after a block is removed (block, not variable tag!).
	// Defaults to False.
	TrimBlocks bool
	// If this is set to True leading spaces and tabs are stripped from the start of a line to a block.
	// Defaults to False.
	LstripBlocks bool
	// The sequence that starts a newline.
	// Must be one of '\r', '\n' or '\r\n'.
	// The default is '\n' which is a useful default for Linux and OS X systems as well as web applications.
	NewlineSequence string
	// Preserve the trailing newline when rendering templates.
	// The default is False, which causes a single newline,
	// if present, to be stripped from the end of the template.
	KeepTrailingNewline bool
	// If set to True the XML/HTML autoescaping feature is enabled by default.
	// For more details about autoescaping see Markup.
	// This can also be a callable that is passed the template name
	// and has to return True or False depending on autoescape should be enabled by default.
	Autoescape bool

	// Allow extensions to store some config
	Ext map[string]Inheritable
}

func NewConfig() *Config {
	return &Config{
		Debug:               false,
		BlockStartString:    "{%",
		BlockEndString:      "%}",
		VariableStartString: "{{",
		VariableEndString:   "}}",
		CommentStartString:  "{#",
		CommentEndString:    "#}",
		TrimBlocks:          false,
		LstripBlocks:        false,
		NewlineSequence:     "\n",
		KeepTrailingNewline: false,
		Autoescape:          false,
		Ext:                 map[string]Inheritable{},
	}
}

func (cfg *Config) Inherit() *Config {
	ext := map[string]Inheritable{}
	for key, cfg := range cfg.Ext {
		ext[key] = cfg.Inherit()
	}
	return &Config{
		Debug:               cfg.Debug,
		BlockStartString:    cfg.BlockStartString,
		BlockEndString:      cfg.BlockEndString,
		VariableStartString: cfg.VariableStartString,
		VariableEndString:   cfg.VariableEndString,
		CommentStartString:  cfg.CommentStartString,
		CommentEndString:    cfg.CommentEndString,
		TrimBlocks:          cfg.TrimBlocks,
		LstripBlocks:        cfg.LstripBlocks,
		NewlineSequence:     cfg.NewlineSequence,
		KeepTrailingNewline: cfg.KeepTrailingNewline,
		Autoescape:          cfg.Autoescape,
		Ext:                 ext,
	}
}

// DefaultConfig is a configuration with default values
var DefaultConfig = NewConfig()


<|start_filename|>builtins/statements/if.go<|end_filename|>
package statements

import (
	"fmt"

	log "github.com/sirupsen/logrus"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type IfStmt struct {
	Location   *tokens.Token
	conditions []nodes.Expression
	wrappers   []*nodes.Wrapper
}

func (stmt *IfStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *IfStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("IfStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (node *IfStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	for i, condition := range node.conditions {
		result := r.Eval(condition)
		if result.IsError() {
			return result
		}

		if result.IsTrue() {
			return r.ExecuteWrapper(node.wrappers[i])
		}
		// Last condition?
		if len(node.conditions) == i+1 && len(node.wrappers) > i+1 {
			return r.ExecuteWrapper(node.wrappers[i+1])
		}
	}
	return nil
}

func ifParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	log.WithFields(log.Fields{
		"arg":     args.Current(),
		"current": p.Current(),
	}).Trace("ParseIf")
	ifNode := &IfStmt{
		Location: args.Current(),
	}

	// Parse first and main IF condition
	condition, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	ifNode.conditions = append(ifNode.conditions, condition)

	if !args.End() {
		return nil, args.Error("If-condition is malformed.", nil)
	}

	// Check the rest
	for {
		wrapper, tagArgs, err := p.WrapUntil("elif", "else", "endif")
		if err != nil {
			return nil, err
		}
		ifNode.wrappers = append(ifNode.wrappers, wrapper)

		if wrapper.EndTag == "elif" {
			// elif can take a condition
			condition, err = tagArgs.ParseExpression()
			if err != nil {
				return nil, err
			}
			ifNode.conditions = append(ifNode.conditions, condition)

			if !tagArgs.End() {
				return nil, tagArgs.Error("Elif-condition is malformed.", nil)
			}
		} else {
			if !tagArgs.End() {
				// else/endif can't take any conditions
				return nil, tagArgs.Error("Arguments not allowed here.", nil)
			}
		}

		if wrapper.EndTag == "endif" {
			break
		}
	}

	return ifNode, nil
}

func init() {
	All.Register("if", ifParser)
}


<|start_filename|>parser/parser.go<|end_filename|>
package parser

import (
	"fmt"
	"strings"

	"github.com/noirbizarre/gonja/config"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
)

// The parser provides you a comprehensive and easy tool to
// work with the template document and arguments provided by
// the user for your custom tag.
//
// The parser works on a token list which will be provided by gonja.
// A token is a unit you can work with. Tokens are either of type identifier,
// string, number, keyword, HTML or symbol.
//
// (See Token's documentation for more about tokens)
type Parser struct {
	Name   string
	Stream *tokens.Stream
	Config *config.Config

	Template       *nodes.Template
	Statements     map[string]StatementParser
	Level          int8
	TemplateParser TemplateParser
}

// Creates a new parser to parse tokens.
// Used inside gonja to parse documents and to provide an easy-to-use
// parser for tag authors
// func NewParser(name string, tokens []*tokens.Token) *Parser {
// 	p := &Parser{
// 		name:          name,
// 		tokens:        tokens,
// 		template:      template,
// 		// bannedStmts:   make(map[string]bool),
// 		// bannedFilters: make(map[string]bool),
// 	}
// 	if len(tokens) > 0 {
// 		p.lastToken = tokens[len(tokens)-1]
// 	}
// 	return p
// }

func NewParser(name string, cfg *config.Config, stream *tokens.Stream) *Parser {
	return &Parser{
		Name:   name,
		Stream: stream,
		Config: cfg,
	}
}

func Parse(input string) (*nodes.Template, error) {
	stream := tokens.Lex(input)
	p := NewParser("parser", config.DefaultConfig, stream)
	return p.Parse()
}

func (p *Parser) Parse() (*nodes.Template, error) {
	// for p.state = parseProg; p.state != nil; {
	// 	p.state = p.state(p)
	// }

	// lex everything
	// t := p.Lexer.NextItem()
	// for ; t.Typ != lex.EOF; t = p.Lexer.NextItem() {
	// 	p.Items = append(p.Items, t)
	// }
	// p.Items = append(p.Items, t)

	// tokens := []*l.Token{}
	// for token := range p.Tokens {
	// 	p.tokens = append(p.tokens, token)
	// }

	return p.ParseTemplate()
}

// Consume one token. It will be gone forever.
func (p *Parser) Consume() {
	p.Stream.Next()
}

// // Consume N tokens. They will be gone forever.
// func (p *Parser) ConsumeN(count int) {
// 	p.idx += count
// }

// Current returns the current token.
func (p *Parser) Current() *tokens.Token {
	return p.Stream.Current()
}

// Next returns and consume the current token
func (p *Parser) Next() *tokens.Token {
	// t := p.Stream.Next()
	// p.Consume()
	// return t
	return p.Stream.Next()
}

func (p *Parser) End() bool {
	return p.Stream.End()
}

// Match returns the CURRENT token if the given type matches.
// Consumes this token on success.
func (p *Parser) Match(types ...tokens.Type) *tokens.Token {
	tok := p.Stream.Current()
	for _, t := range types {
		if tok.Type == t {
			p.Stream.Next()
			return tok
		}
	}
	return nil
}

func (p *Parser) MatchName(names ...string) *tokens.Token {
	t := p.Peek(tokens.Name)
	if t != nil {
		for _, name := range names {
			if t.Val == name {
				return p.Pop()
			}
		}
	}
	// if t != nil && t.Val == name { return p.Pop() }
	return nil
}

// Pop returns the current token and advance to the next
func (p *Parser) Pop() *tokens.Token {
	t := p.Stream.Current()
	p.Stream.Next()
	return t
}

// Peek returns the next token without consuming the current
// if it matches one of the given types
func (p *Parser) Peek(types ...tokens.Type) *tokens.Token {
	tok := p.Stream.Current()
	for _, t := range types {
		if tok.Type == t {
			return tok
		}
	}
	return nil
}

func (p *Parser) PeekName(names ...string) *tokens.Token {
	t := p.Peek(tokens.Name)
	if t != nil {
		for _, name := range names {
			if t.Val == name {
				return t
			}
		}
	}
	// if t != nil && t.Val == name { return t }
	return nil
}

// WrapUntil wraps all nodes between starting tag and "{% endtag %}" and provides
// one simple interface to execute the wrapped nodes.
// It returns a parser to process provided arguments to the tag.
func (p *Parser) WrapUntil(names ...string) (*nodes.Wrapper, *Parser, error) {
	wrapper := &nodes.Wrapper{
		Location: p.Current(),
		Trim:     &nodes.Trim{},
	}

	var args []*tokens.Token

	for !p.Stream.End() {
		// New tag, check whether we have to stop wrapping here
		if begin := p.Match(tokens.BlockBegin); begin != nil {
			ident := p.Peek(tokens.Name)

			if ident != nil {
				// We've found a (!) end-tag

				found := false
				for _, n := range names {
					if ident.Val == n {
						found = true
						break
					}
				}

				// We only process the tag if we've found an end tag
				if found {
					// Okay, endtag found.
					p.Consume() // '{%' tagname
					wrapper.Trim.Left = begin.Val[len(begin.Val)-1] == '-'
					wrapper.LStrip = begin.Val[len(begin.Val)-1] == '+'

					for {
						if end := p.Match(tokens.BlockEnd); end != nil {
							// Okay, end the wrapping here
							wrapper.EndTag = ident.Val
							wrapper.Trim.Right = end.Val[0] == '-'
							stream := tokens.NewStream(args)
							return wrapper, NewParser(p.Name, p.Config, stream), nil
						}
						t := p.Next()
						// p.Consume()
						if t == nil {
							return nil, nil, p.Error("Unexpected EOF.", p.Current())
						}
						args = append(args, t)
					}
				}
			}
			p.Stream.Backup()
		}

		// Otherwise process next element to be wrapped
		node, err := p.parseDocElement()
		if err != nil {
			return nil, nil, err
		}
		wrapper.Nodes = append(wrapper.Nodes, node)
	}

	return nil, nil, p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")),
		p.Current())
}

// Skips all nodes between starting tag and "{% endtag %}"
func (p *Parser) SkipUntil(names ...string) error {
	for !p.End() {
		// New tag, check whether we have to stop wrapping here
		if p.Match(tokens.BlockBegin) != nil {
			ident := p.Peek(tokens.Name)

			if ident != nil {
				// We've found a (!) end-tag

				found := false
				for _, n := range names {
					if ident.Val == n {
						found = true
						break
					}
				}

				// We only process the tag if we've found an end tag
				if found {
					// Okay, endtag found.
					p.Consume() // '{%' tagname

					for {
						if p.Match(tokens.BlockEnd) != nil {
							// Done skipping, exit.
							return nil
						}
					}
				}
			} else {
				p.Stream.Backup()
			}
		}
		t := p.Next()
		if t == nil {
			return p.Error("Unexpected EOF.", p.Current())
		}
	}

	return p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")), p.Current())
}


<|start_filename|>builtins/statements/import.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type ImportStmt struct {
	Location     *tokens.Token
	Filename     string
	FilenameExpr nodes.Expression
	As           string
	WithContext  bool
	Template     *nodes.Template
}

func (stmt *ImportStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *ImportStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("ImportStmt(Line=%d Col=%d)", t.Line, t.Col)
}
func (stmt *ImportStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	var imported map[string]*nodes.Macro
	macros := map[string]exec.Macro{}

	if stmt.FilenameExpr != nil {
		filenameValue := r.Eval(stmt.FilenameExpr)
		if filenameValue.IsError() {
			return errors.Wrap(filenameValue, `Unable to evaluate filename`)
		}

		filename := filenameValue.String()
		tpl, err := r.Loader.GetTemplate(filename)
		if err != nil {
			return errors.Wrapf(err, `Unable to load template '%s'`, filename)
		}
		imported = tpl.Root.Macros

	} else {
		imported = stmt.Template.Macros
	}

	for name, macro := range imported {
		fn, err := exec.MacroNodeToFunc(macro, r)
		if err != nil {
			return errors.Wrapf(err, `Unable to import macro '%s'`, name)
		}
		macros[name] = fn
	}

	r.Ctx.Set(stmt.As, macros)
	return nil
}

type FromImportStmt struct {
	Location     *tokens.Token
	Filename     string
	FilenameExpr nodes.Expression
	WithContext  bool
	Template     *nodes.Template
	As           map[string]string
	Macros       map[string]*nodes.Macro // alias/name -> macro instance
}

func (stmt *FromImportStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *FromImportStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("FromImportStmt(Line=%d Col=%d)", t.Line, t.Col)
}
func (stmt *FromImportStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	var imported map[string]*nodes.Macro

	if stmt.FilenameExpr != nil {
		filenameValue := r.Eval(stmt.FilenameExpr)
		if filenameValue.IsError() {
			return errors.Wrap(filenameValue, `Unable to evaluate filename`)
		}

		filename := filenameValue.String()
		tpl, err := r.Loader.GetTemplate(filename)
		if err != nil {
			return errors.Wrapf(err, `Unable to load template '%s'`, filename)
		}
		imported = tpl.Root.Macros

	} else {
		imported = stmt.Template.Macros
	}

	for alias, name := range stmt.As {
		node := imported[name]
		fn, err := exec.MacroNodeToFunc(node, r)
		if err != nil {
			return errors.Wrapf(err, `Unable to import macro '%s'`, name)
		}
		r.Ctx.Set(alias, fn)
	}
	return nil
}

func importParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &ImportStmt{
		Location: p.Current(),
		// Macros:   map[string]*nodes.Macro{},
	}

	if args.End() {
		return nil, args.Error("You must at least specify one macro to import.", nil)
	}

	if tok := args.Match(tokens.String); tok != nil {
		stmt.Filename = tok.Val
	} else {
		expr, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.FilenameExpr = expr
	}
	if args.MatchName("as") == nil {
		return nil, args.Error(`Expected "as" keyword`, args.Current())
	}

	alias := args.Match(tokens.Name)
	if alias == nil {
		return nil, args.Error("Expected macro alias name (identifier)", args.Current())
	}
	stmt.As = alias.Val

	if tok := args.MatchName("with", "without"); tok != nil {
		if args.MatchName("context") != nil {
			stmt.WithContext = tok.Val == "with"
		} else {
			args.Stream.Backup()
		}
	}

	// Preload static template
	if stmt.Filename != "" {
		tpl, err := p.TemplateParser(stmt.Filename)
		if err != nil {
			return nil, errors.Wrapf(err, `Unable to parse imported template '%s'`, stmt.Filename)
		} else {
			stmt.Template = tpl
		}
	}

	return stmt, nil
}

func fromParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &FromImportStmt{
		Location: p.Current(),
		As:       map[string]string{},
		// Macros:   map[string]*nodes.Macro{},
	}

	if args.End() {
		return nil, args.Error("You must at least specify one macro to import.", nil)
	}

	if tok := args.Match(tokens.String); tok != nil {
		stmt.Filename = tok.Val
	} else {
		filename, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.FilenameExpr = filename
	}

	if args.MatchName("import") == nil {
		return nil, args.Error("Expected import keyword", args.Current())
	}

	for !args.End() {
		name := args.Match(tokens.Name)
		if name == nil {
			return nil, args.Error("Expected macro name (identifier).", args.Current())
		}

		// asName := macroNameToken.Val
		if args.MatchName("as") != nil {
			alias := args.Match(tokens.Name)
			if alias == nil {
				return nil, args.Error("Expected macro alias name (identifier).", nil)
			}
			// asName = aliasToken.Val
			stmt.As[alias.Val] = name.Val
		} else {
			stmt.As[name.Val] = name.Val
		}

		// macroInstance, has := tpl.exportedMacros[macroNameToken.Val]
		// if !has {
		// 	return nil, args.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
		// 		stmt.filename), macroNameToken)
		// }

		// stmt.macros[asName] = macroInstance
		if tok := args.MatchName("with", "without"); tok != nil {
			if args.MatchName("context") != nil {
				stmt.WithContext = tok.Val == "with"
				break
			} else {
				args.Stream.Backup()
			}
		}

		if args.End() {
			break
		}

		if args.Match(tokens.Comma) == nil {
			return nil, args.Error("Expected ','.", nil)
		}
	}

	// Preload static template
	if stmt.Filename != "" {
		tpl, err := p.TemplateParser(stmt.Filename)
		if err != nil {
			return nil, errors.Wrapf(err, `Unable to parse imported template '%s'`, stmt.Filename)
		} else {
			stmt.Template = tpl
		}
	}

	return stmt, nil
}

func init() {
	All.Register("import", importParser)
	All.Register("from", fromParser)
}


<|start_filename|>builtins/filters.go<|end_filename|>
package builtins

import (
	"encoding/json"
	"fmt"
	"math"
	"math/rand"
	"net/url"
	"regexp"
	"sort"
	"strings"
	"time"
	"unicode"
	"unicode/utf8"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	u "github.com/noirbizarre/gonja/utils"
)

func init() {
	rand.Seed(time.Now().Unix())
}

// Filters export all builtin filters
var Filters = exec.FilterSet{
	"abs":            filterAbs,
	"attr":           filterAttr,
	"batch":          filterBatch,
	"capitalize":     filterCapitalize,
	"center":         filterCenter,
	"d":              filterDefault,
	"default":        filterDefault,
	"dictsort":       filterDictSort,
	"e":              filterEscape,
	"escape":         filterEscape,
	"filesizeformat": filterFileSize,
	"first":          filterFirst,
	"float":          filterFloat,
	"forceescape":    filterForceEscape,
	"format":         filterFormat,
	"groupby":        filterGroupBy,
	"indent":         filterIndent,
	"int":            filterInteger,
	"join":           filterJoin,
	"last":           filterLast,
	"length":         filterLength,
	"list":           filterList,
	"lower":          filterLower,
	"map":            filterMap,
	"max":            filterMax,
	"min":            filterMin,
	"pprint":         filterPPrint,
	"random":         filterRandom,
	"reject":         filterReject,
	"rejectattr":     filterRejectAttr,
	"replace":        filterReplace,
	"reverse":        filterReverse,
	"round":          filterRound,
	"safe":           filterSafe,
	"select":         filterSelect,
	"selectattr":     filterSelectAttr,
	"slice":          filterSlice,
	"sort":           filterSort,
	"string":         filterString,
	"striptags":      filterStriptags,
	"sum":            filterSum,
	"title":          filterTitle,
	"tojson":         filterToJSON,
	"trim":           filterTrim,
	"truncate":       filterTruncate,
	"unique":         filterUnique,
	"upper":          filterUpper,
	"urlencode":      filterUrlencode,
	"urlize":         filterUrlize,
	"wordcount":      filterWordcount,
	"wordwrap":       filterWordwrap,
	"xmlattr":        filterXMLAttr,
}

func filterAbs(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'abs'"))
	}
	if in.IsInteger() {
		asInt := in.Integer()
		if asInt < 0 {
			return exec.AsValue(-asInt)
		}
		return in
	} else if in.IsFloat() {
		return exec.AsValue(math.Abs(in.Float()))
	}
	return exec.AsValue(math.Abs(in.Float())) // nothing to do here, just to keep track of the safe application
}

func filterAttr(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.ExpectArgs(1)
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'attr'"))
	}
	attr := p.First().String()
	value, _ := in.Getattr(attr)
	return value
}

func filterBatch(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(1, []*exec.KwArg{{"fill_with", nil}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'batch'"))
	}
	size := p.First().Integer()
	out := []*exec.Value{}
	var row []*exec.Value
	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		if math.Mod(float64(idx), float64(size)) == 0 {
			if row != nil {
				out = append(out, exec.AsValue(row))
			}
			row = []*exec.Value{}
		}
		row = append(row, key)
		return true
	}, func() {})
	if len(row) > 0 {
		fillWith := p.KwArgs["fill_with"]
		if !fillWith.IsNil() {
			for len(row) < size {
				row = append(row, fillWith)
			}
		}
		out = append(out, exec.AsValue(row))
	}
	return exec.AsValue(out)
}

func filterCapitalize(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'capitalize'"))
	}
	if in.Len() <= 0 {
		return exec.AsValue("")
	}
	t := in.String()
	r, size := utf8.DecodeRuneInString(t)
	return exec.AsValue(strings.ToUpper(string(r)) + strings.ToLower(t[size:]))
}

func filterCenter(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.ExpectArgs(1)
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'center'"))
	}
	width := p.First().Integer()
	slen := in.Len()
	if width <= slen {
		return in
	}

	spaces := width - slen
	left := spaces/2 + spaces%2
	right := spaces / 2

	return exec.AsValue(fmt.Sprintf("%s%s%s", strings.Repeat(" ", left),
		in.String(), strings.Repeat(" ", right)))
}

func filterDefault(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(1, []*exec.KwArg{{"boolean", false}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'default'"))
	}
	defaultVal := p.First()
	falsy := p.KwArgs["boolean"]
	if falsy.Bool() && (in.IsError() || !in.IsTrue()) {
		return defaultVal
	} else if in.IsError() || in.IsNil() {
		return defaultVal
	}
	return in
}

func sortByKey(in *exec.Value, caseSensitive bool, reverse bool) [][2]*exec.Value {
	out := [][2]*exec.Value{}
	in.IterateOrder(func(idx, count int, key, value *exec.Value) bool {
		out = append(out, [2]*exec.Value{key, value})
		return true
	}, func() {}, reverse, true, caseSensitive)
	return out
}

func sortByValue(in *exec.Value, caseSensitive, reverse bool) [][2]*exec.Value {
	out := [][2]*exec.Value{}
	items := in.Items()
	var sorter func(i, j int) bool
	switch {
	case caseSensitive && reverse:
		sorter = func(i, j int) bool {
			return items[i].Value.String() > items[j].Value.String()
		}
	case caseSensitive && !reverse:
		sorter = func(i, j int) bool {
			return items[i].Value.String() < items[j].Value.String()
		}
	case !caseSensitive && reverse:
		sorter = func(i, j int) bool {
			return strings.ToLower(items[i].Value.String()) > strings.ToLower(items[j].Value.String())
		}
	case !caseSensitive && !reverse:
		sorter = func(i, j int) bool {
			return strings.ToLower(items[i].Value.String()) < strings.ToLower(items[j].Value.String())
		}
	}
	sort.Slice(items, sorter)
	for _, item := range items {
		out = append(out, [2]*exec.Value{item.Key, item.Value})
	}
	return out
}

func filterDictSort(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"case_sensitive", false},
		{"by", "key"},
		{"reverse", false},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'dictsort'"))
	}

	caseSensitive := p.KwArgs["case_sensitive"].Bool()
	by := p.KwArgs["by"].String()
	reverse := p.KwArgs["reverse"].Bool()

	switch by {
	case "key":
		return exec.AsValue(sortByKey(in, caseSensitive, reverse))
	case "value":
		return exec.AsValue(sortByValue(in, caseSensitive, reverse))
	default:
		return exec.AsValue(errors.New(`by should be either 'key' or 'value`))
	}
}

func filterEscape(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'escape'"))
	}
	if in.Safe {
		return in
	}
	return exec.AsSafeValue(in.Escaped())
}

var (
	bytesPrefixes  = []string{"kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
	binaryPrefixes = []string{"KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
)

func filterFileSize(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"binary", false}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'filesizeformat'"))
	}
	bytes := in.Float()
	binary := p.KwArgs["binary"].Bool()
	var base float64
	var prefixes []string
	if binary {
		base = 1024.0
		prefixes = binaryPrefixes
	} else {
		base = 1000.0
		prefixes = bytesPrefixes
	}
	if bytes == 1.0 {
		return exec.AsValue("1 Byte")
	} else if bytes < base {
		return exec.AsValue(fmt.Sprintf("%.0f Bytes", bytes))
	} else {
		var i int
		var unit float64
		var prefix string
		for i, prefix = range prefixes {
			unit = math.Pow(base, float64(i+2))
			if bytes < unit {
				return exec.AsValue(fmt.Sprintf("%.1f %s", (base * bytes / unit), prefix))
			}
		}
		return exec.AsValue(fmt.Sprintf("%.1f %s", (base * bytes / unit), prefix))
	}
}

func filterFirst(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'first'"))
	}
	if in.CanSlice() && in.Len() > 0 {
		return in.Index(0)
	}
	return exec.AsValue("")
}

func filterFloat(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'float'"))
	}
	return exec.AsValue(in.Float())
}

func filterForceEscape(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'forceescape'"))
	}
	return exec.AsSafeValue(in.Escaped())
}

func filterFormat(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	args := []interface{}{}
	for _, arg := range params.Args {
		args = append(args, arg.Interface())
	}
	return exec.AsValue(fmt.Sprintf(in.String(), args...))
}

func filterGroupBy(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.ExpectArgs(1)
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'groupby"))
	}
	field := p.First().String()
	groups := map[interface{}][]*exec.Value{}
	groupers := []interface{}{}

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		attr, found := key.Get(field)
		if !found {
			return true
		}
		lst, exists := groups[attr.Interface()]
		if !exists {
			lst = []*exec.Value{}
			groupers = append(groupers, attr.Interface())
		}
		lst = append(lst, key)
		groups[attr.Interface()] = lst
		return true
	}, func() {})

	out := []map[string]*exec.Value{}
	for _, grouper := range groupers {
		out = append(out, map[string]*exec.Value{
			"grouper": exec.AsValue(grouper),
			"list":    exec.AsValue(groups[grouper]),
		})
	}
	return exec.AsValue(out)
}

func filterIndent(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"width", 4},
		{"first", false},
		{"blank", false},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'indent'"))
	}
	width := p.KwArgs["width"].Integer()
	first := p.KwArgs["first"].Bool()
	blank := p.KwArgs["blank"].Bool()
	indent := strings.Repeat(" ", width)
	lines := strings.Split(in.String(), "\n")
	// start := 1
	// if first {start = 0}
	var out strings.Builder
	for idx, line := range lines {
		if line == "" && !blank {
			out.WriteByte('\n')
			continue
		}
		if idx > 0 || first {
			out.WriteString(indent)
		}
		out.WriteString(line)
		out.WriteByte('\n')
	}
	return exec.AsValue(out.String())
}

func filterInteger(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'int'"))
	}
	return exec.AsValue(in.Integer())
}

func filterJoin(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"d", ""},
		{"attribute", nil},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'join'"))
	}
	if !in.CanSlice() {
		return in
	}
	sep := p.KwArgs["d"].String()
	sl := make([]string, 0, in.Len())
	for i := 0; i < in.Len(); i++ {
		sl = append(sl, in.Index(i).String())
	}
	return exec.AsValue(strings.Join(sl, sep))
}

func filterLast(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'last'"))
	}
	if in.CanSlice() && in.Len() > 0 {
		return in.Index(in.Len() - 1)
	}
	return exec.AsValue("")
}

func filterLength(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'length'"))
	}
	return exec.AsValue(in.Len())
}

func filterList(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'list'"))
	}
	if in.IsString() {
		out := []string{}
		for _, r := range in.String() {
			out = append(out, string(r))
		}
		return exec.AsValue(out)
	}
	out := []*exec.Value{}
	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		out = append(out, key)
		return true
	}, func() {})
	return exec.AsValue(out)
}

func filterLower(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'lower'"))
	}
	return exec.AsValue(strings.ToLower(in.String()))
}

func filterMap(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"filter", ""},
		{"attribute", nil},
		{"default", nil},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'map'"))
	}
	filter := p.KwArgs["filter"].String()
	attribute := p.KwArgs["attribute"].String()
	defaultVal := p.KwArgs["default"]
	out := []*exec.Value{}
	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		val := key
		if len(attribute) > 0 {
			attr, found := val.Get(attribute)
			if found {
				val = attr
			} else if defaultVal != nil {
				val = defaultVal
			} else {
				return true
			}
		}
		if len(filter) > 0 {
			val = e.ExecuteFilterByName(filter, val, exec.NewVarArgs())
		}
		out = append(out, val)
		return true
	}, func() {})
	return exec.AsValue(out)
}

func filterMax(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"case_sensitive", false},
		{"attribute", nil},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'max'"))
	}
	caseSensitive := p.KwArgs["case_sensitive"].Bool()
	attribute := p.KwArgs["attribute"].String()

	var max *exec.Value
	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		val := key
		if len(attribute) > 0 {
			attr, found := val.Get(attribute)
			if found {
				val = attr
			} else {
				val = nil
			}
		}
		if max == nil {
			max = val
			return true
		}
		if val == nil || max == nil {
			return true
		}
		switch {
		case max.IsFloat() || max.IsInteger() && val.IsFloat() || val.IsInteger():
			if val.Float() > max.Float() {
				max = val
			}
		case max.IsString() && val.IsString():
			if !caseSensitive && strings.ToLower(val.String()) > strings.ToLower(max.String()) {
				max = val
			} else if caseSensitive && val.String() > max.String() {
				max = val
			}
		default:
			max = exec.AsValue(errors.Errorf(`%s and %s are not comparable`, max.Val.Type(), val.Val.Type()))
		}
		return true
	}, func() {})

	if max == nil {
		return exec.AsValue("")
	}
	return max
}

func filterMin(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"case_sensitive", false},
		{"attribute", nil},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'min'"))
	}
	caseSensitive := p.KwArgs["case_sensitive"].Bool()
	attribute := p.KwArgs["attribute"].String()

	var min *exec.Value
	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		val := key
		if len(attribute) > 0 {
			attr, found := val.Get(attribute)
			if found {
				val = attr
			} else {
				val = nil
			}
		}
		if min == nil {
			min = val
			return true
		}
		if val == nil || min == nil {
			return true
		}
		switch {
		case min.IsFloat() || min.IsInteger() && val.IsFloat() || val.IsInteger():
			if val.Float() < min.Float() {
				min = val
			}
		case min.IsString() && val.IsString():
			if !caseSensitive && strings.ToLower(val.String()) < strings.ToLower(min.String()) {
				min = val
			} else if caseSensitive && val.String() < min.String() {
				min = val
			}
		default:
			min = exec.AsValue(errors.Errorf(`%s and %s are not comparable`, min.Val.Type(), val.Val.Type()))
		}
		return true
	}, func() {})

	if min == nil {
		return exec.AsValue("")
	}
	return min
}

func filterPPrint(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"verbose", false}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'pprint'"))
	}
	b, err := json.MarshalIndent(in.Interface(), "", "  ")
	if err != nil {
		return exec.AsValue(errors.Wrapf(err, `Unable to pretty print '%s'`, in.String()))
	}
	return exec.AsSafeValue(string(b))
}

func filterRandom(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'random'"))
	}
	if !in.CanSlice() || in.Len() <= 0 {
		return in
	}
	i := rand.Intn(in.Len())
	return in.Index(i)
}

func filterReject(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	var test func(*exec.Value) bool
	if len(params.Args) == 0 {
		// Reject truthy value
		test = func(in *exec.Value) bool {
			return in.IsTrue()
		}
	} else {
		name := params.First().String()
		testParams := &exec.VarArgs{
			Args:   params.Args[1:],
			KwArgs: params.KwArgs,
		}
		test = func(in *exec.Value) bool {
			out := e.ExecuteTestByName(name, in, testParams)
			return out.IsTrue()
		}
	}

	out := []*exec.Value{}

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		if !test(key) {
			out = append(out, key)
		}
		return true
	}, func() {})

	return exec.AsValue(out)
}

func filterRejectAttr(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	var test func(*exec.Value) *exec.Value
	if len(params.Args) < 1 {
		return exec.AsValue(errors.New("Wrong signature for 'rejectattr', expect at least an attribute name as argument"))
	}
	attribute := params.First().String()
	if len(params.Args) == 1 {
		// Reject truthy value
		test = func(in *exec.Value) *exec.Value {
			attr, found := in.Get(attribute)
			if !found {
				return exec.AsValue(errors.Errorf(`%s has no attribute '%s'`, in.String(), attribute))
			}
			return attr
		}
	} else {
		name := params.Args[1].String()
		testParams := &exec.VarArgs{
			Args:   params.Args[2:],
			KwArgs: params.KwArgs,
		}
		test = func(in *exec.Value) *exec.Value {
			attr, found := in.Get(attribute)
			if !found {
				return exec.AsValue(errors.Errorf(`%s has no attribute '%s'`, in.String(), attribute))
			}
			out := e.ExecuteTestByName(name, attr, testParams)
			return out
		}
	}

	out := []*exec.Value{}
	var err *exec.Value

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		result := test(key)
		if result.IsError() {
			err = result
			return false
		}
		if !result.IsTrue() {
			out = append(out, key)
		}
		return true
	}, func() {})

	if err != nil {
		return err
	}
	return exec.AsValue(out)
}

func filterReplace(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(2, []*exec.KwArg{{"count", nil}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'replace'"))
	}
	old := p.Args[0].String()
	new := p.Args[1].String()
	count := p.KwArgs["count"]
	if count.IsNil() {
		return exec.AsValue(strings.ReplaceAll(in.String(), old, new))
	}
	return exec.AsValue(strings.Replace(in.String(), old, new, count.Integer()))
}

func filterReverse(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'safe'"))
	}
	if in.IsString() {
		var out strings.Builder
		in.IterateOrder(func(idx, count int, key, value *exec.Value) bool {
			out.WriteString(key.String())
			return true
		}, func() {}, true, false, false)
		return exec.AsValue(out.String())
	}
	out := []*exec.Value{}
	in.IterateOrder(func(idx, count int, key, value *exec.Value) bool {
		out = append(out, key)
		return true
	}, func() {}, true, true, false)
	return exec.AsValue(out)
}

func filterRound(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"precision", 0}, {"method", "common"}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'round'"))
	}
	method := p.KwArgs["method"].String()
	var op func(float64) float64
	switch method {
	case "common":
		op = math.Round
	case "floor":
		op = math.Floor
	case "ceil":
		op = math.Ceil
	default:
		return exec.AsValue(errors.Errorf(`Unknown method '%s', mush be one of 'common, 'floor', 'ceil`, method))
	}
	value := in.Float()
	factor := float64(10 * p.KwArgs["precision"].Integer())
	if factor > 0 {
		value = value * factor
	}
	value = op(value)
	if factor > 0 {
		value = value / factor
	}
	return exec.AsValue(value)
}

func filterSafe(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'safe'"))
	}
	in.Safe = true
	return in // nothing to do here, just to keep track of the safe application
}

func filterSelect(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	var test func(*exec.Value) bool
	if len(params.Args) == 0 {
		// Reject truthy value
		test = func(in *exec.Value) bool {
			return in.IsTrue()
		}
	} else {
		name := params.First().String()
		testParams := &exec.VarArgs{
			Args:   params.Args[1:],
			KwArgs: params.KwArgs,
		}
		test = func(in *exec.Value) bool {
			out := e.ExecuteTestByName(name, in, testParams)
			return out.IsTrue()
		}
	}

	out := []*exec.Value{}

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		if test(key) {
			out = append(out, key)
		}
		return true
	}, func() {})

	return exec.AsValue(out)
}

func filterSelectAttr(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	var test func(*exec.Value) *exec.Value
	if len(params.Args) < 1 {
		return exec.AsValue(errors.New("Wrong signature for 'selectattr', expect at least an attribute name as argument"))
	}
	attribute := params.First().String()
	if len(params.Args) == 1 {
		// Reject truthy value
		test = func(in *exec.Value) *exec.Value {
			attr, found := in.Get(attribute)
			if !found {
				return exec.AsValue(errors.Errorf(`%s has no attribute '%s'`, in.String(), attribute))
			}
			return attr
		}
	} else {
		name := params.Args[1].String()
		testParams := &exec.VarArgs{
			Args:   params.Args[2:],
			KwArgs: params.KwArgs,
		}
		test = func(in *exec.Value) *exec.Value {
			attr, found := in.Get(attribute)
			if !found {
				return exec.AsValue(errors.Errorf(`%s has no attribute '%s'`, in.String(), attribute))
			}
			out := e.ExecuteTestByName(name, attr, testParams)
			return out
		}
	}

	out := []*exec.Value{}
	var err *exec.Value

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		result := test(key)
		if result.IsError() {
			err = result
			return false
		}
		if result.IsTrue() {
			out = append(out, key)
		}
		return true
	}, func() {})

	if err != nil {
		return err
	}
	return exec.AsValue(out)
}

func filterSlice(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	comp := strings.Split(params.Args[0].String(), ":")
	if len(comp) != 2 {
		return exec.AsValue(errors.New("Slice string must have the format 'from:to' [from/to can be omitted, but the ':' is required]"))
	}

	if !in.CanSlice() {
		return in
	}

	from := exec.AsValue(comp[0]).Integer()
	to := in.Len()

	if from > to {
		from = to
	}

	vto := exec.AsValue(comp[1]).Integer()
	if vto >= from && vto <= in.Len() {
		to = vto
	}

	return in.Slice(from, to)
}

func filterSort(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"reverse", false}, {"case_sensitive", false}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'sort'"))
	}
	reverse := p.KwArgs["reverse"].Bool()
	caseSensitive := p.KwArgs["case_sensitive"].Bool()
	out := []*exec.Value{}
	in.IterateOrder(func(idx, count int, key, value *exec.Value) bool {
		out = append(out, key)
		return true
	}, func() {}, reverse, true, caseSensitive)
	return exec.AsValue(out)
}

func filterString(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'string'"))
	}
	return exec.AsValue(in.String())
}

var reStriptags = regexp.MustCompile("<[^>]*?>")

func filterStriptags(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'striptags'"))
	}
	s := in.String()

	// Strip all tags
	s = reStriptags.ReplaceAllString(s, "")

	return exec.AsValue(strings.TrimSpace(s))
}

func filterSum(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"attribute", nil}, {"start", 0}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'sum'"))
	}

	attribute := p.KwArgs["attribute"]
	sum := p.KwArgs["start"].Float()
	var err error

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		if attribute.IsString() {
			val := key
			found := true
			for _, attr := range strings.Split(attribute.String(), ".") {
				val, found = val.Get(attr)
				if !found {
					err = errors.Errorf("'%s' has no attribute '%s'", key.String(), attribute.String())
					return false
				}
			}
			if found && val.IsNumber() {
				sum += val.Float()
			}
		} else if attribute.IsInteger() {
			value, found := key.Getitem(attribute.Integer())
			if found {
				sum += value.Float()
			}
		} else {
			sum += key.Float()
		}
		return true
	}, func() {})

	if err != nil {
		return exec.AsValue(err)
	} else if sum == math.Trunc(sum) {
		return exec.AsValue(int64(sum))
	}
	return exec.AsValue(sum)
}

func filterTitle(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'title'"))
	}
	if !in.IsString() {
		return exec.AsValue("")
	}
	return exec.AsValue(strings.Title(strings.ToLower(in.String())))
}

func filterTrim(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'trim'"))
	}
	return exec.AsValue(strings.TrimSpace(in.String()))
}

func filterToJSON(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"indent", nil}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'tojson'"))
	}

	indent := p.KwArgs["indent"]
	var out string
	if indent.IsNil() {
		b, err := json.Marshal(in.Interface())
		if err != nil {
			return exec.AsValue(errors.Wrap(err, "Unable to marhsall to json"))
		}
		out = string(b)
	} else if indent.IsInteger() {
		b, err := json.MarshalIndent(in.Interface(), "", strings.Repeat(" ", indent.Integer()))
		if err != nil {
			return exec.AsValue(errors.Wrap(err, "Unable to marhsall to json"))
		}
		out = string(b)
	} else {
		return exec.AsValue(errors.Errorf("Expected an integer for 'indent', got %s", indent.String()))
	}
	return exec.AsSafeValue(out)
}

func filterTruncate(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"length", 255},
		{"killwords", false},
		{"end", "..."},
		{"leeway", 0},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'truncate'"))
	}

	source := in.String()
	length := p.KwArgs["length"].Integer()
	leeway := p.KwArgs["leeway"].Integer()
	killwords := p.KwArgs["killwords"].Bool()
	end := p.KwArgs["end"].String()
	rEnd := []rune(end)
	fullLength := length + leeway
	runes := []rune(source)

	if length < len(rEnd) {
		return exec.AsValue(errors.Errorf(`expected length >= %d, got %d`, len(rEnd), length))
	}

	if len(runes) <= fullLength {
		return exec.AsValue(source)
	}

	atLength := string(runes[:length-len(rEnd)])
	if !killwords {
		atLength = strings.TrimRightFunc(atLength, func(r rune) bool {
			return !unicode.IsSpace(r)
		})
		atLength = strings.TrimRight(atLength, " \n\t")
	}
	return exec.AsValue(fmt.Sprintf("%s%s", atLength, end))
}

func filterUnique(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{{"case_sensitive", false}, {"attribute", nil}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'unique'"))
	}

	caseSensitive := p.KwArgs["case_sensitive"].Bool()
	attribute := p.KwArgs["attribute"]

	out := exec.ValuesList{}
	tracker := map[interface{}]bool{}
	var err error

	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		val := key
		if attribute.IsString() {
			attr := attribute.String()
			nested, found := key.Get(attr)
			if !found {
				err = errors.Errorf(`%s has no attribute %s`, key.String(), attr)
				return false
			}
			val = nested
		}
		tracked := val.Interface()
		if !caseSensitive && val.IsString() {
			tracked = strings.ToLower(val.String())
		}
		if _, contains := tracker[tracked]; !contains {
			tracker[tracked] = true
			out = append(out, key)
		}
		return true
	}, func() {})

	if err != nil {
		return exec.AsValue(err)
	}
	return exec.AsValue(out)
}

func filterUpper(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'upper'"))
	}
	return exec.AsValue(strings.ToUpper(in.String()))
}

func filterUrlencode(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'urlencode'"))
	}
	return exec.AsValue(url.QueryEscape(in.String()))
}

// TODO: This regexp could do some work
var filterUrlizeURLRegexp = regexp.MustCompile(`((((http|https)://)|www\.|((^|[ ])[0-9A-Za-z_\-]+(\.com|\.net|\.org|\.info|\.biz|\.de))))(?U:.*)([ ]+|$)`)
var filterUrlizeEmailRegexp = regexp.MustCompile(`(\w+@\w+\.\w{2,4})`)

func filterUrlizeHelper(input string, trunc int, rel string, target string) (string, error) {
	var soutErr error
	sout := filterUrlizeURLRegexp.ReplaceAllStringFunc(input, func(raw_url string) string {
		var prefix string
		var suffix string
		if strings.HasPrefix(raw_url, " ") {
			prefix = " "
		}
		if strings.HasSuffix(raw_url, " ") {
			suffix = " "
		}

		raw_url = strings.TrimSpace(raw_url)

		url := u.IRIEncode(raw_url)

		if !strings.HasPrefix(url, "http") {
			url = fmt.Sprintf("http://%s", url)
		}

		title := raw_url

		if trunc > 3 && len(title) > trunc {
			title = fmt.Sprintf("%s...", title[:trunc-3])
		}

		title = u.Escape(title)

		attrs := ""
		if len(target) > 0 {
			attrs = fmt.Sprintf(` target="%s"`, target)
		}

		rels := []string{}
		cleanedRel := strings.Trim(strings.Replace(rel, "noopener", "", -1), " ")
		if len(cleanedRel) > 0 {
			rels = append(rels, cleanedRel)
		}
		rels = append(rels, "noopener")
		rel = strings.Join(rels, " ")

		return fmt.Sprintf(`%s<a href="%s" rel="%s"%s>%s</a>%s`, prefix, url, rel, attrs, title, suffix)
	})
	if soutErr != nil {
		return "", soutErr
	}

	sout = filterUrlizeEmailRegexp.ReplaceAllStringFunc(sout, func(mail string) string {
		title := mail

		if trunc > 3 && len(title) > trunc {
			title = fmt.Sprintf("%s...", title[:trunc-3])
		}

		return fmt.Sprintf(`<a href="mailto:%s">%s</a>`, mail, title)
	})
	return sout, nil
}

func filterUrlize(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.Expect(0, []*exec.KwArg{
		{"trim_url_limit", nil},
		{"nofollow", false},
		{"target", nil},
		{"rel", nil},
	})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'urlize'"))
	}
	truncate := -1
	if param := p.KwArgs["trim_url_limit"]; param.IsInteger() {
		truncate = param.Integer()
	}
	rel := p.KwArgs["rel"]
	target := p.KwArgs["target"]

	s, err := filterUrlizeHelper(in.String(), truncate, rel.String(), target.String())
	if err != nil {
		return exec.AsValue(err)
	}

	return exec.AsValue(s)
}

func filterWordcount(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	if p := params.ExpectNothing(); p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'wordcount'"))
	}
	return exec.AsValue(len(strings.Fields(in.String())))
}

func filterWordwrap(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	words := strings.Fields(in.String())
	wordsLen := len(words)
	wrapAt := params.Args[0].Integer()
	if wrapAt <= 0 {
		return in
	}

	linecount := wordsLen/wrapAt + wordsLen%wrapAt
	lines := make([]string, 0, linecount)
	for i := 0; i < linecount; i++ {
		lines = append(lines, strings.Join(words[wrapAt*i:u.Min(wrapAt*(i+1), wordsLen)], " "))
	}
	return exec.AsValue(strings.Join(lines, "\n"))
}

func filterXMLAttr(e *exec.Evaluator, in *exec.Value, params *exec.VarArgs) *exec.Value {
	p := params.ExpectKwArgs([]*exec.KwArg{{"autospace", true}})
	if p.IsError() {
		return exec.AsValue(errors.Wrap(p, "Wrong signature for 'xmlattr'"))
	}
	autospace := p.KwArgs["autospace"].Bool()
	kvs := []string{}
	in.Iterate(func(idx, count int, key, value *exec.Value) bool {
		if !value.IsTrue() {
			return true
		}
		kv := fmt.Sprintf(`%s="%s"`, key.Escaped(), value.Escaped())
		kvs = append(kvs, kv)
		return true
	}, func() {})
	out := strings.Join(kvs, " ")
	if autospace {
		out = " " + out
	}
	return exec.AsValue(out)
}


<|start_filename|>utils/iri.go<|end_filename|>
package utils

import (
	"bytes"
	"net/url"
	"strings"
)

const filterIRIChars = "/#%[]=:;$&()+,!?*@'~"

func IRIEncode(in string) string {
	var b bytes.Buffer

	for _, r := range in {
		if strings.IndexRune(filterIRIChars, r) >= 0 {
			b.WriteRune(r)
		} else {
			b.WriteString(url.QueryEscape(string(r)))
		}
	}

	return b.String()
}


<|start_filename|>ext/django/statements/ifequal.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type IfEqualStmt struct {
	Location    *tokens.Token
	var1, var2  nodes.Expression
	thenWrapper *nodes.Wrapper
	elseWrapper *nodes.Wrapper
}

func (stmt *IfEqualStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *IfEqualStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("IfEqualStmt(Line=%d Col=%d)", t.Line, t.Col)
}

// func (node *IfEqualStmt) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
// 	r1, err := node.var1.Evaluate(ctx)
// 	if err != nil {
// 		return err
// 	}
// 	r2, err := node.var2.Evaluate(ctx)
// 	if err != nil {
// 		return err
// 	}

// 	result := r1.EqualValueTo(r2)

// 	if result {
// 		return node.thenWrapper.Execute(ctx, writer)
// 	}
// 	if node.elseWrapper != nil {
// 		return node.elseWrapper.Execute(ctx, writer)
// 	}
// 	return nil
// }

func ifEqualParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	ifequalNode := &IfEqualStmt{}

	// Parse two expressions
	var1, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	var2, err := args.ParseExpression()
	if err != nil {
		return nil, err
	}
	ifequalNode.var1 = var1
	ifequalNode.var2 = var2

	if !args.End() {
		return nil, args.Error("ifequal only takes 2 args.", nil)
	}

	// Wrap then/else-blocks
	wrapper, endargs, err := p.WrapUntil("else", "endifequal")
	if err != nil {
		return nil, err
	}
	ifequalNode.thenWrapper = wrapper

	if !endargs.End() {
		return nil, endargs.Error("Arguments not allowed here.", nil)
	}

	if wrapper.EndTag == "else" {
		// if there's an else in the if-statement, we need the else-Block as well
		wrapper, endargs, err = p.WrapUntil("endifequal")
		if err != nil {
			return nil, err
		}
		ifequalNode.elseWrapper = wrapper

		if !endargs.End() {
			return nil, endargs.Error("Arguments not allowed here.", nil)
		}
	}

	return ifequalNode, nil
}

func init() {
	All.Register("ifequal", ifEqualParser)
}


<|start_filename|>ext/time/now.go<|end_filename|>
package time

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pkg/errors"

	arrow "github.com/bmuller/arrow/lib"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type TimeOffset struct {
	Years   int
	Months  int
	Days    int
	Hours   int
	Minutes int
	Seconds int
}

type NowStmt struct {
	Location *tokens.Token
	TZ       string
	Format   string
	Offset   *TimeOffset
}

func (stmt *NowStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *NowStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("NowStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *NowStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	var now arrow.Arrow

	cfg := r.Config.Ext["time"].(*Config)
	format := cfg.DatetimeFormat

	if cfg.Now != nil {
		now = *cfg.Now
	} else {
		now = arrow.Now()
	}

	if stmt.Format != "" {
		format = stmt.Format
	}

	now = now.InTimezone(stmt.TZ)

	if stmt.Offset != nil {
		offset := stmt.Offset
		if offset.Years != 0 || offset.Months != 0 || offset.Days != 0 {
			now = arrow.New(now.AddDate(offset.Years, offset.Months, offset.Days))
		}
		if offset.Hours != 0 {
			now = now.AddHours(offset.Hours)
		}
		if offset.Minutes != 0 {
			now = now.AddMinutes(offset.Minutes)
		}
		if offset.Seconds != 0 {
			now = now.AddSeconds(offset.Seconds)
		}
	}

	r.WriteString(now.CFormat(format))

	return nil
}

func nowParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &NowStmt{
		Location: p.Current(),
	}

	// Timezone
	tz := args.Match(tokens.String)
	if tz == nil {
		return nil, args.Error(`now expect a timezone as first argument`, args.Current())
	}
	stmt.TZ = tz.Val

	// Offset
	if sign := args.Match(tokens.Add, tokens.Sub); sign != nil {
		offset := args.Match(tokens.String)
		if offset == nil {
			return nil, args.Error("Expected an time offset.", args.Current())
		}
		timeOffset, err := parseTimeOffset(offset.Val, sign.Val == "+")
		if err != nil {
			return nil, errors.Wrapf(err, `Unable to parse time offset '%s'`, offset.Val)
		}
		stmt.Offset = timeOffset
	}

	// Format
	if args.Match(tokens.Comma) != nil {
		format := args.Match(tokens.String)
		if format == nil {
			return nil, args.Error("Expected a format string.", args.Current())
		}
		stmt.Format = format.Val
	}

	if !args.End() {
		return nil, args.Error("Malformed now-tag args.", nil)
	}

	return stmt, nil
}

func parseTimeOffset(offset string, add bool) (*TimeOffset, error) {
	pairs := strings.Split(offset, ",")
	specs := map[string]int{}
	for _, pair := range pairs {
		splitted := strings.Split(pair, "=")
		if len(splitted) != 2 {
			return nil, errors.Errorf(`Expected a key=value pair, got '%s'`, pair)
		}
		unit := strings.TrimSpace(splitted[0])
		value, err := strconv.Atoi(strings.TrimSpace(splitted[1]))
		if err != nil {
			return nil, errors.Wrap(err, `Unable to parse int`)
		}
		specs[unit] = value
	}
	to := &TimeOffset{}
	for unit, value := range specs {
		if !add {
			value = -value
		}
		switch strings.ToLower(unit) {
		case "year", "years":
			to.Years = value
		case "month", "months":
			to.Months = value
		case "day", "days":
			to.Days = value
		case "hour", "hours":
			to.Hours = value
		case "minute", "minutes":
			to.Minutes = value
		case "second", "seconds":
			to.Seconds = value
		default:
			return nil, errors.Errorf(`Unknown unit '%s`, unit)
		}
	}
	return to, nil
}

func init() {
	Statements.Register("now", nowParser)
}


<|start_filename|>parser/expression.go<|end_filename|>
package parser

import (
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
	log "github.com/sirupsen/logrus"
)

// ParseFilterExpression parses an optionnal filter chain for a node
func (p *Parser) ParseFilterExpression(expr nodes.Expression) (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseFilterExpression")

	if p.Peek(tokens.Pipe) != nil {

		filtered := &nodes.FilteredExpression{
			Expression: expr,
		}
		for p.Match(tokens.Pipe) != nil {
			// Parse one single filter
			filter, err := p.ParseFilter()
			if err != nil {
				return nil, err
			}

			// Check sandbox filter restriction
			// if _, isBanned := p.template.set.bannedFilters[filter.name]; isBanned {
			// 	return nil, p.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", filter.name), nil)
			// }

			filtered.Filters = append(filtered.Filters, filter)
		}
		expr = filtered
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("ParseFilterExpression return")
	return expr, nil
}

// ParseExpression parses an expression with optionnal filters
// Nested expression shoulds call this method
func (p *Parser) ParseExpression() (nodes.Expression, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseExpression")
	var expr nodes.Expression

	expr, err := p.ParseLogicalExpression()
	if err != nil {
		return nil, err
	}

	expr, err = p.ParseFilterExpression(expr)
	if err != nil {
		return nil, err
	}

	log.WithFields(log.Fields{
		"expr": expr,
	}).Trace("ParseExpression return")
	return expr, nil
}

func (p *Parser) ParseExpressionNode() (nodes.Node, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseExpressionNode")

	tok := p.Match(tokens.VariableBegin)
	if tok == nil {
		return nil, p.Error("'{{' expected here", p.Current())
	}

	node := &nodes.Output{
		Start: tok,
		Trim: &nodes.Trim{
			Left: tok.Val[len(tok.Val)-1] == '-',
		},
	}

	expr, err := p.ParseExpression()
	if err != nil {
		return nil, err
	}
	if expr == nil {
		return nil, p.Error("Expected an expression.", p.Current())
	}
	node.Expression = expr

	tok = p.Match(tokens.VariableEnd)
	if tok == nil {
		return nil, p.Error("'}}' expected here", p.Current())
	}
	node.End = tok
	node.Trim.Right = tok.Val[0] == '-'

	log.WithFields(log.Fields{
		"node": node,
	}).Trace("parseExpressionNode return")
	return node, nil
}


<|start_filename|>parser/parser_test.go<|end_filename|>
package parser_test

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
	log "github.com/sirupsen/logrus"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

var logLevel = flag.String("log.level", "", "Log Level")

func TestMain(m *testing.M) {
	flag.Parse()

	log.SetFormatter(&prefixed.TextFormatter{
		ForceColors:      true,
		DisableTimestamp: true,
		ForceFormatting:  true,
	})

	switch *logLevel {
	case "error":
		log.SetLevel(log.ErrorLevel)
	case "warning", "warn":
		log.SetLevel(log.WarnLevel)
	case "info":
		log.SetLevel(log.InfoLevel)
	case "debug":
		log.SetLevel(log.DebugLevel)
	case "trace":
		log.SetLevel(log.TraceLevel)
	default:
		log.SetLevel(log.PanicLevel)
	}
	os.Exit(m.Run())
}

var testCases = []struct {
	name     string
	text     string
	expected specs
}{
	{"comment", "{# My comment #}", specs{nodes.Comment{}, attrs{
		"Text": val{" My comment "},
	}}},
	{"multiline comment", "{# My\nmultiline\ncomment #}", specs{nodes.Comment{}, attrs{
		"Text": val{" My\nmultiline\ncomment "},
	}}},
	{"empty comment", "{##}", specs{nodes.Comment{}, attrs{
		"Text": val{""},
	}}},
	{"raw text", "raw text", specs{nodes.Data{}, attrs{
		"Data": _token("raw text"),
	}}},
	// Literals
	{"single quotes string", "{{ 'test' }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "test"),
	}}},
	{"single quotes string with whitespace chars", "{{ '  \n\ttest' }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "  \n\ttest"),
	}}},
	{"single quotes string with raw whitespace chars", `{{ '  \n\ttest' }}`, specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "  \n\ttest"),
	}}},
	{"double quotes string", `{{ "test" }}`, specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "test"),
	}}},
	{"double quotes string with whitespace chars", "{{ \"  \n\ttest\" }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "  \n\ttest"),
	}}},
	{"double quotes string with raw whitespace chars", `{{ "  \n\ttest" }}`, specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "  \n\ttest"),
	}}},
	{"single quotes inside double quotes string", `{{ "'quoted' test" }}`, specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.String{}, "'quoted' test"),
	}}},
	{"integer", "{{ 42 }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Integer{}, int64(42)),
	}}},
	{"negative-integer", "{{ -42 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.UnaryExpression{}, attrs{
			"Negative": val{true},
			"Term":     _literal(nodes.Integer{}, int64(42)),
		}},
	}}},
	{"float", "{{ 42.0 }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Float{}, float64(42)),
	}}},
	{"negative-float", "{{ -42.0 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.UnaryExpression{}, attrs{
			"Negative": val{true},
			"Term":     _literal(nodes.Float{}, float64(42)),
		}},
	}}},
	{"bool-true", "{{ true }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Bool{}, true),
	}}},
	{"bool-True", "{{ True }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Bool{}, true),
	}}},
	{"bool-false", "{{ false }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Bool{}, false),
	}}},
	{"bool-False", "{{ False }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Bool{}, false),
	}}},
	{"list", "{{ ['list', \"of\", 'objects'] }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.List{}, slice{
			_literal(nodes.String{}, "list"),
			_literal(nodes.String{}, "of"),
			_literal(nodes.String{}, "objects"),
		}),
	}}},
	{"list with trailing coma", "{{ ['list', \"of\", 'objects',] }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.List{}, slice{
			_literal(nodes.String{}, "list"),
			_literal(nodes.String{}, "of"),
			_literal(nodes.String{}, "objects"),
		}),
	}}},
	{"single entry list", "{{ ['list'] }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.List{}, slice{
			_literal(nodes.String{}, "list"),
		}),
	}}},
	{"empty list", "{{ [] }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.List{}, slice{}),
	}}},
	{"tuple", "{{ ('tuple', \"of\", 'objects') }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Tuple{}, slice{
			_literal(nodes.String{}, "tuple"),
			_literal(nodes.String{}, "of"),
			_literal(nodes.String{}, "objects"),
		}),
	}}},
	{"tuple with trailing coma", "{{ ('tuple', \"of\", 'objects',) }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Tuple{}, slice{
			_literal(nodes.String{}, "tuple"),
			_literal(nodes.String{}, "of"),
			_literal(nodes.String{}, "objects"),
		}),
	}}},
	{"single entry tuple", "{{ ('tuple',) }}", specs{nodes.Output{}, attrs{
		"Expression": _literal(nodes.Tuple{}, slice{
			_literal(nodes.String{}, "tuple"),
		}),
	}}},
	{"empty dict", "{{ {} }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Dict{}, attrs{}},
	}}},
	{"dict string", "{{ {'dict': 'of', 'key': 'and', 'value': 'pairs'} }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Dict{}, attrs{
			"Pairs": slice{
				specs{nodes.Pair{}, attrs{
					"Key":   _literal(nodes.String{}, "dict"),
					"Value": _literal(nodes.String{}, "of"),
				}},
				specs{nodes.Pair{}, attrs{
					"Key":   _literal(nodes.String{}, "key"),
					"Value": _literal(nodes.String{}, "and"),
				}},
				specs{nodes.Pair{}, attrs{
					"Key":   _literal(nodes.String{}, "value"),
					"Value": _literal(nodes.String{}, "pairs"),
				}},
			},
		}},
	}}},
	{"dict int", "{{ {1: 'one', 2: 'two', 3: 'three'} }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Dict{}, attrs{
			"Pairs": slice{
				specs{nodes.Pair{}, attrs{
					"Key":   _literal(nodes.Integer{}, int64(1)),
					"Value": _literal(nodes.String{}, "one"),
				}},
				specs{nodes.Pair{}, attrs{
					"Key":   _literal(nodes.Integer{}, int64(2)),
					"Value": _literal(nodes.String{}, "two"),
				}},
				specs{nodes.Pair{}, attrs{
					"Key":   _literal(nodes.Integer{}, int64(3)),
					"Value": _literal(nodes.String{}, "three"),
				}},
			},
		}},
	}}},
	{"addition", "{{ 40 + 2 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left":     _literal(nodes.Integer{}, int64(40)),
			"Right":    _literal(nodes.Integer{}, int64(2)),
			"Operator": _binOp("+"),
		}},
	}}},
	{"multiple additions", "{{ 40 + 1 + 1 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.BinaryExpression{}, attrs{
				"Left":     _literal(nodes.Integer{}, int64(40)),
				"Right":    _literal(nodes.Integer{}, int64(1)),
				"Operator": _binOp("+"),
			}},
			"Right":    _literal(nodes.Integer{}, int64(1)),
			"Operator": _binOp("+"),
		}},
	}}},
	{"multiple additions with power", "{{ 40 + 2 ** 1 + 0 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.BinaryExpression{}, attrs{
				"Left": _literal(nodes.Integer{}, int64(40)),
				"Right": specs{nodes.BinaryExpression{}, attrs{
					"Left":     _literal(nodes.Integer{}, int64(2)),
					"Right":    _literal(nodes.Integer{}, int64(1)),
					"Operator": _binOp("**"),
				}},
				"Operator": _binOp("+"),
			}},
			"Right":    _literal(nodes.Integer{}, int64(0)),
			"Operator": _binOp("+"),
		}},
	}}},
	{"substract", "{{ 40 - 2 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left":     _literal(nodes.Integer{}, int64(40)),
			"Right":    _literal(nodes.Integer{}, int64(2)),
			"Operator": _binOp("-"),
		}},
	}}},
	{"complex math", "{{ -1 * (-(-(10-100)) ** 2) ** 3 + 3 * (5 - 17) + 1 + 2 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.BinaryExpression{}, attrs{
				"Left": specs{nodes.BinaryExpression{}, attrs{
					"Left": specs{nodes.BinaryExpression{}, attrs{
						"Left": specs{nodes.UnaryExpression{}, attrs{
							"Negative": val{true},
							"Term":     _literal(nodes.Integer{}, int64(1)),
						}},
						"Right": specs{nodes.BinaryExpression{}, attrs{
							"Left": specs{nodes.UnaryExpression{}, attrs{
								"Negative": val{true},
								"Term": specs{nodes.BinaryExpression{}, attrs{
									"Left": specs{nodes.UnaryExpression{}, attrs{
										"Negative": val{true},
										"Term": specs{nodes.BinaryExpression{}, attrs{
											"Left":     _literal(nodes.Integer{}, int64(10)),
											"Right":    _literal(nodes.Integer{}, int64(100)),
											"Operator": _binOp("-"),
										}},
									}},
									"Right":    _literal(nodes.Integer{}, int64(2)),
									"Operator": _binOp("**"),
								}},
							}},
							"Right":    _literal(nodes.Integer{}, int64(3)),
							"Operator": _binOp("**"),
						}},
						"Operator": _binOp("*"),
					}},
					"Right": specs{nodes.BinaryExpression{}, attrs{
						"Left": _literal(nodes.Integer{}, int64(3)),
						"Right": specs{nodes.BinaryExpression{}, attrs{
							"Left":     _literal(nodes.Integer{}, int64(5)),
							"Right":    _literal(nodes.Integer{}, int64(17)),
							"Operator": _binOp("-"),
						}},
						"Operator": _binOp("*"),
					}},
					"Operator": _binOp("+"),
				}},
				"Right":    _literal(nodes.Integer{}, int64(1)),
				"Operator": _binOp("+"),
			}},
			"Right":    _literal(nodes.Integer{}, int64(2)),
			"Operator": _binOp("+"),
		}},
	}}},
	{"negative-expression", "{{ -(40 + 2) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.UnaryExpression{}, attrs{
			"Negative": val{true},
			"Term": specs{nodes.BinaryExpression{}, attrs{
				"Left":     _literal(nodes.Integer{}, int64(40)),
				"Right":    _literal(nodes.Integer{}, int64(2)),
				"Operator": _binOp("+"),
			}},
		}},
	}}},
	{"Operators precedence", "{{ 2 * 3 + 4 % 2 + 1 - 2 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.BinaryExpression{}, attrs{
				"Left": specs{nodes.BinaryExpression{}, attrs{
					"Left": specs{nodes.BinaryExpression{}, attrs{
						"Left":     _literal(nodes.Integer{}, int64(2)),
						"Right":    _literal(nodes.Integer{}, int64(3)),
						"Operator": _binOp("*"),
					}},
					"Right": specs{nodes.BinaryExpression{}, attrs{
						"Left":     _literal(nodes.Integer{}, int64(4)),
						"Right":    _literal(nodes.Integer{}, int64(2)),
						"Operator": _binOp("%"),
					}},
					"Operator": _binOp("+"),
				}},
				"Right":    _literal(nodes.Integer{}, int64(1)),
				"Operator": _binOp("+"),
			}},
			"Right":    _literal(nodes.Integer{}, int64(2)),
			"Operator": _binOp("-"),
		}},
	}}},
	{"Operators precedence with parenthesis", "{{ 2 * (3 + 4) % 2 + (1 - 2) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.BinaryExpression{}, attrs{
				"Left": specs{nodes.BinaryExpression{}, attrs{
					"Left": _literal(nodes.Integer{}, int64(2)),
					"Right": specs{nodes.BinaryExpression{}, attrs{
						"Left":     _literal(nodes.Integer{}, int64(3)),
						"Right":    _literal(nodes.Integer{}, int64(4)),
						"Operator": _binOp("+"),
					}},
					"Operator": _binOp("*"),
				}},
				"Right":    _literal(nodes.Integer{}, int64(2)),
				"Operator": _binOp("%"),
			}},
			"Right": specs{nodes.BinaryExpression{}, attrs{
				"Left":     _literal(nodes.Integer{}, int64(1)),
				"Right":    _literal(nodes.Integer{}, int64(2)),
				"Operator": _binOp("-"),
			}},
			"Operator": _binOp("+"),
		}},
	}}},
	{"variable", "{{ a_var }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Name{}, attrs{
			"Name": _token("a_var"),
		}},
	}}},
	{"variable attribute", "{{ a_var.attr }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Getattr{}, attrs{
			"Node": specs{nodes.Name{}, attrs{
				"Name": _token("a_var"),
			}},
			"Attr": val{"attr"},
		}},
	}}},
	{"variable and filter", "{{ a_var|safe }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": specs{nodes.Name{}, attrs{
				"Name": _token("a_var"),
			}},
			"Filters": slice{
				filter{"safe", slice{}, attrs{}},
			},
		}},
	}}},
	{"integer and filter", "{{ 42|safe }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": _literal(nodes.Integer{}, int64(42)),
			"Filters": slice{
				filter{"safe", slice{}, attrs{}},
			},
		}},
	}}},
	{"negative integer and filter", "{{ -42|safe }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": specs{nodes.UnaryExpression{}, attrs{
				"Negative": val{true},
				"Term":     _literal(nodes.Integer{}, int64(42)),
			}},
			"Filters": slice{
				filter{"safe", slice{}, attrs{}},
			},
		}},
	}}},
	{"logical expressions", "{{ true and false }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left":     _literal(nodes.Bool{}, true),
			"Right":    _literal(nodes.Bool{}, false),
			"Operator": _binOp("and"),
		}},
	}}},
	{"negated boolean", "{{ not true }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Negation{}, attrs{
			"Term": _literal(nodes.Bool{}, true),
		}},
	}}},
	{"negated logical expression", "{{ not false and true }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.Negation{}, attrs{
				"Term": _literal(nodes.Bool{}, false),
			}},
			"Right":    _literal(nodes.Bool{}, true),
			"Operator": _binOp("and"),
		}},
	}}},
	{"negated logical expression with parenthesis", "{{ not (false and true) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Negation{}, attrs{
			"Term": specs{nodes.BinaryExpression{}, attrs{
				"Left":     _literal(nodes.Bool{}, false),
				"Right":    _literal(nodes.Bool{}, true),
				"Operator": _binOp("and"),
			}},
		}},
	}}},
	{"logical expression with math comparison", "{{ 40 + 2 > 5 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": specs{nodes.BinaryExpression{}, attrs{
				"Left":     _literal(nodes.Integer{}, int64(40)),
				"Right":    _literal(nodes.Integer{}, int64(2)),
				"Operator": _binOp("+"),
			}},
			"Right":    _literal(nodes.Integer{}, int64(5)),
			"Operator": _binOp(">"),
		}},
	}}},
	{"logical expression with filter", "{{ false and true|safe }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.BinaryExpression{}, attrs{
			"Left": _literal(nodes.Bool{}, false),
			"Right": specs{nodes.FilteredExpression{}, attrs{
				"Expression": _literal(nodes.Bool{}, true),
				"Filters": slice{
					filter{"safe", slice{}, attrs{}},
				},
			}},
			"Operator": _binOp("and"),
		}},
	}}},
	{"logical expression with parenthesis and filter", "{{ (false and true)|safe }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": specs{nodes.BinaryExpression{}, attrs{
				"Left":     _literal(nodes.Bool{}, false),
				"Right":    _literal(nodes.Bool{}, true),
				"Operator": _binOp("and"),
			}},
			"Filters": slice{
				filter{"safe", slice{}, attrs{}},
			},
		}},
	}}},
	{"function", "{{ a_func(42) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Call{}, attrs{
			"Func": specs{nodes.Name{}, attrs{"Name": _token("a_func")}},
			"Args": slice{_literal(nodes.Integer{}, int64(42))},
		}},
	}}},
	{"method", "{{ an_obj.a_method(42) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Call{}, attrs{
			"Func": specs{nodes.Getattr{}, attrs{
				"Node": specs{nodes.Name{}, attrs{"Name": _token("an_obj")}},
				"Attr": val{"a_method"},
			}},
			"Args": slice{_literal(nodes.Integer{}, int64(42))},
		}},
	}}},
	{"function with filtered args", "{{ a_func(42|safe) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.Call{}, attrs{
			"Func": specs{nodes.Name{}, attrs{"Name": _token("a_func")}},
			"Args": slice{
				specs{nodes.FilteredExpression{}, attrs{
					"Expression": _literal(nodes.Integer{}, int64(42)),
					"Filters": slice{
						filter{"safe", slice{}, attrs{}},
					},
				}},
			},
		}},
	}}},
	{"variable and multiple filters", "{{ a_var|add(42)|safe }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": specs{nodes.Name{}, attrs{"Name": _token("a_var")}},
			"Filters": slice{
				filter{"add", slice{_literal(nodes.Integer{}, int64(42))}, attrs{}},
				filter{"safe", slice{}, attrs{}},
			},
		}},
	}}},
	{"variable and expression filters", "{{ a_var|add(40 + 2) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": specs{nodes.Name{}, attrs{"Name": _token("a_var")}},
			"Filters": slice{
				filter{"add", slice{
					specs{nodes.BinaryExpression{}, attrs{
						"Left":     _literal(nodes.Integer{}, int64(40)),
						"Right":    _literal(nodes.Integer{}, int64(2)),
						"Operator": _binOp("+"),
					}},
				}, attrs{}},
			},
		}},
	}}},
	{"variable and nested filters", "{{ a_var|add( 42|add(2) ) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.FilteredExpression{}, attrs{
			"Expression": specs{nodes.Name{}, attrs{"Name": _token("a_var")}},
			"Filters": slice{
				filter{"add", slice{
					specs{nodes.FilteredExpression{}, attrs{
						"Expression": _literal(nodes.Integer{}, int64(42)),
						"Filters": slice{
							filter{"add", slice{_literal(nodes.Integer{}, int64(2))}, attrs{}},
						},
					}},
				}, attrs{}},
			},
		}},
	}}},
	{"Test equal", "{{ 3 is equal 3 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.TestExpression{}, attrs{
			"Expression": _literal(nodes.Integer{}, int64(3)),
			"Test": specs{nodes.TestCall{}, attrs{
				"Name": val{"equal"},
				"Args": slice{_literal(nodes.Integer{}, int64(3))},
			}},
		}},
	}}},
	{"Test equal parenthesis", "{{ 3 is equal(3) }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.TestExpression{}, attrs{
			"Expression": _literal(nodes.Integer{}, int64(3)),
			"Test": specs{nodes.TestCall{}, attrs{
				"Name": val{"equal"},
				"Args": slice{_literal(nodes.Integer{}, int64(3))},
			}},
		}},
	}}},
	{"Test ==", "{{ 3 is == 3 }}", specs{nodes.Output{}, attrs{
		"Expression": specs{nodes.TestExpression{}, attrs{
			"Expression": _literal(nodes.Integer{}, int64(3)),
			"Test": specs{nodes.TestCall{}, attrs{
				"Name": val{"=="},
				"Args": slice{_literal(nodes.Integer{}, int64(3))},
			}},
		}},
	}}},
}

// func parseText(text string) (*nodeDocument, *Error) {
// 	tokens, err := lex("test", text)
// 	if err != nil {
// 		return nil, err
// 	}
// 	parser := newParser("test", tokens, &Template{
// 		set: &TemplateSet{},
// 	})
// 	return parser.parseDocument()
// }

func _deref(value reflect.Value) reflect.Value {
	for (value.Kind() == reflect.Interface || value.Kind() == reflect.Ptr) && !value.IsNil() {
		value = value.Elem()
	}
	return value
}

type asserter interface {
	assert(t *testing.T, value reflect.Value)
}

type specs struct {
	typ   interface{}
	attrs attrs
}

func (specs specs) assert(t *testing.T, value reflect.Value) {
	assert := assert.New(t)
	value = _deref(value)
	// t.Logf("type(expected %+v, actual %+v)", reflect.TypeOf(specs.typ), value.Type())
	if !assert.Equal(reflect.TypeOf(specs.typ), value.Type()) {
		return
	}
	if specs.attrs != nil {
		specs.attrs.assert(t, value)
	}
}

type val struct {
	value interface{}
}

func (val val) assert(t *testing.T, value reflect.Value) {
	assert := assert.New(t)
	value = _deref(value)
	switch value.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		assert.Equal(val.value, value.Int())
	case reflect.Float32, reflect.Float64:
		assert.Equal(val.value, value.Float())
	case reflect.String:
		assert.Equal(val.value, value.String())
	case reflect.Bool:
		assert.Equal(val.value, value.Bool())
	case reflect.Slice:
		current, ok := val.value.(asserter)
		if assert.True(ok) {
			current.assert(t, value)
		}
	case reflect.Map:
		assert.Len(val.value, value.Len())
		v2 := reflect.ValueOf(val.value)

		iter := value.MapRange()
		for iter.Next() {
			assert.Equal(iter.Value(), v2.MapIndex(iter.Key()))
		}
	case reflect.Func:
		assert.Equal(value, reflect.ValueOf(val.value))
	default:
		assert.Failf("Unknown value", "Unknown value kind '%s'", value.Kind())
	}
}

func _literal(typ interface{}, value interface{}) asserter {
	return specs{typ, attrs{
		"Val": val{value},
	}}
}

func _token(value string) asserter {
	return specs{tokens.Token{}, attrs{
		"Val": val{value},
	}}
}

func _binOp(value string) asserter {
	return specs{nodes.BinOperator{}, attrs{
		"Token": _token(value),
	}}
}

type attrs map[string]asserter

func (attrs attrs) assert(t *testing.T, value reflect.Value) {
	assert := assert.New(t)
	for attr, specs := range attrs {
		field := value.FieldByName(attr)
		if assert.True(field.IsValid(), fmt.Sprintf("No field named '%s' found", attr)) {
			specs.assert(t, field)
		}
	}
}

type slice []asserter

func (slice slice) assert(t *testing.T, value reflect.Value) {
	if assert.Equal(t, reflect.Slice, value.Kind()) {
		if assert.Equal(t, len(slice), value.Len()) {
			for idx, specs := range slice {
				specs.assert(t, value.Index(idx))
			}
		}
	}
}

type filter struct {
	name   string
	args   slice
	kwargs attrs
}

func (filter filter) assert(t *testing.T, value reflect.Value) {
	value = _deref(value)
	assert := assert.New(t)
	assert.Equal(reflect.TypeOf(nodes.FilterCall{}), value.Type())
	assert.Equal(filter.name, value.FieldByName("Name").String())
	args := value.FieldByName("Args")
	kwargs := value.FieldByName("Kwargs")
	if assert.Equal(len(filter.args), args.Len()) {
		for idx, specs := range filter.args {
			specs.assert(t, args.Index(idx))
		}
	}
	if assert.Equal(len(filter.kwargs), kwargs.Len()) {
		for key, specs := range filter.kwargs {
			specs.assert(t, args.MapIndex(reflect.ValueOf(key)))
		}
	}
}

func TestParser(t *testing.T) {
	for _, tc := range testCases {
		test := tc
		t.Run(test.name, func(t *testing.T) {
			defer func() {
				if err := recover(); err != nil {
					t.Error(err)
				}
			}()
			// t.Parallel()
			assert := assert.New(t)
			tpl, err := parser.Parse(test.text)
			if assert.Nil(err, "Unable to parse template: %s", err) {
				if assert.Equal(1, len(tpl.Nodes), "Expected one node") {
					test.expected.assert(t, reflect.ValueOf(tpl.Nodes[0]))
				} else {
					t.Logf("Nodes %+v", tpl.Nodes)
				}
			}
		})
	}
}


<|start_filename|>loaders/loader.go<|end_filename|>
package loaders

import (
	"io"
)

// TemplateLoader allows to implement a virtual file system.
type Loader interface {
	// Abs calculates the path to a given template. Whenever a path must be resolved
	// due to an import from another template, the base equals the parent template's path.
	// Abs(base, name string) string

	// Get returns an io.Reader where the template's content can be read from.
	Get(path string) (io.Reader, error)
}


<|start_filename|>parser/statement.go<|end_filename|>
package parser

import (
	"fmt"

	log "github.com/sirupsen/logrus"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/tokens"
)

type StatementParser func(parser *Parser, args *Parser) (nodes.Statement, error)

// Tag = "{%" IDENT ARGS "%}"
func (p *Parser) ParseStatement() (nodes.Statement, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseStatement")

	if p.Match(tokens.BlockBegin) == nil {
		return nil, p.Error("'{%' expected here", p.Current())
	}

	name := p.Match(tokens.Name)
	if name == nil {
		return nil, p.Error("Expected a statement name here", p.Current())
	}

	// Check for the existing statement
	stmtParser, exists := p.Statements[name.Val]
	if !exists {
		// Does not exists
		return nil, p.Error(fmt.Sprintf("Statement '%s' not found (or beginning not provided)", name.Val), name)
	}

	// Check sandbox tag restriction
	// if _, isBanned := p.bannedStmts[tokenName.Val]; isBanned {
	// 	return nil, p.Error(fmt.Sprintf("Usage of statement '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
	// }

	var args []*tokens.Token
	for p.Peek(tokens.BlockEnd) == nil && !p.Stream.End() {
		// Add token to args
		args = append(args, p.Next())
		// p.Consume() // next token
	}

	// EOF?
	// if p.Remaining() == 0 {
	// 	return nil, p.Error("Unexpectedly reached EOF, no statement end found.", p.lastToken)
	// }

	if p.Match(tokens.BlockEnd) == nil {
		return nil, p.Error(fmt.Sprintf(`Expected end of block "%s"`, p.Config.BlockEndString), p.Current())
	}

	argParser := NewParser("statement", p.Config, tokens.NewStream(args))
	// argParser := newParser(p.name, argsToken, p.template)
	// if len(argsToken) == 0 {
	// 	// This is done to have nice EOF error messages
	// 	argParser.lastToken = tokenName
	// }

	p.Level++
	defer func() { p.Level-- }()
	return stmtParser(p, argParser)
}

// type StatementParser func(parser *Parser, args *Parser) (nodes.Stmt, error)

func (p *Parser) ParseStatementBlock() (*nodes.StatementBlock, error) {
	log.WithFields(log.Fields{
		"current": p.Current(),
	}).Trace("ParseStatementBlock")

	begin := p.Match(tokens.BlockBegin)
	if begin == nil {
		return nil, errors.Errorf(`Expected "%s" got "%s"`, p.Config.BlockStartString, p.Current())
	}

	name := p.Match(tokens.Name)
	if name == nil {
		return nil, p.Error("Expected a statement name here", p.Current())
	}

	// Check for the existing statement
	stmtParser, exists := p.Statements[name.Val]
	if !exists {
		// Does not exists
		return nil, p.Error(fmt.Sprintf("Statement '%s' not found (or beginning not provided)", name.Val), name)
	}

	// Check sandbox tag restriction
	// if _, isBanned := p.bannedStmts[tokenName.Val]; isBanned {
	// 	return nil, p.Error(fmt.Sprintf("Usage of statement '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
	// }

	log.Trace("args")
	var args []*tokens.Token
	for p.Peek(tokens.BlockEnd) == nil && !p.Stream.End() {
		log.Trace("for args")
		// Add token to args
		args = append(args, p.Next())
		// p.Consume() // next token
	}
	log.Trace("loop ended")

	// EOF?
	// if p.Remaining() == 0 {
	// 	return nil, p.Error("Unexpectedly reached EOF, no statement end found.", p.lastToken)
	// }

	end := p.Match(tokens.BlockEnd)
	if end == nil {
		return nil, p.Error(fmt.Sprintf(`Expected end of block "%s"`, p.Config.BlockEndString), p.Current())
	}
	log.WithFields(log.Fields{
		"args": args,
	}).Trace("Matched end block")

	stream := tokens.NewStream(args)
	log.WithFields(log.Fields{
		"stream": stream,
	}).Trace("Got stream")
	argParser := NewParser(fmt.Sprintf("%s:args", name.Val), p.Config, stream)
	log.Trace("argparser")
	// argParser := newParser(p.name, argsToken, p.template)
	// if len(argsToken) == 0 {
	// 	// This is done to have nice EOF error messages
	// 	argParser.lastToken = tokenName
	// }

	// p.template.level++
	// defer func() { p.template.level-- }()
	stmt, err := stmtParser(p, argParser)
	if err != nil {
		return nil, errors.Wrapf(err, `Unable to parse statement "%s"`, name.Val)
	}
	log.Trace("got stmt and return")
	return &nodes.StatementBlock{
		Location: begin,
		Name:     name.Val,
		Stmt:     stmt,
		LStrip:   begin.Val[len(begin.Val)-1] == '+',
		Trim: &nodes.Trim{
			Left:  begin.Val[len(begin.Val)-1] == '-',
			Right: end.Val[0] == '-',
		},
	}, nil
}


<|start_filename|>builtins/statements/macro.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
	"github.com/pkg/errors"
)

type MacroStmt struct {
	*nodes.Macro
}

// func (stmt *MacroStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *MacroStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("MacroStmt(Macro=%s Line=%d Col=%d)", stmt.Macro, t.Line, t.Col)
}

func (stmt *MacroStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	macro, err := exec.MacroNodeToFunc(stmt.Macro, r)
	if err != nil {
		return errors.Wrapf(err, `Unable to parse marco '%s'`, stmt.Name)
	}
	r.Ctx.Set(stmt.Name, macro)
	return nil
}

func (node *MacroStmt) call(ctx *exec.Context, args ...*exec.Value) *exec.Value {
	// argsCtx := make(exec.Context)

	// for k, v := range node.args {
	// 	if v == nil {
	// 		// User did not provided a default value
	// 		argsCtx[k] = nil
	// 	} else {
	// 		// Evaluate the default value
	// 		valueExpr, err := v.Evaluate(ctx)
	// 		if err != nil {
	// 			ctx.Logf(err.Error())
	// 			return AsSafeValue(err.Error())
	// 		}

	// 		argsCtx[k] = valueExpr
	// 	}
	// }

	// if len(args) > len(node.argsOrder) {
	// 	// Too many arguments, we're ignoring them and just logging into debug mode.
	// 	err := ctx.Error(fmt.Sprintf("Macro '%s' called with too many arguments (%d instead of %d).",
	// 		node.name, len(args), len(node.argsOrder)), nil).updateFromTokenIfNeeded(ctx.template, node.position)

	// 	ctx.Logf(err.Error()) // TODO: This is a workaround, because the error is not returned yet to the Execution()-methods
	// 	return AsSafeValue(err.Error())
	// }

	// // Make a context for the macro execution
	// macroCtx := NewChildExecutionContext(ctx)

	// // Register all arguments in the private context
	// macroCtx.Private.Update(argsCtx)

	// for idx, argValue := range args {
	// 	macroCtx.Private[node.argsOrder[idx]] = argValue.Interface()
	// }

	// var b bytes.Buffer
	// err := node.wrapper.Execute(macroCtx, &b)
	// if err != nil {
	// 	return AsSafeValue(err.updateFromTokenIfNeeded(ctx.template, node.position).Error())
	// }

	// return AsSafeValue(b.String())
	return nil
}

func macroParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &nodes.Macro{
		Location: p.Current(),
		Args:     []string{},
		Kwargs:   []*nodes.Pair{},
	}

	name := args.Match(tokens.Name)
	if name == nil {
		return nil, args.Error("Macro-tag needs at least an identifier as name.", nil)
	}
	stmt.Name = name.Val

	if args.Match(tokens.Lparen) == nil {
		return nil, args.Error("Expected '('.", nil)
	}

	for args.Match(tokens.Rparen) == nil {
		argName := args.Match(tokens.Name)
		if argName == nil {
			return nil, args.Error("Expected argument name as identifier.", nil)
		}

		if args.Match(tokens.Assign) != nil {
			// Default expression follows
			expr, err := args.ParseExpression()
			if err != nil {
				return nil, err
			}
			stmt.Kwargs = append(stmt.Kwargs, &nodes.Pair{
				Key:   &nodes.String{argName, argName.Val},
				Value: expr,
			})
			// stmt.Kwargs[argName.Val] = expr
		} else {
			stmt.Args = append(stmt.Args, argName.Val)
		}

		if args.Match(tokens.Rparen) != nil {
			break
		}
		if args.Match(tokens.Comma) == nil {
			return nil, args.Error("Expected ',' or ')'.", nil)
		}
	}

	// if args.MatchName("export") != nil {
	// 	stmt.exported = true
	// }

	if !args.End() {
		return nil, args.Error("Malformed macro-tag.", nil)
	}

	// Body wrapping
	wrapper, endargs, err := p.WrapUntil("endmacro")
	if err != nil {
		return nil, err
	}
	stmt.Wrapper = wrapper

	if !endargs.End() {
		return nil, endargs.Error("Arguments not allowed here.", nil)
	}

	p.Template.Macros[stmt.Name] = stmt

	// if stmt.exported {
	// 	// Now register the macro if it wants to be exported
	// 	_, has := p.template.exportedMacros[stmt.name]
	// 	if has {
	// 		return nil, p.Error(fmt.Sprintf("another macro with name '%s' already exported", stmt.name), start)
	// 	}
	// 	p.template.exportedMacros[stmt.name] = stmt
	// }

	return &MacroStmt{stmt}, nil
}

func init() {
	All.Register("macro", macroParser)
}


<|start_filename|>exec/macro.go<|end_filename|>
package exec

import (
	"strings"

	"github.com/noirbizarre/gonja/nodes"
	"github.com/pkg/errors"
	// "github.com/noirbizarre/gonja/nodes"
)

// FilterFunction is the type filter functions must fulfil
type Macro func(params *VarArgs) *Value

type MacroSet map[string]Macro

// Exists returns true if the given filter is already registered
func (ms MacroSet) Exists(name string) bool {
	_, existing := ms[name]
	return existing
}

// Register registers a new filter. If there's already a filter with the same
// name, Register will panic. You usually want to call this
// function in the filter's init() function:
// http://golang.org/doc/effective_go.html#init
//
// See http://www.florian-schlachter.de/post/gonja/ for more about
// writing filters and tags.
func (ms *MacroSet) Register(name string, fn Macro) error {
	if ms.Exists(name) {
		return errors.Errorf("filter with name '%s' is already registered", name)
	}
	(*ms)[name] = fn
	return nil
}

// Replace replaces an already registered filter with a new implementation. Use this
// function with caution since it allows you to change existing filter behaviour.
func (ms *MacroSet) Replace(name string, fn Macro) error {
	if !ms.Exists(name) {
		return errors.Errorf("filter with name '%s' does not exist (therefore cannot be overridden)", name)
	}
	(*ms)[name] = fn
	return nil
}

func MacroNodeToFunc(node *nodes.Macro, r *Renderer) (Macro, error) {
	// Compute default values once
	defaultKwargs := []*KwArg{}
	var err error
	for _, pair := range node.Kwargs {
		key := r.Eval(pair.Key).String()
		value := r.Eval(pair.Value)
		if value.IsError() {
			return nil, errors.Wrapf(value, `Unable to evaluate parameter %s=%s`, key, pair.Value)
		}
		defaultKwargs = append(defaultKwargs, &KwArg{key, value.Interface()})
	}

	return func(params *VarArgs) *Value {
		var out strings.Builder
		sub := r.Inherit()
		sub.Out = &out

		if err != nil {
			return AsValue(err)
		}
		p := params.Expect(len(node.Args), defaultKwargs)
		if p.IsError() {
			return AsValue(errors.Wrapf(p, `Wrong '%s' macro signature`, node.Name))
		}
		for idx, arg := range p.Args {
			sub.Ctx.Set(node.Args[idx], arg)
		}
		for key, value := range p.KwArgs {
			sub.Ctx.Set(key, value)
		}
		err := sub.ExecuteWrapper(node.Wrapper)
		if err != nil {
			return AsValue(errors.Wrapf(err, `Unable to execute macro '%s`, node.Name))
		}
		return AsSafeValue(out.String())
	}, err
}


<|start_filename|>tokens/stream.go<|end_filename|>
package tokens

import "fmt"

type Stream struct {
	it       TokenIterator
	previous *Token
	current  *Token
	next     *Token
	backup   *Token
	buffer   []*Token
	tokens   []*Token
}

type TokenIterator interface {
	Next() *Token
}

type chanIterator struct {
	input chan *Token
}

func ChanIterator(input chan *Token) TokenIterator {
	return &chanIterator{input}
}

func (ci *chanIterator) Next() *Token {
	return <-ci.input
}

type sliceIterator struct {
	input []*Token
	idx   int
}

func SliceIterator(input []*Token) TokenIterator {
	length := len(input)
	var last *Token
	if length > 0 {
		last = input[length-1]
	}
	if last == nil || last.Type != EOF {
		input = append(input, &Token{Type: EOF})
	}
	return &sliceIterator{input, 0}
}

func (si *sliceIterator) Next() *Token {
	if si.idx < len(si.input) {
		tok := si.input[si.idx]
		si.idx++
		return tok
	} else {
		return nil
	}
}

func NewStream(input interface{}) *Stream {
	var it TokenIterator

	switch t := input.(type) {
	case chan *Token:
		it = ChanIterator(t)
	case []*Token:
		it = SliceIterator(t)
	default:
		panic(fmt.Sprintf(`Unsupported stream input type "%T"`, t))
	}

	s := &Stream{
		it:     it,
		buffer: []*Token{},
		tokens: []*Token{},
	}
	s.init()
	return s
}

func (s *Stream) init() {
	s.current = s.nonIgnored()
	if !s.End() {
		s.next = s.nonIgnored()
	}
}

func (s *Stream) nonIgnored() *Token {
	var tok *Token
	for tok = s.it.Next(); tok.Type == Whitespace; tok = s.it.Next() {
	}
	return tok
}

func (s *Stream) consume() *Token {
	s.previous = s.current
	s.current = s.next
	if s.backup != nil {
		s.next = s.backup
		s.backup = nil
	} else if s.End() {
		s.next = nil
	} else {
		s.next = s.nonIgnored()
	}
	return s.previous
}

func (s *Stream) Current() *Token {
	return s.current
}

func (s *Stream) Next() *Token {
	return s.consume()
}

func (s *Stream) EOF() bool {
	return s.current.Type == EOF
}

func (s *Stream) IsError() bool {
	return s.current.Type == Error
}

func (s *Stream) End() bool {
	return s.EOF() || s.IsError()
}

func (s *Stream) Peek() *Token {
	return s.next
}

func (s *Stream) Backup() {
	if s.previous == nil {
		panic("Can't backup")
	}
	s.backup = s.next
	s.next = s.current
	s.current = s.previous
	s.previous = nil
}


<|start_filename|>builtins/statements/with.go<|end_filename|>
package statements

import (
	"fmt"

	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/exec"
	"github.com/noirbizarre/gonja/nodes"
	"github.com/noirbizarre/gonja/parser"
	"github.com/noirbizarre/gonja/tokens"
)

type WithStmt struct {
	Location *tokens.Token
	Pairs    map[string]nodes.Expression
	Wrapper  *nodes.Wrapper
}

func (stmt *WithStmt) Position() *tokens.Token { return stmt.Location }
func (stmt *WithStmt) String() string {
	t := stmt.Position()
	return fmt.Sprintf("WithStmt(Line=%d Col=%d)", t.Line, t.Col)
}

func (stmt *WithStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
	sub := r.Inherit()

	for key, value := range stmt.Pairs {
		val := r.Eval(value)
		if val.IsError() {
			return errors.Wrapf(val, `unable to evaluate parameter %s`, value)
		}
		sub.Ctx.Set(key, val)
	}

	return sub.ExecuteWrapper(stmt.Wrapper)
}

func withParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
	stmt := &WithStmt{
		Location: p.Current(),
		Pairs:    map[string]nodes.Expression{},
	}

	wrapper, endargs, err := p.WrapUntil("endwith")
	if err != nil {
		return nil, err
	}
	stmt.Wrapper = wrapper

	if !endargs.End() {
		return nil, endargs.Error("Arguments not allowed here.", nil)
	}

	for !args.End() {
		key := args.Match(tokens.Name)
		if key == nil {
			return nil, args.Error("Expected an identifier", args.Current())
		}
		if args.Match(tokens.Assign) == nil {
			return nil, args.Error("Expected '='.", args.Current())
		}
		value, err := args.ParseExpression()
		if err != nil {
			return nil, err
		}
		stmt.Pairs[key.Val] = value

		if args.Match(tokens.Comma) == nil {
			break
		}
	}

	if !args.End() {
		return nil, errors.New("")
	}

	return stmt, nil
}

func init() {
	All.Register("with", withParser)
}


<|start_filename|>exec/filters.go<|end_filename|>
package exec

import (
	"github.com/pkg/errors"

	"github.com/noirbizarre/gonja/nodes"
)

// FilterFunction is the type filter functions must fulfil
type FilterFunction func(e *Evaluator, in *Value, params *VarArgs) *Value

type FilterSet map[string]FilterFunction

// Exists returns true if the given filter is already registered
func (fs FilterSet) Exists(name string) bool {
	_, existing := fs[name]
	return existing
}

// Register registers a new filter. If there's already a filter with the same
// name, Register will panic. You usually want to call this
// function in the filter's init() function:
// http://golang.org/doc/effective_go.html#init
//
// See http://www.florian-schlachter.de/post/gonja/ for more about
// writing filters and tags.
func (fs *FilterSet) Register(name string, fn FilterFunction) error {
	if fs.Exists(name) {
		return errors.Errorf("filter with name '%s' is already registered", name)
	}
	(*fs)[name] = fn
	return nil
}

// Replace replaces an already registered filter with a new implementation. Use this
// function with caution since it allows you to change existing filter behaviour.
func (fs *FilterSet) Replace(name string, fn FilterFunction) error {
	if !fs.Exists(name) {
		return errors.Errorf("filter with name '%s' does not exist (therefore cannot be overridden)", name)
	}
	(*fs)[name] = fn
	return nil
}

func (fs *FilterSet) Update(other FilterSet) FilterSet {
	for name, filter := range other {
		(*fs)[name] = filter
	}
	return *fs
}

// EvaluateFiltered evaluate a filtered expression
func (e *Evaluator) EvaluateFiltered(expr *nodes.FilteredExpression) *Value {
	value := e.Eval(expr.Expression)

	for _, filter := range expr.Filters {
		value = e.ExecuteFilter(filter, value)
		if value.IsError() {
			return AsValue(errors.Wrapf(value, `Unable to evaluate filter %s`, filter))
		}
	}

	// if value.IsError() {
	// 	return AsValue(errors.Wrapf(value, `Unable to filter chain`, expr.Expression))
	// }
	return value
}

// ExecuteFilter execute a filter node
func (e *Evaluator) ExecuteFilter(fc *nodes.FilterCall, v *Value) *Value {
	params := NewVarArgs()

	for _, param := range fc.Args {
		value := e.Eval(param)
		if value.IsError() {
			return AsValue(errors.Wrapf(value, `Unable to evaluate parameter %s`, param))
		}
		params.Args = append(params.Args, value)
	}

	for key, param := range fc.Kwargs {
		value := e.Eval(param)
		if value.IsError() {
			return AsValue(errors.Wrapf(value, `Unable to evaluate parameter %s=%s`, key, param))
		}
		params.KwArgs[key] = value
	}
	return e.ExecuteFilterByName(fc.Name, v, params)
}

// ExecuteFilterByName execute a filter given its name
func (e *Evaluator) ExecuteFilterByName(name string, in *Value, params *VarArgs) *Value {
	if !e.Filters.Exists(name) {
		return AsValue(errors.Errorf(`Filter "%s" not found`, name))
	}
	fn, _ := (*e.Filters)[name]

	return fn(e, in, params)
}


<|start_filename|>ext/time/config.go<|end_filename|>
package time

import (
	arrow "github.com/bmuller/arrow/lib"

	"github.com/noirbizarre/gonja/config"
)

type Config struct {
	// Default format
	DatetimeFormat string
	// If defined, now returns this parsed value
	Now *arrow.Arrow
}

func NewConfig() *Config {
	return &Config{
		DatetimeFormat: "%Y-%m-%d",
		Now:            nil,
	}
}

func (cfg *Config) Inherit() config.Inheritable {
	return &Config{
		DatetimeFormat: cfg.DatetimeFormat,
		Now:            cfg.Now,
	}
}

// DefaultConfig is a configuration with default values
var DefaultConfig = NewConfig()


<|start_filename|>tokens/position.go<|end_filename|>
package tokens

import (
	"fmt"
	"strings"
)

type Pos interface {
	Pos() int
}

// Position describes an arbitrary source position
// including the file, line, and column location.
// A Position is valid if the line number is > 0.
//
type Position struct {
	Filename string // filename, if any
	Offset   int    // offset, starting at 0
	Line     int    // line number, starting at 1
	Column   int    // column number, starting at 1 (byte count)
}

// IsValid reports whether the position is valid.
func (pos *Position) IsValid() bool { return pos.Line > 0 }

// Pos return the current offset starting at 0
func (pos *Position) Pos() int { return pos.Offset }

// String returns a string in one of several forms:
//
//	file:line:column    valid position with file name
//	file:line           valid position with file name but no column (column == 0)
//	line:column         valid position without file name
//	line                valid position without file name and no column (column == 0)
//	file                invalid position with file name
//	-                   invalid position without file name
//
func (pos Position) String() string {
	s := pos.Filename
	if pos.IsValid() {
		if s != "" {
			s += ":"
		}
		s += fmt.Sprintf("%d", pos.Line)
		if pos.Column != 0 {
			s += fmt.Sprintf(":%d", pos.Column)
		}
	}
	if s == "" {
		s = "-"
	}
	return s
}

func ReadablePosition(pos int, input string) (int, int) {
	before := input[:pos]
	lines := strings.Split(before, "\n")
	length := len(lines)
	return length, len(lines[length-1]) + 1
}
