diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index cc3869dcee..6640ec8d90 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -346,7 +346,7 @@ pub fn execute(cmd string) Result { // if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { // return Result{ exit_code: -1, output: ';, &&, || and \\n are not allowed in shell commands' } // } - pcmd := '$cmd 2>&1' + pcmd := if cmd.contains('2>') { cmd } else { '$cmd 2>&1' } f := vpopen(pcmd) if isnil(f) { return Result{ diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index a6d7c67c0a..6b74f4f80c 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -457,7 +457,7 @@ pub fn (mut g Gen) inline_strlen(r Register) { } // TODO: strlen of string at runtime -pub fn (mut g Gen) gen_print_reg(r Register, n int) { +pub fn (mut g Gen) gen_print_reg(r Register, n int, fd int) { mystrlen := true g.mov_reg(.rsi, r) if mystrlen { @@ -467,16 +467,16 @@ pub fn (mut g Gen) gen_print_reg(r Register, n int) { g.mov(.edx, n) } g.mov(.eax, g.nsyscall_write()) - g.mov(.edi, 1) + g.mov(.edi, fd) g.syscall() } -pub fn (mut g Gen) gen_print(s string) { +pub fn (mut g Gen) gen_print(s string, fd int) { // // qq := s + '\n' // g.mov(.eax, g.nsyscall_write()) - g.mov(.edi, 1) + g.mov(.edi, fd) // segment_start + 0x9f) // str pos // placeholder g.mov64(.rsi, g.allocate_string(s, 2)) // for rsi its 2 g.mov(.edx, s.len) // len diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 8df68a923d..c149ac2c45 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -12,7 +12,7 @@ import v.errors import v.pref import term -pub const builtins = ['println', 'exit'] +pub const builtins = ['print', 'eprint', 'println', 'eprintln', 'exit'] interface CodeGen { mut: @@ -227,22 +227,24 @@ fn (mut g Gen) get_var_offset(var_name string) int { return offset } -pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) { +pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { + newline := name in ['println', 'eprintln'] + fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 } match expr { ast.StringLiteral { if newline { - g.gen_print(expr.val + '\n') + g.gen_print(expr.val + '\n', fd) } else { - g.gen_print(expr.val) + g.gen_print(expr.val, fd) } } ast.CallExpr { g.call_fn(expr) - g.gen_print_reg(.rax, 3) + g.gen_print_reg(.rax, 3, fd) } ast.Ident { g.expr(expr) - g.gen_print_reg(.rax, 3) + g.gen_print_reg(.rax, 3, fd) } else { dump(typeof(expr).name) @@ -389,7 +391,7 @@ fn (mut g Gen) expr(node ast.Expr) { } if node.name in ['println', 'print', 'eprintln', 'eprint'] { expr := node.args[0].expr - g.gen_print_from_expr(expr, node.name in ['println', 'eprintln']) + g.gen_print_from_expr(expr, node.name) return } g.call_fn(node) diff --git a/vlib/v/gen/native/tests/native_test.v b/vlib/v/gen/native/tests/native_test.v index 1ae7bec27d..7ed5507c3d 100644 --- a/vlib/v/gen/native/tests/native_test.v +++ b/vlib/v/gen/native/tests/native_test.v @@ -46,7 +46,8 @@ fn test_native() { eprintln(bench.step_message_fail(cmd)) continue } - res := os.execute(exe_test_path) + tmperrfile := '$dir/${test}.tmperr' + res := os.execute('$exe_test_path 2> $tmperrfile') if res.exit_code != 0 { bench.fail() eprintln(bench.step_message_fail('$full_test_path failed to run')) @@ -54,6 +55,24 @@ fn test_native() { continue } mut expected := os.read_file('$dir/${test}.out') or { panic(err) } + errfile := '$dir/${test}.err' + if os.exists(errfile) { + mut err_expected := os.read_file('$dir/${test}.err') or { panic(err) } + err_expected = err_expected.trim_right('\r\n').replace('\r\n', '\n') + errstr := os.read_file(tmperrfile) or { panic(err) } + mut err_found := errstr.trim_right('\r\n').replace('\r\n', '\n') + if err_expected != err_found { + println(term.red('FAIL')) + println('============') + println('stderr expected: "$err_expected" len=$err_expected.len') + println('============') + println('stderr found:"$err_found" len=$err_found.len') + println('============\n') + bench.fail() + continue + } + } + os.rm(tmperrfile) or {} expected = expected.trim_right('\r\n').replace('\r\n', '\n') mut found := res.output.trim_right('\r\n').replace('\r\n', '\n') found = found.trim_space() diff --git a/vlib/v/gen/native/tests/print.vv b/vlib/v/gen/native/tests/print.vv new file mode 100644 index 0000000000..5ddae6417a --- /dev/null +++ b/vlib/v/gen/native/tests/print.vv @@ -0,0 +1,14 @@ +fn test_stdout() { + print('Hello ') + println('World') +} + +fn test_stderr() { + eprint('2(Hello)') + eprintln('2(World)') +} + +fn main() { + test_stdout() + test_stderr() +} diff --git a/vlib/v/gen/native/tests/print.vv.err b/vlib/v/gen/native/tests/print.vv.err new file mode 100644 index 0000000000..651cf357e5 --- /dev/null +++ b/vlib/v/gen/native/tests/print.vv.err @@ -0,0 +1 @@ +2(Hello)2(World) diff --git a/vlib/v/gen/native/tests/print.vv.out b/vlib/v/gen/native/tests/print.vv.out new file mode 100644 index 0000000000..557db03de9 --- /dev/null +++ b/vlib/v/gen/native/tests/print.vv.out @@ -0,0 +1 @@ +Hello World