- Move from pkg/eval/mods to pkg/mods
- Introduce mods.AddTo that adds all standard library modules
- Move epm and readline-binding into their own packages
The `edit:after-command` hooks are called with a single argument:
a pseudo-map with these keys:
"command": the command line that was run
"duration": the execution duration in seconds
"error": any error that occurred ($nil if no error occurred)
The `edit:command-duration` variable is the elapsed seconds (as a
float64) of the most recently run interactive command.
Resolves#1029
This commit replaces scopeOp, the only remaining place that mutates *Ns in
place, with nsOp, which performs copy-on-write for *Ns.
As a result, the "eval" command no longer mutates the passed namespace. The
default namespace it uses is also changed to match the default of "-source" (an
amalgamated namespace from the local and upvalue scopes), making "-source $file"
equivalent to "eval (slurp <$file)", and formally deprecated.
Another result is that (*Evaler).Eval can now guard the mutation of the global
namespace with the mutex, making it concurrency-safe to execute multiple sources
that touch the global namespace.
This fixes#1137.
- Move NewEnvListVar to pkg/eval/vars.
- De-export GlobPattern, GlobFlag and ExternalCmd.
- Merge editor.go and chdir.go into eval.go, value_helper.go into compile_value.go.
- Remove eval_internal_test.go and replace it with a new test for $pid.
This change makes Ns immutable from the exposed API. Internally there is exactly
one place that still mutates Ns, in scopeOp; this will be addressed later.
- Make Evaler mostly thread-safe. The only remaining thread-unsafe part is the
modules field, which is more tricky than other fields.
- Remove the state and evalerScopes type, and move their fields into Evaler.
- Expose valuePrefix via a get method, and change PortsFromFiles to take the
prefix instead of a *Evaler. Also expose a PortsFromStdFiles.
- Make Evaler a normal field of Frame, instead of an embedded field. This makes
access to global states more explicit.
The Evaler keeps global states and needs to be accessed concurrently. Mutations
to global states have fairly low throughput, so it makes sense to use a single
mutex.
On the other hand, the compiler is always used on a single thread, so it does
not need any mutex protection, so there is no need to put the mutex inside
deprecationRegistry.
- Remove the Op type; it is no longer used by any code outside the eval package
and its use within the package is limited.
- Replace (*Evaler).execOp with (*Evaler).prepareFrame.
Most of the places that need to directly call a function is in the edit package,
which need to call user-defined callbacks.
This change eliminates most call sites of NewTopFrame (including all call sites
outside the eval package). Remove the function and inline it in the remaining
few call sites.
Remove NewTopFrame means that the eval package no longer offers other packages
a way to construct Frame instances. This is intended: Frame is a relatively
low-level concept, and all code outside the eval package now uses the more
high-level Eval, Call, Check/CheckTree methods of *Evaler. The most notable
exception is packages that implement modules; they may still use Frame to access
the information kept in it, but they never construct Frame instances.
In future, the Frame type can be changed to an interface.
This feature supersedes the CompileWithGlobal method, and simplifies the only
use of that method in pkg/edit, where the default binding is evaluated using the
edit: namespace as the global Ns.
The Compile method was used only by the syntax highlighting code to find
compilation errors. Since it only needs the error part but not the Op part,
provide an alternative API that only exposes the error.
This method has the property that it always tries to compile the code even if
there is a parse failure. This is the more desirable behavior when checking
code: if there is a parse failure near the end of a chunk of code, the user may
like to learn about compile errors earlier in the code.