func emitProgram(pkgMain *ast.Package, typeInfos map[ast.Node]*typeInfo, indirectVars map[*ast.Identifier]bool) (_ *Code, err error) {
	defer func() {
		if r := recover(); r != nil {
			if e, ok := r.(*LimitExceededError); ok {
				err = e
				return
			}
			panic(r)
		}
	}()
	e := newEmitter(typeInfos, nil, indirectVars)
	functions, _, _ := e.emitPackage(pkgMain, false, "main")
	main, _ := e.fnStore.availableScriggoFn(pkgMain, "main")
	pkg := &Code{
		Globals:   e.varStore.getGlobals(),
		Functions: functions,
		Main:      main,
		TypeOf:    e.types.TypeOf,
	}
	return pkg, nil
}
emitProgram emits the code for a program given its ast node, the type info
and indirect variables. emitProgram returns an emittedPackage  instance
with the global variables and the main function.
package compiler
import (
	"fmt"
	"io"
	"io/fs"
	"reflect"
	"unicode"
	"unicode/utf8"
	"github.com/open2b/scriggo/ast"
	"github.com/open2b/scriggo/internal/runtime"
	"github.com/open2b/scriggo/native"
)
var formatTypeName = [...]string{"string", "html", "css", "js", "json", "markdown"}
const (
	internalOperatorZero = ast.OperatorExtendedNot + iota + 1
	internalOperatorNotZero
)
type Error interface {
	error
	Position() ast.Position
	Path() string
	Message() string
}
type Options struct {
	AllowGoStmt          bool
	NoParseShortShowStmt bool
	DollarIdentifier bool
	FormatTypes map[ast.Format]reflect.Type
	Globals     native.Declarations
	Importer native.Importer
	MDConverter Converter
	TreeTransformer func(*ast.Tree) error
}
type GoModError struct {
	path string
	pos  ast.Position
	msg  string
}
func (e *GoModError) Error() string {
	return fmt.Sprintf("%s:%s: %s", e.path, e.pos, e.msg)
}
func (e *GoModError) Message() string {
	return e.msg
}
func (e *GoModError) Path() string {
	return e.path
}
func (e *GoModError) Position() ast.Position {
	return e.pos
}
func BuildProgram(fsys fs.FS, opts Options) (*Code, error) {
	tree, err := ParseProgram(fsys)
	if err != nil {
		return nil, err
	}
	if opts.TreeTransformer != nil {
		err := opts.TreeTransformer(tree)
		if err != nil {
			return nil, err
		}
	}
	checkerOpts := checkerOptions{
		mod:         programMod,
		allowGoStmt: opts.AllowGoStmt,
		globals:     opts.Globals,
	}
	tci, err := typecheck(tree, opts.Importer, checkerOpts)
	if err != nil {
		return nil, err
	}
	typeInfos := map[ast.Node]*typeInfo{}
	for _, pkgInfos := range tci {
		for node, ti := range pkgInfos.TypeInfos {
			typeInfos[node] = ti
		}
	}
	code, err := emitProgram(tree.Nodes[0].(*ast.Package), typeInfos, tci["main"].IndirectVars)
	if err != nil {
		return nil, err
	}
	return code, nil
}
func BuildScript(r io.Reader, opts Options) (*Code, error) {
	var tree *ast.Tree
	var err error
	tree, err = ParseScript(r, opts.Importer)
	if err != nil {
		return nil, err
	}
	if opts.TreeTransformer != nil {
		err := opts.TreeTransformer(tree)
		if err != nil {
			return nil, err
		}
	}
	checkerOpts := checkerOptions{
		mod:         scriptMod,
		allowGoStmt: opts.AllowGoStmt,
		globals:     opts.Globals,
	}
	tci, err := typecheck(tree, opts.Importer, checkerOpts)
	if err != nil {
		return nil, err
	}
	typeInfos := map[ast.Node]*typeInfo{}
	for _, pkgInfos := range tci {
		for node, ti := range pkgInfos.TypeInfos {
			typeInfos[node] = ti
		}
	}
	code, err := emitScript(tree, typeInfos, tci["main"].IndirectVars)
	return code, err
}
func BuildTemplate(fsys fs.FS, name string, opts Options) (*Code, error) {
	var tree *ast.Tree
	var err error
	tree, err = ParseTemplate(fsys, name, opts.NoParseShortShowStmt, opts.DollarIdentifier)
	if err != nil {
		return nil, err
	}
	if opts.TreeTransformer != nil {
		err := opts.TreeTransformer(tree)
		if err != nil {
			return nil, err
		}
	}
	checkerOpts := checkerOptions{
		allowGoStmt: opts.AllowGoStmt,
		formatTypes: opts.FormatTypes,
		globals:     opts.Globals,
		mdConverter: opts.MDConverter,
		mod:         templateMod,
	}
	tci, err := typecheck(tree, opts.Importer, checkerOpts)
	if err != nil {
		return nil, err
	}
	typeInfos := map[ast.Node]*typeInfo{}
	for _, pkgInfos := range tci {
		for node, ti := range pkgInfos.TypeInfos {
			typeInfos[node] = ti
		}
	}
	code, err := emitTemplate(tree, typeInfos, tci["main"].IndirectVars, opts.FormatTypes)
	return code, err
}
type CheckingError struct {
	path string
	pos  ast.Position
	err  error
}
func (e *CheckingError) Error() string {
	return fmt.Sprintf("%s:%s: %s", e.path, e.pos, e.err)
}
func (e *CheckingError) Message() string {
	return e.err.Error()
}
func (e *CheckingError) Path() string {
	return e.path
}
func (e *CheckingError) Position() ast.Position {
	return e.pos
}
type Global struct {
	Pkg   string
	Name  string
	Type  reflect.Type
	Value reflect.Value
}
type Code struct {
	Globals []Global
	Functions map[string]*runtime.Function
	Main *runtime.Function
	TypeOf runtime.TypeOfFunc
}