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
|
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 struct Error {
|
||||||
pub:
|
pub:
|
||||||
msg string
|
msg string
|
||||||
code int
|
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 {
|
pub fn (o Option) str() string {
|
||||||
if o.state == 0 {
|
if o.state == 0 {
|
||||||
return 'Option{ ok }'
|
return 'Option{ ok }'
|
||||||
|
@ -48,21 +74,28 @@ pub fn (o Option) str() string {
|
||||||
return 'Option{ error: "$o.err" }'
|
return 'Option{ error: "$o.err" }'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(s string) Option {
|
[if trace_error ?]
|
||||||
return Option{
|
fn trace_error(x string) {
|
||||||
state: 2
|
eprintln('> ${@FN} | $x')
|
||||||
err: Error{
|
}
|
||||||
msg: s
|
|
||||||
}
|
// 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 {
|
// error_with_code returns a default error instance containing the given `message` and error `code`.
|
||||||
return Option{
|
// `if ouch { return error_with_code('an error occurred', 1) }`
|
||||||
state: 2
|
[inline]
|
||||||
err: Error{
|
pub fn error_with_code(message string, code int) IError {
|
||||||
msg: s
|
// trace_error('$message | code: $code')
|
||||||
code: code
|
return &Error{
|
||||||
}
|
msg: message
|
||||||
|
code: code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,15 @@ module builtin
|
||||||
|
|
||||||
pub fn (b byte) is_space() bool {
|
pub fn (b byte) is_space() bool {
|
||||||
mut result := false
|
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
|
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]
|
with := vals[rep_i + 1]
|
||||||
for {
|
for {
|
||||||
idx = s_.index_after(rep, idx)
|
idx = s_.index_after(rep, idx)
|
||||||
|
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -374,6 +375,7 @@ pub fn (s string) replace_each(vals []string) string {
|
||||||
idx: idx
|
idx: idx
|
||||||
val_idx: rep_i
|
val_idx: rep_i
|
||||||
}
|
}
|
||||||
|
|
||||||
idx += rep.len
|
idx += rep.len
|
||||||
new_len += with.len - rep.len
|
new_len += with.len - rep.len
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module os_js
|
module os
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub:
|
pub:
|
||||||
|
@ -128,3 +128,9 @@ pub fn (mut f File) write_string(s string) ?int {
|
||||||
nbytes := f.write(s.bytes()) ?
|
nbytes := f.write(s.bytes()) ?
|
||||||
return nbytes
|
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');
|
#const $path = require('path');
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
args = []string{}
|
|
||||||
path_delimiter = '/'
|
path_delimiter = '/'
|
||||||
path_separator = '/'
|
path_separator = '/'
|
||||||
|
args = []string{}
|
||||||
)
|
)
|
||||||
|
|
||||||
$if js_node {
|
$if js_node {
|
||||||
|
|
21
vlib/os/os.v
21
vlib/os/os.v
|
@ -4,7 +4,6 @@
|
||||||
module os
|
module os
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
args = []string{}
|
|
||||||
max_path_len = 4096
|
max_path_len = 4096
|
||||||
wd_at_startup = getwd()
|
wd_at_startup = getwd()
|
||||||
)
|
)
|
||||||
|
@ -344,22 +343,15 @@ pub fn write_file(path string, text string) ? {
|
||||||
f.close()
|
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.
|
// 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
|
// 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.
|
// all cases, but it should be better, than just using os.args[0] directly.
|
||||||
fn executable_fallback() string {
|
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 :-|
|
// we are early in the bootstrap, os.args has not been initialized yet :-|
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
mut exepath := os.args[0]
|
mut exepath := args[0]
|
||||||
$if windows {
|
$if windows {
|
||||||
if !exepath.contains('.exe') {
|
if !exepath.contains('.exe') {
|
||||||
exepath += '.exe'
|
exepath += '.exe'
|
||||||
|
@ -639,12 +631,3 @@ pub fn execute_or_exit(cmd string) Result {
|
||||||
}
|
}
|
||||||
return res
|
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 {
|
pub fn is_dir(path string) bool {
|
||||||
res := false
|
res := false
|
||||||
#res.val = $fs.existsSync(path,str) && $fs.lstatSync(path.str).isDirectory()
|
$if js_node {
|
||||||
|
#res.val = $fs.existsSync(path,str) && $fs.lstatSync(path.str).isDirectory()
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_link(path string) bool {
|
pub fn is_link(path string) bool {
|
||||||
res := false
|
res := false
|
||||||
#res.val = $fs.existsSync(path.str) && $fs.lstatSync(path.str).isSymbolicLink()
|
$if js_node {
|
||||||
|
#res.val = $fs.existsSync(path.str) && $fs.lstatSync(path.str).isSymbolicLink()
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exists(path string) bool {
|
pub fn exists(path string) bool {
|
||||||
res := false
|
res := false
|
||||||
#res.val = $fs.existsSync(path.str)
|
$if js_node {
|
||||||
|
#res.val = $fs.existsSync(path.str)
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,8 +43,85 @@ pub fn ls(path string) ?[]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
result := []string{}
|
result := []string{}
|
||||||
#let i = 0
|
$if js_node {
|
||||||
#$fs.readdirSync(path.str).forEach((path) => result.arr[i++] = new builtin.string(path))
|
#let i = 0
|
||||||
|
#$fs.readdirSync(path.str).forEach((path) => result.arr[i++] = new builtin.string(path))
|
||||||
|
}
|
||||||
return result
|
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(
|
g.gen_builtin_prototype(
|
||||||
typ_name: typ_name
|
typ_name: typ_name
|
||||||
default_value: 'new Number(0)'
|
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'
|
value_of: 'this.val | 0'
|
||||||
to_string: 'new string(this.val + "")'
|
to_string: 'new string(this.val + "")'
|
||||||
eq: 'this.valueOf() === other.valueOf()'
|
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) {
|
fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||||
g.stmt_start_pos = g.ns.out.len
|
g.stmt_start_pos = g.ns.out.len
|
||||||
match node {
|
match node {
|
||||||
|
@ -538,7 +643,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
ast.AssignStmt {
|
ast.AssignStmt {
|
||||||
g.write_v_source_line_info(node.pos)
|
g.write_v_source_line_info(node.pos)
|
||||||
g.gen_assign_stmt(node)
|
g.gen_assign_stmt(node, true)
|
||||||
}
|
}
|
||||||
ast.Block {
|
ast.Block {
|
||||||
g.write_v_source_line_info(node.pos)
|
g.write_v_source_line_info(node.pos)
|
||||||
|
@ -860,7 +965,7 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
||||||
g.writeln('}')
|
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 {
|
if stmt.left.len > stmt.right.len {
|
||||||
// multi return
|
// multi return
|
||||||
g.write('const [')
|
g.write('const [')
|
||||||
|
@ -874,7 +979,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
g.write('] = ')
|
g.write('] = ')
|
||||||
g.expr(stmt.right[0])
|
g.expr(stmt.right[0])
|
||||||
g.writeln(';')
|
if semicolon {
|
||||||
|
g.writeln(';')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// `a := 1` | `a,b := 1,2`
|
// `a := 1` | `a,b := 1,2`
|
||||||
for i, left in stmt.left {
|
for i, left in stmt.left {
|
||||||
|
@ -996,10 +1103,12 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
||||||
g.cast_stack.delete_last()
|
g.cast_stack.delete_last()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if g.inside_loop {
|
if semicolon {
|
||||||
g.write('; ')
|
if g.inside_loop {
|
||||||
} else {
|
g.write('; ')
|
||||||
g.writeln(';')
|
} else {
|
||||||
|
g.writeln(';')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||||
if it.no_body || it.is_method {
|
if it.no_body || it.is_method {
|
||||||
// Struct methods are handled by class generation code.
|
// 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('; ')
|
g.write('; ')
|
||||||
if it.has_inc {
|
if it.has_inc {
|
||||||
g.stmt(it.inc)
|
g.stmt_no_semi(it.inc)
|
||||||
}
|
}
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
g.stmts(it.stmts)
|
g.stmts(it.stmts)
|
||||||
|
@ -1349,6 +1462,7 @@ fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {
|
||||||
// TODO: interfaces are always `pub`?
|
// TODO: interfaces are always `pub`?
|
||||||
name := g.js_name(it.name)
|
name := g.js_name(it.name)
|
||||||
g.push_pub_var('/** @type $name */\n\t\t$name: undefined')
|
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) {
|
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 {
|
if it.or_block.stmts.len > 1 {
|
||||||
g.stmts(it.or_block.stmts[..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())
|
g.stmt(it.or_block.stmts.last())
|
||||||
}
|
}
|
||||||
.propagate {
|
.propagate {
|
||||||
|
@ -1707,7 +1821,8 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||||
if it.or_block.stmts.len > 1 {
|
if it.or_block.stmts.len > 1 {
|
||||||
g.stmts(it.or_block.stmts[..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())
|
g.stmt(it.or_block.stmts.last())
|
||||||
}
|
}
|
||||||
.propagate {
|
.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
|
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}
|
cond_var = CondExpr{node.cond}
|
||||||
} else {
|
} else {
|
||||||
s := g.new_tmp_var()
|
s := g.new_tmp_var()
|
||||||
|
@ -2577,7 +2693,15 @@ fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
|
||||||
}
|
}
|
||||||
g.write('string(')
|
g.write('string(')
|
||||||
}
|
}
|
||||||
g.write("\"$text\"")
|
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 {
|
if true || should_cast {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue