func ExprFunc(filename string, src interface{}, env StringDict) (*Function, error) {
	expr, err := syntax.ParseExpr(filename, src, 0)
	if err != nil {
		return nil, err
	}
	return makeExprFunc(expr, env)
}
ExprFunc returns a no-argument function
that evaluates the expression whose source is src.
package starlark
import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/big"
	"sort"
	"strings"
	"sync/atomic"
	"time"
	"unicode"
	"unicode/utf8"
	"unsafe"
	"go.starlark.net/internal/compile"
	"go.starlark.net/internal/spell"
	"go.starlark.net/resolve"
	"go.starlark.net/syntax"
)
type Thread struct {
	Name string
	stack []*frame
	Print func(thread *Thread, msg string)
	Load func(thread *Thread, module string) (StringDict, error)
	steps, maxSteps uint64
	cancelReason *string
	locals map[string]interface{}
	proftime time.Duration
}
func (thread *Thread) ExecutionSteps() uint64 {
	return thread.steps
}
func (thread *Thread) SetMaxExecutionSteps(max uint64) {
	thread.maxSteps = max
}
func (thread *Thread) Cancel(reason string) {
	atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&thread.cancelReason)), nil, unsafe.Pointer(&reason))
}
func (thread *Thread) SetLocal(key string, value interface{}) {
	if thread.locals == nil {
		thread.locals = make(map[string]interface{})
	}
	thread.locals[key] = value
}
func (thread *Thread) Local(key string) interface{} {
	return thread.locals[key]
}
func (thread *Thread) CallFrame(depth int) CallFrame {
	return thread.frameAt(depth).asCallFrame()
}
func (thread *Thread) frameAt(depth int) *frame {
	return thread.stack[len(thread.stack)-1-depth]
}
func (thread *Thread) CallStack() CallStack {
	frames := make([]CallFrame, len(thread.stack))
	for i, fr := range thread.stack {
		frames[i] = fr.asCallFrame()
	}
	return frames
}
func (thread *Thread) CallStackDepth() int { return len(thread.stack) }
type StringDict map[string]Value
func (d StringDict) Keys() []string {
	names := make([]string, 0, len(d))
	for name := range d {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}
func (d StringDict) String() string {
	buf := new(strings.Builder)
	buf.WriteByte('{')
	sep := ""
	for _, name := range d.Keys() {
		buf.WriteString(sep)
		buf.WriteString(name)
		buf.WriteString(": ")
		writeValue(buf, d[name], nil)
		sep = ", "
	}
	buf.WriteByte('}')
	return buf.String()
}
func (d StringDict) Freeze() {
	for _, v := range d {
		v.Freeze()
	}
}
func (d StringDict) Has(key string) bool { _, ok := d[key]; return ok }
type frame struct {
	callable  Callable  
	pc        uint32    
	locals    []Value   
	spanStart int64     
}
func (fr *frame) Position() syntax.Position {
	switch c := fr.callable.(type) {
	case *Function:
		return c.funcode.Position(fr.pc)
	case callableWithPosition:
		return c.Position()
	}
	return syntax.MakePosition(&builtinFilename, 0, 0)
}
var builtinFilename = "<builtin>"
func (fr *frame) Callable() Callable { return fr.callable }
type CallStack []CallFrame
func (stack CallStack) At(i int) CallFrame { return stack[len(stack)-1-i] }
func (stack *CallStack) Pop() CallFrame {
	last := len(*stack) - 1
	top := (*stack)[last]
	*stack = (*stack)[:last]
	return top
}
func (stack CallStack) String() string {
	out := new(strings.Builder)
	if len(stack) > 0 {
		fmt.Fprintf(out, "Traceback (most recent call last):\n")
	}
	for _, fr := range stack {
		fmt.Fprintf(out, "  %s: in %s\n", fr.Pos, fr.Name)
	}
	return out.String()
}
type EvalError struct {
	Msg       string
	CallStack CallStack
	cause     error
}
type CallFrame struct {
	Name string
	Pos  syntax.Position
}
func (fr *frame) asCallFrame() CallFrame {
	return CallFrame{
		Name: fr.Callable().Name(),
		Pos:  fr.Position(),
	}
}
func (thread *Thread) evalError(err error) *EvalError {
	return &EvalError{
		Msg:       err.Error(),
		CallStack: thread.CallStack(),
		cause:     err,
	}
}
func (e *EvalError) Error() string { return e.Msg }
func (e *EvalError) Backtrace() string {
	stack := e.CallStack
	suffix := ""
	if last := len(stack) - 1; last >= 0 && stack[last].Pos.Filename() == builtinFilename {
		suffix = " in " + stack[last].Name
		stack = stack[:last]
	}
	return fmt.Sprintf("%sError%s: %s", stack, suffix, e.Msg)
}
func (e *EvalError) Unwrap() error { return e.cause }
type Program struct {
	compiled *compile.Program
}
const CompilerVersion = compile.Version
func (prog *Program) Filename() string { return prog.compiled.Toplevel.Pos.Filename() }
func (prog *Program) String() string { return prog.Filename() }
func (prog *Program) NumLoads() int { return len(prog.compiled.Loads) }
func (prog *Program) Load(i int) (string, syntax.Position) {
	id := prog.compiled.Loads[i]
	return id.Name, id.Pos
}
func (prog *Program) Write(out io.Writer) error {
	data := prog.compiled.Encode()
	_, err := out.Write(data)
	return err
}
func ExecFile(thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) {
	_, mod, err := SourceProgram(filename, src, predeclared.Has)
	if err != nil {
		return nil, err
	}
	g, err := mod.Init(thread, predeclared)
	g.Freeze()
	return g, err
}
func SourceProgram(filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) {
	f, err := syntax.Parse(filename, src, 0)
	if err != nil {
		return nil, nil, err
	}
	prog, err := FileProgram(f, isPredeclared)
	return f, prog, err
}
func FileProgram(f *syntax.File, isPredeclared func(string) bool) (*Program, error) {
	if err := resolve.File(f, isPredeclared, Universe.Has); err != nil {
		return nil, err
	}
	var pos syntax.Position
	if len(f.Stmts) > 0 {
		pos = syntax.Start(f.Stmts[0])
	} else {
		pos = syntax.MakePosition(&f.Path, 1, 1)
	}
	module := f.Module.(*resolve.Module)
	compiled := compile.File(f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
	return &Program{compiled}, nil
}
func CompiledProgram(in io.Reader) (*Program, error) {
	data, err := ioutil.ReadAll(in)
	if err != nil {
		return nil, err
	}
	compiled, err := compile.DecodeProgram(data)
	if err != nil {
		return nil, err
	}
	return &Program{compiled}, nil
}
func (prog *Program) Init(thread *Thread, predeclared StringDict) (StringDict, error) {
	toplevel := makeToplevelFunction(prog.compiled, predeclared)
	_, err := Call(thread, toplevel, nil, nil)
	return toplevel.Globals(), err
}
func ExecREPLChunk(f *syntax.File, thread *Thread, globals StringDict) error {
	var predeclared StringDict
	if err := resolve.REPLChunk(f, globals.Has, predeclared.Has, Universe.Has); err != nil {
		return err
	}
	var pos syntax.Position
	if len(f.Stmts) > 0 {
		pos = syntax.Start(f.Stmts[0])
	} else {
		pos = syntax.MakePosition(&f.Path, 1, 1)
	}
	module := f.Module.(*resolve.Module)
	compiled := compile.File(f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
	prog := &Program{compiled}
	toplevel := makeToplevelFunction(prog.compiled, predeclared)
	for i, id := range prog.compiled.Globals {
		if v := globals[id.Name]; v != nil {
			toplevel.module.globals[i] = v
		}
	}
	_, err := Call(thread, toplevel, nil, nil)
	for i, id := range prog.compiled.Globals {
		if v := toplevel.module.globals[i]; v != nil {
			globals[id.Name] = v
		}
	}
	return err
}
func makeToplevelFunction(prog *compile.Program, predeclared StringDict) *Function {
	constants := make([]Value, len(prog.Constants))
	for i, c := range prog.Constants {
		var v Value
		switch c := c.(type) {
		case int64:
			v = MakeInt64(c)
		case *big.Int:
			v = MakeBigInt(c)
		case string:
			v = String(c)
		case compile.Bytes:
			v = Bytes(c)
		case float64:
			v = Float(c)
		default:
			log.Panicf("unexpected constant %T: %v", c, c)
		}
		constants[i] = v
	}
	return &Function{
		funcode: prog.Toplevel,
		module: &module{
			program:     prog,
			predeclared: predeclared,
			globals:     make([]Value, len(prog.Globals)),
			constants:   constants,
		},
	}
}
func Eval(thread *Thread, filename string, src interface{}, env StringDict) (Value, error) {
	expr, err := syntax.ParseExpr(filename, src, 0)
	if err != nil {
		return nil, err
	}
	f, err := makeExprFunc(expr, env)
	if err != nil {
		return nil, err
	}
	return Call(thread, f, nil, nil)
}
func EvalExpr(thread *Thread, expr syntax.Expr, env StringDict) (Value, error) {
	fn, err := makeExprFunc(expr, env)
	if err != nil {
		return nil, err
	}
	return Call(thread, fn, nil, nil)
}