native: add support for print, eprint and eprintln (#11034)

pull/11039/head
pancake 2021-08-03 15:04:31 +02:00 committed by GitHub
parent 80976e640c
commit 00d4c7082e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 13 deletions

View File

@ -346,7 +346,7 @@ pub fn execute(cmd string) Result {
// if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { // if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
// return Result{ exit_code: -1, output: ';, &&, || and \\n are not allowed in shell commands' } // 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) f := vpopen(pcmd)
if isnil(f) { if isnil(f) {
return Result{ return Result{

View File

@ -457,7 +457,7 @@ pub fn (mut g Gen) inline_strlen(r Register) {
} }
// TODO: strlen of string at runtime // 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 mystrlen := true
g.mov_reg(.rsi, r) g.mov_reg(.rsi, r)
if mystrlen { if mystrlen {
@ -467,16 +467,16 @@ pub fn (mut g Gen) gen_print_reg(r Register, n int) {
g.mov(.edx, n) g.mov(.edx, n)
} }
g.mov(.eax, g.nsyscall_write()) g.mov(.eax, g.nsyscall_write())
g.mov(.edi, 1) g.mov(.edi, fd)
g.syscall() 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' // qq := s + '\n'
// //
g.mov(.eax, g.nsyscall_write()) g.mov(.eax, g.nsyscall_write())
g.mov(.edi, 1) g.mov(.edi, fd)
// segment_start + 0x9f) // str pos // placeholder // segment_start + 0x9f) // str pos // placeholder
g.mov64(.rsi, g.allocate_string(s, 2)) // for rsi its 2 g.mov64(.rsi, g.allocate_string(s, 2)) // for rsi its 2
g.mov(.edx, s.len) // len g.mov(.edx, s.len) // len

View File

@ -12,7 +12,7 @@ import v.errors
import v.pref import v.pref
import term import term
pub const builtins = ['println', 'exit'] pub const builtins = ['print', 'eprint', 'println', 'eprintln', 'exit']
interface CodeGen { interface CodeGen {
mut: mut:
@ -227,22 +227,24 @@ fn (mut g Gen) get_var_offset(var_name string) int {
return offset 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 { match expr {
ast.StringLiteral { ast.StringLiteral {
if newline { if newline {
g.gen_print(expr.val + '\n') g.gen_print(expr.val + '\n', fd)
} else { } else {
g.gen_print(expr.val) g.gen_print(expr.val, fd)
} }
} }
ast.CallExpr { ast.CallExpr {
g.call_fn(expr) g.call_fn(expr)
g.gen_print_reg(.rax, 3) g.gen_print_reg(.rax, 3, fd)
} }
ast.Ident { ast.Ident {
g.expr(expr) g.expr(expr)
g.gen_print_reg(.rax, 3) g.gen_print_reg(.rax, 3, fd)
} }
else { else {
dump(typeof(expr).name) dump(typeof(expr).name)
@ -389,7 +391,7 @@ fn (mut g Gen) expr(node ast.Expr) {
} }
if node.name in ['println', 'print', 'eprintln', 'eprint'] { if node.name in ['println', 'print', 'eprintln', 'eprint'] {
expr := node.args[0].expr 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 return
} }
g.call_fn(node) g.call_fn(node)

View File

@ -46,7 +46,8 @@ fn test_native() {
eprintln(bench.step_message_fail(cmd)) eprintln(bench.step_message_fail(cmd))
continue continue
} }
res := os.execute(exe_test_path) tmperrfile := '$dir/${test}.tmperr'
res := os.execute('$exe_test_path 2> $tmperrfile')
if res.exit_code != 0 { if res.exit_code != 0 {
bench.fail() bench.fail()
eprintln(bench.step_message_fail('$full_test_path failed to run')) eprintln(bench.step_message_fail('$full_test_path failed to run'))
@ -54,6 +55,24 @@ fn test_native() {
continue continue
} }
mut expected := os.read_file('$dir/${test}.out') or { panic(err) } 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') expected = expected.trim_right('\r\n').replace('\r\n', '\n')
mut found := res.output.trim_right('\r\n').replace('\r\n', '\n') mut found := res.output.trim_right('\r\n').replace('\r\n', '\n')
found = found.trim_space() found = found.trim_space()

View File

@ -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()
}

View File

@ -0,0 +1 @@
2(Hello)2(World)

View File

@ -0,0 +1 @@
Hello World