func runScript(w *eval.World, scriptName string, optional bool) error {
	fileName := scriptName + ".go"
	path, err := spectrum.ScriptPath(fileName)
	if err != nil {
		return err
	}
	scriptData, err := ioutil.ReadFile(path)
	if err != nil {
		if !optional {
			return err
		} else {
			return nil
		}
	}
	err = intp.run(w, fileName, string(scriptData))
	return err
}
Loads and evaluates the specified Go script
package interpreter
import (
	"fmt"
	"github.com/remogatto/gospeccy/src/spectrum"
	"github.com/sbinet/go-eval"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"sync"
)
var (
	app                 *spectrum.Application
	cmdLineArg          string  
	speccy              *spectrum.Spectrum48k
	w                   *eval.World
	intp                *Interpreter = newInterpreter()
	stdout              io.Writer    = os.Stdout
	IgnoreStartupScript              = false
)
var mutex sync.Mutex
const (
	SCRIPT_DIRECTORY = "scripts"
	STARTUP_SCRIPT   = "startup"
)
type Interpreter struct {
	vars map[string]bool
}
func newInterpreter() *Interpreter {
	return &Interpreter{
		vars: make(map[string]bool),
	}
}
func (i *Interpreter) SetStdout(newStdout io.Writer) io.Writer {
	mutex.Lock()
	defer mutex.Unlock()
	old := stdout
	stdout = newStdout
	return old
}
func (i *Interpreter) Run(sourceCode string) error {
	sourceCode = strings.TrimSpace(sourceCode)
	if sourceCode == "" {
		sourceCode = "help()"
	}
	err := i.run(w, "", sourceCode)
	return err
}
type ast_state_t int
const (
	NONE           ast_state_t = iota
	DEFINE_VAR_LHS              
)
type ast_visitor_t struct {
	newVars map[string]bool
	state   ast_state_t
}
func (v *ast_visitor_t) Visit(node ast.Node) ast.Visitor {
	switch v.state {
	case NONE:
		switch n := node.(type) {
		case *ast.AssignStmt:
			{
				if n.Tok == token.DEFINE {
					oldState := v.state
					v.state = DEFINE_VAR_LHS
					for _, lhs := range n.Lhs {
						ast.Walk(v, lhs)
					}
					v.state = oldState
				}
				return nil
			}
		case *ast.DeclStmt:
			return v
		case *ast.GenDecl:
			return v
		case *ast.ValueSpec:
			{
				var ident *ast.Ident
				for _, ident = range n.Names {
					v.newVars[ident.Name] = true
				}
				return nil
			}
		default:
			return nil
		}
	case DEFINE_VAR_LHS:
		if ident, isIdent := node.(*ast.Ident); isIdent {
			v.newVars[ident.Name] = true
			return nil
		} else {
			return v
		}
	}
	return nil
}
func addTopLevelVars(node ast.Node, buffer map[string]bool) {
	v := &ast_visitor_t{
		newVars: buffer,
		state:   NONE,
	}
	ast.Walk(v, node)
}
func parseStmtList(fset *token.FileSet, src string) ([]ast.Stmt, error) {
	f, err := parser.ParseFile(fset, "input", "package p;func _(){"+src+"\n}", 0)
	if err != nil {
		return nil, err
	}
	return f.Decls[0].(*ast.FuncDecl).Body.List, nil
}
func parseDeclList(fset *token.FileSet, src string) ([]ast.Decl, error) {
	f, err := parser.ParseFile(fset, "input", "package p;"+src, 0)
	if err != nil {
		return nil, err
	}
	return f.Decls, nil
}
func (i *Interpreter) compile(w *eval.World, fileSet *token.FileSet, sourceCode string) (code eval.Code, vars []string, err error) {
	var statements []ast.Stmt
	var declarations []ast.Decl
	vars_buffer := make(map[string]bool)
	statements, err1 := parseStmtList(fileSet, sourceCode)
	if err1 == nil {
		for _, s := range statements {
			addTopLevelVars(s, vars_buffer)
		}
		vars = make([]string, 0, len(vars_buffer))
		for varName, _ := range vars_buffer {
			vars = append(vars, varName)
		}
		code, err = w.CompileStmtList(fileSet, statements)
		return code, vars, err
	}
	declarations, err2 := parseDeclList(fileSet, sourceCode)
	if err2 == nil {
		for _, d := range declarations {
			addTopLevelVars(d, vars_buffer)
		}
		vars = make([]string, 0, len(vars_buffer))
		for varName, _ := range vars_buffer {
			vars = append(vars, varName)
		}
		code, err = w.CompileDeclList(fileSet, declarations)
		return code, vars, err
	}
	return nil, nil, err1
}
func (i *Interpreter) tryToAddVars(w *eval.World, fileSet *token.FileSet, vars []string) {
	for _, name := range vars {
		_, err := w.Compile(fileSet, name  )
		if err == nil {
			i.vars[name] = true
		} else {
		}
	}
}
func (i *Interpreter) run(w *eval.World, path_orEmpty string, sourceCode string) error {
	var code eval.Code
	var vars []string
	var err error
	fileSet := token.NewFileSet()
	if len(path_orEmpty) > 0 {
		fileSet.AddFile(path_orEmpty, fileSet.Base(), len(sourceCode))
	}
	code, vars, err = i.compile(w, fileSet, sourceCode)
	i.tryToAddVars(w, fileSet, vars)
	if err != nil {
		return err
	}
	result, err := code.Run()
	if err != nil {
		return err
	}
	if result != nil {
		fmt.Fprintf(stdout, "%s\n", result)
	}
	return nil
}