diff --git a/vlib/os/os.js.v b/vlib/os/os.js.v index bdb5ea0db1..c1641db3dd 100644 --- a/vlib/os/os.js.v +++ b/vlib/os/os.js.v @@ -2,6 +2,7 @@ module os #const $fs = require('fs'); #const $path = require('path'); +#const tty = require('tty') pub const ( path_delimiter = '/' @@ -95,3 +96,10 @@ pub fn execute(cmd string) Result { output: stdout } } + +pub fn is_atty(fd int) int { + res := 0 + #res.val = +tty.isatty(fd.val) + + return res +} diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index 2ad79ad55d..199f23b0c4 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -258,6 +258,9 @@ pub fn (v &Builder) get_user_files() []string { if v.pref.is_test && v.pref.is_stats { user_files << os.join_path(preludes_path, 'tests_with_stats.v') } + if v.pref.backend.is_js() && v.pref.is_stats && v.pref.is_test { + user_files << os.join_path(preludes_path, 'stats_import.js.v') + } if v.pref.is_prof { user_files << os.join_path(preludes_path, 'profiled_program.v') } diff --git a/vlib/v/gen/js/auto_eq_methods.v b/vlib/v/gen/js/auto_eq_methods.v index 2f7a59668c..eaa447c191 100644 --- a/vlib/v/gen/js/auto_eq_methods.v +++ b/vlib/v/gen/js/auto_eq_methods.v @@ -12,6 +12,9 @@ fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string { g.sumtype_fn_definitions << ptr_styp info := left.sym.sumtype_info() mut fn_builder := strings.new_builder(512) + defer { + g.definitions.writeln(fn_builder.str()) + } fn_builder.writeln('function ${ptr_styp}_sumtype_eq(a,b) {') fn_builder.writeln('\tlet aProto = Object.getPrototypeOf(a);') fn_builder.writeln('\tlet bProto = Object.getPrototypeOf(b);') @@ -48,7 +51,7 @@ fn (mut g JsGen) gen_sumtype_equality_fn(left_type ast.Type) string { } fn_builder.writeln('\treturn new bool(false);') fn_builder.writeln('}') - g.definitions.writeln(fn_builder.str()) + return ptr_styp } diff --git a/vlib/v/gen/js/builtin_types.v b/vlib/v/gen/js/builtin_types.v index 71e2d17914..eb275912a0 100644 --- a/vlib/v/gen/js/builtin_types.v +++ b/vlib/v/gen/js/builtin_types.v @@ -120,10 +120,11 @@ pub fn (mut g JsGen) base_type(t ast.Type) string { } pub fn (mut g JsGen) typ(t ast.Type) string { - sym := g.table.get_type_symbol(t) + sym := g.table.get_final_type_symbol(t) if sym.kind == .voidptr { return 'any' } + styp := g.base_type(t) return styp } diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index eeaa5e3bdf..1d2cd25f08 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -3,6 +3,7 @@ module js import v.ast import v.util import v.parser +import strings fn (mut g JsGen) js_mname(name_ string) string { mut is_js := false @@ -348,3 +349,178 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { } g.call_stack.delete_last() } + +enum FnGenType { + function + struct_method + alias_method + iface_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 && g.table.get_type_symbol(it.params[0].typ).kind == .interface_ { + return .iface_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) { + res := g.fn_gen_type(it) + if it.language == .js { + return + } + if g.inside_builtin { + g.builtin_fns << it.name + } + cur_fn_decl := g.fn_decl + g.gen_method_decl(it, res) + g.fn_decl = cur_fn_decl +} + +fn fn_has_go(node ast.FnDecl) bool { + mut has_go := false + for stmt in node.stmts { + if stmt is ast.ExprStmt { + if stmt.expr is ast.GoExpr { + has_go = true + break + } + } + } + return has_go +} + +fn (mut g JsGen) generic_fn_name(types []ast.Type, before string, is_decl bool) string { + if types.len == 0 { + return before + } + + mut name := before + '_T' + for typ in types { + name += '_' + strings.repeat_string('__ptr__', typ.nr_muls()) + g.typ(typ.set_nr_muls(0)) + } + return name +} + +fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { + unsafe { + g.fn_decl = &it + } + cur_fn_save := g.table.cur_fn + defer { + g.table.cur_fn = cur_fn_save + } + unsafe { + g.table.cur_fn = &it + } + node := it + mut name := it.name + if name in ['+', '-', '*', '/', '%', '<', '=='] { + name = util.replace_op(name) + } + + if node.is_method { + unwrapped_rec_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver.typ)) + if unwrapped_rec_sym.kind == .placeholder { + return + } + name = g.cc_type(node.receiver.typ, false) + '_' + name + } + + name = g.js_name(name) + + name = g.generic_fn_name(g.table.cur_concrete_types, name, true) + if name in parser.builtin_functions { + name = 'builtin__$name' + } + has_go := fn_has_go(it) + if it.is_pub && !it.is_method { + g.push_pub_var(name) + } + is_main := it.name == 'main.main' + g.gen_attrs(it.attrs) + if is_main { + // there is no concept of main in JS but we do have iife + g.writeln('/* program entry point */') + + // g.write('(') + if has_go { + g.write('async ') + } + g.write('function js_main(') + } else if it.is_anon { + g.write('function (') + } else { + c := name[0] + if c in [`+`, `-`, `*`, `/`] { + name = util.replace_op(name) + } + // type_name := g.typ(it.return_type) + // generate jsdoc for the function + g.doc.gen_fn(it) + if has_go { + g.write('async ') + } + + g.write('function ') + + g.write('${name}(') + if it.is_pub && !it.is_method { + g.push_pub_var(name) + } + } + mut args := it.params + + g.fn_args(args, it.is_variadic) + g.write(') {') + for i, arg in args { + is_varg := i == args.len - 1 && it.is_variadic + arg_name := g.js_name(arg.name) + if is_varg { + g.writeln('$arg_name = new array($arg_name);') + } else { + if arg.typ.is_ptr() || arg.is_mut { + g.writeln('$arg_name = new \$ref($arg_name)') + } + } + } + g.stmts(it.stmts) + g.writeln('}') + + if is_main { + // g.write(')') + } + g.writeln('') + + for attr in it.attrs { + match attr.name { + 'export' { + g.writeln('globalThis.$attr.arg = ${g.js_name(it.name)};') + } + else {} + } + } + + g.fn_decl = voidptr(0) +} + +fn (mut g JsGen) fn_args(args []ast.Param, is_variadic bool) { + for i, arg in args { + name := g.js_name(arg.name) + is_varg := i == args.len - 1 && is_variadic + if is_varg { + g.write('...$name') + } else { + g.write(name) + } + // if its not the last argument + if i < args.len - 1 { + g.write(', ') + } + } +} diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 1256e5b726..3dc723ad9f 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -9,12 +9,6 @@ import v.util.version import v.depgraph import encoding.base64 import v.gen.js.sourcemap -import v.parser - -struct MutArg { - tmp_var string - expr ast.Expr = ast.empty_expr() -} const ( // https://ecma-international.org/ecma-262/#sec-reserved-words @@ -285,24 +279,24 @@ pub fn (mut g JsGen) gen_js_main_for_tests() { g.writeln('') g.writeln('globalThis.VTEST=1') if g.pref.is_stats { - g.writeln('let bt = start_testing($all_tfuncs.len, "$g.pref.path")') + g.writeln('let bt = main__start_testing(new int($all_tfuncs.len), new string("$g.pref.path"))') } for tname in all_tfuncs { tcname := g.js_name(tname) if g.pref.is_stats { - g.writeln('bt.testing_step_start("$tcname")') + g.writeln('main__BenchedTests_testing_step_start(bt,new string("$tcname"))') } g.writeln('try { ${tcname}(); } catch (_e) {} ') if g.pref.is_stats { - g.writeln('bt.testing_step_end();') + g.writeln('main__BenchedTests_testing_step_end(bt);') } } g.writeln('') if g.pref.is_stats { - g.writeln('bt.end_testing();') + g.writeln('main__BenchedTests_end_testing(bt);') } g.dec_indent() g.writeln('}') @@ -489,62 +483,6 @@ fn (mut g JsGen) get_alias(name string) string { } fn (mut g JsGen) js_name(name_ string) string { - /* - mut is_js := false - is_overload := ['+', '-', '*', '/', '==', '<', '>'] - mut name := name_ - if name.starts_with('JS.') { - name = name[3..] - is_js = true - } - ns := get_ns(name) - name = if name in is_overload { - match name { - '+' { - '\$add' - } - '-' { - '\$sub' - } - '/' { - '\$div' - } - '*' { - '\$mul' - } - '%' { - '\$mod' - } - '==' { - 'eq' - } - '>' { - '\$gt' - } - '<' { - '\$lt' - } - else { - '' - } - } - } else if g.ns == 0 { - name - } else if ns == g.ns.name { - name.split('.').last() - } else { - g.get_alias(name) - } - mut parts := name.split('.') - if !is_js { - for i, p in parts { - if p in js.js_reserved { - parts[i] = 'v_$p' - } - } - } - return parts.join('.')*/ - mut name := name_ if name.starts_with('JS.') { name = name[3..] @@ -558,11 +496,9 @@ fn (mut g JsGen) js_name(name_ string) string { } fn (mut g JsGen) stmts(stmts []ast.Stmt) { - g.inc_indent() for stmt in stmts { g.stmt(stmt) } - g.dec_indent() } [inline] @@ -619,6 +555,11 @@ fn (mut g JsGen) gen_global_decl(node ast.GlobalDecl) { } } +fn (mut g JsGen) gen_alias_type_decl(node ast.AliasTypeDecl) { + name := if g.ns.name == 'builtin' { node.name } else { '${g.js_name(g.ns.name)}__$node.name' } + g.writeln('function ${name}(val) { return val; }') +} + fn (mut g JsGen) stmt_no_semi(node ast.Stmt) { g.stmt_start_pos = g.out.len match node { @@ -822,7 +763,12 @@ fn (mut g JsGen) stmt(node ast.Stmt) { g.gen_struct_decl(node) } ast.TypeDecl { - // skip JS has no typedecl + match node { + ast.AliasTypeDecl { + g.gen_alias_type_decl(node) + } + else {} + } } } } @@ -1275,7 +1221,9 @@ fn (mut g JsGen) gen_attrs(attrs []ast.Attr) { fn (mut g JsGen) gen_block(it ast.Block) { g.writeln('{') + g.inc_indent() g.stmts(it.stmts) + g.dec_indent() g.writeln('}') } @@ -1338,59 +1286,9 @@ fn (mut g JsGen) gen_expr_stmt_no_semi(it ast.ExprStmt) { g.expr(it.expr) } -enum FnGenType { - function - struct_method - alias_method - iface_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 && g.table.get_type_symbol(it.params[0].typ).kind == .interface_ { - return .iface_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) { - res := g.fn_gen_type(it) - if it.language == .js { - return - } - /* - if res == .struct_method { - // Struct methods are handled by class generation code. - return - }*/ - if g.inside_builtin { - g.builtin_fns << it.name - } - cur_fn_decl := g.fn_decl - g.gen_method_decl(it, res) - g.fn_decl = cur_fn_decl -} - -fn fn_has_go(node ast.FnDecl) bool { - mut has_go := false - for stmt in node.stmts { - if stmt is ast.ExprStmt { - if stmt.expr is ast.GoExpr { - has_go = true - break - } - } - } - return has_go -} - // cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo) fn (mut g JsGen) cc_type(typ ast.Type, is_prefix_struct bool) string { - sym := g.table.get_type_symbol(g.unwrap_generic(typ)) + sym := g.table.get_final_type_symbol(g.unwrap_generic(typ)) mut styp := sym.cname match mut sym.info { ast.Struct, ast.Interface, ast.SumType { @@ -1408,231 +1306,6 @@ fn (mut g JsGen) cc_type(typ ast.Type, is_prefix_struct bool) string { return styp } -fn (mut g JsGen) generic_fn_name(types []ast.Type, before string, is_decl bool) string { - if types.len == 0 { - return before - } - - mut name := before + '_T' - for typ in types { - name += '_' + strings.repeat_string('__ptr__', typ.nr_muls()) + g.typ(typ.set_nr_muls(0)) - } - return name -} - -fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { - unsafe { - g.fn_decl = &it - } - cur_fn_save := g.table.cur_fn - defer { - g.table.cur_fn = cur_fn_save - } - unsafe { - g.table.cur_fn = &it - } - node := it - mut name := it.name - if name in ['+', '-', '*', '/', '%', '<', '=='] { - name = util.replace_op(name) - } - - if node.is_method { - unwrapped_rec_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver.typ)) - if unwrapped_rec_sym.kind == .placeholder { - return - } - name = g.cc_type(node.receiver.typ, false) + '_' + name - } - - name = g.js_name(name) - - name = g.generic_fn_name(g.table.cur_concrete_types, name, true) - if name in parser.builtin_functions { - name = 'builtin__$name' - } - has_go := fn_has_go(it) - if it.is_pub && !it.is_method { - g.push_pub_var(name) - } - is_main := it.name == 'main.main' - g.gen_attrs(it.attrs) - if is_main { - // there is no concept of main in JS but we do have iife - g.writeln('/* program entry point */') - - // g.write('(') - if has_go { - g.write('async ') - } - g.write('function js_main(') - } else if it.is_anon { - g.write('function (') - } else { - c := name[0] - if c in [`+`, `-`, `*`, `/`] { - name = util.replace_op(name) - } - // type_name := g.typ(it.return_type) - // generate jsdoc for the function - g.doc.gen_fn(it) - if has_go { - g.write('async ') - } - - g.write('function ') - - g.write('${name}(') - if it.is_pub && !it.is_method { - g.push_pub_var(name) - } - } - mut args := it.params - - g.fn_args(args, it.is_variadic) - g.write(') {') - for i, arg in args { - is_varg := i == args.len - 1 && it.is_variadic - arg_name := g.js_name(arg.name) - if is_varg { - g.writeln('$arg_name = new array($arg_name);') - } else { - if arg.typ.is_ptr() || arg.is_mut { - g.writeln('$arg_name = new \$ref($arg_name)') - } - } - } - g.stmts(it.stmts) - g.writeln('}') - - if is_main { - // g.write(')') - } - g.writeln('') - - for attr in it.attrs { - match attr.name { - 'export' { - g.writeln('globalThis.$attr.arg = ${g.js_name(it.name)};') - } - else {} - } - } - /* - if typ == .alias_method || typ == .iface_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('') - } - g.writeln('${name}.prototype.$it.name = function ') - } - has_go := fn_has_go(it) - is_main := it.name == 'main.main' - g.gen_attrs(it.attrs) - if is_main { - // there is no concept of main in JS but we do have iife - g.writeln('/* program entry point */') - - g.write('(') - if has_go { - g.write('async ') - } - g.write('function(') - } else if it.is_anon { - g.write('function (') - } else { - mut name := g.js_name(it.name) - c := name[0] - if c in [`+`, `-`, `*`, `/`] { - name = util.replace_op(name) - } - // type_name := g.typ(it.return_type) - // generate jsdoc for the function - g.doc.gen_fn(it) - if has_go { - g.write('async ') - } - if !it.is_method { - g.write('function ') - } else { - if it.attrs.contains('js_getter') { - g.write('get ') - } else if it.attrs.contains('js_setter') { - g.write('set ') - } - } - g.write('${name}(') - if it.is_pub && !it.is_method { - g.push_pub_var(name) - } - } - mut args := it.params - if it.is_method { - args = args[1..] - } - g.fn_args(args, it.is_variadic) - if it.is_method { - if args.len > 0 { - g.write(', ') - } - if it.params[0].is_mut || it.params[0].typ.is_ptr() { - g.write('${it.params[0].name} = new \$ref(this)') - } else { - g.write('${it.params[0].name} = this') - } - } - g.writeln(') {') - for i, arg in args { - is_varg := i == args.len - 1 && it.is_variadic - name := g.js_name(arg.name) - if is_varg { - g.writeln('$name = new array($name);') - } else { - if arg.typ.is_ptr() || arg.is_mut { - g.writeln('$name = new \$ref($name)') - } - } - } - - g.stmts(it.stmts) - g.writeln('}') - for attr in it.attrs { - match attr.name { - 'export' { - g.writeln('globalThis.$attr.arg = ${g.js_name(it.name)};') - } - else {} - } - } - if is_main { - g.write(')();') - } else if typ != .struct_method { - // g.write(';') - } - if typ == .struct_method || typ == .alias_method || typ == .iface_method { - g.writeln('\n') - } - */ - g.fn_decl = voidptr(0) -} - -fn (mut g JsGen) fn_args(args []ast.Param, is_variadic bool) { - for i, arg in args { - name := g.js_name(arg.name) - is_varg := i == args.len - 1 && is_variadic - if is_varg { - g.write('...$name') - } else { - g.write(name) - } - // if its not the last argument - if i < args.len - 1 { - g.write(', ') - } - } -} - fn (mut g JsGen) gen_for_c_stmt(it ast.ForCStmt) { g.inside_loop = true g.write('for (') @@ -1918,11 +1591,6 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { g.writeln('};\n') g.dec_indent() - /* - for cfn in fns { - g.gen_method_decl(cfn, .struct_method) - }*/ - if node.is_pub { g.push_pub_var(name) } @@ -2553,11 +2221,12 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) { g.write('.valueOf()') } g.write('.arr') - g.write('[+') + g.write('[Number(') g.cast_stack << ast.int_type_idx g.expr(expr.index) + g.write('.valueOf()') g.cast_stack.delete_last() - g.write(']') + g.write(')]') } } @@ -2617,37 +2286,6 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { g.write('.valueOf()') g.write(')') } else if it.op == .eq || it.op == .ne { - /* - has_operator_overloading := g.table.type_has_method(l_sym, '==') - if has_operator_overloading { - g.expr(it.left) - g.gen_deref_ptr(it.left_type) - g.write('.eq(') - g.expr(it.right) - g.gen_deref_ptr(it.right_type) - g.write(')') - // Shallow equatables - } else if l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables { - // wrap left expr in parens so binary operations will work correctly. - g.write('(') - g.expr(it.left) - g.gen_deref_ptr(it.left_type) - g.write(')') - g.write('.eq(') - g.cast_stack << int(l_sym.kind) - g.expr(it.right) - g.gen_deref_ptr(it.right_type) - g.cast_stack.delete_last() - g.write(')') - } else { - g.write('vEq(') - g.expr(it.left) - g.gen_deref_ptr(it.left_type) - g.write(', ') - g.expr(it.right) - g.gen_deref_ptr(it.right_type) - g.write(')') - }*/ node := it left := g.unwrap(node.left_type) right := g.unwrap(node.right_type) diff --git a/vlib/v/preludes_js/stats_import.v b/vlib/v/preludes_js/stats_import.v deleted file mode 100644 index b91c88cd28..0000000000 --- a/vlib/v/preludes_js/stats_import.v +++ /dev/null @@ -1 +0,0 @@ -module stats_import