From a02aff912613cf50b583edd655539b2a3ee9d159 Mon Sep 17 00:00:00 2001 From: spaceface777 Date: Sat, 20 Jun 2020 13:22:49 +0200 Subject: [PATCH] jsgen: fixes and improvements --- vlib/builtin/js/builtin.v | 35 +- vlib/builtin/js/jsfns.js.v | 65 ++++ vlib/builtin/js/jsfns_browser.js.v | 53 +++ vlib/builtin/js/jsfns_node.js.v | 14 + vlib/v/gen/js/js.v | 185 ++++++----- vlib/v/gen/js/jsdoc.v | 16 +- vlib/v/gen/js/jsgen_test.v | 36 ++ vlib/v/gen/js/tests/.gitignore | 1 + vlib/v/gen/js/tests/array.js | 174 ---------- vlib/v/gen/js/tests/array.v | 15 + vlib/v/gen/js/tests/enum.js | 139 -------- vlib/v/gen/js/tests/hello/hello.v | 4 +- .../tests/hello/{Hello1 => hello1}/hello1.v | 2 - vlib/v/gen/js/tests/interface.v | 29 ++ vlib/v/gen/js/tests/interp.js | 260 --------------- vlib/v/gen/js/tests/js.js | 313 ------------------ vlib/v/gen/js/tests/js.v | 6 +- vlib/v/gen/js/tests/life.js | 204 ------------ vlib/v/gen/js/tests/life.v | 16 +- vlib/v/gen/js/tests/simple.js | 45 --- vlib/v/gen/js/tests/struct.js | 122 ------- vlib/v/gen/js/tests/struct.v | 4 +- vlib/v/parser/fn.v | 2 +- 23 files changed, 376 insertions(+), 1364 deletions(-) create mode 100644 vlib/builtin/js/jsfns.js.v create mode 100644 vlib/builtin/js/jsfns_browser.js.v create mode 100644 vlib/builtin/js/jsfns_node.js.v create mode 100644 vlib/v/gen/js/jsgen_test.v create mode 100644 vlib/v/gen/js/tests/.gitignore delete mode 100644 vlib/v/gen/js/tests/array.js delete mode 100644 vlib/v/gen/js/tests/enum.js rename vlib/v/gen/js/tests/hello/{Hello1 => hello1}/hello1.v (53%) create mode 100644 vlib/v/gen/js/tests/interface.v delete mode 100644 vlib/v/gen/js/tests/interp.js delete mode 100644 vlib/v/gen/js/tests/js.js delete mode 100644 vlib/v/gen/js/tests/life.js delete mode 100644 vlib/v/gen/js/tests/simple.js delete mode 100644 vlib/v/gen/js/tests/struct.js diff --git a/vlib/builtin/js/builtin.v b/vlib/builtin/js/builtin.v index d5be73abbe..a4ca33f78d 100644 --- a/vlib/builtin/js/builtin.v +++ b/vlib/builtin/js/builtin.v @@ -4,13 +4,40 @@ module builtin -fn JS.console.log(arg ...string) -fn JS.process.stdout.write(arg string) - pub fn println(s any) { JS.console.log(s) } pub fn print(s any) { - JS.process.stdout.write(s) + // TODO + // $if js.node { + JS.process.stdout.write(s) + // } $else { + // panic('Cannot `print` in a browser, use `println` instead') + // } +} + +pub fn eprintln(s any) { + JS.console.error(s) +} + +pub fn eprint(s any) { + // TODO + // $if js.node { + JS.process.stderr.write(s) + // } $else { + // panic('Cannot `eprint` in a browser, use `eprintln` instead') + // } +} + +// Exits the process in node, and halts execution in the browser +// because `process.exit` is undefined. Workaround for not having +// a 'real' way to exit in the browser. +pub fn exit(c int) { + JS.process.exit(c) +} + +pub fn panic(s string) { + eprintln('V panic: $s') + exit(1) } diff --git a/vlib/builtin/js/jsfns.js.v b/vlib/builtin/js/jsfns.js.v new file mode 100644 index 0000000000..4c023a1bfa --- /dev/null +++ b/vlib/builtin/js/jsfns.js.v @@ -0,0 +1,65 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// This file contains JS functions present in both node and the browser. +// They have been ported from their TypeScript definitions. + +module builtin + +// Top level functions +fn JS.eval(string) any +fn JS.parseInt(string, f64) f64 +fn JS.parseFloat(string) f64 +fn JS.isNaN(f64) bool +fn JS.isFinite(f64) bool +fn JS.decodeURI(string) string +fn JS.decodeURIComponent(string) string +fn JS.encodeURI(string) string +type EncodeURIComponentArg = string | f64 | bool +fn JS.encodeURIComponent(EncodeURIComponentArg) string +fn JS.escape(string) string +fn JS.unescape(string) string + +// console +fn JS.console.assert(bool, ...any) +fn JS.console.clear() +fn JS.console.count(string) +fn JS.console.countReset(string) +fn JS.console.debug(...any) +fn JS.console.dir(any, any) +fn JS.console.dirxml(...any) +fn JS.console.error(...any) +fn JS.console.exception(string, ...any) +fn JS.console.group(...any) +fn JS.console.groupCollapsed(...any) +fn JS.console.groupEnd() +fn JS.console.info(...any) +fn JS.console.log(...any) +fn JS.console.table(any, []string) +fn JS.console.time(string) +fn JS.console.timeEnd(string) +fn JS.console.timeLog(string, ...any) +fn JS.console.timeStamp(string) +fn JS.console.trace(...any) +fn JS.console.warn(...any) + +// Math +fn JS.Math.abs(f64) f64 +fn JS.Math.acos(f64) f64 +fn JS.Math.asin(f64) f64 +fn JS.Math.atan(f64) f64 +fn JS.Math.atan2(f64, f64) f64 +fn JS.Math.ceil(f64) f64 +fn JS.Math.cos(f64) f64 +fn JS.Math.exp(f64) f64 +fn JS.Math.floor(f64) f64 +fn JS.Math.log(f64) f64 +fn JS.Math.max(...f64) f64 +fn JS.Math.min(...f64) f64 +fn JS.Math.pow(f64, f64) f64 +fn JS.Math.random() f64 +fn JS.Math.round(f64) f64 +fn JS.Math.sin(f64) f64 +fn JS.Math.sqrt(f64) f64 +fn JS.Math.tan(f64) f64 diff --git a/vlib/builtin/js/jsfns_browser.js.v b/vlib/builtin/js/jsfns_browser.js.v new file mode 100644 index 0000000000..d8fdb77123 --- /dev/null +++ b/vlib/builtin/js/jsfns_browser.js.v @@ -0,0 +1,53 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// This file contains JS functions only present in the browser. +// They have been ported from their TypeScript definitions. + +module builtin + +// Window +fn JS.atob(string) string +fn JS.btoa(string) string +fn JS.clearInterval(int) +fn JS.clearTimeout(int) + +// fn JS.createImageBitmap(ImageBitmapSource, ImageBitmapOptions) Promise +// fn JS.createImageBitmap(ImageBitmapSource, int, int, int, int, ImageBitmapOptions) Promise + +// TODO: js async attribute +// [js_async] +// fn JS.fetch(RequestInfo, RequestInit) Promise +fn JS.queueMicrotask(fn()) +fn JS.setInterval(any, int, ...any) int +fn JS.setTimeout(any, int, ...any) int + +fn JS.alert(any) +fn JS.blur() +fn JS.captureEvents() +fn JS.close() +fn JS.confirm(string) bool +// fn JS.departFocus(NavigationReason, FocusNavigationOrigin) +fn JS.focus() +// fn JS.getComputedStyle(Element, string | null) CSSStyleDeclaration +// fn JS.getMatchedCSSRules(Element, string | null) CSSRuleList +// fn JS.getSelection() Selection | null +// fn JS.matchMedia(string) MediaQueryList +fn JS.moveBy(int, int) +fn JS.moveTo(int, int) +fn JS.msWriteProfilerMark(string) +// fn JS.open(string, string, string, bool) ?Window +// fn JS.postMessage(any, string, []Transferable) +fn JS.print() +fn JS.prompt(string, string) ?string +fn JS.releaseEvents() +fn JS.resizeBy(int, int) +fn JS.resizeTo(int, int) +// fn JS.scroll(ScrollToOptions) +fn JS.scroll(int, int) +//fn JS.scrollBy(ScrollToOptions) +fn JS.scrollBy(int, int) +// fn JS.scrollTo(ScrollToOptions) +fn JS.scrollTo(int, int) +fn JS.stop() diff --git a/vlib/builtin/js/jsfns_node.js.v b/vlib/builtin/js/jsfns_node.js.v new file mode 100644 index 0000000000..161a58b7c4 --- /dev/null +++ b/vlib/builtin/js/jsfns_node.js.v @@ -0,0 +1,14 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// This file contains JS functions only present in node.js. +// They have been ported from their TypeScript definitions. + +module builtin + +fn JS.process.exit(int) +fn JS.process.stdout.write(string) bool +fn JS.process.stdout.writeln(string) bool +fn JS.process.stderr.write(string) bool +fn JS.process.stderr.writeln(string) bool diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 5069189e18..19e8a655bc 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -15,10 +15,6 @@ const ( 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield'] tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t'] - builtin_globals = ['println', 'print'] - type_values = { - - } ) struct JsGen { @@ -44,7 +40,8 @@ mut: defer_stmts []ast.DeferStmt fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 str_types []string // types that need automatic str() generation - method_fn_decls map[string][]ast.Stmt + method_fn_decls map[string][]ast.FnDecl + builtin_fns []string // Functions defined in `builtin` empty_line bool } @@ -99,7 +96,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string mut out := g.hashes() + g.definitions.str() for node in deps_resolved.nodes { - name := g.js_name(node.name) + name := g.js_name(node.name).replace('.', '_') if g.enable_doc { out += '/** @namespace $name */\n' } @@ -127,7 +124,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string out += '\n})(' for i, key in imports.keys() { if i > 0 { out += ', ' } - out += key + out += key.replace('.', '_') } out += ');\n\n' } @@ -225,7 +222,7 @@ pub fn (mut g JsGen) typ(t table.Type) string { } .array_fixed { info := sym.info as table.ArrayFixed - styp = g.array_fixed_typ(info.elem_type) or { g.typ(info.elem_type) + '[]' } + styp = g.typ(info.elem_type) + '[]' } // 'map[string]int' => 'Map' .map { @@ -266,16 +263,10 @@ pub fn (mut g JsGen) typ(t table.Type) string { // 'anon_fn_7_7_1' => '(a number, b number) => void' .function { info := sym.info as table.FnType - mut res := '(' - for i, arg in info.func.args { - res += '$arg.name: ${g.typ(arg.typ)}' - if i < info.func.args.len - 1 { res += ', ' } - } - styp = res + ') => ' + g.typ(info.func.return_type) + styp = g.fn_typ(info.func.args, info.func.return_type) } .interface_ { - // TODO: Implement interfaces - styp = 'interface' + styp = g.js_name(sym.name) } } /* else { @@ -286,6 +277,16 @@ pub fn (mut g JsGen) typ(t table.Type) string { return styp } +fn (mut g JsGen) fn_typ(args []table.Arg, return_type table.Type) string { + mut res := '(' + for i, arg in args { + res += '$arg.name: ${g.typ(arg.typ)}' + if i < args.len - 1 { res += ', ' } + } + return res + ') => ' + g.typ(return_type) + +} + fn (mut g JsGen) struct_typ(s string) string { ns := get_ns(s) mut name := if ns == g.namespace { s.split('.').last() } else { g.get_alias(s) } @@ -329,23 +330,6 @@ fn (mut g JsGen) to_js_typ_val(t table.Type) string { return styp } -fn (mut g JsGen) array_fixed_typ(t table.Type) ?string { - sym := g.table.get_type_symbol(t) - match sym.kind { - .i8 { return 'Int8Array' } - .i16 { return 'Int16Array' } - .int { return 'Int32Array' } - .i64 { return 'BigInt64Array' } - .byte { return 'Uint8Array' } - .u16 { return 'Uint16Array' } - .u32 { return 'Uint32Array' } - .u64 { return 'BigUint64Array' } - .f32 { return 'Float32Array' } - .f64 { return 'Float64Array' } - else { return none } - } -} - pub fn (mut g JsGen) gen_indent() { if g.indents[g.namespace] > 0 && g.empty_line { g.out.write(tabs[g.indents[g.namespace]]) @@ -456,7 +440,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) { ast.FnDecl { g.fn_decl = it g.gen_fn_decl(it) - g.writeln('') } ast.ForCStmt { g.gen_for_c_stmt(it) @@ -490,7 +473,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) { g.gen_import_stmt(it) } ast.InterfaceDecl { - // TODO skip: interfaces not implemented yet + g.gen_interface_decl(it) } ast.Module { // skip: namespacing implemented externally @@ -541,8 +524,9 @@ fn (mut g JsGen) expr(node ast.Expr) { 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 + // JS has no types, so no need to cast + // Just write the expression inside + g.expr(it.expr) } ast.CharLiteral { g.write("'$it.val'") @@ -589,14 +573,21 @@ fn (mut g JsGen) expr(node ast.Expr) { // TODO } ast.ParExpr { - // TODO + g.write('(') + g.expr(it.expr) + g.write(')') } ast.PostfixExpr { g.expr(it.expr) g.write(it.op.str()) } ast.PrefixExpr { - // TODO + if it.op in [.amp, .mul] { + // C pointers/references: ignore them + } else { + g.write(it.op.str()) + } + g.expr(it.right) } ast.RangeExpr { // Only used in IndexExpr, requires index type info @@ -649,8 +640,8 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) { g.write('if( ') g.expr(a.expr) g.write(' ) {') - s_assertion := a.expr.str().replace('"', "\'") - mut mod_path := g.file.path + s_assertion := a.expr.str().replace('"', "'") + mut mod_path := g.file.path.replace('\\', '\\\\') if g.is_test { g.writeln(' g_test_oks++;') g.writeln(' cb_assertion_ok("${mod_path}", ${a.pos.line_nr+1}, "assert ${s_assertion}", "${g.fn_decl.name}()" );') @@ -662,8 +653,10 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) { return } g.writeln('} else {') - g.writeln(' eprintln("${mod_path}:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");') - g.writeln(' exit(1);') + g.inc_indent() + g.writeln('builtin.eprintln("${mod_path}:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");') + g.writeln('builtin.exit(1);') + g.dec_indent() g.writeln('}') } @@ -795,18 +788,16 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) { fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) { g.expr(it.expr) - expr := it.expr - if expr is ast.IfExpr { } // no ; after an if expression - else if !g.inside_ternary && !it.is_expr { g.writeln(';') } + if !it.is_expr && it.expr !is ast.IfExpr && !g.inside_ternary { g.writeln(';') } } fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) { - if it.is_method { + if it.no_body || it.is_method { // Struct methods are handled by class generation code. return } - if it.no_body { - return + if g.namespace == 'builtin' { + g.builtin_fns << it.name } g.gen_method_decl(it) } @@ -877,7 +868,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) { g.write(')();') } if !it.is_anon && !it.is_method { - g.writeln('') + g.writeln('\n') } g.fn_decl = voidptr(0) @@ -1012,6 +1003,17 @@ fn (mut g JsGen) gen_import_stmt(it ast.Import) { g.namespace_imports[g.namespace] = imports } +fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) { + // JS is dynamically typed, so we don't need any codegen at all + // We just need the JSDoc so TypeScript type checking works + g.doc.gen_interface(it) + + // This is a hack to make the interface's type accessible outside its namespace + // TODO: interfaces are always `pub`? + name := g.js_name(it.name) + g.push_pub_var('/** @type $name */\n\t\t$name: undefined') +} + fn (mut g JsGen) gen_return_stmt(it ast.Return) { if it.exprs.len == 0 { // Returns nothing @@ -1022,16 +1024,8 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) { g.write('return ') if it.exprs.len == 1 { g.expr(it.exprs[0]) - } else { - // Multi return - g.write('[') - for i, expr in it.exprs { - g.expr(expr) - if i < it.exprs.len - 1 { - g.write(', ') - } - } - g.write(']') + } else { // Multi return + g.gen_array_init_values(it.exprs) } g.writeln(';') } @@ -1073,9 +1067,7 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { } for i, cfn in fns { - // TODO: Move cast to the entire array whenever it's possible - it := cfn as ast.FnDecl - g.gen_method_decl(it) + g.gen_method_decl(cfn) if i < fns.len - 1 { g.writeln(',') } else { g.writeln('') } } g.dec_indent() @@ -1086,17 +1078,50 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { } 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(', ') - } + // NB: Fixed arrays and regular arrays are handled the same, since fixed arrays: + // 1) Are only available for number types + // 2) Give the code unnecessary complexity + // 3) Have several limitations like missing most `Array.prototype` methods + // 4) Modern engines can optimize regular arrays into typed arrays anyways, + // offering similar performance + if it.has_len { + t1 := g.new_tmp_var() + t2 := g.new_tmp_var() + g.writeln('(function() {') + g.inc_indent() + g.writeln('const $t1 = [];') + g.write('for (let $t2 = 0; $t2 < ') + g.expr(it.len_expr) + g.writeln('; $t2++) {') + g.inc_indent() + g.write('${t1}.push(') + if it.has_default { + g.expr(it.default_expr) + } else { + // Fill the array with the default values for its type + t := g.to_js_typ_val(it.elem_type) + g.write(t) } - g.write(']') - } else {} + g.writeln(');') + g.dec_indent() + g.writeln('};') + g.writeln('return $t1;') + g.dec_indent() + g.write('})()') + } else { + g.gen_array_init_values(it.exprs) + } +} + +fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) { + g.write('[') + for i, expr in exprs { + g.expr(expr) + if i < exprs.len - 1 { + g.write(', ') + } + } + g.write(']') } fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { @@ -1143,7 +1168,7 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { return } } else { - if name in builtin_globals { + if name in g.builtin_fns { g.write('builtin.') } } @@ -1281,19 +1306,19 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { if r_sym.kind == .array { g.write('...') } // arr << [1, 2] g.expr(it.right) g.write(')') - } else if r_sym.kind in [.array, .map] && it.op in [.key_in, .not_in] { + } else if r_sym.kind in [.array, .map, .string] && it.op in [.key_in, .not_in] { if it.op == .not_in { g.write('!(') } g.expr(it.right) g.write(if r_sym.kind == .map { '.has(' } else { '.includes(' }) g.expr(it.left) g.write(')') if it.op == .not_in { g.write(')') } - } else if it.op == .key_is { // foo is Foo - g.write('/*') + } else if it.op in [.key_is, .not_is] { // foo is Foo + if it.op == .not_is { g.write('!(') } g.expr(it.left) - g.write(' is $r_sym.name') - g.write('*/0') - // TODO + g.write(' instanceof ') + g.write(g.typ(it.right_type)) + if it.op == .not_is { g.write(')') } } else { g.expr(it.left) diff --git a/vlib/v/gen/js/jsdoc.v b/vlib/v/gen/js/jsdoc.v index 08ac931bb9..5acbde6a57 100644 --- a/vlib/v/gen/js/jsdoc.v +++ b/vlib/v/gen/js/jsdoc.v @@ -59,7 +59,7 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) { d.writeln(' * @deprecated') } for i, arg in it.args { - if it.is_method && i == 0 { + if (it.is_method || it.receiver.typ == 0) && i == 0 { continue } arg_type_name := d.gen.typ(arg.typ) @@ -74,3 +74,17 @@ fn (mut d JsDoc) gen_fn(it ast.FnDecl) { d.writeln(' * @returns {$type_name}') d.writeln('*/') } + +fn (mut d JsDoc) gen_interface(it ast.InterfaceDecl) { + name := d.gen.js_name(it.name) + d.writeln('/**') + d.writeln(' * @interface $name') + d.writeln(' * @typedef $name') + for method in it.methods { + // Skip receiver + typ := d.gen.fn_typ(method.args[1..], method.return_type) + method_name := d.gen.js_name(method.name) + d.writeln(' * @property {$typ} $method_name') + } + d.writeln(' */\n') +} diff --git a/vlib/v/gen/js/jsgen_test.v b/vlib/v/gen/js/jsgen_test.v new file mode 100644 index 0000000000..9b3440ff70 --- /dev/null +++ b/vlib/v/gen/js/jsgen_test.v @@ -0,0 +1,36 @@ +import os + +const ( + test_dir = 'vlib/v/gen/js/tests/' + output_dir = '_js_tests/' + v_options = '-b js -w' +) + +fn test_example_compilation() { + vexe := os.getenv('VEXE') + os.chdir(os.dir(vexe)) + + os.mkdir_all(output_dir) + + files := find_test_files() + for file in files { + path := os.join_path(test_dir, file) + println('Testing $file') + + v_code := os.system('$vexe $v_options -o ${output_dir}${file}.js $path') + if v_code != 0 { assert false } // Compilation failed + + js_code := os.system('node ${output_dir}${file}.js') + if js_code != 0 { assert false } // Running failed + } + + os.rmdir_all(output_dir) +} + +fn find_test_files() []string { + files := os.ls(test_dir) or { panic(err) } + // The life example never exits, so tests would hang with it, skip + mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v') + tests.sort() + return tests +} diff --git a/vlib/v/gen/js/tests/.gitignore b/vlib/v/gen/js/tests/.gitignore new file mode 100644 index 0000000000..4c43fe68f6 --- /dev/null +++ b/vlib/v/gen/js/tests/.gitignore @@ -0,0 +1 @@ +*.js \ No newline at end of file diff --git a/vlib/v/gen/js/tests/array.js b/vlib/v/gen/js/tests/array.js deleted file mode 100644 index 45ad2dc0af..0000000000 --- a/vlib/v/gen/js/tests/array.js +++ /dev/null @@ -1,174 +0,0 @@ -// V_COMMIT_HASH 8a24d7d -// V_CURRENT_COMMIT_HASH 6f886dc -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print - }; -})(); - -/** @namespace main */ -const main = (function () { - /** - * @function - * @param {string} s - * @returns {string} - */ - function map_cb(s) { - return `CB: ${s}`; - } - - /** - * @function - * @param {number} n - * @returns {boolean} - */ - function filter_cb(n) { - return n < 4; - } - - /** - * @function - * @param {...number} args - * @returns {void} - */ - function variadic(...args) { - builtin.println(args); - builtin.println(args[0]); - builtin.println(args[1]); - } - - /** - * @function - * @returns {void} - */ - function vararg_test() { - variadic(1, 2, 3); - } - - /* program entry point */ - (function() { - vararg_test(); - /** @type {string[]} */ - const arr1 = ["Hello", "JS", "Backend"]; - /** @type {number[]} */ - let arr2 = [1, 2, 3, 4, 5]; - /** @type {string[]} */ - const slice1 = arr1.slice(1, 3); - /** @type {number[]} */ - const slice2 = arr2.slice(0, 3); - /** @type {number[]} */ - const slice3 = arr2.slice(3, arr2.length); - /** @type {string} */ - const idx1 = slice1[1]; - arr2[0] = 1; - arr2[0 + 1] = 2; - builtin.println(arr2); - arr2.push(6); - arr2.push(...[7, 8, 9]); - builtin.println(arr2); - builtin.println("\n\n"); - /** @type {string} */ - let slice4 = idx1.slice(0, 4); - builtin.print("Back\t=> "); - builtin.println(slice4); - /** @type {number} */ - const idx2 = slice4.charCodeAt(0); - builtin.print("66\t=> "); - builtin.println(idx2); - /** @type {Map} */ - let m = new Map(); - /** @type {string} */ - const key = "key"; - m.set(key, "value"); - /** @type {string} */ - const val = m.get("key"); - builtin.print("value\t=> "); - builtin.println(val); - builtin.print("true\t=> "); - builtin.println(arr1.includes("JS")); - builtin.print("false\t=> "); - builtin.println(!(arr2.includes(3))); - builtin.print("true\t=> "); - builtin.println(m.has("key")); - builtin.print("true\t=> "); - builtin.println(!(m.has("badkey"))); - for (let _tmp1 = 0; _tmp1 < arr1.length; ++_tmp1) { - } - - builtin.println("0 to 8\t=>"); - for (let i = 0; i < arr2.length; ++i) { - builtin.println(i); - } - - builtin.println("\n\n4 to 5\t=> "); - for (let _tmp2 = 0; _tmp2 < slice3.length; ++_tmp2) { - const v = slice3[_tmp2]; - builtin.println(v); - } - - /** @type {string[]} */ - const a = arr1.map(it => `VAL: ${it}`); - /** @type {string[]} */ - const b = arr1.map(map_cb); - /** @type {string[]} */ - const c = arr1.map(it => map_cb(it)); - /** @type {string[]} */ - const d = arr1.map(function (a) { - const _tmp3 = a; - return `ANON: ${a}`; - }); - /** @type {number[]} */ - const e = arr1.map(it => 456); - builtin.println(a); - builtin.println(b); - builtin.println(c); - builtin.println(d); - builtin.println(e); - builtin.println("\n\n"); - /** @type {number[]} */ - const aa = arr2.filter(it => it < 4); - /** @type {number[]} */ - const bb = arr2.filter(filter_cb); - /** @type {number[]} */ - const cc = arr2.filter(it => filter_cb(it)); - /** @type {number[]} */ - const dd = arr2.filter(function (a) { - const _tmp4 = a; - return a < 4; - }); - builtin.println(aa); - builtin.println(bb); - builtin.println(cc); - builtin.println(dd); - })(); - - /* module exports */ - return {}; -})(); - - diff --git a/vlib/v/gen/js/tests/array.v b/vlib/v/gen/js/tests/array.v index 076016d0f8..4463ac9238 100644 --- a/vlib/v/gen/js/tests/array.v +++ b/vlib/v/gen/js/tests/array.v @@ -66,6 +66,8 @@ print('true\t=> ') println('key' in m) print('true\t=> ') println('badkey' !in m) +print('true\t=> ') +println('o' in 'hello') // for in for _ in arr1 {} @@ -103,3 +105,16 @@ println(aa) println(bb) println(cc) println(dd) + +// fixed arrays: implemented as normal arrays +f1 := [1, 2, 3, 4, 5]!! +mut f2 := [8]f32 +f2[0] = f32(1.23) +f3 := ['foo', 'bar']!! +f4 := [u64(0xffffffffffffffff), 0xdeadface]!! + +println(' +$f1 +$f2 +$f3 +$f4') diff --git a/vlib/v/gen/js/tests/enum.js b/vlib/v/gen/js/tests/enum.js deleted file mode 100644 index bcb38d04fc..0000000000 --- a/vlib/v/gen/js/tests/enum.js +++ /dev/null @@ -1,139 +0,0 @@ -// V_COMMIT_HASH 2943bdc -// V_CURRENT_COMMIT_HASH ad5deef -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print, - }; -})(); - -/** @namespace hello */ -const hello = (function () { - /** - * @function - * @returns {void} - */ - function raw_js_log() { - console.log('hello') - } - - /** @constant {string} */ - const hello = "Hello"; - - /** - * @constructor - * @param {{foo?: string}} init - */ - function Aaa({ foo = "" }) { - this.foo = foo - }; - Aaa.prototype = { - /** @type {string} */ - foo: "", - /** - * @function - * @param {string} s - * @returns {void} - */ - update(s) { - const a = this; - a.foo = s; - } - }; - - - /** - * @constructor - * @param {{}} init - */ - function Bbb({ }) { - }; - Bbb.prototype = { - }; - - /** @enum {number} */ - const Ccc = { - a: 0, - b: 5, - c: 6, - }; - - /** - * @function - * @returns {string} - */ - function v_debugger() { - /** @type {Bbb} */ - const v = new Bbb({}); - return hello; - } - - /** - * @function - * @returns {string} - */ - function excited() { - return v_debugger() + "!"; - } - - /* module exports */ - return { - raw_js_log, - Aaa, - Ccc, - v_debugger, - excited, - }; -})(); - -/** @namespace main */ -const main = (function (hello) { - /** @enum {number} */ - const Test = { - foo: 2, - bar: 5, - baz: 6, - }; - - /* program entry point */ - (function() { - /** @type {number} */ - let a = hello.Ccc.a; - a = hello.Ccc.b; - a = hello.Ccc.c; - builtin.println(a); - /** @type {number} */ - let b = Test.foo; - b = Test.bar; - builtin.println(b); - })(); - - /* module exports */ - return {}; -})(hello); - - diff --git a/vlib/v/gen/js/tests/hello/hello.v b/vlib/v/gen/js/tests/hello/hello.v index e1ad262087..40fb89c86e 100644 --- a/vlib/v/gen/js/tests/hello/hello.v +++ b/vlib/v/gen/js/tests/hello/hello.v @@ -1,5 +1,7 @@ module hello +import hello.hello1 + pub const ( hello = 'Hello' ) @@ -27,5 +29,5 @@ pub fn debugger() string { } pub fn excited() string { - return debugger() + "!" + return "$hello1.nested() $debugger()!" } diff --git a/vlib/v/gen/js/tests/hello/Hello1/hello1.v b/vlib/v/gen/js/tests/hello/hello1/hello1.v similarity index 53% rename from vlib/v/gen/js/tests/hello/Hello1/hello1.v rename to vlib/v/gen/js/tests/hello/hello1/hello1.v index 6e017dde69..030e704981 100644 --- a/vlib/v/gen/js/tests/hello/Hello1/hello1.v +++ b/vlib/v/gen/js/tests/hello/hello1/hello1.v @@ -1,7 +1,5 @@ module hello1 -// Unused for now: nested modules do not work yet - pub fn nested() string { return 'Nested' } diff --git a/vlib/v/gen/js/tests/interface.v b/vlib/v/gen/js/tests/interface.v new file mode 100644 index 0000000000..4b39a3ed63 --- /dev/null +++ b/vlib/v/gen/js/tests/interface.v @@ -0,0 +1,29 @@ +struct Dog { + name string + age int +} + +struct Cat { + name string + age int +} + +interface Animal { + say(s string) + greet() int +} + +fn (d Dog) say(s string) { println('Dog $d.name: "$s"') } +fn (c Cat) say(s string) { println('Cat $c.name: "$s"') } + +fn (d Dog) greet() int { d.say('Hello!') return d.age } +fn (c Cat) greet() int { c.say('Hello!') return c.age } + +fn use(a Animal) { + if a is Dog { println('dog') } + else if a is Cat { println('cat') } + else { println('its a bug!') } +} + +use(Dog{ 'Doggo', 5 }) +use(Cat{ 'Nyancat', 6 }) \ No newline at end of file diff --git a/vlib/v/gen/js/tests/interp.js b/vlib/v/gen/js/tests/interp.js deleted file mode 100644 index e118984bd6..0000000000 --- a/vlib/v/gen/js/tests/interp.js +++ /dev/null @@ -1,260 +0,0 @@ -// V_COMMIT_HASH 8a24d7d -// V_CURRENT_COMMIT_HASH 123d788 -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print - }; -})(); - -/** @namespace main */ -const main = (function () { - /** - * @function - * @param {string} s1 - * @param {string} s2 - * @returns {void} - */ - function test_fn(s1, s2) { - builtin.print((s1 === s2 ? "true" : "false")); - builtin.print("\t=> "); - builtin.println(`"${s1}", "${s2}"`); - } - - /** - * @function - * @returns {void} - */ - function simple_string_interpolation() { - /** @type {string} */ - const a = "Hello"; - /** @type {string} */ - const b = "World"; - /** @type {string} */ - const res = `${a} ${b}`; - test_fn(res, "Hello World"); - } - - /** - * @function - * @returns {void} - */ - function mixed_string_interpolation() { - /** @type {number} */ - const num = 7; - /** @type {string} */ - const str = "abc"; - /** @type {string} */ - const s1 = `number=${num}`; - test_fn(s1, "number=7"); - /** @type {string} */ - const s2 = `string=${str}`; - test_fn(s2, "string=abc"); - /** @type {string} */ - const s3 = `a: ${num} | b: ${str}`; - test_fn(s3, "a: 7 | b: abc"); - } - - /** - * @function - * @returns {void} - */ - function formatted_string_interpolation() { - /** @type {string} */ - const x = "abc"; - /** @type {string} */ - const axb = `a:${x}:b`; - test_fn(axb, "a:abc:b"); - /** @type {string} */ - const x_10 = `a:${x}:b`; - /** @type {string} */ - const x10_ = `a:${x}:b`; - test_fn(x_10, "a: abc:b"); - test_fn(x10_, "a:abc :b"); - /** @type {number} */ - const i = 23; - /** @type {string} */ - const si_right = `${i}`; - /** @type {string} */ - const si__left = `${i}`; - test_fn(si_right, " 23"); - test_fn(si__left, "23 "); - } - - /** - * @function - * @returns {void} - */ - function implicit_str() { - /** @type {number} */ - const i = 42; - test_fn(`int ${i}`, "int 42"); - test_fn(`${i}`, "42"); - /** @type {boolean} */ - const check = `${i}` === "42"; - /** @type {string} */ - const text = `${i}` + "42"; - test_fn(text, "4242"); - } - - /** - * @function - * @returns {void} - */ - function string_interpolation_percent_escaping() { - /** @type {string} */ - const test = "hello"; - /** @type {string} */ - const hello = "world"; - /** @type {string} */ - const x = `%.*s${hello}${test} |${hello}|`; - test_fn(x, "%.*sworldhello |world |"); - } - - /** - * @function - * @returns {void} - */ - function string_interpolation_string_prefix() { - /** @type {string} */ - const r = "r"; - /** @type {string} */ - const rr = `${r}${r}`; - test_fn(rr, "rr"); - /** @type {string} */ - const c = "c"; - /** @type {string} */ - const cc = `${c}${c}`; - test_fn(cc, "cc"); - /** @type {string} */ - const js = "js"; - /** @type {string} */ - const jsjs = `${js}${js}`; - test_fn(jsjs, "jsjs"); - } - - /** - * @function - * @returns {void} - */ - function interpolation_string_prefix_expr() { - /** @type {number} */ - const r = 1; - /** @type {number} */ - const c = 2; - /** @type {number} */ - const js = 1; - test_fn(`>${3 + r}<`, ">4<"); - test_fn(`${r === js} ${js}`, "true 1"); - test_fn(`>${js + c} ${js + r === c}<`, ">3 true<"); - } - - /** - * @function - * @returns {void} - */ - function utf8_string_interpolation() { - /** @type {string} */ - const a = "à-côté"; - /** @type {string} */ - const st = "Sträßle"; - /** @type {string} */ - const m = "10€"; - test_fn(`${a} ${st} ${m}`, "à-côté Sträßle 10€"); - /** @type {string} */ - const zz = `>${a}< >${st}< >${m}<-`; - /** @type {string} */ - const zz_expected = "> à-côté< >Sträßle < > 10€<-"; - test_fn(zz, zz_expected); - /** @type {string} */ - const e = "€"; - test_fn(`100.00 ${e}`, "100.00 €"); - /** @type {string} */ - const m2 = "Москва́"; - /** @type {string} */ - const d = "Antonín Dvořák"; - test_fn(`:${m2}:${d}:`, ": Москва́:Antonín Dvořák :"); - /** @type {string} */ - const g = "Πελοπόννησος"; - test_fn(`>${g}<`, ">Πελοπόννησος <"); - } - - /** - * @constructor - * @param {{v1?: number, v2?: number}} init - */ - function Sss({ v1 = 0, v2 = 0 }) { - this.v1 = v1 - this.v2 = v2 - }; - Sss.prototype = { - /** @type {number} */ - v1: 0, - /** @type {number} */ - v2: 0, - /** - * @function - * @returns {string} - */ - str() { - const s = this; - return `[${s.v1}, ${s.v2}]`; - } - }; - - - /** - * @function - * @returns {void} - */ - function string_interpolation_str_evaluation() { - /** @type {Sss} */ - let x = new Sss({ - v1: 17, - v2: 13.455893 - }); - test_fn(`${x.str()}`, "[17, 13.456]"); - } - - /* program entry point */ - (function() { - simple_string_interpolation(); - mixed_string_interpolation(); - formatted_string_interpolation(); - implicit_str(); - string_interpolation_percent_escaping(); - string_interpolation_string_prefix(); - interpolation_string_prefix_expr(); - utf8_string_interpolation(); - string_interpolation_str_evaluation(); - })(); - - /* module exports */ - return {}; -})(); - - diff --git a/vlib/v/gen/js/tests/js.js b/vlib/v/gen/js/tests/js.js deleted file mode 100644 index 1cd2ab78a8..0000000000 --- a/vlib/v/gen/js/tests/js.js +++ /dev/null @@ -1,313 +0,0 @@ -// V_COMMIT_HASH 8a24d7d -// V_CURRENT_COMMIT_HASH 123d788 -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print - }; -})(); - -/** @namespace hello */ -const hello = (function () { - /** - * @function - * @returns {void} - */ - function raw_js_log() { - console.log('hello') - } - - /** @constant {string} */ - const hello = "Hello"; - - /** - * @constructor - * @param {{foo?: string}} init - */ - function Aaa({ foo = "" }) { - this.foo = foo - }; - Aaa.prototype = { - /** @type {string} */ - foo: "", - /** - * @function - * @param {string} s - * @returns {void} - */ - update(s) { - const a = this; - a.foo = s; - } - }; - - - /** - * @constructor - * @param {{}} init - */ - function Bbb({ }) { - }; - Bbb.prototype = { - }; - - /** @enum {number} */ - const Ccc = { - a: 0, - b: 5, - c: 6, - }; - - /** - * @function - * @returns {string} - */ - function v_debugger() { - /** @type {Bbb} */ - const v = new Bbb({}); - return hello; - } - - /** - * @function - * @returns {string} - */ - function excited() { - return v_debugger() + "!"; - } - - /* module exports */ - return { - raw_js_log, - Aaa, - Ccc, - v_debugger, - excited - }; -})(); - -/** @namespace main */ -const main = (function (hl) { - /** @constant {number} */ - const i_am_a_const = 21214; - /** @constant {string} */ - const v_super = "amazing keyword"; - - /** - * @constructor - * @param {{a?: hl["Aaa"]["prototype"]}} init - */ - function Foo({ a = new hl.Aaa({}) }) { - this.a = a - }; - Foo.prototype = { - /** @type {hl["Aaa"]["prototype"]} */ - a: new hl.Aaa({}) - }; - - /** - * @constructor - * @param {{google?: number, amazon?: boolean, yahoo?: string}} init - */ - function Companies({ google = 0, amazon = false, yahoo = "" }) { - this.google = google - this.amazon = amazon - this.yahoo = yahoo - }; - Companies.prototype = { - /** @type {number} */ - google: 0, - /** @type {boolean} */ - amazon: false, - /** @type {string} */ - yahoo: "", - /** - * @function - * @returns {number} - */ - method() { - const it = this; - /** @type {Companies} */ - const ss = new Companies({ - google: 2, - amazon: true, - yahoo: "hello" - }); - const [a, b] = hello(2, "google", "not google"); - /** @type {string} */ - const glue = (a > 2 ? "more_glue" : a > 5 ? "more glueee" : "less glue"); - if (a !== 2) { - } - - return 0; - } - }; - - /** @enum {number} */ - const POSITION = { - go_back: 0, - dont_go_back: 1, - }; - - /** - * @function - * @param {string} v_extends - * @param {number} v_instanceof - * @returns {void} - */ - function v_class(v_extends, v_instanceof) { - /** @type {number} */ - const v_delete = v_instanceof; - const _tmp1 = v_delete; - } - - /* program entry point */ - (async function() { - builtin.println("Hello from V.js!"); - builtin.println(Math.atan2(1, 0)); - /** @type {number} */ - let a = 1; - a *= 2; - a += 3; - builtin.println(a); - /** @type {hl["Aaa"]["prototype"]} */ - let b = new hl.Aaa({}); - b.update("an update"); - builtin.println(b); - /** @type {Foo} */ - let c = new Foo({ - a: new hl.Aaa({}) - }); - c.a.update("another update"); - builtin.println(c); - const _tmp2 = "done"; - { - const _tmp3 = "block"; - } - - const _tmp4 = POSITION.go_back; - const _tmp5 = hl.Ccc.a; - /** @type {string} */ - const v_debugger = "JS keywords"; - /** @type {string} */ - const v_await = `${v_super}: ${v_debugger}`; - /** @type {string} */ - let v_finally = "implemented"; - builtin.println(`${v_await} ${v_finally}`); - /** @type {number} */ - const dun = i_am_a_const * 20; - /** @type {string} */ - const dunn = hl.hello; - for (let i = 0; i < 10; i++) { - } - - for (let i = 0; i < "hello".length; ++i) { - const x = "hello"[i]; - } - - for (let x = 1; x < 10; ++x) { - } - - /** @type {number[]} */ - const arr = [1, 2, 3, 4, 5]; - for (let _tmp6 = 0; _tmp6 < arr.length; ++_tmp6) { - const i = arr[_tmp6]; - } - - /** @type {Map} */ - const ma = new Map([ - ["str", "done"], - ["ddo", "baba"] - ]); - for (let [m, n] of ma) { - /** @type {string} */ - const iss = m; - } - - await new Promise(function(resolve){ - async(0, "hello"); - resolve(); - }); - - /** @type {(number: number) => void} */ - const fn_in_var = function (number) { - builtin.println(`number: ${number}`); - }; - hl.v_debugger(); - anon_consumer(hl.excited(), function (message) { - builtin.println(message); - }); - hl.raw_js_log(); - })(); - - /** - * @function - * @param {string} greeting - * @param {(message: string) => void} anon - * @returns {void} - */ - function anon_consumer(greeting, anon) { - anon(greeting); - } - - /** - * @function - * @param {number} num - * @param {string} def - * @returns {void} - */ - function async(num, def) { - } - - /* [inline] */ - /* [deprecated] */ - /** - * @function - * @deprecated - * @param {number} game_on - * @param {...string} dummy - * @returns {[number, number]} - */ - function hello(game_on, ...dummy) { - for (let _tmp7 = 0; _tmp7 < dummy.length; ++_tmp7) { - const dd = dummy[_tmp7]; - /** @type {string} */ - const l = dd; - } - - (function defer() { - /** @type {string} */ - const v_do = "not"; - })(); - return [game_on + 2, 221]; - } - - /* module exports */ - return {}; -})(hello); - - diff --git a/vlib/v/gen/js/tests/js.v b/vlib/v/gen/js/tests/js.v index 6ee557034f..7143e38984 100644 --- a/vlib/v/gen/js/tests/js.v +++ b/vlib/v/gen/js/tests/js.v @@ -1,7 +1,5 @@ import hello as hl - -fn JS.alert(arg string) -fn JS.Math.atan2(f64, f64) f64 +import hello.hello1 as hl1 const ( i_am_a_const = 21214 @@ -64,6 +62,7 @@ fn main() { dun := i_am_a_const * 20 dunn := hl.hello // External constant + _ = hl1.nested() for i := 0; i < 10; i++ {} @@ -79,6 +78,7 @@ fn main() { 'ddo': "baba" } + // panic('foo') for m, n in ma { iss := m } diff --git a/vlib/v/gen/js/tests/life.js b/vlib/v/gen/js/tests/life.js deleted file mode 100644 index df9c068cbd..0000000000 --- a/vlib/v/gen/js/tests/life.js +++ /dev/null @@ -1,204 +0,0 @@ -// V_COMMIT_HASH 2943bdc -// V_CURRENT_COMMIT_HASH ad5deef -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print, - }; -})(); - -/** @namespace main */ -const main = (function () { - /** - * @function - * @returns {void} - */ - function clear() { - console.clear(); - } - - /** @constant {number} */ - const w = 30; - /** @constant {number} */ - const h = 30; - - /** - * @function - * @param {boolean[][]} game - * @param {number} x - * @param {number} y - * @returns {boolean} - */ - function get(game, x, y) { - if (y < 0 || x < 0) { - return false; - } - - if (y >= h || x >= w) { - return false; - } - - return game[y][x]; - } - - /** - * @function - * @param {boolean[][]} game - * @param {number} x - * @param {number} y - * @returns {number} - */ - function neighbours(game, x, y) { - /** @type {number} */ - let count = 0; - if (get(game, x - 1, y - 1)) { - count++; - } - - if (get(game, x, y - 1)) { - count++; - } - - if (get(game, x + 1, y - 1)) { - count++; - } - - if (get(game, x - 1, y)) { - count++; - } - - if (get(game, x + 1, y)) { - count++; - } - - if (get(game, x - 1, y + 1)) { - count++; - } - - if (get(game, x, y + 1)) { - count++; - } - - if (get(game, x + 1, y + 1)) { - count++; - } - - return count; - } - - /** - * @function - * @param {boolean[][]} game - * @returns {boolean[][]} - */ - function step(game) { - /** @type {boolean[][]} */ - let new_game = [[]]; - for (let y = 0; y < game.length; ++y) { - let row = game[y]; - /** @type {boolean[]} */ - let new_row = []; - new_game[y] = new_row; - for (let x = 0; x < row.length; ++x) { - let cell = row[x]; - /** @type {number} */ - const count = neighbours(game, x, y); - new_row[x] = cell && count === 2 || count === 3; - } - - } - - return new_game; - } - - /** - * @function - * @param {boolean[]} row - * @returns {string} - */ - function row_str(row) { - /** @type {string} */ - let str = ""; - for (let _tmp1 = 0; _tmp1 < row.length; ++_tmp1) { - let cell = row[_tmp1]; - if (cell) { - str += "◼ "; - } else { - str += "◻ "; - } - - } - - return str; - } - - /** - * @function - * @param {boolean[][]} game - * @returns {void} - */ - function show(game) { - clear(); - for (let _tmp2 = 0; _tmp2 < game.length; ++_tmp2) { - let row = game[_tmp2]; - builtin.println(row_str(row)); - } - - } - - /* program entry point */ - (function() { - /** @type {boolean[][]} */ - let game = [[]]; - for (let y = 0; y < h; ++y) { - /** @type {boolean[]} */ - let row = []; - for (let x = 0; x < w; ++x) { - row[x] = false; - } - - game[y] = row; - } - - game[11][15] = true; - game[11][16] = true; - game[12][16] = true; - game[10][21] = true; - game[12][20] = true; - game[12][21] = true; - game[12][22] = true; - setInterval(function () { - show(game); - game = step(game); - }, 500); - })(); - - /* module exports */ - return {}; -})(); - - diff --git a/vlib/v/gen/js/tests/life.v b/vlib/v/gen/js/tests/life.v index 029d3f489b..6ed5db832f 100644 --- a/vlib/v/gen/js/tests/life.v +++ b/vlib/v/gen/js/tests/life.v @@ -1,5 +1,3 @@ -fn JS.setInterval(f fn (), ms int) -fn JS.console.clear() fn clear() { JS.console.clear() } const (w = 30 h = 30) @@ -25,13 +23,13 @@ fn neighbours(game [][]bool, x int, y int) int { } fn step(game [][]bool) [][]bool { - mut new_game := [[]bool{}] + mut new_game := [][]bool{} for y, row in game { mut new_row := []bool{} new_game[y] = new_row for x, cell in row { count := neighbours(game, x, y) - new_row[x] = cell && count == 2 || count == 3 // TODO: count in [2, 3] + new_row[x] = (cell && count in [2, 3]) || count == 3 } } return new_game @@ -53,15 +51,7 @@ fn show(game [][]bool) { } } -mut game := [[]bool{}] - -for y in 0..h { - mut row := []bool{} - for x in 0..w { - row[x] = false - } - game[y] = row -} +mut game := [][]bool{ len: h, init: []bool{ len: w } } game[11][15] = true game[11][16] = true diff --git a/vlib/v/gen/js/tests/simple.js b/vlib/v/gen/js/tests/simple.js deleted file mode 100644 index 301ccee213..0000000000 --- a/vlib/v/gen/js/tests/simple.js +++ /dev/null @@ -1,45 +0,0 @@ -// V_COMMIT_HASH 2943bdc -// V_CURRENT_COMMIT_HASH ad5deef -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print, - }; -})(); - -/** @namespace main */ -const main = (function () { - /* program entry point */ - (function() { - builtin.println("hello world"); - })(); - - /* module exports */ - return {}; -})(); - - diff --git a/vlib/v/gen/js/tests/struct.js b/vlib/v/gen/js/tests/struct.js deleted file mode 100644 index 57162dcbdc..0000000000 --- a/vlib/v/gen/js/tests/struct.js +++ /dev/null @@ -1,122 +0,0 @@ -// V_COMMIT_HASH 2943bdc -// V_CURRENT_COMMIT_HASH ad5deef -// Generated by the V compiler - -"use strict"; - -/** @namespace builtin */ -const builtin = (function () { - /** - * @function - * @param {any} s - * @returns {void} - */ - function println(s) { - console.log(s); - } - - /** - * @function - * @param {any} s - * @returns {void} - */ - function print(s) { - process.stdout.write(s); - } - - /* module exports */ - return { - println, - print, - }; -})(); - -/** @namespace main */ -const main = (function () { - /** - * @constructor - * @param {{value?: number, test?: Map, hello?: number[]}} init - */ - function Int({ value = 0, test = new Map(), hello = [] }) { - this.value = value - this.test = test - this.hello = hello - }; - Int.prototype = { - /** @type {number} */ - value: 0, - /** @type {Map} */ - test: new Map(), - /** @type {number[]} */ - hello: [], - /** - * @function - * @param {number} value - * @returns {void} - */ - add(value) { - const i = this; - i.value += value; - }, - /** - * @function - * @returns {number} - */ - get() { - const i = this; - return i.value; - } - }; - - - - /** - * @constructor - * @param {{foo?: number, bar?: string}} init - */ - function Config({ foo = 0, bar = "" }) { - this.foo = foo - this.bar = bar - }; - Config.prototype = { - /** @type {number} */ - foo: 0, - /** @type {string} */ - bar: "" - }; - - /** - * @function - * @param {Config} c - * @returns {void} - */ - function use_config(c) { - } - - /* program entry point */ - (function() { - /** @type {Int} */ - const a = new Int({ - value: 10 - }); - a.add(5); - builtin.println(a); - /** @type {Int} */ - const b = new Int({}); - b.add(10); - builtin.println(b.get()); - use_config(new Config({ - foo: 2, - bar: "bar" - })); - use_config(new Config({ - foo: 2, - bar: "bar" - })); - })(); - - /* module exports */ - return {}; -})(); - - diff --git a/vlib/v/gen/js/tests/struct.v b/vlib/v/gen/js/tests/struct.v index d3fbf78534..4d7e48c536 100644 --- a/vlib/v/gen/js/tests/struct.v +++ b/vlib/v/gen/js/tests/struct.v @@ -23,11 +23,11 @@ struct Config { fn use_config(c Config) {} fn main() { - a := Int { value: 10 } + mut a := Int { value: 10 } a.add(5) println(a) // 15 - b := Int{} + mut b := Int{} b.add(10) println(b.get()) // 10 diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 96359157e2..9cea66a17e 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -355,7 +355,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool) { mut args := []table.Arg{} mut is_variadic := false // `int, int, string` (no names, just types) - types_only := p.tok.kind in [.amp, .ellipsis] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) || + types_only := p.tok.kind in [.amp, .ellipsis, .key_fn] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) || p.peek_tok.kind == .rpar // TODO copy pasta, merge 2 branches if types_only {