v.eval: add tests and fix runtime cast crash (#13019)
							parent
							
								
									89d92d536a
								
							
						
					
					
						commit
						4b55800ffd
					
				| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +171,8 @@ 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 {
 | 
			
		||||
							ast.Ident {
 | 
			
		||||
								match (branch.cond as ast.Ident).name {
 | 
			
		||||
									'windows' {
 | 
			
		||||
										do_if = e.pref.os == .windows
 | 
			
		||||
| 
						 | 
				
			
			@ -185,6 +187,11 @@ pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) {
 | 
			
		|||
									break
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
							else {
 | 
			
		||||
								eprintln('unsupported expression')
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					e.error('unknown declaration expression statement $x.type_name()')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue