From 4b55800ffd109f843feee9915003385bcba5dba4 Mon Sep 17 00:00:00 2001 From: pancake Date: Mon, 3 Jan 2022 17:30:42 +0100 Subject: [PATCH] v.eval: add tests and fix runtime cast crash (#13019) --- cmd/v/help/build.txt | 1 + vlib/v/builder/compile.v | 4 ++ .../interpreterbuilder/v_interpret_test.v | 55 +++++++++++++++++++ vlib/v/eval/eval.v | 25 ++++++--- vlib/v/parser/v_parser_test.v | 4 +- 5 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 vlib/v/builder/interpreterbuilder/v_interpret_test.v diff --git a/cmd/v/help/build.txt b/cmd/v/help/build.txt index a23be49eb6..65089b1587 100644 --- a/cmd/v/help/build.txt +++ b/cmd/v/help/build.txt @@ -37,6 +37,7 @@ NB: the build flags are shared with the run command too: Specify the backend to use while building the executable. Current list of supported backends: * `c` (default) - V outputs C source code which is passed to a C compiler to be compiled. + * `interpret` - Same as `v interpret` to run the V program * `js` - V outputs JS source code which can be passed to NodeJS to be ran. * `js_browser` - V outputs JS source code ready for the browser. * `js_node` - V outputs JS source code to run with nodejs. diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index f634bdce00..b951fd8a7f 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -102,6 +102,10 @@ fn (b &Builder) exit_on_invalid_syntax() { } fn (mut b Builder) run_compiled_executable_and_exit() { + if b.pref.backend == .interpret { + // the interpreted code has already ran + return + } if b.pref.skip_running { return } diff --git a/vlib/v/builder/interpreterbuilder/v_interpret_test.v b/vlib/v/builder/interpreterbuilder/v_interpret_test.v new file mode 100644 index 0000000000..131982908f --- /dev/null +++ b/vlib/v/builder/interpreterbuilder/v_interpret_test.v @@ -0,0 +1,55 @@ +import os +import rand +import term + +const vexe = @VEXE + +fn interpreter_wrap(a string) string { + return 'fn main() {$a}' +} + +fn interp_test(expression string, expected string) ? { + tmpdir := os.join_path(os.temp_dir(), 'v_interpret_test_$rand.ulid()') + os.mkdir_all(tmpdir) or {} + defer { + os.rmdir_all(tmpdir) or {} + } + // + tmpfile := os.join_path(tmpdir, 'input.v') + outfile := os.join_path(tmpdir, 'output.txt') + os.write_file(tmpfile, interpreter_wrap(expression)) ? + if os.system('"$vexe" interpret $tmpfile > $outfile') != 0 { + eprintln('>>> Failed to interpret V expression: |$expression|') + return error('v interp') + } + res := os.read_file(outfile) ? + output := res.trim_space() + if output != expected { + eprintln('>>> The output of the V expression, is not the same as the expected one') + eprintln(' V expression: $expression') + eprintln(' output: |$output|') + eprintln(' expected: |$expected|') + return error('test') + } + println('${term.colorize(term.green, 'OK')} ${term.colorize(term.bright_blue, expression.replace('\n', + ' '))}') + println(' >> ${term.colorize(term.bright_yellow, output)}') +} + +struct InterpTest { + input string + output string +} + +fn test_interpreter() ? { + mut tests := []InterpTest{} + tests << InterpTest{'println(3+3)', '6'} + tests << InterpTest{'println(3)', '3'} + tests << InterpTest{'println(3-4)', '-1'} + tests << InterpTest{'println(3*3)', '9'} + tests << InterpTest{'a := 3\nprintln(a*3)', '9'} + for test in tests { + interp_test(test.input, test.output) ? + assert true + } +} diff --git a/vlib/v/eval/eval.v b/vlib/v/eval/eval.v index 57d8929757..bace061fdc 100644 --- a/vlib/v/eval/eval.v +++ b/vlib/v/eval/eval.v @@ -171,19 +171,26 @@ pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) { for i, branch in x.branches { mut do_if := false println('branch:$branch') - match (branch.cond as ast.Ident).name { - 'windows' { - do_if = e.pref.os == .windows + match branch.cond { + ast.Ident { + match (branch.cond as ast.Ident).name { + 'windows' { + do_if = e.pref.os == .windows + } + else { + e.error('unknown compile time if') + } + } + do_if = do_if || x.branches.len == i + 1 + if do_if { + e.register_symbol_stmts(branch.stmts, mod, file) + break + } } else { - e.error('unknown compile time if') + eprintln('unsupported expression') } } - do_if = do_if || x.branches.len == i + 1 - if do_if { - e.register_symbol_stmts(branch.stmts, mod, file) - break - } } } else { diff --git a/vlib/v/parser/v_parser_test.v b/vlib/v/parser/v_parser_test.v index 41dd65dae9..8c660add1e 100644 --- a/vlib/v/parser/v_parser_test.v +++ b/vlib/v/parser/v_parser_test.v @@ -133,7 +133,7 @@ fn test_parse_expr() { mut e := []ast.Stmt{} table := ast.new_table() vpref := &pref.Preferences{} - mut checker := checker.new_checker(table, vpref) + mut chk := checker.new_checker(table, vpref) scope := &ast.Scope{ start_pos: 0 parent: 0 @@ -147,7 +147,7 @@ fn test_parse_expr() { scope: scope global_scope: scope } - checker.check(program) + chk.check(program) res := c.gen([program], table, vpref).after('#endif') println('========') println(res)