js: codegen fixes, W.I.P `os` availability for JS backend (#11281)
parent
47278b4a7d
commit
d78e7e3b2b
|
@ -239,3 +239,7 @@ pub fn (a array) contains(key voidptr) bool {
|
||||||
pub fn (mut a array) delete_last() {
|
pub fn (mut a array) delete_last() {
|
||||||
#a.val.arr.pop();
|
#a.val.arr.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
pub fn (a array) free() {
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
module math
|
module math
|
||||||
|
|
||||||
fn JS.Math.pow(x f64, y f64) f64
|
fn JS.Math.pow(x f64, y f64) f64
|
||||||
|
|
||||||
|
pub fn pow(x f64, y f64) f64 {
|
||||||
|
return JS.Math.pow(x, y)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
$if js_node {
|
||||||
|
#const $ENV = $process.env
|
||||||
|
} $else {
|
||||||
|
#const $ENV = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setenv sets the value of an environment variable with `name` to `value`.
|
||||||
|
pub fn setenv(key string, val string, overwrite bool) {
|
||||||
|
#if ($ENV[key] && !(overwrite.valueOf())) return;
|
||||||
|
#$ENV[key] = val + '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// `getenv` returns the value of the environment variable named by the key.
|
||||||
|
pub fn getenv(key string) string {
|
||||||
|
mut res := ''
|
||||||
|
#if ($ENV[key]) res = new builtin.string($ENV[key])
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsetenv clears an environment variable with `name`.
|
||||||
|
pub fn unsetenv(name string) int {
|
||||||
|
#$ENV[name] = ""
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn environ() map[string]string {
|
||||||
|
mut res := map[string]string{}
|
||||||
|
#for (const key in $ENV) {
|
||||||
|
#res.map.set(key,$ENV[key])
|
||||||
|
#}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
#const $fs = require('fs');
|
||||||
|
#const $path = require('path');
|
||||||
|
|
||||||
|
pub const (
|
||||||
|
args = []string{}
|
||||||
|
path_delimiter = '/'
|
||||||
|
path_separator = '/'
|
||||||
|
)
|
||||||
|
|
||||||
|
$if js_node {
|
||||||
|
#$process.argv.forEach(function(val,index) { args.arr[index] = new string(val); })
|
||||||
|
}
|
||||||
|
|
||||||
|
// real_path returns the full absolute path for fpath, with all relative ../../, symlinks and so on resolved.
|
||||||
|
// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html
|
||||||
|
// Also https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
||||||
|
// and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html
|
||||||
|
// NB: this particular rabbit hole is *deep* ...
|
||||||
|
pub fn real_path(fpath string) string {
|
||||||
|
$if js_node {
|
||||||
|
mut res := ''
|
||||||
|
#res = new string( $fs.realpathSync(fpath))
|
||||||
|
|
||||||
|
return res
|
||||||
|
} $else {
|
||||||
|
return fpath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush will flush the stdout buffer.
|
||||||
|
pub fn flush() {
|
||||||
|
$if js_node {
|
||||||
|
#$process.stdout.write('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// chmod change file access attributes of `path` to `mode`.
|
||||||
|
// Octals like `0o600` can be used.
|
||||||
|
pub fn chmod(path string, mode int) {
|
||||||
|
$if js_node {
|
||||||
|
#$fs.chmodSync(''+path,mode.valueOf())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// chown changes the owner and group attributes of `path` to `owner` and `group`.
|
||||||
|
// Octals like `0o600` can be used.
|
||||||
|
pub fn chown(path string, owner int, group int) {
|
||||||
|
$if js_node {
|
||||||
|
#$fs.chownSync(''+path,owner.valueOf(),group.valueOf())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn temp_dir() string {
|
||||||
|
mut res := ''
|
||||||
|
$if js_node {
|
||||||
|
#res = new builtin.string($os.tmpdir())
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn home_dir() string {
|
||||||
|
mut res := ''
|
||||||
|
$if js_node {
|
||||||
|
#res = new builtin.string($os.homedir())
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// join_path returns a path as string from input string parameter(s).
|
||||||
|
pub fn join_path(base string, dirs ...string) string {
|
||||||
|
mut result := []string{}
|
||||||
|
result << base.trim_right('\\/')
|
||||||
|
for d in dirs {
|
||||||
|
result << d
|
||||||
|
}
|
||||||
|
mut path_sep := ''
|
||||||
|
#path_sep = $path.sep;
|
||||||
|
|
||||||
|
res := result.join(path_sep)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(cmd string) Result {
|
||||||
|
mut exit_code := 0
|
||||||
|
mut stdout := ''
|
||||||
|
#let commands = cmd.str.split(' ');
|
||||||
|
#let output = $child_process.spawnSync(commands[0],commands.slice(1,commands.length));
|
||||||
|
#exit_code = new builtin.int(output.status)
|
||||||
|
#stdout = new builtin.string(output.stdout + '')
|
||||||
|
|
||||||
|
return Result{
|
||||||
|
exit_code: exit_code
|
||||||
|
output: stdout
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
pub fn mkdir(path string) ?bool {
|
||||||
|
$if js_node {
|
||||||
|
if path == '.' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
#$fs.mkdirSync(path.valueOf())
|
||||||
|
|
||||||
|
return true
|
||||||
|
} $else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_dir(path string) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = $fs.existsSync(path,str) && $fs.lstatSync(path.str).isDirectory()
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_link(path string) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = $fs.existsSync(path.str) && $fs.lstatSync(path.str).isSymbolicLink()
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exists(path string) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = $fs.existsSync(path.str)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ls(path string) ?[]string {
|
||||||
|
if !is_dir(path) {
|
||||||
|
return error('ls(): cannot open dir $dir')
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []string{}
|
||||||
|
#let i = 0
|
||||||
|
#$fs.readdirSync(path.str).forEach((path) => result.arr[i++] = new builtin.string(path))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
// signal_kill - kills the process, after that it is no longer running
|
||||||
|
pub fn (mut p Process) signal_kill() {
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p._signal_kill()
|
||||||
|
p.status = .aborted
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal_pgkill - kills the whole process group
|
||||||
|
pub fn (mut p Process) signal_pgkill() {
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p._signal_pgkill()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal_stop - stops the process, you can resume it with p.signal_continue()
|
||||||
|
pub fn (mut p Process) signal_stop() {
|
||||||
|
if p.status != .running {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p._signal_stop()
|
||||||
|
p.status = .stopped
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal_continue - tell a stopped process to continue/resume its work
|
||||||
|
pub fn (mut p Process) signal_continue() {
|
||||||
|
if p.status != .stopped {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p._signal_continue()
|
||||||
|
p.status = .running
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait - wait for a process to finish.
|
||||||
|
// NB: You have to call p.wait(), otherwise a finished process
|
||||||
|
// would get to a zombie state, and its resources will not get
|
||||||
|
// released fully, until its parent process exits.
|
||||||
|
// NB: This call will block the calling process until the child
|
||||||
|
// process is finished.
|
||||||
|
pub fn (mut p Process) wait() {
|
||||||
|
if p.status == .not_started {
|
||||||
|
p._spawn()
|
||||||
|
}
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p._wait()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// close - free the OS resources associated with the process.
|
||||||
|
// Can be called multiple times, but will free the resources just once.
|
||||||
|
// This sets the process state to .closed, which is final.
|
||||||
|
pub fn (mut p Process) close() {
|
||||||
|
if p.status in [.not_started, .closed] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.status = .closed
|
||||||
|
$if !windows {
|
||||||
|
for i in 0 .. 3 {
|
||||||
|
if p.stdio_fd[i] != 0 {
|
||||||
|
fd_close(p.stdio_fd[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
pub fn (mut p Process) free() {
|
||||||
|
p.close()
|
||||||
|
unsafe {
|
||||||
|
p.filename.free()
|
||||||
|
p.err.free()
|
||||||
|
p.args.free()
|
||||||
|
p.env.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// _spawn - should not be called directly, but only by p.run()/p.wait() .
|
||||||
|
// It encapsulates the fork/execve mechanism that allows the
|
||||||
|
// asynchronous starting of the new child process.
|
||||||
|
fn (mut p Process) _spawn() int {
|
||||||
|
if !p.env_is_custom {
|
||||||
|
p.env = []string{}
|
||||||
|
current_environment := environ()
|
||||||
|
for k, v in current_environment {
|
||||||
|
p.env << '$k=$v'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut pid := 0
|
||||||
|
$if windows {
|
||||||
|
pid = p.win_spawn_process()
|
||||||
|
} $else {
|
||||||
|
pid = p.unix_spawn_process()
|
||||||
|
}
|
||||||
|
p.pid = pid
|
||||||
|
p.status = .running
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// is_alive - query whether the process p.pid is still alive
|
||||||
|
pub fn (mut p Process) is_alive() bool {
|
||||||
|
if p.status in [.running, .stopped] {
|
||||||
|
return p._is_alive()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
pub fn (mut p Process) set_redirect_stdio() {
|
||||||
|
p.use_stdio_ctl = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stdin_write(s string) {
|
||||||
|
p._check_redirection_call('stdin_write')
|
||||||
|
$if windows {
|
||||||
|
p.win_write_string(0, s)
|
||||||
|
} $else {
|
||||||
|
fd_write(p.stdio_fd[0], s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will read from stdout pipe, will only return when EOF (end of file) or data
|
||||||
|
// means this will block unless there is data
|
||||||
|
pub fn (mut p Process) stdout_slurp() string {
|
||||||
|
p._check_redirection_call('stdout_slurp')
|
||||||
|
$if windows {
|
||||||
|
return p.win_slurp(1)
|
||||||
|
} $else {
|
||||||
|
return fd_slurp(p.stdio_fd[1]).join('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read from stderr pipe, wait for data or EOF
|
||||||
|
pub fn (mut p Process) stderr_slurp() string {
|
||||||
|
p._check_redirection_call('stderr_slurp')
|
||||||
|
$if windows {
|
||||||
|
return p.win_slurp(2)
|
||||||
|
} $else {
|
||||||
|
return fd_slurp(p.stdio_fd[2]).join('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read from stdout, return if data or not
|
||||||
|
pub fn (mut p Process) stdout_read() string {
|
||||||
|
p._check_redirection_call('stdout_read')
|
||||||
|
$if windows {
|
||||||
|
s, _ := p.win_read_string(1, 4096)
|
||||||
|
return s
|
||||||
|
} $else {
|
||||||
|
s, _ := fd_read(p.stdio_fd[1], 4096)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stderr_read() string {
|
||||||
|
p._check_redirection_call('stderr_read')
|
||||||
|
$if windows {
|
||||||
|
s, _ := p.win_read_string(2, 4096)
|
||||||
|
return s
|
||||||
|
} $else {
|
||||||
|
s, _ := fd_read(p.stdio_fd[2], 4096)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _check_redirection_call - should be called just by stdxxx methods
|
||||||
|
fn (mut p Process) _check_redirection_call(fn_name string) {
|
||||||
|
if !p.use_stdio_ctl {
|
||||||
|
panic('Call p.set_redirect_stdio() before calling p.$fn_name')
|
||||||
|
}
|
||||||
|
if p.status == .not_started {
|
||||||
|
panic('Call p.${fn_name}() after you have called p.run()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_stop - should not be called directly, except by p.signal_stop
|
||||||
|
fn (mut p Process) _signal_stop() {
|
||||||
|
$if windows {
|
||||||
|
p.win_stop_process()
|
||||||
|
} $else {
|
||||||
|
p.unix_stop_process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_continue - should not be called directly, just by p.signal_continue
|
||||||
|
fn (mut p Process) _signal_continue() {
|
||||||
|
$if windows {
|
||||||
|
p.win_resume_process()
|
||||||
|
} $else {
|
||||||
|
p.unix_resume_process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_kill - should not be called directly, except by p.signal_kill
|
||||||
|
fn (mut p Process) _signal_kill() {
|
||||||
|
$if windows {
|
||||||
|
p.win_kill_process()
|
||||||
|
} $else {
|
||||||
|
p.unix_kill_process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_pgkill - should not be called directly, except by p.signal_pgkill
|
||||||
|
fn (mut p Process) _signal_pgkill() {
|
||||||
|
$if windows {
|
||||||
|
p.win_kill_pgroup()
|
||||||
|
} $else {
|
||||||
|
p.unix_kill_pgroup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _wait - should not be called directly, except by p.wait()
|
||||||
|
fn (mut p Process) _wait() {
|
||||||
|
$if windows {
|
||||||
|
p.win_wait()
|
||||||
|
} $else {
|
||||||
|
p.unix_wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _is_alive - should not be called directly, except by p.is_alive()
|
||||||
|
fn (mut p Process) _is_alive() bool {
|
||||||
|
$if windows {
|
||||||
|
return p.win_is_alive()
|
||||||
|
} $else {
|
||||||
|
return p.unix_is_alive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run - starts the new process
|
||||||
|
pub fn (mut p Process) run() {
|
||||||
|
if p.status != .not_started {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p._spawn()
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
#const $child_process = require('child_process')
|
||||||
|
|
||||||
|
// new_process - create a new process descriptor
|
||||||
|
// NB: new does NOT start the new process.
|
||||||
|
// That is done because you may want to customize it first,
|
||||||
|
// by calling different set_ methods on it.
|
||||||
|
// In order to start it, call p.run() or p.wait()
|
||||||
|
pub fn new_process(filename string) &Process {
|
||||||
|
return &Process{
|
||||||
|
filename: filename
|
||||||
|
stdio_fd: [-1, -1, -1]!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) spawn_internal() {
|
||||||
|
#p.val.pid = $child_process.spawn(
|
||||||
|
#p.val.filename+'',
|
||||||
|
#p.val.args.arr.map((x) => x.valueOf() + ''),
|
||||||
|
#{
|
||||||
|
#env: (p.val.env_is_custom ? p.val.env : $process.env),
|
||||||
|
#})
|
||||||
|
#p.val.pid.on('error', function (err) { builtin.panic('Failed to start subprocess') })
|
||||||
|
|
||||||
|
p.status = .running
|
||||||
|
// todo(playX): stderr,stdin
|
||||||
|
if p.use_stdio_ctl {
|
||||||
|
#p.val.pid.stdout.pipe(process.stdout)
|
||||||
|
#p.val.pid.stdin.pipe(process.stdin)
|
||||||
|
#p.val.pid.stderr.pipe(process.stderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) run() {
|
||||||
|
if p.status != .not_started {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.spawn_internal()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) signal_kill() {
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
#p.val.pid.kill('SIGKILL');
|
||||||
|
|
||||||
|
p.status = .aborted
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) signal_stop() {
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
#p.val.pid.kill('SIGSTOP');
|
||||||
|
|
||||||
|
p.status = .aborted
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) signal_continue() {
|
||||||
|
if p.status != .stopped {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
#p.val.pid.kill('SIGCONT');
|
||||||
|
|
||||||
|
p.status = .running
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) wait() {
|
||||||
|
if p.status == .not_started {
|
||||||
|
p.spawn_internal()
|
||||||
|
}
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.wait_internal()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) wait_internal() {
|
||||||
|
#p.val.pid.on('exit', function (code) { console.log(code) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) set_redirect_stdio() {
|
||||||
|
p.use_stdio_ctl = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stdin_write(s string) {
|
||||||
|
p.check_redirection_call('stdin_write')
|
||||||
|
#p.val.pid.stdin.write(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo(playX): probably does not work
|
||||||
|
|
||||||
|
// will read from stdout pipe, will only return when EOF (end of file) or data
|
||||||
|
// means this will block unless there is data
|
||||||
|
pub fn (mut p Process) stdout_slurp() string {
|
||||||
|
p.check_redirection_call('stdout_slurp')
|
||||||
|
mut res := ''
|
||||||
|
#p.val.pid.stdout.on('data', function (data) { res = new builtin.string(data) })
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// _check_redirection_call - should be called just by stdxxx methods
|
||||||
|
fn (mut p Process) check_redirection_call(fn_name string) {
|
||||||
|
if !p.use_stdio_ctl {
|
||||||
|
panic('Call p.set_redirect_stdio() before calling p.$fn_name')
|
||||||
|
}
|
||||||
|
if p.status == .not_started {
|
||||||
|
panic('Call p.${fn_name}() after you have called p.run()')
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,250 +68,3 @@ pub fn (mut p Process) set_environment(envs map[string]string) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// run - starts the new process
|
|
||||||
pub fn (mut p Process) run() {
|
|
||||||
if p.status != .not_started {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p._spawn()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// signal_kill - kills the process, after that it is no longer running
|
|
||||||
pub fn (mut p Process) signal_kill() {
|
|
||||||
if p.status !in [.running, .stopped] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p._signal_kill()
|
|
||||||
p.status = .aborted
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// signal_pgkill - kills the whole process group
|
|
||||||
pub fn (mut p Process) signal_pgkill() {
|
|
||||||
if p.status !in [.running, .stopped] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p._signal_pgkill()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// signal_stop - stops the process, you can resume it with p.signal_continue()
|
|
||||||
pub fn (mut p Process) signal_stop() {
|
|
||||||
if p.status != .running {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p._signal_stop()
|
|
||||||
p.status = .stopped
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// signal_continue - tell a stopped process to continue/resume its work
|
|
||||||
pub fn (mut p Process) signal_continue() {
|
|
||||||
if p.status != .stopped {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p._signal_continue()
|
|
||||||
p.status = .running
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait - wait for a process to finish.
|
|
||||||
// NB: You have to call p.wait(), otherwise a finished process
|
|
||||||
// would get to a zombie state, and its resources will not get
|
|
||||||
// released fully, until its parent process exits.
|
|
||||||
// NB: This call will block the calling process until the child
|
|
||||||
// process is finished.
|
|
||||||
pub fn (mut p Process) wait() {
|
|
||||||
if p.status == .not_started {
|
|
||||||
p._spawn()
|
|
||||||
}
|
|
||||||
if p.status !in [.running, .stopped] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p._wait()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// close - free the OS resources associated with the process.
|
|
||||||
// Can be called multiple times, but will free the resources just once.
|
|
||||||
// This sets the process state to .closed, which is final.
|
|
||||||
pub fn (mut p Process) close() {
|
|
||||||
if p.status in [.not_started, .closed] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.status = .closed
|
|
||||||
$if !windows {
|
|
||||||
for i in 0 .. 3 {
|
|
||||||
if p.stdio_fd[i] != 0 {
|
|
||||||
fd_close(p.stdio_fd[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[unsafe]
|
|
||||||
pub fn (mut p Process) free() {
|
|
||||||
p.close()
|
|
||||||
unsafe {
|
|
||||||
p.filename.free()
|
|
||||||
p.err.free()
|
|
||||||
p.args.free()
|
|
||||||
p.env.free()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// _spawn - should not be called directly, but only by p.run()/p.wait() .
|
|
||||||
// It encapsulates the fork/execve mechanism that allows the
|
|
||||||
// asynchronous starting of the new child process.
|
|
||||||
fn (mut p Process) _spawn() int {
|
|
||||||
if !p.env_is_custom {
|
|
||||||
p.env = []string{}
|
|
||||||
current_environment := environ()
|
|
||||||
for k, v in current_environment {
|
|
||||||
p.env << '$k=$v'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut pid := 0
|
|
||||||
$if windows {
|
|
||||||
pid = p.win_spawn_process()
|
|
||||||
} $else {
|
|
||||||
pid = p.unix_spawn_process()
|
|
||||||
}
|
|
||||||
p.pid = pid
|
|
||||||
p.status = .running
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// is_alive - query whether the process p.pid is still alive
|
|
||||||
pub fn (mut p Process) is_alive() bool {
|
|
||||||
if p.status in [.running, .stopped] {
|
|
||||||
return p._is_alive()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
pub fn (mut p Process) set_redirect_stdio() {
|
|
||||||
p.use_stdio_ctl = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut p Process) stdin_write(s string) {
|
|
||||||
p._check_redirection_call('stdin_write')
|
|
||||||
$if windows {
|
|
||||||
p.win_write_string(0, s)
|
|
||||||
} $else {
|
|
||||||
fd_write(p.stdio_fd[0], s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// will read from stdout pipe, will only return when EOF (end of file) or data
|
|
||||||
// means this will block unless there is data
|
|
||||||
pub fn (mut p Process) stdout_slurp() string {
|
|
||||||
p._check_redirection_call('stdout_slurp')
|
|
||||||
$if windows {
|
|
||||||
return p.win_slurp(1)
|
|
||||||
} $else {
|
|
||||||
return fd_slurp(p.stdio_fd[1]).join('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// read from stderr pipe, wait for data or EOF
|
|
||||||
pub fn (mut p Process) stderr_slurp() string {
|
|
||||||
p._check_redirection_call('stderr_slurp')
|
|
||||||
$if windows {
|
|
||||||
return p.win_slurp(2)
|
|
||||||
} $else {
|
|
||||||
return fd_slurp(p.stdio_fd[2]).join('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// read from stdout, return if data or not
|
|
||||||
pub fn (mut p Process) stdout_read() string {
|
|
||||||
p._check_redirection_call('stdout_read')
|
|
||||||
$if windows {
|
|
||||||
s, _ := p.win_read_string(1, 4096)
|
|
||||||
return s
|
|
||||||
} $else {
|
|
||||||
s, _ := fd_read(p.stdio_fd[1], 4096)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut p Process) stderr_read() string {
|
|
||||||
p._check_redirection_call('stderr_read')
|
|
||||||
$if windows {
|
|
||||||
s, _ := p.win_read_string(2, 4096)
|
|
||||||
return s
|
|
||||||
} $else {
|
|
||||||
s, _ := fd_read(p.stdio_fd[2], 4096)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _check_redirection_call - should be called just by stdxxx methods
|
|
||||||
fn (mut p Process) _check_redirection_call(fn_name string) {
|
|
||||||
if !p.use_stdio_ctl {
|
|
||||||
panic('Call p.set_redirect_stdio() before calling p.$fn_name')
|
|
||||||
}
|
|
||||||
if p.status == .not_started {
|
|
||||||
panic('Call p.${fn_name}() after you have called p.run()')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _signal_stop - should not be called directly, except by p.signal_stop
|
|
||||||
fn (mut p Process) _signal_stop() {
|
|
||||||
$if windows {
|
|
||||||
p.win_stop_process()
|
|
||||||
} $else {
|
|
||||||
p.unix_stop_process()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _signal_continue - should not be called directly, just by p.signal_continue
|
|
||||||
fn (mut p Process) _signal_continue() {
|
|
||||||
$if windows {
|
|
||||||
p.win_resume_process()
|
|
||||||
} $else {
|
|
||||||
p.unix_resume_process()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _signal_kill - should not be called directly, except by p.signal_kill
|
|
||||||
fn (mut p Process) _signal_kill() {
|
|
||||||
$if windows {
|
|
||||||
p.win_kill_process()
|
|
||||||
} $else {
|
|
||||||
p.unix_kill_process()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _signal_pgkill - should not be called directly, except by p.signal_pgkill
|
|
||||||
fn (mut p Process) _signal_pgkill() {
|
|
||||||
$if windows {
|
|
||||||
p.win_kill_pgroup()
|
|
||||||
} $else {
|
|
||||||
p.unix_kill_pgroup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _wait - should not be called directly, except by p.wait()
|
|
||||||
fn (mut p Process) _wait() {
|
|
||||||
$if windows {
|
|
||||||
p.win_wait()
|
|
||||||
} $else {
|
|
||||||
p.unix_wait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// _is_alive - should not be called directly, except by p.is_alive()
|
|
||||||
fn (mut p Process) _is_alive() bool {
|
|
||||||
$if windows {
|
|
||||||
return p.win_is_alive()
|
|
||||||
} $else {
|
|
||||||
return p.unix_is_alive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -348,7 +348,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
||||||
'f32', 'f64', 'float_literal' {
|
'f32', 'f64', 'float_literal' {
|
||||||
g.gen_builtin_prototype(
|
g.gen_builtin_prototype(
|
||||||
typ_name: typ_name
|
typ_name: typ_name
|
||||||
constructor: 'this.val = +val'
|
constructor: 'this.val = Number(val)'
|
||||||
default_value: 'new Number(0)'
|
default_value: 'new Number(0)'
|
||||||
to_jsval: '+this'
|
to_jsval: '+this'
|
||||||
)
|
)
|
||||||
|
|
|
@ -1595,6 +1595,7 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// interfaces require dynamic dispatch. To obtain method table we use getPrototypeOf
|
// interfaces require dynamic dispatch. To obtain method table we use getPrototypeOf
|
||||||
g.write('Object.getPrototypeOf(')
|
g.write('Object.getPrototypeOf(')
|
||||||
g.expr(it.left)
|
g.expr(it.left)
|
||||||
|
@ -1660,6 +1661,15 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||||
}
|
}
|
||||||
g.call_stack << it
|
g.call_stack << it
|
||||||
mut name := g.js_name(it.name)
|
mut name := g.js_name(it.name)
|
||||||
|
ret_sym := g.table.get_type_symbol(it.return_type)
|
||||||
|
if it.language == .js && ret_sym.name in js.v_types && ret_sym.name != 'void' {
|
||||||
|
g.write('new ')
|
||||||
|
if g.ns.name != 'builtin' {
|
||||||
|
g.write('builtin.')
|
||||||
|
}
|
||||||
|
g.write(ret_sym.name)
|
||||||
|
g.write('(')
|
||||||
|
}
|
||||||
call_return_is_optional := it.return_type.has_flag(.optional)
|
call_return_is_optional := it.return_type.has_flag(.optional)
|
||||||
if call_return_is_optional {
|
if call_return_is_optional {
|
||||||
g.writeln('(function(){')
|
g.writeln('(function(){')
|
||||||
|
@ -1717,6 +1727,9 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.write('})()')
|
g.write('})()')
|
||||||
}
|
}
|
||||||
|
if it.language == .js && ret_sym.name in js.v_types && ret_sym.name != 'void' {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
g.call_stack.delete_last()
|
g.call_stack.delete_last()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1761,7 +1774,7 @@ fn (mut g JsGen) need_tmp_var_in_match(node ast.MatchExpr) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var string, tmp_var string) {
|
fn (mut g JsGen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var MatchCond, tmp_var string) {
|
||||||
type_sym := g.table.get_type_symbol(node.cond_type)
|
type_sym := g.table.get_type_symbol(node.cond_type)
|
||||||
for j, branch in node.branches {
|
for j, branch in node.branches {
|
||||||
is_last := j == node.branches.len - 1
|
is_last := j == node.branches.len - 1
|
||||||
|
@ -1801,27 +1814,37 @@ fn (mut g JsGen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var s
|
||||||
}
|
}
|
||||||
match type_sym.kind {
|
match type_sym.kind {
|
||||||
.array {
|
.array {
|
||||||
g.write('vEq($cond_var, ')
|
g.write('vEq(')
|
||||||
|
g.match_cond(cond_var)
|
||||||
|
g.write(',')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.array_fixed {
|
.array_fixed {
|
||||||
g.write('vEq($cond_var, ')
|
g.write('vEq(')
|
||||||
|
g.match_cond(cond_var)
|
||||||
|
g.write(',')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
g.write('vEq($cond_var, ')
|
g.write('vEq(')
|
||||||
|
g.match_cond(cond_var)
|
||||||
|
g.write(',')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.string {
|
.string {
|
||||||
g.write('vEq($cond_var, ')
|
g.write('vEq(')
|
||||||
|
g.match_cond(cond_var)
|
||||||
|
g.write(',')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.struct_ {
|
.struct_ {
|
||||||
g.write('vEq($cond_var, ')
|
g.write('vEq(')
|
||||||
|
g.match_cond(cond_var)
|
||||||
|
g.write(',')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
@ -1837,15 +1860,19 @@ fn (mut g JsGen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var s
|
||||||
}
|
}
|
||||||
g.write('(')
|
g.write('(')
|
||||||
if !skip_low {
|
if !skip_low {
|
||||||
g.write('$cond_var >= ')
|
g.match_cond(cond_var)
|
||||||
|
g.write(' >= ')
|
||||||
g.expr(expr.low)
|
g.expr(expr.low)
|
||||||
g.write(' && ')
|
g.write(' && ')
|
||||||
}
|
}
|
||||||
g.write('$cond_var <= ')
|
g.match_cond(cond_var)
|
||||||
|
g.write(' <= ')
|
||||||
g.expr(expr.high)
|
g.expr(expr.high)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else {
|
} else {
|
||||||
g.write('vEq($cond_var,')
|
g.write('vEq(')
|
||||||
|
g.match_cond(cond_var)
|
||||||
|
g.write(',')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
@ -1865,6 +1892,27 @@ fn (mut g JsGen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MatchCond = CondExpr | CondString
|
||||||
|
|
||||||
|
struct CondString {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CondExpr {
|
||||||
|
expr ast.Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) match_cond(cond MatchCond) {
|
||||||
|
match cond {
|
||||||
|
CondString {
|
||||||
|
g.writeln(cond.s)
|
||||||
|
}
|
||||||
|
CondExpr {
|
||||||
|
g.expr(cond.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) match_expr(node ast.MatchExpr) {
|
fn (mut g JsGen) match_expr(node ast.MatchExpr) {
|
||||||
if node.cond_type == 0 {
|
if node.cond_type == 0 {
|
||||||
g.writeln('// match 0')
|
g.writeln('// match 0')
|
||||||
|
@ -1873,16 +1921,22 @@ fn (mut g JsGen) match_expr(node ast.MatchExpr) {
|
||||||
prev := g.inside_ternary
|
prev := g.inside_ternary
|
||||||
need_tmp_var := g.need_tmp_var_in_match(node)
|
need_tmp_var := g.need_tmp_var_in_match(node)
|
||||||
is_expr := (node.is_expr && node.return_type != ast.void_type) || g.inside_ternary
|
is_expr := (node.is_expr && node.return_type != ast.void_type) || g.inside_ternary
|
||||||
mut cond_var := ''
|
mut cond_var := MatchCond(CondString{''})
|
||||||
mut tmp_var := ''
|
mut tmp_var := ''
|
||||||
if is_expr && !need_tmp_var {
|
if is_expr && !need_tmp_var {
|
||||||
g.inside_ternary = true
|
g.inside_ternary = true
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_var = g.new_tmp_var()
|
if node.cond is ast.Ident || node.cond is ast.SelectorExpr || node.cond is ast.IntegerLiteral
|
||||||
g.write('let $cond_var = ')
|
|| node.cond is ast.StringLiteral || node.cond is ast.FloatLiteral {
|
||||||
g.expr(node.cond)
|
cond_var = CondExpr{node.cond}
|
||||||
g.write(';')
|
} else {
|
||||||
|
s := g.new_tmp_var()
|
||||||
|
cond_var = CondString{s}
|
||||||
|
g.write('let $s = ')
|
||||||
|
g.expr(node.cond)
|
||||||
|
g.writeln(';')
|
||||||
|
}
|
||||||
if need_tmp_var {
|
if need_tmp_var {
|
||||||
tmp_var = g.new_tmp_var()
|
tmp_var = g.new_tmp_var()
|
||||||
g.writeln('let $tmp_var = undefined;')
|
g.writeln('let $tmp_var = undefined;')
|
||||||
|
@ -1927,7 +1981,7 @@ fn (mut g JsGen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var string, tmp_var string) {
|
fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var MatchCond, tmp_var string) {
|
||||||
for j, branch in node.branches {
|
for j, branch in node.branches {
|
||||||
mut sumtype_index := 0
|
mut sumtype_index := 0
|
||||||
for {
|
for {
|
||||||
|
@ -1954,7 +2008,7 @@ fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var s
|
||||||
} else {
|
} else {
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
}
|
}
|
||||||
g.write(cond_var)
|
g.match_cond(cond_var)
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
g.write(' instanceof ')
|
g.write(' instanceof ')
|
||||||
g.expr(branch.exprs[sumtype_index])
|
g.expr(branch.exprs[sumtype_index])
|
||||||
|
@ -2669,20 +2723,20 @@ fn (mut g JsGen) gen_float_literal_expr(it ast.FloatLiteral) {
|
||||||
// TODO: call.language always seems to be "v", parser bug?
|
// TODO: call.language always seems to be "v", parser bug?
|
||||||
if g.call_stack.len > 0 {
|
if g.call_stack.len > 0 {
|
||||||
call := g.call_stack[g.call_stack.len - 1]
|
call := g.call_stack[g.call_stack.len - 1]
|
||||||
// if call.language == .js {
|
if call.language == .js {
|
||||||
for i, t in call.args {
|
for i, t in call.args {
|
||||||
if t.expr is ast.FloatLiteral {
|
if t.expr is ast.FloatLiteral {
|
||||||
if t.expr == it {
|
if t.expr == it {
|
||||||
if call.expected_arg_types[i] in ast.integer_type_idxs {
|
if call.expected_arg_types[i] in ast.integer_type_idxs {
|
||||||
g.write(int(it.val.f64()).str())
|
g.write(int(it.val.f64()).str())
|
||||||
} else {
|
} else {
|
||||||
g.write(it.val)
|
g.write(it.val)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip cast if type is the same as the parrent caster
|
// Skip cast if type is the same as the parrent caster
|
||||||
|
|
Loading…
Reference in New Issue