updated hseval behavior
This commit is contained in:
@@ -185,13 +185,13 @@ While diverging from some "purity" aspects, Clyx is a decent choice for newcomer
|
||||
|
||||
### What do I need to do to create my own Clyx implementation?
|
||||
|
||||
Just port the core interpreter along with the 50 primitive words, stubbing out the words that cannot be supported by the target platform if there are any, so that if a program that e.g. uses `nopen` runs on a non-networked host environment, or a program that uses `hseval` runs on a C-based interpreter, then the user would get a clear message that an unsupported core primitive word has been encountered and the program has been terminated because of that.
|
||||
Just port the core interpreter along with the 50 primitive words, stubbing out the words that cannot be supported by the target platform if there are any, so that if a program that e.g. uses `nopen` runs on a non-networked host environment, then the user would get a clear message that an unsupported core primitive word has been encountered and the program has been terminated because of that.
|
||||
|
||||
Apart from that, your implementation needs to be able to load `lib.clx` (standard library source) upon initialization, and `clyx_repl.clx` upon passing no parameters (if it is CLI-based).
|
||||
|
||||
### Doesn't `hseval` primitive make Clyx programs non-portable across different implementations?
|
||||
|
||||
Yes, it does, because it works differently across different host languages (and Clyx implementations like `clyx-go` are allowed to not support it at all), so it must only be used as a last resort when any other attempts to interact with the outside world are unsuccessful. Additionally, using `hseval` introduces extra security risks. Nevertheless, this primitive had been added in order to enable some host-specific interoperability that would otherwise be impossible or very cumbersome to implement, such as browser-based deployments.
|
||||
Yes, it does, because it works differently across different host environments and languages (e.g. Python expression evaluation vs. Go system shell command execution), so it must only be used as a last resort when any other attempts to interact with the outside world are unsuccessful. Additionally, using `hseval` introduces extra security risks. Nevertheless, this primitive had been added in order to enable some host-specific interoperability that would otherwise be impossible or very cumbersome to implement, such as browser-based deployments.
|
||||
|
||||
In other words, `hseval` is sometimes very useful in very specific cases, but please avoid using it unless you have a really good reason to use it.
|
||||
|
||||
|
||||
+27
-1
@@ -11,6 +11,8 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
@@ -474,7 +476,31 @@ func NewClyx(libfname string, libCode string) *Clyx {
|
||||
}
|
||||
c.stack = append(c.stack, sb.String())
|
||||
}
|
||||
c.words["hseval"] = func() { fmt.Fprintln(os.Stderr, "Error: unsupported word"); os.Exit(1) }
|
||||
c.words["hseval"] = func() {
|
||||
cmdStr := c.pop().(string)
|
||||
var shell, flag string
|
||||
if runtime.GOOS == "windows" {
|
||||
shell = "cmd"
|
||||
flag = "/c"
|
||||
} else {
|
||||
shell = "sh"
|
||||
flag = "-c"
|
||||
}
|
||||
cmd := exec.Command(shell, flag, cmdStr)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
err := cmd.Run()
|
||||
var exitCode int64 = 0
|
||||
if err != nil {
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
exitCode = int64(exitError.ExitCode())
|
||||
} else {
|
||||
exitCode = -1
|
||||
}
|
||||
}
|
||||
c.stack = append(c.stack, exitCode)
|
||||
}
|
||||
c.words["chr"] = func() { c.stack = append(c.stack, string(rune(toInt(c.pop())))) }
|
||||
|
||||
regMath := func(name string, f func(float64) float64) {
|
||||
|
||||
+5
-3
@@ -313,11 +313,13 @@ Any line fragment starting with `#` to the end of the physical source line is re
|
||||
|
||||
**N.B.**: on the platforms that don't support specifying process exit codes, this primitive may either do nothing, exit the program the usual way supported by the platform or trigger a global interpreter restart.
|
||||
|
||||
### `hseval` (Host Language Evaluation)
|
||||
### `hseval` (Host Evaluation / Execution)
|
||||
- **Stack Effect**: `( expr -- val )`
|
||||
- **Description**: Pops the string `expr` from the stack, evaluates it as an expression in the host language (e.g., Python), and pushes the resulting value back onto the stack.
|
||||
- **Description**: Pops the string `expr` from the stack and evaluates or executes it in the host environment.
|
||||
- In the Python implementation, it evaluates `expr` as a Python expression and pushes the resulting value back onto the stack.
|
||||
- In the Go implementation, it executes `expr` as a system shell command, redirects its stdin/stdout/stderr to the current process, and pushes the command's exit code back onto the stack.
|
||||
|
||||
**N.B.**: this primitive may not be supported on all targets. Only use as a last resort in controlled and/or sandboxed environments. Never pass user input to this primitive.
|
||||
**N.B.**: this primitive may not be supported on all targets, and its behavior varies by implementation. Only use as a last resort in controlled and/or sandboxed environments. Never pass unvalidated user input to this primitive.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user