From 4189190bb8414fb57b5bd3f4369d7ea27aae2d9a Mon Sep 17 00:00:00 2001 From: spaceface777 Date: Sun, 24 May 2020 22:49:01 +0200 Subject: [PATCH] jsgen: start implementing remaining `expr`s and `stmt`s --- vlib/v/gen/js/js.v | 499 +++++++++++++++++++++-------------- vlib/v/gen/js/tests/array.js | 92 +++++++ vlib/v/gen/js/tests/array.v | 44 +++ vlib/v/gen/js/tests/js.js | 157 ++++++----- vlib/v/gen/js/tests/js.v | 13 +- 5 files changed, 539 insertions(+), 266 deletions(-) create mode 100644 vlib/v/gen/js/tests/array.js create mode 100644 vlib/v/gen/js/tests/array.v diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 2cd15d0922..4530e8f57d 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -4,7 +4,6 @@ import strings import v.ast import v.table import v.pref -import term import v.util import v.depgraph @@ -193,7 +192,6 @@ pub fn (g JsGen) hashes() string { return res } - // V type to JS type pub fn (mut g JsGen) typ(t table.Type) string { sym := g.table.get_type_symbol(t) @@ -206,7 +204,7 @@ pub fn (mut g JsGen) typ(t table.Type) string { tokens := styp.replace('multi_return_', '').split('_') return '[' + tokens.map(g.to_js_typ(it)).join(', ') + ']' } - // 'anon_fn_7_7_1' => '(a number, b number) => void' + // 'anon_fn_7_7_1' => '(a number, b number) => void' if styp.starts_with('anon_') { info := sym.info as table.FnType mut res := '(' @@ -352,7 +350,7 @@ fn (mut g JsGen) get_alias(name string) string { if split.len > 1 { imports := g.namespace_imports[g.namespace] alias := imports[split[0]] - + if alias != '' { return alias + '.' + split[1..].join('.') } @@ -382,9 +380,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) { g.stmt_start_pos = g.out.len match node { - ast.Module { - // TODO: Implement namespaces - } ast.AssertStmt { g.gen_assert_stmt(it) } @@ -401,12 +396,15 @@ fn (mut g JsGen) stmt(node ast.Stmt) { ast.BranchStmt { g.gen_branch_stmt(it) } - ast.ConstDecl { - g.gen_const_decl(it) + ast.Comment { + // Skip: don't generate comments } ast.CompIf { // skip: JS has no compile time if } + ast.ConstDecl { + g.gen_const_decl(it) + } ast.DeferStmt { g.defer_stmts << *it } @@ -434,6 +432,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) { g.gen_for_stmt(it) g.writeln('') } + ast.GlobalDecl { + // TODO + } ast.GoStmt { g.gen_go_stmt(it) g.writeln('') @@ -453,6 +454,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) { ast.InterfaceDecl { // TODO skip: interfaces not implemented yet } + ast.Module { + // skip: namespacing implemented externally + } ast.Return { if g.defer_stmts.len > 0 { g.gen_defer_stmts() @@ -468,20 +472,32 @@ fn (mut g JsGen) stmt(node ast.Stmt) { ast.UnsafeStmt { g.stmts(it.stmts) } + /* else { verror('jsgen.stmt(): bad node ${typeof(node)}') } + */ } } fn (mut g JsGen) expr(node ast.Expr) { match node { + ast.AnonFn { + g.gen_fn_decl(it.decl) + } ast.ArrayInit { g.gen_array_init_expr(it) } + ast.AsCast { + // skip: JS has no types, so no need to cast + // TODO: Is jsdoc needed here for TS support? + } ast.AssignExpr { g.gen_assign_expr(it) } + ast.Assoc { + // TODO + } ast.BoolLiteral { if it.val == true { g.write('true') @@ -489,11 +505,18 @@ fn (mut g JsGen) expr(node ast.Expr) { g.write('false') } } + ast.CallExpr { + g.gen_call_expr(it) + } + ast.CastExpr { + // skip: JS has no types, so no need to cast + // TODO: Check if jsdoc is needed for TS support + } ast.CharLiteral { g.write("'$it.val'") } - ast.CallExpr { - g.gen_call_expr(it) + ast.ConcatExpr { + // TODO } ast.EnumVal { styp := g.typ(it.typ) @@ -511,123 +534,74 @@ fn (mut g JsGen) expr(node ast.Expr) { ast.IfGuardExpr { // TODO no optionals yet } - ast.IntegerLiteral { - g.write(it.val) + ast.IndexExpr { + g.gen_index_expr(it) } ast.InfixExpr { - g.expr(it.left) - - mut op := it.op.str() - // in js == is non-strict & === is strict, always do strict - if op == '==' { op = '===' } - else if op == '!=' { op = '!==' } - - g.write(' $op ') - g.expr(it.right) + g.gen_infix_expr(it) + } + ast.IntegerLiteral { + g.write(it.val) } ast.MapInit { g.gen_map_init_expr(it) } - /* - ast.UnaryExpr { - g.expr(it.left) - g.write(' $it.op ') + ast.MatchExpr { + // TODO } - */ - - ast.StringLiteral { - g.write('"$it.val"') + ast.None { + // TODO } - ast.StringInterLiteral { - g.gen_string_inter_literal(it) + ast.OrExpr { + // TODO + } + ast.ParExpr { + // TODO } ast.PostfixExpr { g.expr(it.expr) g.write(it.op.str()) } - ast.StructInit { - // `user := User{name: 'Bob'}` - g.gen_struct_init(it) + ast.PrefixExpr { + // TODO + } + ast.RangeExpr { + // Only used in IndexExpr, requires index type info } ast.SelectorExpr { g.gen_selector_expr(it) } - ast.AnonFn { - g.gen_anon_fn_decl(it) + ast.SizeOf { + // TODO } + ast.StringInterLiteral { + g.gen_string_inter_literal(it) + } + ast.StringLiteral { + g.write('"$it.val"') + } + ast.StructInit { + // `user := User{name: 'Bob'}` + g.gen_struct_init(it) + } + ast.Type { + // skip: JS has no types + // TODO maybe? + } + ast.TypeOf { + g.gen_typeof_expr(it) + // TODO: Should this print the V type or the JS type? + } + /* else { - println(term.red('jsgen.expr(): bad node "${typeof(node)}"')) + println(term.red('jsgen.expr(): unhandled node "${typeof(node)}"')) } + */ } } -fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) { - g.write('tos3(`') - for i, val in it.vals { - escaped_val := val.replace_each(['`', '\`', '\r\n', '\n']) - g.write(escaped_val) - if i >= it.exprs.len { - continue - } - expr := it.exprs[i] - sfmt := it.expr_fmts[i] - g.write('\${') - if sfmt.len > 0 { - fspec := sfmt[sfmt.len - 1] - if fspec == `s` && it.expr_types[i] == table.string_type { - g.expr(expr) - g.write('.str') - } else { - g.expr(expr) - } - } else if it.expr_types[i] == table.string_type { - // `name.str` - g.expr(expr) - g.write('.str') - } else if it.expr_types[i] == table.bool_type { - // `expr ? "true" : "false"` - g.expr(expr) - g.write(' ? "true" : "false"') - } else { - sym := g.table.get_type_symbol(it.expr_types[i]) - - match sym.kind { - .struct_ { - g.expr(expr) - if sym.has_method('str') { - g.write('.str()') - } - } - else { - g.expr(expr) - } - } - } - g.write('}') - } - g.write('`)') -} - -fn (mut g JsGen) gen_import_stmt(it ast.Import) { - mut imports := g.namespace_imports[g.namespace] - imports[it.mod] = it.alias - g.namespace_imports[g.namespace] = imports -} - -fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) { - type_sym := g.table.get_type_symbol(it.typ) - if type_sym.kind != .array_fixed { - g.write('[') - for i, expr in it.exprs { - g.expr(expr) - if i < it.exprs.len - 1 { - g.write(', ') - } - } - g.write(']') - } else {} -} +// TODO fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) { g.writeln('// assert') g.write('if( ') @@ -713,12 +687,6 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) { } } -fn (mut g JsGen) gen_assign_expr(it ast.AssignExpr) { - g.expr(it.left) - g.write(' $it.op ') - g.expr(it.val) -} - fn (mut g JsGen) gen_attr(it ast.Attr) { g.writeln('/* [$it.name] */') } @@ -807,8 +775,12 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) { g.gen_method_decl(it) } -fn (mut g JsGen) gen_anon_fn_decl(it ast.AnonFn) { - g.gen_method_decl(it.decl) +fn fn_has_go(it ast.FnDecl) bool { + mut has_go := false + for stmt in it.stmts { + if stmt is ast.GoStmt { has_go = true } + } + return has_go } fn (mut g JsGen) gen_method_decl(it ast.FnDecl) { @@ -875,6 +847,23 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) { g.fn_decl = 0 } +fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) { + // no_names := args.len > 0 && args[0].name == 'arg_1' + 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 (') @@ -961,23 +950,6 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) { g.writeln('}') } -fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) { - // no_names := args.len > 0 && args[0].name == 'arg_1' - 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_go_stmt(node ast.GoStmt) { // x := node.call_expr as ast.CallEpxr // TODO match node.call_expr { @@ -1005,39 +977,21 @@ fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) { } } -fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) { - // key_typ_sym := g.table.get_type_symbol(it.key_type) - // value_typ_sym := g.table.get_type_symbol(it.value_type) - // key_typ_str := key_typ_sym.name.replace('.', '__') - // value_typ_str := value_typ_sym.name.replace('.', '__') - if it.vals.len > 0 { - g.writeln('new Map([') - g.inc_indent() - for i, key in it.keys { - val := it.vals[i] - g.write('[') - g.expr(key) - g.write(', ') - g.expr(val) - g.write(']') - if i < it.keys.len - 1 { - g.write(',') - } - g.writeln('') - } - g.dec_indent() - g.write('])') - } else { - g.write('new Map()') - } +fn (mut g JsGen) gen_import_stmt(it ast.Import) { + mut imports := g.namespace_imports[g.namespace] + imports[it.mod] = it.alias + g.namespace_imports[g.namespace] = imports } fn (mut g JsGen) gen_return_stmt(it ast.Return) { - g.write('return ') - if it.exprs.len == 0 { // Returns nothing - } else if it.exprs.len == 1 { + g.write('return;') + return + } + + g.write('return ') + if it.exprs.len == 1 { g.expr(it.exprs[0]) } else { // Multi return @@ -1053,13 +1007,6 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) { g.writeln(';') } -fn (mut g JsGen) enum_expr(node ast.Expr) { - match node { - ast.EnumVal { g.write(it.val) } - else { g.expr(node) } - } -} - fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { g.writeln(g.doc.gen_fac_fn(node.fields)) g.write('function ${g.js_name(node.name)}({ ') @@ -1104,37 +1051,24 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { } } -fn (mut g JsGen) gen_struct_init(it ast.StructInit) { +fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) { type_sym := g.table.get_type_symbol(it.typ) - name := type_sym.name - if it.fields.len == 0 { - g.write('new ${g.js_name(name)}({})') - } else { - g.writeln('new ${g.js_name(name)}({') - g.inc_indent() - for i, field in it.fields { - g.write('$field.name: ') - g.expr(field.expr) - if i < it.fields.len - 1 { + if type_sym.kind != .array_fixed { + g.write('[') + for i, expr in it.exprs { + g.expr(expr) + if i < it.exprs.len - 1 { g.write(', ') } - g.writeln('') } - g.dec_indent() - g.write('})') - } + g.write(']') + } else {} } -fn (mut g JsGen) gen_ident(node ast.Ident) { - if node.kind == .constant { - // TODO: Handle const namespacing: only consts in the main module are handled rn - g.write('_CONSTS.') - } - - name := g.js_name(node.name) - // TODO `is` - // TODO handle optionals - g.write(name) +fn (mut g JsGen) gen_assign_expr(it ast.AssignExpr) { + g.expr(it.left) + g.write(' $it.op ') + g.expr(it.val) } fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { @@ -1163,9 +1097,16 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { g.write(')') } -fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) { - g.expr(it.expr) - g.write('.$it.field_name') +fn (mut g JsGen) gen_ident(node ast.Ident) { + if node.kind == .constant { + // TODO: Handle const namespacing: only consts in the main module are handled rn + g.write('_CONSTS.') + } + + name := g.js_name(node.name) + // TODO `is` + // TODO handle optionals + g.write(name) } fn (mut g JsGen) gen_if_expr(node ast.IfExpr) { @@ -1223,14 +1164,172 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) { } } -fn verror(s string) { - util.verror('jsgen error', s) +fn (mut g JsGen) gen_index_expr(it ast.IndexExpr) { + // TODO: Handle splice setting if it's implemented + if it.index is ast.RangeExpr { + range := it.index as ast.RangeExpr + g.expr(it.left) + g.write('.slice(') + if range.has_low { + g.expr(range.low) + } else { + g.write('0') + } + g.write(', ') + if range.has_high { + g.expr(range.high) + } else { + g.expr(it.left) + g.write('.length') + } + g.write(')') + } else { + // TODO Does this work in all cases? + g.expr(it.left) + g.write('[') + g.expr(it.index) + g.write(']') + } } -fn fn_has_go(it ast.FnDecl) bool { - mut has_go := false - for stmt in it.stmts { - if stmt is ast.GoStmt { has_go = true } - } - return has_go +fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { + g.expr(it.left) + + mut op := it.op.str() + // in js == is non-strict & === is strict, always do strict + if op == '==' { op = '===' } + else if op == '!=' { op = '!==' } + + g.write(' $op ') + g.expr(it.right) +} + + +fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) { + // key_typ_sym := g.table.get_type_symbol(it.key_type) + // value_typ_sym := g.table.get_type_symbol(it.value_type) + // key_typ_str := key_typ_sym.name.replace('.', '__') + // value_typ_str := value_typ_sym.name.replace('.', '__') + if it.vals.len > 0 { + g.writeln('new Map([') + g.inc_indent() + for i, key in it.keys { + val := it.vals[i] + g.write('[') + g.expr(key) + g.write(', ') + g.expr(val) + g.write(']') + if i < it.keys.len - 1 { + g.write(',') + } + g.writeln('') + } + g.dec_indent() + g.write('])') + } else { + g.write('new Map()') + } +} + +fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) { + g.expr(it.expr) + g.write('.$it.field_name') +} + +fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) { + // TODO Implement `tos3` + g.write('tos3(`') + for i, val in it.vals { + escaped_val := val.replace_each(['`', '\`', '\r\n', '\n']) + g.write(escaped_val) + if i >= it.exprs.len { + continue + } + expr := it.exprs[i] + sfmt := it.expr_fmts[i] + g.write('\${') + if sfmt.len > 0 { + fspec := sfmt[sfmt.len - 1] + if fspec == `s` && it.expr_types[i] == table.string_type { + g.expr(expr) + g.write('.str') + } else { + g.expr(expr) + } + } else if it.expr_types[i] == table.string_type { + // `name.str` + g.expr(expr) + g.write('.str') + } else if it.expr_types[i] == table.bool_type { + // `expr ? "true" : "false"` + g.expr(expr) + g.write(' ? "true" : "false"') + } else { + sym := g.table.get_type_symbol(it.expr_types[i]) + + match sym.kind { + .struct_ { + g.expr(expr) + if sym.has_method('str') { + g.write('.str()') + } + } + else { + g.expr(expr) + } + } + } + g.write('}') + } + g.write('`)') +} + +fn (mut g JsGen) gen_struct_init(it ast.StructInit) { + type_sym := g.table.get_type_symbol(it.typ) + name := type_sym.name + if it.fields.len == 0 { + g.write('new ${g.js_name(name)}({})') + } else { + g.writeln('new ${g.js_name(name)}({') + g.inc_indent() + for i, field in it.fields { + g.write('$field.name: ') + g.expr(field.expr) + if i < it.fields.len - 1 { + g.write(',') + } + g.writeln('') + } + g.dec_indent() + g.write('})') + } +} + +fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) { + sym := g.table.get_type_symbol(it.expr_type) + if sym.kind == .sum_type { + // TODO: JS sumtypes not implemented yet + } else if sym.kind == .array_fixed { + fixed_info := sym.info as table.ArrayFixed + typ_name := g.table.get_type_name(fixed_info.elem_type) + g.write('"[$fixed_info.size]${typ_name}"') + } else if sym.kind == .function { + info := sym.info as table.FnType + fn_info := info.func + mut repr := 'fn (' + for i, arg in fn_info.args { + if i > 0 { + repr += ', ' + } + repr += g.table.get_type_name(arg.typ) + } + repr += ')' + if fn_info.return_type != table.void_type { + repr += ' ${g.table.get_type_name(fn_info.return_type)}' + } + g.write('"$repr"') + } else { + g.write('"${sym.name}"') + } } diff --git a/vlib/v/gen/js/tests/array.js b/vlib/v/gen/js/tests/array.js new file mode 100644 index 0000000000..84c836cd17 --- /dev/null +++ b/vlib/v/gen/js/tests/array.js @@ -0,0 +1,92 @@ +// V_COMMIT_HASH 0de70e8 +// V_CURRENT_COMMIT_HASH 4271eb4 +// Generated by the V compiler + +"use strict"; + +/** @namespace builtin */ +const builtin = (function () { + /** + * @param {any} s + * @returns {void} + * @function + */ + function println(s) { + console.log(s); + } + + /** + * @param {any} s + * @returns {void} + * @function + */ + function print(s) { + process.stdout.write(s); + } + + /* module exports */ + return { + println, + print, + }; +})(); + +/** @namespace main */ +const main = (function () { + /** + * @param {...number} args + * @returns {void} + * @function + */ + function variadic(...args) { + builtin.println(args); + builtin.println(args[0]); + builtin.println(args[1]); + } + + /** + * @returns {void} + * @function + */ + function vararg_test() { + variadic(1, 2, 3); + } + + /* program entry point */ + (function() { + vararg_test(); + /** @type {string[]} - arr1 */ + const arr1 = ["Hello", "JS", "Backend"]; + /** @type {number[]} - arr2 */ + let arr2 = [1, 2, 3, 4, 5]; + /** @type {string[]} - slice1 */ + const slice1 = arr1.slice(1, 3); + /** @type {number[]} - slice2 */ + const slice2 = arr2.slice(0, 3); + /** @type {number[]} - slice3 */ + const slice3 = arr2.slice(3, arr2.length); + /** @type {string} - idx1 */ + const idx1 = slice1[1]; + arr2[0] = 1; + arr2[0 + 1] = 2; + builtin.println(arr2); + /** @type {string} - slice4 */ + const slice4 = idx1.slice(0, 4); + builtin.println(slice4); + /** @type {byte} - idx2 */ + const idx2 = slice4[0]; + /** @type {Map} - m */ + let m = new Map(); + /** @type {string} - key */ + const key = "key"; + m[key] = "value"; + /** @type {string} - val */ + const val = m["key"]; + builtin.println(val); + })(); + + /* module exports */ + return {}; +})(); + + diff --git a/vlib/v/gen/js/tests/array.v b/vlib/v/gen/js/tests/array.v new file mode 100644 index 0000000000..56938f292c --- /dev/null +++ b/vlib/v/gen/js/tests/array.v @@ -0,0 +1,44 @@ +fn variadic(args ...int) { + println(args) + println(args[0]) + println(args[1]) +} + +fn vararg_test() { + variadic(1, 2, 3) +} + +vararg_test() + +arr1 := ['Hello', 'JS', 'Backend'] +mut arr2 := [1, 2, 3, 4, 5] + +// Array slices +slice1 := arr1[1..3] +slice2 := arr2[..3] +slice3 := arr2[3..] + +// Array indexes +idx1 := slice1[1] +arr2[0] = 1 +arr2[0 + 1] = 2 +println(arr2) + +// String slices +slice4 := idx1[..4] +println(slice4) // 'Back' + +// String indexes +idx2 := slice4[0] + +// TODO: This does not work for now +// arr2[0..1] = arr2[3..4] +// println(arr2) + + +// Maps +mut m := map[string]string +key := 'key' +m[key] = 'value' +val := m['key'] +println(val) \ No newline at end of file diff --git a/vlib/v/gen/js/tests/js.js b/vlib/v/gen/js/tests/js.js index ea4e320cc4..f14affdd6e 100644 --- a/vlib/v/gen/js/tests/js.js +++ b/vlib/v/gen/js/tests/js.js @@ -1,5 +1,5 @@ -// V_COMMIT_HASH 74686d0 -// V_CURRENT_COMMIT_HASH 0d3f133 +// V_COMMIT_HASH 0de70e8 +// V_CURRENT_COMMIT_HASH 4271eb4 // Generated by the V compiler "use strict"; @@ -11,51 +11,81 @@ const _CONSTS = Object.freeze({ v_super: "amazing keyword" }); -/* namespace: hello */ +/** @namespace builtin */ +const builtin = (function () { + /** + * @param {any} s + * @returns {void} + * @function + */ + function println(s) { + console.log(s); + } + + /** + * @param {any} s + * @returns {void} + * @function + */ + function print(s) { + process.stdout.write(s); + } + + /* module exports */ + return { + println, + print, + }; +})(); + +/** @namespace hello */ const hello = (function () { - class A { - /** - * @param {{foo?: string}} values - values for this class fields - * @constructor - */ - constructor(values) { - this.foo = values.foo - } - + /** + * @param {{foo?: string}} values - values for this class fields + * @constructor + */ + function A({ foo = "" }) { + this.foo = foo + }; + A.prototype = { + /** @type {string} - foo */ + foo: "", /** * @param {string} s * @returns {void} + * @function */ update(s) { const a = this; a.foo = s; } - } + }; - class B { - /** - * @param {{}} values - values for this class fields - * @constructor - */ - constructor(values) { - } - } + /** + * @param {{}} values - values for this class fields + * @constructor + */ + function B({ }) { + }; + B.prototype = { + }; const C = Object.freeze({ }); /** * @returns {string} + * @function */ function v_debugger() { - const v = new B({ - }); + const v = new B({}); return "Hello"; } /** * @returns {string} + * @function */ function excited() { return v_debugger() + "!"; @@ -70,37 +100,45 @@ const hello = (function () { }; })(); -/* namespace: main */ +/** @namespace main */ const main = (function (hl) { - class Foo { - /** - * @param {{a?: hl["A"]["prototype"]}} values - values for this class fields - * @constructor - */ - constructor(values) { - this.a = values.a - } - } + /** + * @param {{a?: hl["A"]["prototype"]}} values - values for this class fields + * @constructor + */ + function Foo({ a = {} }) { + this.a = a + }; + Foo.prototype = { + /** @type {hl["A"]["prototype"]} - a */ + a: {} + }; - class Companies { - /** - * @param {{google?: number, amazon?: boolean, yahoo?: string}} values - values for this class fields - * @constructor - */ - constructor(values) { - this.google = values.google - this.amazon = values.amazon - this.yahoo = values.yahoo - } - + /** + * @param {{google?: number, amazon?: boolean, yahoo?: string}} values - values for this class fields + * @constructor + */ + function Companies({ google = 0, amazon = false, yahoo = "" }) { + this.google = google + this.amazon = amazon + this.yahoo = yahoo + }; + Companies.prototype = { + /** @type {number} - google */ + google: 0, + /** @type {boolean} - amazon */ + amazon: false, + /** @type {string} - yahoo */ + yahoo: "", /** * @returns {number} + * @function */ method() { const it = this; const ss = new Companies({ - google: 2, - amazon: true, + google: 2, + amazon: true, yahoo: "hello" }); /** @type {[number, number]} */ @@ -112,7 +150,7 @@ const main = (function (hl) { return 0; } - } + }; const POSITION = Object.freeze({ go_back: 0, @@ -123,6 +161,7 @@ const main = (function (hl) { * @param {string} v_extends * @param {number} v_instanceof * @returns {void} + * @function */ function v_class(v_extends, v_instanceof) { /** @type {number} - v_delete */ @@ -131,22 +170,20 @@ const main = (function (hl) { /* program entry point */ (async function() { - console.log("Hello from V.js!"); + builtin.println("Hello from V.js!"); /** @type {number} - a */ let a = 1; a *= 2; a += 3; - console.log(a, " == 5"); - const b = new hl.A({ - }); + builtin.println(a); + const b = new hl.A({}); b.update("an update"); - console.log(b); + builtin.println(b); const c = new Foo({ - a: new hl.A({ - }) + a: new hl.A({}) }); c.a.update("another update"); - console.log(c); + builtin.println(c); /** @type {string} - v */ const v = "done"; { @@ -198,11 +235,11 @@ const main = (function (hl) { /** @type {(number: number) => void} - fn_in_var */ const fn_in_var = function (number) { - console.log(tos3(`number: ${number}`)); + builtin.println(tos3(`number: ${number}`)); }; hl.v_debugger(); anon_consumer(hl.excited(), function (message) { - console.log(message); + builtin.println(message); }); })(); @@ -210,6 +247,7 @@ const main = (function (hl) { * @param {string} greeting * @param {(message: string) => void} anon * @returns {void} + * @function */ function anon_consumer(greeting, anon) { anon(greeting); @@ -219,6 +257,7 @@ const main = (function (hl) { * @param {number} num * @param {string} def * @returns {void} + * @function */ function async(num, def) { } @@ -230,6 +269,7 @@ const main = (function (hl) { * @param {number} game_on * @param {...string} dummy * @returns {[number, number]} + * @function */ function hello(game_on, ...dummy) { for (let _tmp2 = 0; _tmp2 < dummy.length; ++_tmp2) { @@ -246,8 +286,7 @@ const main = (function (hl) { } /* module exports */ - return { - }; + return {}; })(hello); diff --git a/vlib/v/gen/js/tests/js.v b/vlib/v/gen/js/tests/js.v index 26aab2a389..37e74e5393 100644 --- a/vlib/v/gen/js/tests/js.v +++ b/vlib/v/gen/js/tests/js.v @@ -1,7 +1,6 @@ import hello as hl fn JS.alert(arg string) -fn JS.console.log(arg string) const ( i_am_a_const = 21214 @@ -29,20 +28,20 @@ fn class(extends string, instanceof int) { fn main() { - JS.console.log('Hello from V.js!') + println('Hello from V.js!') mut a := 1 a *= 2 a += 3 - JS.console.log(a, ' == 5') // TODO: Handle string interpolation + println(a) // TODO: Handle string interpolation b := hl.A{} b.update('an update') - JS.console.log(b) + println(b) c := Foo{ hl.A{} } c.a.update('another update') - JS.console.log(c) + println(c) v := "done" { @@ -81,12 +80,12 @@ fn main() { go async(0, "hello") fn_in_var := fn (number int) { - JS.console.log("number: $number") + println("number: $number") } hl.debugger() anon_consumer(hl.excited(), fn (message string) { - JS.console.log(message) + println(message) }) }