js: `os` now compiles to the JS backend, more builtins & minor codegen fixes (#11302)
parent
f257a23313
commit
109d5d5847
|
@ -32,12 +32,38 @@ struct Option {
|
|||
err Error
|
||||
}
|
||||
|
||||
// IError holds information about an error instance
|
||||
pub interface IError {
|
||||
msg string
|
||||
code int
|
||||
}
|
||||
|
||||
// Error is the default implementation of IError, that is returned by e.g. `error()`
|
||||
pub struct Error {
|
||||
pub:
|
||||
msg string
|
||||
code int
|
||||
}
|
||||
|
||||
const none__ = IError(&None__{})
|
||||
|
||||
struct None__ {
|
||||
msg string
|
||||
code int
|
||||
}
|
||||
|
||||
fn (_ None__) str() string {
|
||||
return 'none'
|
||||
}
|
||||
|
||||
pub fn (err IError) str() string {
|
||||
return match err {
|
||||
None__ { 'none' }
|
||||
Error { err.msg }
|
||||
else { '$err.type_name(): $err.msg' }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (o Option) str() string {
|
||||
if o.state == 0 {
|
||||
return 'Option{ ok }'
|
||||
|
@ -48,21 +74,28 @@ pub fn (o Option) str() string {
|
|||
return 'Option{ error: "$o.err" }'
|
||||
}
|
||||
|
||||
pub fn error(s string) Option {
|
||||
return Option{
|
||||
state: 2
|
||||
err: Error{
|
||||
msg: s
|
||||
[if trace_error ?]
|
||||
fn trace_error(x string) {
|
||||
eprintln('> ${@FN} | $x')
|
||||
}
|
||||
|
||||
// error returns a default error instance containing the error given in `message`.
|
||||
// Example: `if ouch { return error('an error occurred') }`
|
||||
[inline]
|
||||
pub fn error(message string) IError {
|
||||
trace_error(message)
|
||||
return &Error{
|
||||
msg: message
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_with_code(s string, code int) Option {
|
||||
return Option{
|
||||
state: 2
|
||||
err: Error{
|
||||
msg: s
|
||||
// error_with_code returns a default error instance containing the given `message` and error `code`.
|
||||
// `if ouch { return error_with_code('an error occurred', 1) }`
|
||||
[inline]
|
||||
pub fn error_with_code(message string, code int) IError {
|
||||
// trace_error('$message | code: $code')
|
||||
return &Error{
|
||||
msg: message
|
||||
code: code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,15 @@ module builtin
|
|||
|
||||
pub fn (b byte) is_space() bool {
|
||||
mut result := false
|
||||
#result = /^\s*$/.test(String.fromCharCode(b))
|
||||
#result.val = /^\s*$/.test(String.fromCharCode(b))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
pub fn (c byte) is_letter() bool {
|
||||
result := false
|
||||
|
||||
#result.val = (c.val >= `a`.charCodeAt() && c.val <= `z`.charCodeAt()) || (c.val >= `A`.charCodeAt() && c.val <= `Z`.charCodeAt())
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -541,3 +541,168 @@ pub fn (s string) split_nth(delim string, nth int) []string {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RepIndex {
|
||||
idx int
|
||||
val_idx int
|
||||
}
|
||||
|
||||
// replace_each replaces all occurences of the string pairs given in `vals`.
|
||||
// Example: assert 'ABCD'.replace_each(['B','C/','C','D','D','C']) == 'AC/DC'
|
||||
[direct_array_access]
|
||||
pub fn (s string) replace_each(vals []string) string {
|
||||
if s.len == 0 || vals.len == 0 {
|
||||
return s.clone()
|
||||
}
|
||||
|
||||
if vals.len % 2 != 0 {
|
||||
eprintln('string.replace_each(): odd number of strings')
|
||||
return s.clone()
|
||||
}
|
||||
|
||||
// `rep` - string to replace
|
||||
// `with_` - string to replace with_
|
||||
// Remember positions of all rep strings, and calculate the length
|
||||
// of the new string to do just one allocation.
|
||||
|
||||
mut idxs := []RepIndex{}
|
||||
mut idx := 0
|
||||
s_ := s.clone()
|
||||
#function setCharAt(str,index,chr) {
|
||||
#if(index > str.length-1) return str;
|
||||
#return str.substring(0,index) + chr + str.substring(index+1);
|
||||
#}
|
||||
|
||||
for rep_i := 0; rep_i < vals.len; rep_i += 2 {
|
||||
rep := vals[rep_i]
|
||||
mut with_ := vals[rep_i + 1]
|
||||
with_ = with_
|
||||
for {
|
||||
idx = s_.index_after(rep, idx)
|
||||
if idx == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
for i in 0 .. rep.len {
|
||||
mut j_ := i
|
||||
j_ = j_
|
||||
#s_.str = setCharAt(s_.str,idx + i, String.fromCharCode(127))
|
||||
}
|
||||
|
||||
idxs << RepIndex{
|
||||
idx: idx
|
||||
val_idx: rep_i
|
||||
}
|
||||
idx += rep.len
|
||||
}
|
||||
}
|
||||
|
||||
if idxs.len == 0 {
|
||||
return s.clone()
|
||||
}
|
||||
|
||||
idxs.sort(a.idx < b.idx)
|
||||
|
||||
mut b := ''
|
||||
mut idx_pos := 0
|
||||
mut cur_idx := idxs[idx_pos]
|
||||
mut b_i := 0
|
||||
for i := 0; i < s.len; i++ {
|
||||
if i == cur_idx.idx {
|
||||
rep := vals[cur_idx.val_idx]
|
||||
with_ := vals[cur_idx.val_idx + 1]
|
||||
for j in 0 .. with_.len {
|
||||
mut j_ := j
|
||||
j_ = j_
|
||||
#b.str = setCharAt(b.str,b_i, with_.str[j])
|
||||
//#b.str[b_i] = with_.str[j]
|
||||
b_i++
|
||||
}
|
||||
i += rep.len - 1
|
||||
idx_pos++
|
||||
if idx_pos < idxs.len {
|
||||
cur_idx = idxs[idx_pos]
|
||||
}
|
||||
} else {
|
||||
#b.str = setCharAt(b.str,b_i,s.str[i]) //b.str[b_i] = s.str[i]
|
||||
b_i++
|
||||
}
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// last_index returns the position of the last occurence of the input string.
|
||||
fn (s string) last_index_(p string) int {
|
||||
if p.len > s.len || p.len == 0 {
|
||||
return -1
|
||||
}
|
||||
mut i := s.len - p.len
|
||||
for i >= 0 {
|
||||
mut j := 0
|
||||
for j < p.len && s[i + j] == p[j] {
|
||||
j++
|
||||
}
|
||||
if j == p.len {
|
||||
return i
|
||||
}
|
||||
i--
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// last_index returns the position of the last occurence of the input string.
|
||||
pub fn (s string) last_index(p string) ?int {
|
||||
idx := s.last_index_(p)
|
||||
if idx == -1 {
|
||||
return none
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
pub fn (s string) trim_space() string {
|
||||
res := ''
|
||||
#res.str = s.str.trim()
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (s string) index_after(p string, start int) int {
|
||||
if p.len > s.len {
|
||||
return -1
|
||||
}
|
||||
|
||||
mut strt := start
|
||||
if start < 0 {
|
||||
strt = 0
|
||||
}
|
||||
if start >= s.len {
|
||||
return -1
|
||||
}
|
||||
mut i := strt
|
||||
|
||||
for i < s.len {
|
||||
mut j := 0
|
||||
mut ii := i
|
||||
for j < p.len && s[ii] == p[j] {
|
||||
j++
|
||||
ii++
|
||||
}
|
||||
|
||||
if j == p.len {
|
||||
return i
|
||||
}
|
||||
i++
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
pub fn (s string) split_into_lines() []string {
|
||||
mut res := []string{}
|
||||
#let i = 0
|
||||
#s.str.split('\n').forEach((str) => {
|
||||
#res.arr[i] = new string(str);
|
||||
#})
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -359,6 +359,7 @@ pub fn (s string) replace_each(vals []string) string {
|
|||
with := vals[rep_i + 1]
|
||||
for {
|
||||
idx = s_.index_after(rep, idx)
|
||||
|
||||
if idx == -1 {
|
||||
break
|
||||
}
|
||||
|
@ -374,6 +375,7 @@ pub fn (s string) replace_each(vals []string) string {
|
|||
idx: idx
|
||||
val_idx: rep_i
|
||||
}
|
||||
|
||||
idx += rep.len
|
||||
new_len += with.len - rep.len
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module os_js
|
||||
module os
|
||||
|
||||
pub struct File {
|
||||
pub:
|
||||
|
@ -128,3 +128,9 @@ pub fn (mut f File) write_string(s string) ?int {
|
|||
nbytes := f.write(s.bytes()) ?
|
||||
return nbytes
|
||||
}
|
||||
|
||||
pub fn (mut f File) close() {
|
||||
#f.valueOf().fd.close()
|
||||
}
|
||||
|
||||
pub fn (mut f File) write_full_buffer(s voidptr, buffer_len size_t) ? {}
|
|
@ -0,0 +1,21 @@
|
|||
module os
|
||||
|
||||
// write_file_array writes the data in `buffer` to a file in `path`.
|
||||
pub fn write_file_array(path string, buffer array) ? {
|
||||
mut f := create(path) ?
|
||||
unsafe { f.write_full_buffer(buffer.data, size_t(buffer.len * buffer.element_size)) ? }
|
||||
f.close()
|
||||
}
|
||||
|
||||
pub fn glob(patterns ...string) ?[]string {
|
||||
mut matches := []string{}
|
||||
for pattern in patterns {
|
||||
native_glob_pattern(pattern, mut matches) ?
|
||||
}
|
||||
matches.sort()
|
||||
return matches
|
||||
}
|
||||
|
||||
pub const (
|
||||
args = []string{}
|
||||
)
|
|
@ -4,9 +4,9 @@ module os
|
|||
#const $path = require('path');
|
||||
|
||||
pub const (
|
||||
args = []string{}
|
||||
path_delimiter = '/'
|
||||
path_separator = '/'
|
||||
args = []string{}
|
||||
)
|
||||
|
||||
$if js_node {
|
||||
|
|
21
vlib/os/os.v
21
vlib/os/os.v
|
@ -4,7 +4,6 @@
|
|||
module os
|
||||
|
||||
pub const (
|
||||
args = []string{}
|
||||
max_path_len = 4096
|
||||
wd_at_startup = getwd()
|
||||
)
|
||||
|
@ -344,22 +343,15 @@ pub fn write_file(path string, text string) ? {
|
|||
f.close()
|
||||
}
|
||||
|
||||
// write_file_array writes the data in `buffer` to a file in `path`.
|
||||
pub fn write_file_array(path string, buffer array) ? {
|
||||
mut f := create(path) ?
|
||||
unsafe { f.write_full_buffer(buffer.data, size_t(buffer.len * buffer.element_size)) ? }
|
||||
f.close()
|
||||
}
|
||||
|
||||
// executable_fallback is used when there is not a more platform specific and accurate implementation.
|
||||
// It relies on path manipulation of os.args[0] and os.wd_at_startup, so it may not work properly in
|
||||
// all cases, but it should be better, than just using os.args[0] directly.
|
||||
fn executable_fallback() string {
|
||||
if os.args.len == 0 {
|
||||
if args.len == 0 {
|
||||
// we are early in the bootstrap, os.args has not been initialized yet :-|
|
||||
return ''
|
||||
}
|
||||
mut exepath := os.args[0]
|
||||
mut exepath := args[0]
|
||||
$if windows {
|
||||
if !exepath.contains('.exe') {
|
||||
exepath += '.exe'
|
||||
|
@ -639,12 +631,3 @@ pub fn execute_or_exit(cmd string) Result {
|
|||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn glob(patterns ...string) ?[]string {
|
||||
mut matches := []string{}
|
||||
for pattern in patterns {
|
||||
native_glob_pattern(pattern, mut matches) ?
|
||||
}
|
||||
matches.sort()
|
||||
return matches
|
||||
}
|
||||
|
|
|
@ -15,22 +15,25 @@ pub fn mkdir(path string) ?bool {
|
|||
|
||||
pub fn is_dir(path string) bool {
|
||||
res := false
|
||||
$if js_node {
|
||||
#res.val = $fs.existsSync(path,str) && $fs.lstatSync(path.str).isDirectory()
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn is_link(path string) bool {
|
||||
res := false
|
||||
$if js_node {
|
||||
#res.val = $fs.existsSync(path.str) && $fs.lstatSync(path.str).isSymbolicLink()
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn exists(path string) bool {
|
||||
res := false
|
||||
$if js_node {
|
||||
#res.val = $fs.existsSync(path.str)
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -40,8 +43,85 @@ pub fn ls(path string) ?[]string {
|
|||
}
|
||||
|
||||
result := []string{}
|
||||
$if js_node {
|
||||
#let i = 0
|
||||
#$fs.readdirSync(path.str).forEach((path) => result.arr[i++] = new builtin.string(path))
|
||||
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
pub fn get_raw_line() string {
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn executable() string {
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn is_executable(path string) bool {
|
||||
eprintln('TODO: There is no isExecutable on fs.stats')
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn rmdir(path string) ? {
|
||||
$if js_node {
|
||||
err := ''
|
||||
#try {
|
||||
#$fs.rmdirSync(path.str)
|
||||
#return;
|
||||
#} catch (e) {
|
||||
#err.str = 'Failed to remove "' + path.str + '": ' + e.toString()
|
||||
#}
|
||||
|
||||
return error(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rm(path string) ? {
|
||||
$if js_node {
|
||||
err := ''
|
||||
#try {
|
||||
#$fs.rmSync(path.str)
|
||||
#return;
|
||||
#} catch (e) {
|
||||
#err.str = 'Failed to remove "' + path.str + '": ' + e.toString()
|
||||
#}
|
||||
|
||||
return error(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cp(src string, dst string) ? {
|
||||
$if js_node {
|
||||
err := ''
|
||||
#try {
|
||||
#$fs.cpSync(src.str,dst.str);
|
||||
#return;
|
||||
#} catch (e) {
|
||||
#err.str = 'failed to copy ' + src.str + ' to ' + dst.str + ': ' + e.toString();
|
||||
#}
|
||||
|
||||
return error(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_file(s string) ?string {
|
||||
mut err := ''
|
||||
err = err
|
||||
res := ''
|
||||
#try {
|
||||
#res.str = $fs.readFileSync(s.str).toString()
|
||||
#} catch (e) {
|
||||
#err.str = 'Failed to read file: ' + e.toString()
|
||||
#return error(err)
|
||||
#}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn getwd() string {
|
||||
res := ''
|
||||
#res.str = $process.cwd()
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
module os_js
|
||||
|
||||
// setenv sets the value of an environment variable with `name` to `value`.
|
||||
pub fn setenv(key string, val string, overwrite bool) {
|
||||
#if ($process.env[key] && !(overwrite.valueOf())) return;
|
||||
#$process.env[key] = val + '';
|
||||
}
|
||||
|
||||
// `getenv` returns the value of the environment variable named by the key.
|
||||
pub fn getenv(key string) string {
|
||||
mut res := ''
|
||||
#if ($process.env[key]) res = new builtin.string($process.env[key])
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// unsetenv clears an environment variable with `name`.
|
||||
pub fn unsetenv(name string) int {
|
||||
#$process.env[name] = ""
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
pub fn environ() map[string]string {
|
||||
mut res := map[string]string{}
|
||||
#for (const key in $process.env) {
|
||||
#res.map.set(key,$process.env[key])
|
||||
#}
|
||||
|
||||
return res
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
module os_js
|
||||
|
||||
#const $fs = require('fs');
|
||||
#const $path = require('path');
|
||||
|
||||
pub const (
|
||||
args = []string{}
|
||||
)
|
||||
|
||||
$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
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
module os_js
|
||||
|
||||
pub const (
|
||||
// todo(playX): NodeJS does not seem to have any path limit?
|
||||
max_path_len = 4096
|
||||
)
|
||||
|
||||
pub struct Result {
|
||||
pub:
|
||||
exit_code int
|
||||
output string
|
||||
// stderr string // TODO
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
module os_js
|
||||
|
||||
#const $child_process = require('child_process')
|
||||
|
||||
// ProcessState.not_started - the process has not yet started
|
||||
// ProcessState.running - the process is currently running
|
||||
// ProcessState.stopped - the process was running, but was stopped temporarily
|
||||
// ProcessState.exited - the process has finished/exited
|
||||
// ProcessState.aborted - the process was terminated by a signal
|
||||
// ProcessState.closed - the process resources like opened file descriptors were freed/discarded, final state.
|
||||
pub enum ProcessState {
|
||||
not_started
|
||||
running
|
||||
stopped
|
||||
exited
|
||||
aborted
|
||||
closed
|
||||
}
|
||||
|
||||
// todo(playX): fix reference member access in JS backend
|
||||
[heap]
|
||||
pub struct Process {
|
||||
pub:
|
||||
filename string
|
||||
pub mut:
|
||||
pid voidptr
|
||||
code int = -1
|
||||
status ProcessState = .not_started
|
||||
// the current status of the process
|
||||
err string // if the process fails, contains the reason why
|
||||
args []string // the arguments that the command takes
|
||||
env_is_custom bool // true, when the environment was customized with .set_environment
|
||||
env []string // the environment with which the process was started (list of 'var=val')
|
||||
use_stdio_ctl bool // when true, then you can use p.stdin_write(), p.stdout_slurp() and p.stderr_slurp()
|
||||
use_pgroup bool // when true, the process will create a new process group, enabling .signal_pgkill()
|
||||
stdio_fd [3]int // the stdio file descriptors for the child process, used only by the nix implementation
|
||||
}
|
||||
|
||||
// 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]!
|
||||
}
|
||||
}
|
||||
|
||||
// set_args - set the arguments for the new process
|
||||
pub fn (mut p Process) set_args(pargs []string) {
|
||||
if p.status != .not_started {
|
||||
return
|
||||
}
|
||||
p.args = pargs
|
||||
return
|
||||
}
|
||||
|
||||
// set_environment - set a custom environment variable mapping for the new process
|
||||
pub fn (mut p Process) set_environment(envs map[string]string) {
|
||||
if p.status != .not_started {
|
||||
return
|
||||
}
|
||||
p.env_is_custom = true
|
||||
p.env = []string{}
|
||||
for k, v in envs {
|
||||
p.env << '$k=$v'
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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()')
|
||||
}
|
||||
}
|
|
@ -338,7 +338,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
g.gen_builtin_prototype(
|
||||
typ_name: typ_name
|
||||
default_value: 'new Number(0)'
|
||||
constructor: 'this.val = typeof(val) == "string" ? val.charCodeAt() : (val | 0)'
|
||||
constructor: 'if (typeof(val) == "string") { this.val = val.charCodeAt() } else if (val instanceof string) { this.val = val.str.charCodeAt(); } else { this.val = val | 0 }'
|
||||
value_of: 'this.val | 0'
|
||||
to_string: 'new string(this.val + "")'
|
||||
eq: 'this.valueOf() === other.valueOf()'
|
||||
|
|
|
@ -525,6 +525,111 @@ fn (mut g JsGen) gen_global_decl(node ast.GlobalDecl) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) stmt_no_semi(node ast.Stmt) {
|
||||
g.stmt_start_pos = g.ns.out.len
|
||||
match node {
|
||||
ast.EmptyStmt {}
|
||||
ast.AsmStmt {
|
||||
panic('inline asm is not supported by js')
|
||||
}
|
||||
ast.AssertStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_assert_stmt(node)
|
||||
}
|
||||
ast.AssignStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_assign_stmt(node, false)
|
||||
}
|
||||
ast.Block {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_block(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.BranchStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_branch_stmt(node)
|
||||
}
|
||||
ast.CompFor {}
|
||||
ast.ConstDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_const_decl(node)
|
||||
}
|
||||
ast.DeferStmt {
|
||||
g.defer_stmts << node
|
||||
}
|
||||
ast.EnumDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_enum_decl(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ExprStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_expr_stmt_no_semi(node)
|
||||
}
|
||||
ast.FnDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.fn_decl = unsafe { &node }
|
||||
g.gen_fn_decl(node)
|
||||
}
|
||||
ast.ForCStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_for_c_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ForInStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_for_in_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ForStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_for_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.GlobalDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_global_decl(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.GotoLabel {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.writeln('${g.js_name(node.name)}:')
|
||||
}
|
||||
ast.GotoStmt {
|
||||
// skip: JS has no goto
|
||||
}
|
||||
ast.HashStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_hash_stmt(node)
|
||||
}
|
||||
ast.Import {
|
||||
g.ns.imports[node.mod] = node.alias
|
||||
}
|
||||
ast.InterfaceDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_interface_decl(node)
|
||||
}
|
||||
ast.Module {
|
||||
// skip: namespacing implemented externally
|
||||
}
|
||||
ast.NodeError {}
|
||||
ast.Return {
|
||||
if g.defer_stmts.len > 0 {
|
||||
g.gen_defer_stmts()
|
||||
}
|
||||
g.gen_return_stmt(node)
|
||||
}
|
||||
ast.SqlStmt {}
|
||||
ast.StructDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_struct_decl(node)
|
||||
}
|
||||
ast.TypeDecl {
|
||||
// skip JS has no typedecl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||
g.stmt_start_pos = g.ns.out.len
|
||||
match node {
|
||||
|
@ -538,7 +643,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
}
|
||||
ast.AssignStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_assign_stmt(node)
|
||||
g.gen_assign_stmt(node, true)
|
||||
}
|
||||
ast.Block {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
|
@ -860,7 +965,7 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
|||
g.writeln('}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
||||
fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
|
||||
if stmt.left.len > stmt.right.len {
|
||||
// multi return
|
||||
g.write('const [')
|
||||
|
@ -874,7 +979,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
|||
}
|
||||
g.write('] = ')
|
||||
g.expr(stmt.right[0])
|
||||
if semicolon {
|
||||
g.writeln(';')
|
||||
}
|
||||
} else {
|
||||
// `a := 1` | `a,b := 1,2`
|
||||
for i, left in stmt.left {
|
||||
|
@ -996,6 +1103,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
|||
g.cast_stack.delete_last()
|
||||
}
|
||||
}
|
||||
if semicolon {
|
||||
if g.inside_loop {
|
||||
g.write('; ')
|
||||
} else {
|
||||
|
@ -1004,6 +1112,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_attrs(attrs []ast.Attr) {
|
||||
for attr in attrs {
|
||||
|
@ -1072,6 +1181,10 @@ fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_expr_stmt_no_semi(it ast.ExprStmt) {
|
||||
g.expr(it.expr)
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||
if it.no_body || it.is_method {
|
||||
// Struct methods are handled by class generation code.
|
||||
|
@ -1211,7 +1324,7 @@ fn (mut g JsGen) gen_for_c_stmt(it ast.ForCStmt) {
|
|||
}
|
||||
g.write('; ')
|
||||
if it.has_inc {
|
||||
g.stmt(it.inc)
|
||||
g.stmt_no_semi(it.inc)
|
||||
}
|
||||
g.writeln(') {')
|
||||
g.stmts(it.stmts)
|
||||
|
@ -1349,6 +1462,7 @@ fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {
|
|||
// TODO: interfaces are always `pub`?
|
||||
name := g.js_name(it.name)
|
||||
g.push_pub_var('/** @type $name */\n\t\t$name: undefined')
|
||||
g.writeln('function ${g.js_name(it.name)} (arg) { return arg; }')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
||||
|
@ -1629,7 +1743,7 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
|||
if it.or_block.stmts.len > 1 {
|
||||
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
|
||||
}
|
||||
g.write('return ')
|
||||
// g.write('return ')
|
||||
g.stmt(it.or_block.stmts.last())
|
||||
}
|
||||
.propagate {
|
||||
|
@ -1707,7 +1821,8 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
if it.or_block.stmts.len > 1 {
|
||||
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
|
||||
}
|
||||
g.write('return ')
|
||||
|
||||
// g.write('return ')
|
||||
g.stmt(it.or_block.stmts.last())
|
||||
}
|
||||
.propagate {
|
||||
|
@ -1928,7 +2043,8 @@ fn (mut g JsGen) match_expr(node ast.MatchExpr) {
|
|||
}
|
||||
|
||||
if node.cond is ast.Ident || node.cond is ast.SelectorExpr || node.cond is ast.IntegerLiteral
|
||||
|| node.cond is ast.StringLiteral || node.cond is ast.FloatLiteral {
|
||||
|| node.cond is ast.StringLiteral || node.cond is ast.FloatLiteral
|
||||
|| node.cond is ast.CallExpr {
|
||||
cond_var = CondExpr{node.cond}
|
||||
} else {
|
||||
s := g.new_tmp_var()
|
||||
|
@ -2577,7 +2693,15 @@ fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
|
|||
}
|
||||
g.write('string(')
|
||||
}
|
||||
if it.is_raw {
|
||||
g.writeln('(function() { let s = String(); ')
|
||||
for x in text {
|
||||
g.writeln('s += String.fromCharCode($x);')
|
||||
}
|
||||
g.writeln('return s; })()')
|
||||
} else {
|
||||
g.write("\"$text\"")
|
||||
}
|
||||
if true || should_cast {
|
||||
g.write(')')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue