From fe2080ba9ad3ee5b6b0c173d519af9661e87d594 Mon Sep 17 00:00:00 2001 From: HAYAMA_Kaoru Date: Sun, 4 May 2025 16:29:34 +0900 Subject: [PATCH] Add `New` function to construct and initialize Env instances The `New` function creates a new `Env` that embeds a `gmnlisp.World` and sets up the necessary pseudoterminal and inter-goroutine communication channels. This allows users to execute Lisp code with flexible argument control and custom Go function integration, offering more control compared to `RunString` or `RunFile`. --- global.go | 9 +++++++-- main.go | 36 ++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/global.go b/global.go index 80bac9c..fa661cd 100644 --- a/global.go +++ b/global.go @@ -20,8 +20,9 @@ var ( var ErrCtrlC = errors.New("^C") type Env struct { - w *Watcher - term *Term + w *Watcher + term *Term + *gmnlisp.World closer []func() } @@ -30,6 +31,10 @@ func (env *Env) Close() { env.closer[i]() } env.closer = nil + if env.term != nil { + env.term.Close() + env.term = nil + } } func (env *Env) send(ctx context.Context, w *gmnlisp.World, args []gmnlisp.Node) (gmnlisp.Node, error) { diff --git a/main.go b/main.go index 43b0c35..61975e8 100644 --- a/main.go +++ b/main.go @@ -21,18 +21,14 @@ func RunFile(fname string, args []string) error { return RunString(string(script), args) } -// RunString executes a Lisp script given directly as a string. -// -// - script: the Lisp source code to be executed (equivalent to the contents of a file). -// - args: typically corresponds to os.Args[1:]. -// - args[0]: the script file name (not used directly). -// - args[1:]: arguments passed to the script. -func RunString(script string, args []string) error { +// New creates a new Env instance that embeds a gmnlisp.World and +// sets up a pseudoterminal session and related communication structures. +// This allows users to customize and control the Lisp environment flexibly. +func New() (*Env, error) { term, err := NewTerm() if err != nil { - return err + return nil, err } - defer term.Close() watcher := NewWatcher(term) @@ -40,13 +36,12 @@ func RunString(script string, args []string) error { term: term, w: watcher, } - defer env.Close() gmnlisp.NewLineOnFormat = []byte{'\r', '\n'} lisp := gmnlisp.New() - lisp = lisp.Flet( + env.World = lisp.Flet( gmnlisp.Functions{ gmnlisp.NewSymbol("send"): &gmnlisp.Function{Min: 1, F: env.send}, gmnlisp.NewSymbol("sendln"): &gmnlisp.Function{Min: 1, F: env.sendln}, @@ -57,6 +52,23 @@ func RunString(script string, args []string) error { gmnlisp.NewSymbol("setenv"): gmnlisp.Function2(env.setenv), gmnlisp.NewSymbol("wait"): gmnlisp.Function1(env.wait), }) + + return env, nil +} + +// RunString executes a Lisp script given directly as a string. +// +// - script: the Lisp source code to be executed (equivalent to the contents of a file). +// - args: typically corresponds to os.Args[1:]. +// - args[0]: the script file name (not used directly). +// - args[1:]: arguments passed to the script. +func RunString(script string, args []string) error { + env, err := New() + if err != nil { + return err + } + defer env.Close() + posixArgv := []gmnlisp.Node{} for _, s := range args[1:] { posixArgv = append(posixArgv, gmnlisp.String(s)) @@ -65,7 +77,7 @@ func RunString(script string, args []string) error { if value, err := os.Executable(); err == nil { executable = value } - lisp = lisp.Let(gmnlisp.Variables{ + lisp := env.Let(gmnlisp.Variables{ gmnlisp.NewSymbol("ARGV"): gmnlisp.List(posixArgv...), gmnlisp.NewSymbol("*argv*"): gmnlisp.List(posixArgv...), gmnlisp.NewSymbol("PROGRAM-NAME"): gmnlisp.String(args[0]),