js: fix -stats compilation of tests, proper alias codegen (#11327)

pull/11329/head
playX 2021-08-28 16:57:33 +03:00 committed by GitHub
parent 25bf68e2f1
commit 118c5fdcd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 28 deletions

View File

@ -243,3 +243,11 @@ pub fn (mut a array) delete_last() {
[unsafe] [unsafe]
pub fn (a array) free() { pub fn (a array) free() {
} }
// todo: once (a []byte) will work rewrite this
pub fn (a array) bytestr() string {
res := ''
#a.arr.forEach((item) => res.str += String.fromCharCode(+item))
return res
}

View File

@ -184,8 +184,9 @@ pub fn (mut g JsGen) typ(t ast.Type) string {
styp = 'union_sym_type' styp = 'union_sym_type'
} }
.alias { .alias {
// TODO: Implement aliases fsym := g.table.get_final_type_symbol(t)
styp = 'alias' name := g.js_name(fsym.name)
styp += '$name'
} }
.enum_ { .enum_ {
// NB: We could declare them as TypeScript enums but TS doesn't like // NB: We could declare them as TypeScript enums but TS doesn't like
@ -278,7 +279,7 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
} }
for method in g.method_fn_decls[c.typ_name] { for method in g.method_fn_decls[c.typ_name] {
g.inside_def_typ_decl = true g.inside_def_typ_decl = true
g.gen_method_decl(method) g.gen_method_decl(method, .struct_method)
g.inside_def_typ_decl = false g.inside_def_typ_decl = false
g.writeln(',') g.writeln(',')
} }

View File

@ -284,24 +284,25 @@ pub fn (mut g JsGen) gen_js_main_for_tests() {
g.writeln('') g.writeln('')
g.writeln('globalThis.VTEST=1') g.writeln('globalThis.VTEST=1')
// g.writeln('let bt = start_testing($all_tfuncs.len, "$g.pref.path")') if g.pref.is_stats {
g.writeln('let bt = start_testing($all_tfuncs.len, "$g.pref.path")')
}
for tname in all_tfuncs { for tname in all_tfuncs {
tcname := g.js_name(tname) tcname := g.js_name(tname)
if g.pref.is_stats { if g.pref.is_stats {
// g.writeln('bt.testing_step_start("$tcname")') g.writeln('bt.testing_step_start("$tcname")')
} }
g.writeln('try { ${tcname}(); } catch (_e) {} ') g.writeln('try { ${tcname}(); } catch (_e) {} ')
if g.pref.is_stats { if g.pref.is_stats {
// g.writeln('bt.testing_step_end();') g.writeln('bt.testing_step_end();')
} }
} }
g.writeln('') g.writeln('')
if g.pref.is_stats { if g.pref.is_stats {
// g.writeln('bt.end_testing();') g.writeln('bt.end_testing();')
} }
g.dec_indent() g.dec_indent()
g.writeln('})();') g.writeln('})();')
@ -380,7 +381,7 @@ pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
pub fn (mut g JsGen) init() { pub fn (mut g JsGen) init() {
g.definitions.writeln('// Generated by the V compiler\n') g.definitions.writeln('// Generated by the V compiler\n')
g.definitions.writeln('"use strict";') // g.definitions.writeln('"use strict";')
g.definitions.writeln('') g.definitions.writeln('')
g.definitions.writeln('var \$global = (new Function("return this"))();') g.definitions.writeln('var \$global = (new Function("return this"))();')
g.definitions.writeln('function \$ref(value) { if (value instanceof \$ref) { return value; } this.val = value; } ') g.definitions.writeln('function \$ref(value) { if (value instanceof \$ref) { return value; } this.val = value; } ')
@ -699,9 +700,7 @@ fn (mut g JsGen) stmt_no_semi(node ast.Stmt) {
g.write_v_source_line_info(node.pos) g.write_v_source_line_info(node.pos)
g.gen_struct_decl(node) g.gen_struct_decl(node)
} }
ast.TypeDecl { ast.TypeDecl {}
// skip JS has no typedecl
}
} }
} }
@ -1319,8 +1318,25 @@ fn (mut g JsGen) gen_expr_stmt_no_semi(it ast.ExprStmt) {
g.expr(it.expr) g.expr(it.expr)
} }
enum FnGenType {
function
struct_method
alias_method
}
fn (g &JsGen) fn_gen_type(it &ast.FnDecl) FnGenType {
if it.is_method && g.table.get_type_symbol(it.params[0].typ).kind == .alias {
return .alias_method
} else if it.is_method || it.no_body {
return .struct_method
} else {
return .function
}
}
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 { res := g.fn_gen_type(it)
if res == .struct_method {
// Struct methods are handled by class generation code. // Struct methods are handled by class generation code.
return return
} }
@ -1328,7 +1344,7 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
g.builtin_fns << it.name g.builtin_fns << it.name
} }
cur_fn_decl := g.fn_decl cur_fn_decl := g.fn_decl
g.gen_method_decl(it) g.gen_method_decl(it, res)
g.fn_decl = cur_fn_decl g.fn_decl = cur_fn_decl
} }
@ -1345,10 +1361,18 @@ fn fn_has_go(node ast.FnDecl) bool {
return has_go return has_go
} }
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) { fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
unsafe { unsafe {
g.fn_decl = &it g.fn_decl = &it
} }
if typ == .alias_method {
sym := g.table.get_final_type_symbol(it.params[0].typ.set_nr_muls(0))
name := g.js_name(sym.name)
if name in js.v_types {
g.writeln('builtin.')
}
g.writeln('${name}.prototype.$it.name = function ')
}
has_go := fn_has_go(it) has_go := fn_has_go(it)
is_main := it.name == 'main.main' is_main := it.name == 'main.main'
g.gen_attrs(it.attrs) g.gen_attrs(it.attrs)
@ -1422,7 +1446,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
if is_main { if is_main {
g.write(')();') g.write(')();')
} }
if !it.is_anon && !it.is_method { if typ == .struct_method || typ == .alias_method {
g.writeln('\n') g.writeln('\n')
} }
g.fn_decl = voidptr(0) g.fn_decl = voidptr(0)
@ -1661,8 +1685,9 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
g.write('$field.name: ${g.to_js_typ_val(field.typ)}') g.write('$field.name: ${g.to_js_typ_val(field.typ)}')
g.writeln(',') g.writeln(',')
} }
for cfn in fns { for cfn in fns {
g.gen_method_decl(cfn) g.gen_method_decl(cfn, .struct_method)
g.writeln(',') g.writeln(',')
} }
// gen toString method // gen toString method
@ -2435,8 +2460,8 @@ fn (mut g JsGen) gen_deref_ptr(ty ast.Type) {
} }
fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
l_sym := g.table.get_type_symbol(it.left_type) l_sym := g.table.get_final_type_symbol(it.left_type)
r_sym := g.table.get_type_symbol(it.right_type) r_sym := g.table.get_final_type_symbol(it.right_type)
is_not := it.op in [.not_in, .not_is, .ne] is_not := it.op in [.not_in, .not_is, .ne]
if is_not { if is_not {
@ -2444,10 +2469,15 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
} }
is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod, .right_shift, .left_shift, is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod, .right_shift, .left_shift,
.amp, .pipe, .xor] .amp, .pipe, .xor]
if is_arithmetic && ((l_sym.kind == .i64 || l_sym.kind == .u64) if is_arithmetic && ((l_sym.kind == .i64 || l_sym.kind == .u64)
|| (r_sym.kind == .i64 || r_sym.kind == .u64)) { || (r_sym.kind == .i64 || r_sym.kind == .u64)) {
// if left or right is i64 or u64 we convert them to bigint to perform operation. // if left or right is i64 or u64 we convert them to bigint to perform operation.
greater_typ := g.greater_typ(it.left_type, it.right_type) greater_typ := if l_sym.kind == .i64 || l_sym.kind == .u64 {
it.left_type
} else {
it.right_type
} // g.greater_typ(it.left_type, it.right_type)
g.write('new ') g.write('new ')
if g.ns.name != 'builtin' { if g.ns.name != 'builtin' {
g.write('builtin.') g.write('builtin.')
@ -2894,7 +2924,7 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
is_literal := ((it.expr is ast.IntegerLiteral && it.typ in ast.integer_type_idxs) is_literal := ((it.expr is ast.IntegerLiteral && it.typ in ast.integer_type_idxs)
|| (it.expr is ast.FloatLiteral && it.typ in ast.float_type_idxs)) || (it.expr is ast.FloatLiteral && it.typ in ast.float_type_idxs))
// Skip cast if type is the same as the parrent caster // Skip cast if type is the same as the parrent caster
tsym := g.table.get_type_symbol(it.typ) tsym := g.table.get_final_type_symbol(it.typ)
if it.expr is ast.IntegerLiteral && (tsym.kind == .i64 || tsym.kind == .u64) { if it.expr is ast.IntegerLiteral && (tsym.kind == .i64 || tsym.kind == .u64) {
g.write('new ') g.write('new ')
if g.ns.name != 'builtin' { if g.ns.name != 'builtin' {

View File

@ -0,0 +1,15 @@
module stats_import
pub fn get_stats_ok() int {
res := 0
#res.val = +g_test_oks
return res
}
pub fn get_stats_fail() int {
res := 0
#res.val = +g_test_fails
return res
}

View File

@ -1,5 +1,7 @@
module main module main
import stats_import
import benchmark
// ///////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////
// / This file will get compiled as a part of the same module, // / This file will get compiled as a part of the same module,
// / in which a given _test.v file is, when v is given -stats argument // / in which a given _test.v file is, when v is given -stats argument
@ -7,10 +9,12 @@ module main
// / main function, so that customizing the look & feel of the results // / main function, so that customizing the look & feel of the results
// / is easy, since it is done in normal V code, instead of in embedded C ... // / is easy, since it is done in normal V code, instead of in embedded C ...
// ///////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////
const inner_indent = ' ' const inner_indent = ' '
struct BenchedTests { struct BenchedTests {
mut: mut:
bench benchmark.Benchmark
oks int oks int
fails int fails int
test_suit_file string test_suit_file string
@ -21,7 +25,10 @@ mut:
// /////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////
// Called at the start of the test program produced by `v -stats file_test.v` // Called at the start of the test program produced by `v -stats file_test.v`
pub fn start_testing(total_number_of_tests int, vfilename string) BenchedTests { pub fn start_testing(total_number_of_tests int, vfilename string) BenchedTests {
mut benched_tests_res := BenchedTests{} mut benched_tests_res := BenchedTests{
bench: benchmark.new_benchmark()
}
benched_tests_res.bench.set_total_expected_steps(total_number_of_tests)
benched_tests_res.total_number_of_tests = total_number_of_tests benched_tests_res.total_number_of_tests = total_number_of_tests
benched_tests_res.test_suit_file = vfilename benched_tests_res.test_suit_file = vfilename
println('running tests in: $benched_tests_res.test_suit_file') println('running tests in: $benched_tests_res.test_suit_file')
@ -31,14 +38,15 @@ pub fn start_testing(total_number_of_tests int, vfilename string) BenchedTests {
// Called before each test_ function, defined in file_test.v // Called before each test_ function, defined in file_test.v
fn (mut b BenchedTests) testing_step_start(stepfunc string) { fn (mut b BenchedTests) testing_step_start(stepfunc string) {
b.step_func_name = stepfunc.replace('main.', '').replace('__', '.') b.step_func_name = stepfunc.replace('main.', '').replace('__', '.')
b.oks = C.g_test_oks b.oks = stats_import.get_stats_ok()
b.fails = C.g_test_fails b.fails = stats_import.get_stats_fail()
b.bench.step()
} }
// Called after each test_ function, defined in file_test.v // Called after each test_ function, defined in file_test.v
fn (mut b BenchedTests) testing_step_end() { fn (mut b BenchedTests) testing_step_end() {
ok_diff := C.g_test_oks - b.oks ok_diff := stats_import.get_stats_ok() - b.oks
fail_diff := C.g_test_fails - b.fails fail_diff := stats_import.get_stats_fail() - b.fails
// //////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////
if ok_diff == 0 && fail_diff == 0 { if ok_diff == 0 && fail_diff == 0 {
println(inner_indent + ' NO asserts | ' + b.fn_name()) println(inner_indent + ' NO asserts | ' + b.fn_name())
@ -46,17 +54,19 @@ fn (mut b BenchedTests) testing_step_end() {
} }
// //////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////
if ok_diff > 0 { if ok_diff > 0 {
// b.bench.ok_many(ok_diff) b.bench.ok_many(ok_diff)
} }
if fail_diff > 0 { if fail_diff > 0 {
// b.bench.fail_many(fail_diff) b.bench.fail_many(fail_diff)
} }
// //////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////
if ok_diff > 0 && fail_diff == 0 { if ok_diff > 0 && fail_diff == 0 {
println(inner_indent + b.bench.step_message_ok(nasserts(ok_diff)) + b.fn_name())
println(inner_indent + nasserts(ok_diff) + b.fn_name()) println(inner_indent + nasserts(ok_diff) + b.fn_name())
return return
} }
if fail_diff > 0 { if fail_diff > 0 {
println(inner_indent + b.bench.step_message_fail(nasserts(fail_diff)) + b.fn_name())
println(inner_indent + nasserts(fail_diff) + b.fn_name()) println(inner_indent + nasserts(fail_diff) + b.fn_name())
return return
} }