func (c *Compiler) CompileString() (string, error) {
	var buf bytes.Buffer
	if err := c.CompileWriter(&buf); err != nil {
		return "", err
	}
	result := buf.String()
	return result, nil
}
CompileString compiles the template and returns the Go Template source.
You would not be using this unless debugging / checking the output. Please use Compile
method to obtain a template instance directly.
package amber
import (
	"bytes"
	"container/list"
	"errors"
	"fmt"
	"go/ast"
	gp "go/parser"
	gt "go/token"
	"html/template"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"github.com/eknkc/amber/parser"
)
var builtinFunctions = [...]string{
	"len",
	"print",
	"printf",
	"println",
	"urlquery",
	"js",
	"json",
	"index",
	"html",
	"unescaped",
}
const (
	dollar = "__DOLLAR__"
)
type Compiler struct {
	Options
	filename     string
	node         parser.Node
	indentLevel  int
	newline      bool
	buffer       *bytes.Buffer
	tempvarIndex int
	mixins       map[string]*parser.Mixin
}
func New() *Compiler {
	compiler := new(Compiler)
	compiler.filename = ""
	compiler.tempvarIndex = 0
	compiler.PrettyPrint = true
	compiler.Options = DefaultOptions
	compiler.mixins = make(map[string]*parser.Mixin)
	return compiler
}
type Options struct {
	PrettyPrint bool
	LineNumbers bool
	VirtualFilesystem http.FileSystem
}
type DirOptions struct {
	Ext string
	Recursive bool
}
var DefaultOptions = Options{true, false, nil}
var DefaultDirOptions = DirOptions{".amber", true}
func Compile(input string, options Options) (*template.Template, error) {
	comp := New()
	comp.Options = options
	err := comp.Parse(input)
	if err != nil {
		return nil, err
	}
	return comp.Compile()
}
func CompileData(input []byte, filename string, options Options) (*template.Template, error) {
	comp := New()
	comp.Options = options
	err := comp.ParseData(input, filename)
	if err != nil {
		return nil, err
	}
	return comp.Compile()
}
func MustCompile(input string, options Options) *template.Template {
	t, err := Compile(input, options)
	if err != nil {
		panic(err)
	}
	return t
}
func CompileFile(filename string, options Options) (*template.Template, error) {
	comp := New()
	comp.Options = options
	err := comp.ParseFile(filename)
	if err != nil {
		return nil, err
	}
	return comp.Compile()
}
func MustCompileFile(filename string, options Options) *template.Template {
	t, err := CompileFile(filename, options)
	if err != nil {
		panic(err)
	}
	return t
}
func CompileDir(dirname string, dopt DirOptions, opt Options) (map[string]*template.Template, error) {
	dir, err := os.Open(dirname)
	if err != nil && opt.VirtualFilesystem != nil {
		vdir, err := opt.VirtualFilesystem.Open(dirname)
		if err != nil {
			return nil, err
		}
		dir = vdir.(*os.File)
	} else if err != nil {
		return nil, err
	}
	defer dir.Close()
	files, err := dir.Readdir(0)
	if err != nil {
		return nil, err
	}
	compiled := make(map[string]*template.Template)
	for _, file := range files {
		filename := file.Name()
		fileext := filepath.Ext(filename)
		if dopt.Recursive && file.IsDir() {
			dirpath := filepath.Join(dirname, filename)
			subcompiled, err := CompileDir(dirpath, dopt, opt)
			if err != nil {
				return nil, err
			}
			for k, v := range subcompiled {
				key := filepath.Join(filename, k)
				compiled[key] = v
			}
		} else if fileext == dopt.Ext {
			fullpath := filepath.Join(dirname, filename)
			tmpl, err := CompileFile(fullpath, opt)
			if err != nil {
				return nil, err
			}
			key := filename[0 : len(filename)-len(fileext)]
			compiled[key] = tmpl
		}
	}
	return compiled, nil
}
func MustCompileDir(dirname string, dopt DirOptions, opt Options) map[string]*template.Template {
	m, err := CompileDir(dirname, dopt, opt)
	if err != nil {
		panic(err)
	}
	return m
}
func (c *Compiler) Parse(input string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(r.(string))
		}
	}()
	parser, err := parser.StringParser(input)
	if err != nil {
		return
	}
	c.node = parser.Parse()
	return
}
func (c *Compiler) ParseData(input []byte, filename string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(r.(string))
		}
	}()
	parser, err := parser.ByteParser(input)
	parser.SetFilename(filename)
	if c.VirtualFilesystem != nil {
		parser.SetVirtualFilesystem(c.VirtualFilesystem)
	}
	if err != nil {
		return
	}
	c.node = parser.Parse()
	return
}
func (c *Compiler) ParseFile(filename string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(r.(string))
		}
	}()
	p, err := parser.FileParser(filename)
	if err != nil && c.VirtualFilesystem != nil {
		p, err = parser.VirtualFileParser(filename, c.VirtualFilesystem)
	}
	if err != nil {
		return
	}
	c.node = p.Parse()
	c.filename = filename
	return
}
func (c *Compiler) Compile() (*template.Template, error) {
	return c.CompileWithName(filepath.Base(c.filename))
}
func (c *Compiler) CompileWithName(name string) (*template.Template, error) {
	return c.CompileWithTemplate(template.New(name))
}
func (c *Compiler) CompileWithTemplate(t *template.Template) (*template.Template, error) {
	data, err := c.CompileString()
	if err != nil {
		return nil, err
	}
	tpl, err := t.Funcs(FuncMap).Parse(data)
	if err != nil {
		return nil, err
	}
	return tpl, nil
}
func (c *Compiler) CompileWriter(out io.Writer) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(r.(string))
		}
	}()
	c.buffer = new(bytes.Buffer)
	c.visit(c.node)
	if c.buffer.Len() > 0 {
		c.write("\n")
	}
	_, err = c.buffer.WriteTo(out)
	return
}