aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/old/vlib/v/gen/js
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/old/vlib/v/gen/js')
-rw-r--r--v_windows/v/old/vlib/v/gen/js/builtin_types.v393
-rw-r--r--v_windows/v/old/vlib/v/gen/js/comptime.v311
-rw-r--r--v_windows/v/old/vlib/v/gen/js/fast_deep_equal.js72
-rw-r--r--v_windows/v/old/vlib/v/gen/js/js.v2103
-rw-r--r--v_windows/v/old/vlib/v/gen/js/jsdoc.v96
-rw-r--r--v_windows/v/old/vlib/v/gen/js/jsgen_test.v86
-rw-r--r--v_windows/v/old/vlib/v/gen/js/program_test.v98
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/basic_test.v158
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/compare_test.v322
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/mappings.v170
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/sets.v16
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/source_map.v131
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/source_map_generator.v46
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq.v115
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v52
-rw-r--r--v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_encode_test.v35
-rw-r--r--v_windows/v/old/vlib/v/gen/js/temp_fast_deep_equal.v78
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/.gitignore1
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/array.v138
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/auto_deref_args.v13
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/enum.v19
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/hello/hello.js.v5
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/hello/hello.v33
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/hello/hello1/hello1.v5
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/interface.v47
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/interp.v188
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/js.v141
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/life.v98
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/optional.v33
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/simple.v5
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/simple_sourcemap.v23
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/struct.v40
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/array.out231
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/array.v771
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.out2
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.v4
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.out1
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.v15
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.out1
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.v1
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.out3
-rw-r--r--v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.v3
42 files changed, 6103 insertions, 0 deletions
diff --git a/v_windows/v/old/vlib/v/gen/js/builtin_types.v b/v_windows/v/old/vlib/v/gen/js/builtin_types.v
new file mode 100644
index 0000000..1bd1c15
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/builtin_types.v
@@ -0,0 +1,393 @@
+module js
+
+import v.ast
+
+fn (mut g JsGen) to_js_typ_def_val(s string) string {
+ mut dval := ''
+ match s {
+ 'JS.Number' { dval = '0' }
+ 'JS.String' { dval = '""' }
+ 'JS.Boolean' { dval = 'false' }
+ 'JS.Array', 'JS.Map' { dval = '' }
+ else { dval = '{}' }
+ }
+ return dval
+}
+
+fn (mut g JsGen) to_js_typ_val(t ast.Type) string {
+ sym := g.table.get_type_symbol(t)
+ mut styp := ''
+ mut prefix := if g.file.mod.name == 'builtin' { 'new ' } else { '' }
+ match sym.kind {
+ .i8, .i16, .int, .i64, .byte, .u8, .u16, .u32, .u64, .f32, .f64, .int_literal,
+ .float_literal, .size_t {
+ styp = '$prefix${g.sym_to_js_typ(sym)}(0)'
+ }
+ .bool {
+ styp = '$prefix${g.sym_to_js_typ(sym)}(false)'
+ }
+ .string {
+ styp = '$prefix${g.sym_to_js_typ(sym)}("")'
+ }
+ .map {
+ styp = 'new Map()'
+ }
+ .array {
+ styp = '$prefix${g.sym_to_js_typ(sym)}()'
+ }
+ .struct_ {
+ styp = 'new ${g.js_name(sym.name)}(${g.to_js_typ_def_val(sym.name)})'
+ }
+ .voidptr {
+ styp = 'null'
+ }
+ else {
+ // TODO
+ styp = 'undefined'
+ }
+ }
+ return styp
+}
+
+fn (mut g JsGen) sym_to_js_typ(sym ast.TypeSymbol) string {
+ mut styp := ''
+ match sym.kind {
+ .i8 {
+ styp = 'i8'
+ }
+ .i16 {
+ styp = 'i16'
+ }
+ .int {
+ styp = 'int'
+ }
+ .i64 {
+ styp = 'i64'
+ }
+ .byte {
+ styp = 'byte'
+ }
+ .u16 {
+ styp = 'u16'
+ }
+ .u32 {
+ styp = 'u32'
+ }
+ .u64 {
+ styp = 'u64'
+ }
+ .f32 {
+ styp = 'f32'
+ }
+ .f64 {
+ styp = 'f64'
+ }
+ .int_literal {
+ styp = 'int_literal'
+ }
+ .float_literal {
+ styp = 'float_literal'
+ }
+ .size_t {
+ styp = 'size_t'
+ }
+ .bool {
+ styp = 'bool'
+ }
+ .string {
+ styp = 'string'
+ }
+ .map {
+ styp = 'map'
+ }
+ .array {
+ styp = 'array'
+ }
+ .voidptr {
+ styp = 'any'
+ }
+ else {
+ // TODO
+ styp = 'undefined'
+ }
+ }
+ return styp
+}
+
+// V type to JS type
+pub fn (mut g JsGen) typ(t ast.Type) string {
+ sym := g.table.get_type_symbol(t)
+ mut styp := ''
+ match sym.kind {
+ .placeholder {
+ // This should never happen: means checker bug
+ styp = 'any'
+ }
+ .void {
+ styp = 'void'
+ }
+ .voidptr {
+ styp = 'any'
+ }
+ .byteptr, .charptr {
+ styp = '${g.sym_to_js_typ(sym)}'
+ }
+ .i8, .i16, .int, .i64, .byte, .u8, .u16, .u32, .u64, .f32, .f64, .int_literal,
+ .float_literal, .size_t {
+ styp = '${g.sym_to_js_typ(sym)}'
+ }
+ .bool {
+ styp = '${g.sym_to_js_typ(sym)}'
+ }
+ .none_ {
+ styp = 'undefined'
+ }
+ .string, .char {
+ styp = '${g.sym_to_js_typ(sym)}'
+ }
+ // 'array_array_int' => 'number[][]'
+ .array {
+ info := sym.info as ast.Array
+ styp = '${g.sym_to_js_typ(sym)}(${g.typ(info.elem_type)})'
+ }
+ .array_fixed {
+ info := sym.info as ast.ArrayFixed
+ styp = '${g.sym_to_js_typ(sym)}(${g.typ(info.elem_type)})'
+ }
+ .chan {
+ styp = 'chan'
+ }
+ // 'map[string]int' => 'Map<string, number>'
+ .map {
+ info := sym.info as ast.Map
+ key := g.typ(info.key_type)
+ val := g.typ(info.value_type)
+ styp = 'Map<$key, $val>'
+ }
+ .any {
+ styp = 'any'
+ }
+ // ns.Foo => alias["Foo"]["prototype"]
+ .struct_ {
+ styp = g.struct_typ(sym.name)
+ }
+ .generic_struct_inst {}
+ // 'multi_return_int_int' => '[number, number]'
+ .multi_return {
+ info := sym.info as ast.MultiReturn
+ types := info.types.map(g.typ(it))
+ joined := types.join(', ')
+ styp = '[$joined]'
+ }
+ .sum_type {
+ // TODO: Implement sumtypes
+ styp = 'union_sym_type'
+ }
+ .alias {
+ // TODO: Implement aliases
+ styp = 'alias'
+ }
+ .enum_ {
+ // NB: We could declare them as TypeScript enums but TS doesn't like
+ // our namespacing so these break if declared in a different module.
+ // Until this is fixed, We need to use the type of an enum's members
+ // rather than the enum itself, and this can only be 'number' for now
+ styp = 'number'
+ }
+ // 'anon_fn_7_7_1' => '(a number, b number) => void'
+ .function {
+ info := sym.info as ast.FnType
+ styp = g.fn_typ(info.func.params, info.func.return_type)
+ }
+ .interface_ {
+ styp = g.js_name(sym.name)
+ }
+ .rune {
+ styp = 'any'
+ }
+ .aggregate {
+ panic('TODO: unhandled aggregate in JS')
+ }
+ .thread {
+ panic('TODO: unhandled thread in JS')
+ }
+ }
+ /*
+ else {
+ println('jsgen.typ: Unhandled type $t')
+ styp = sym.name
+ }
+ */
+ if styp.starts_with('JS.') {
+ return styp[3..]
+ }
+ return styp
+}
+
+fn (mut g JsGen) fn_typ(args []ast.Param, return_type ast.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)
+ if ns == 'JS' {
+ return s[3..]
+ }
+ mut name := if ns == g.ns.name { s.split('.').last() } else { g.get_alias(s) }
+ mut styp := ''
+ for i, v in name.split('.') {
+ if i == 0 {
+ styp = v
+ } else {
+ styp += '["$v"]'
+ }
+ }
+ if ns in ['', g.ns.name] {
+ return styp
+ }
+ return styp + '["prototype"]'
+}
+
+struct BuiltinPrototypeConfig {
+ typ_name string
+ val_name string = 'val'
+ default_value string
+ constructor string = 'this.val = val'
+ value_of string = 'this.val'
+ to_string string = 'this.val.toString()'
+ eq string = 'this.val === other.val'
+ to_jsval string = 'this'
+ extras string
+ has_strfn bool
+}
+
+fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
+ g.writeln('function ${c.typ_name}($c.val_name = $c.default_value) { $c.constructor }')
+ g.writeln('${c.typ_name}.prototype = {')
+ g.inc_indent()
+ g.writeln('$c.val_name: $c.default_value,')
+ if c.extras.len > 0 {
+ g.writeln('$c.extras,')
+ }
+ for method in g.method_fn_decls[c.typ_name] {
+ g.inside_def_typ_decl = true
+ g.gen_method_decl(method)
+ g.inside_def_typ_decl = false
+ g.writeln(',')
+ }
+ g.writeln('valueOf() { return $c.value_of },')
+ g.writeln('toString() { return $c.to_string },')
+ g.writeln('eq(other) { return $c.eq },')
+ g.writeln('\$toJS() { return $c.to_jsval }, ')
+ if c.has_strfn {
+ g.writeln('str() { return new string(this.toString()) }')
+ }
+ g.dec_indent()
+ g.writeln('};\n')
+}
+
+// generate builtin type definitions, used for casting and methods.
+fn (mut g JsGen) gen_builtin_type_defs() {
+ g.inc_indent()
+ for typ_name in v_types {
+ // TODO: JsDoc
+ match typ_name {
+ 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64', 'int_literal', 'size_t' {
+ // TODO: Bounds checking
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ default_value: 'new Number(0)'
+ constructor: 'this.val = val | 0'
+ value_of: 'this.val | 0'
+ to_string: 'this.valueOf().toString()'
+ eq: 'this.valueOf() === other.valueOf()'
+ to_jsval: '+this'
+ )
+ }
+ 'byte' {
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ default_value: 'new Number(0)'
+ constructor: 'this.val = typeof(val) == "string" ? val.charCodeAt() : (val | 0)'
+ value_of: 'this.val | 0'
+ to_string: 'new string(this.val + "")'
+ eq: 'this.valueOf() === other.valueOf()'
+ to_jsval: '+this'
+ )
+ }
+ 'f32', 'f64', 'float_literal' {
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ default_value: 'new Number(0)'
+ to_jsval: '+this'
+ )
+ }
+ 'bool' {
+ g.gen_builtin_prototype(
+ constructor: 'this.val = +val !== 0'
+ typ_name: typ_name
+ default_value: 'new Boolean(false)'
+ to_jsval: '+this != 0'
+ )
+ }
+ 'string' {
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ val_name: 'str'
+ default_value: 'new String("")'
+ constructor: 'this.str = str.toString(); this.len = this.str.length'
+ value_of: 'this.str'
+ to_string: 'this.str'
+ eq: 'this.str === other.str'
+ has_strfn: false
+ to_jsval: 'this.str'
+ )
+ }
+ 'map' {
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ val_name: 'map'
+ default_value: 'new Map()'
+ constructor: 'this.map = map'
+ value_of: 'this'
+ to_string: 'this.map.toString()'
+ eq: 'vEq(this, other)'
+ to_jsval: 'this.map'
+ )
+ }
+ 'array' {
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ val_name: 'arr'
+ default_value: 'new Array()'
+ constructor: 'this.arr = arr'
+ value_of: 'this'
+ to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))'
+ eq: 'vEq(this, other)'
+ to_jsval: 'this.arr'
+ )
+ }
+ 'any' {
+ g.gen_builtin_prototype(
+ typ_name: typ_name
+ val_name: 'any'
+ default_value: 'null'
+ constructor: 'this.val = any'
+ value_of: 'this.val'
+ to_string: '"&" + this.val'
+ eq: 'this == other' // compare by ptr
+ to_jsval: 'this.val.\$toJS()'
+ )
+ }
+ else {}
+ }
+ }
+ g.dec_indent()
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/comptime.v b/v_windows/v/old/vlib/v/gen/js/comptime.v
new file mode 100644
index 0000000..d4c55ee
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/comptime.v
@@ -0,0 +1,311 @@
+module js
+
+import v.ast
+import v.pref
+
+fn (mut g JsGen) comp_if(node ast.IfExpr) {
+ if !node.is_expr && !node.has_else && node.branches.len == 1 {
+ if node.branches[0].stmts.len == 0 {
+ // empty ifdef; result of target OS != conditional => skip
+ return
+ }
+ }
+
+ for i, branch in node.branches {
+ if i == node.branches.len - 1 && node.has_else {
+ g.writeln('else')
+ } else {
+ if i == 0 {
+ g.write('if (')
+ } else {
+ g.write('else if (')
+ }
+ g.comp_if_cond(branch.cond, branch.pkg_exist)
+ g.writeln(')')
+ }
+
+ if node.is_expr {
+ print('$branch.stmts')
+ len := branch.stmts.len
+ if len > 0 {
+ last := branch.stmts[len - 1] as ast.ExprStmt
+ if len > 1 {
+ tmp := g.new_tmp_var()
+ g.inc_indent()
+ g.writeln('let $tmp;')
+ g.writeln('{')
+ g.stmts(branch.stmts[0..len - 1])
+ g.write('\t$tmp = ')
+ g.stmt(last)
+ g.writeln('}')
+ g.dec_indent()
+ g.writeln('$tmp;')
+ } else {
+ g.stmt(last)
+ }
+ }
+ } else {
+ g.writeln('{')
+ g.stmts(branch.stmts)
+ g.writeln('}')
+ }
+ }
+}
+
+/*
+// returning `false` means the statements inside the $if can be skipped
+*/
+// returns the value of the bool comptime expression
+fn (mut g JsGen) comp_if_cond(cond ast.Expr, pkg_exist bool) bool {
+ match cond {
+ ast.BoolLiteral {
+ g.expr(cond)
+ return true
+ }
+ ast.ParExpr {
+ g.write('(')
+ is_cond_true := g.comp_if_cond(cond.expr, pkg_exist)
+ g.write(')')
+ return is_cond_true
+ }
+ ast.PrefixExpr {
+ g.write(cond.op.str())
+ return g.comp_if_cond(cond.right, pkg_exist)
+ }
+ ast.PostfixExpr {
+ ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
+ verror(err.msg)
+ return false
+ }
+ g.write('$ifdef')
+ return true
+ }
+ ast.InfixExpr {
+ match cond.op {
+ .and, .logical_or {
+ l := g.comp_if_cond(cond.left, pkg_exist)
+ g.write(' $cond.op ')
+ r := g.comp_if_cond(cond.right, pkg_exist)
+ return if cond.op == .and { l && r } else { l || r }
+ }
+ .key_is, .not_is {
+ left := cond.left
+ mut name := ''
+ mut exp_type := ast.Type(0)
+ got_type := (cond.right as ast.TypeNode).typ
+ // Handle `$if x is Interface {`
+ // mut matches_interface := 'false'
+ if left is ast.TypeNode && cond.right is ast.TypeNode
+ && g.table.get_type_symbol(got_type).kind == .interface_ {
+ // `$if Foo is Interface {`
+ interface_sym := g.table.get_type_symbol(got_type)
+ if interface_sym.info is ast.Interface {
+ // q := g.table.get_type_symbol(interface_sym.info.types[0])
+ checked_type := g.unwrap_generic(left.typ)
+ // TODO PERF this check is run twice (also in the checker)
+ // store the result in a field
+ is_true := g.table.does_type_implement_interface(checked_type,
+ got_type)
+ // true // exp_type in interface_sym.info.types
+ if cond.op == .key_is {
+ if is_true {
+ g.write('1')
+ } else {
+ g.write('0')
+ }
+ return is_true
+ } else if cond.op == .not_is {
+ if is_true {
+ g.write('0')
+ } else {
+ g.write('1')
+ }
+ return !is_true
+ }
+ // matches_interface = '/*iface:$got_type $exp_type*/ true'
+ //}
+ }
+ } else if left is ast.SelectorExpr {
+ name = '${left.expr}.$left.field_name'
+ exp_type = g.comptime_var_type_map[name]
+ } else if left is ast.TypeNode {
+ name = left.str()
+ // this is only allowed for generics currently, otherwise blocked by checker
+ exp_type = g.unwrap_generic(left.typ)
+ }
+
+ if cond.op == .key_is {
+ g.write('$exp_type == $got_type')
+ return exp_type == got_type
+ } else {
+ g.write('$exp_type != $got_type')
+ return exp_type != got_type
+ }
+ }
+ .eq, .ne {
+ // TODO Implement `$if method.args.len == 1`
+ g.write('1')
+ return true
+ }
+ else {
+ return true
+ }
+ }
+ }
+ ast.Ident {
+ ifdef := g.comp_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
+ g.write('$ifdef')
+ return true
+ }
+ ast.ComptimeCall {
+ g.write('$pkg_exist')
+ return true
+ }
+ else {
+ // should be unreachable, but just in case
+ g.write('1')
+ return true
+ }
+ }
+}
+
+fn (mut g JsGen) comp_if_to_ifdef(name string, is_comptime_optional bool) ?string {
+ match name {
+ // platforms/os-es:
+ 'windows' {
+ return '(\$process.platform == "windows")'
+ }
+ 'ios' {
+ return '(\$process.platform == "darwin")'
+ }
+ 'macos' {
+ return '(\$process.platform == "darwin")'
+ }
+ 'mach' {
+ return '(\$process.platform == "darwin")'
+ }
+ 'darwin' {
+ return '(\$process.platform == "darwin")'
+ }
+ 'linux' {
+ return '(\$process.platform == "linux")'
+ }
+ 'freebsd' {
+ return '(\$process.platform == "freebsd")'
+ }
+ 'openbsd' {
+ return '(\$process.platform == "openbsd")'
+ }
+ 'bsd' {
+ return '(\$process.platform == "freebsd" || (\$process.platform == "openbsd"))'
+ }
+ 'android' {
+ return '(\$process.platform == "android")'
+ }
+ 'solaris' {
+ return '(\$process.platform == "sunos")'
+ }
+ 'js_node' {
+ if g.pref.backend == .js_node {
+ return 'true'
+ } else {
+ return 'false'
+ }
+ }
+ 'js_freestanding' {
+ if g.pref.backend == .js_freestanding {
+ return 'true'
+ } else {
+ return 'false'
+ }
+ }
+ 'js_browser' {
+ if g.pref.backend == .js_browser {
+ return 'true'
+ } else {
+ return 'false'
+ }
+ }
+ //
+ 'js' {
+ return 'true'
+ }
+ // compilers:
+ 'gcc' {
+ return 'false'
+ }
+ 'tinyc' {
+ return 'false'
+ }
+ 'clang' {
+ return 'false'
+ }
+ 'mingw' {
+ return 'false'
+ }
+ 'msvc' {
+ return 'false'
+ }
+ 'cplusplus' {
+ return 'false'
+ }
+ // other:
+ 'threads' {
+ return 'false'
+ }
+ 'gcboehm' {
+ return 'false'
+ }
+ // todo(playX): these should return true or false depending on CLI options
+ 'debug' {
+ return 'false'
+ }
+ 'prod' {
+ return 'false'
+ }
+ 'test' {
+ return 'false'
+ }
+ 'glibc' {
+ return 'false'
+ }
+ 'prealloc' {
+ return 'false'
+ }
+ 'no_bounds_checking' {
+ return 'CUSTOM_DEFINE_no_bounds_checking'
+ }
+ 'freestanding' {
+ return '_VFREESTANDING'
+ }
+ // architectures:
+ 'amd64' {
+ return '(\$process.arch == "x64")'
+ }
+ 'aarch64', 'arm64' {
+ return '(\$process.arch == "arm64)'
+ }
+ // bitness:
+ 'x64' {
+ return '(\$process.arch == "x64")'
+ }
+ 'x32' {
+ return '(\$process.arch == "x32")'
+ }
+ // endianness:
+ 'little_endian' {
+ return '(\$os.endianess == "LE")'
+ }
+ 'big_endian' {
+ return '(\$os.endianess == "BE")'
+ }
+ else {
+ if is_comptime_optional
+ || (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
+ return 'CUSTOM_DEFINE_$name'
+ }
+ return error('bad os ifdef name "$name"') // should never happen, caught in the checker
+ }
+ }
+ return none
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/fast_deep_equal.js b/v_windows/v/old/vlib/v/gen/js/fast_deep_equal.js
new file mode 100644
index 0000000..50d37e8
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/fast_deep_equal.js
@@ -0,0 +1,72 @@
+// https://www.npmjs.com/package/fast-deep-equal - 3/3/2021
+const envHasBigInt64Array = typeof BigInt64Array !== 'undefined';
+function vEq(a, b) {
+ if (a === b) return true;
+
+ if (a && b && typeof a == 'object' && typeof b == 'object') {
+ if (a.constructor !== b.constructor) return false;
+ // we want to convert all V types to JS for comparison.
+ if ('$toJS' in a)
+ a = a.$toJS();
+
+ if ('$toJS' in b)
+ b = b.$toJS();
+
+ var length, i, keys;
+ if (Array.isArray(a)) {
+ length = a.length;
+ if (length != b.length) return false;
+ for (i = length; i-- !== 0;)
+ if (!vEq(a[i], b[i])) return false;
+ return true;
+ }
+
+
+ if ((a instanceof Map) && (b instanceof Map)) {
+ if (a.size !== b.size) return false;
+ for (i of a.entries())
+ if (!b.has(i[0])) return false;
+ for (i of a.entries())
+ if (!vEq(i[1], b.get(i[0]))) return false;
+ return true;
+ }
+
+ if ((a instanceof Set) && (b instanceof Set)) {
+ if (a.size !== b.size) return false;
+ for (i of a.entries())
+ if (!b.has(i[0])) return false;
+ return true;
+ }
+
+ if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
+ length = a.length;
+ if (length != b.length) return false;
+ for (i = length; i-- !== 0;)
+ if (a[i] !== b[i]) return false;
+ return true;
+ }
+
+
+ if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
+ if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
+ if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
+
+ keys = Object.keys(a);
+ length = keys.length;
+ if (length !== Object.keys(b).length) return false;
+
+ for (i = length; i-- !== 0;)
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
+
+ for (i = length; i-- !== 0;) {
+ var key = keys[i];
+
+ if (!vEq(a[key], b[key])) return false;
+ }
+
+ return true;
+ }
+
+ // true if both NaN, false otherwise
+ return a !== a && b !== b;
+}; \ No newline at end of file
diff --git a/v_windows/v/old/vlib/v/gen/js/js.v b/v_windows/v/old/vlib/v/gen/js/js.v
new file mode 100644
index 0000000..6ec623e
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/js.v
@@ -0,0 +1,2103 @@
+module js
+
+import strings
+import v.ast
+import v.token
+import v.pref
+import v.util
+import v.util.version
+import v.depgraph
+import encoding.base64
+import v.gen.js.sourcemap
+
+struct MutArg {
+ tmp_var string
+ expr ast.Expr = ast.empty_expr()
+}
+
+const (
+ // https://ecma-international.org/ecma-262/#sec-reserved-words
+ js_reserved = ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
+ 'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function',
+ 'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package',
+ 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw',
+ 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield', 'Number', 'String', 'Boolean',
+ 'Array', 'Map']
+ // used to generate type structs
+ v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64',
+ 'int_literal', 'float_literal', 'size_t', 'bool', 'string', 'map', 'array', 'any']
+ shallow_equatables = [ast.Kind.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64,
+ .int_literal, .float_literal, .size_t, .bool, .string]
+)
+
+struct SourcemapHelper {
+ src_path string
+ src_line u32
+ ns_pos u32
+}
+
+struct Namespace {
+ name string
+mut:
+ out strings.Builder = strings.new_builder(128)
+ pub_vars []string
+ imports map[string]string
+ indent int
+ methods map[string][]ast.FnDecl
+ sourcemap_helper []SourcemapHelper
+}
+
+[heap]
+struct JsGen {
+ pref &pref.Preferences
+mut:
+ table &ast.Table
+ definitions strings.Builder
+ ns &Namespace
+ namespaces map[string]&Namespace
+ doc &JsDoc
+ enable_doc bool
+ file &ast.File
+ tmp_count int
+ inside_ternary bool
+ inside_loop bool
+ inside_map_set bool // map.set(key, value)
+ inside_builtin bool
+ generated_builtin bool
+ inside_def_typ_decl bool
+ is_test bool
+ stmt_start_pos int
+ 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.FnDecl
+ builtin_fns []string // Functions defined in `builtin`
+ empty_line bool
+ cast_stack []ast.Type
+ call_stack []ast.CallExpr
+ is_vlines_enabled bool // is it safe to generate #line directives when -g is passed
+ sourcemap sourcemap.SourceMap // maps lines in generated javascrip file to original source files and line
+ comptime_var_type_map map[string]ast.Type
+ defer_ifdef string
+}
+
+pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
+ mut g := &JsGen{
+ definitions: strings.new_builder(100)
+ table: table
+ pref: pref
+ fn_decl: 0
+ empty_line: true
+ doc: 0
+ ns: 0
+ enable_doc: true
+ file: 0
+ }
+ g.doc = new_jsdoc(g)
+ // TODO: Add '[-no]-jsdoc' flag
+ if pref.is_prod {
+ g.enable_doc = false
+ g.is_vlines_enabled = false
+ }
+ g.init()
+ mut graph := depgraph.new_dep_graph()
+ if g.pref.sourcemap {
+ mut sg := sourcemap.generate_empty_map()
+ g.sourcemap = sg.add_map('', '', g.pref.sourcemap_src_included, 0, 0)
+ }
+ // Get class methods
+ for file in files {
+ g.file = file
+ g.enter_namespace(g.file.mod.name)
+ g.is_test = g.pref.is_test
+ g.find_class_methods(file.stmts)
+ g.escape_namespace()
+ }
+
+ for file in files {
+ g.file = file
+ g.enter_namespace(g.file.mod.name)
+ g.is_test = g.pref.is_test
+ // store imports
+ mut imports := []string{}
+ for imp in g.file.imports {
+ imports << imp.mod
+ }
+ graph.add(g.file.mod.name, imports)
+ // builtin types
+ if g.file.mod.name == 'builtin' && !g.generated_builtin {
+ g.gen_builtin_type_defs()
+ g.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return new builtin.int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } }); ')
+ g.writeln('Object.defineProperty(string.prototype,"len", { get: function() {return new builtin.int(this.str.length);}, set: function(l) {/* ignore */ } }); ')
+ g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new builtin.int(this.map.length);}, set: function(l) { this.map.length = l.valueOf(); } }); ')
+ g.writeln('Object.defineProperty(array.prototype,"length", { get: function() {return new builtin.int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } }); ')
+ g.generated_builtin = true
+ }
+
+ g.stmts(file.stmts)
+ // store the current namespace
+ g.escape_namespace()
+ }
+ // resolve imports
+ deps_resolved := graph.resolve()
+ nodes := deps_resolved.nodes
+ mut out := g.hashes() + g.definitions.str()
+ // equality check for js objects
+ // TODO: Fix msvc bug that's preventing $embed_file('fast_deep_equal.js')
+ // unsafe {
+ // mut eq_fn := $embed_file('fast_deep_equal.js')
+ // out += eq_fn.data().vstring()
+ //}
+ out += fast_deep_eq_fn
+ for node in nodes {
+ name := g.js_name(node.name).replace('.', '_')
+ if g.enable_doc {
+ out += '/** @namespace $name */\n'
+ }
+ out += 'const $name = (function ('
+ mut namespace := g.namespaces[node.name]
+ mut first := true
+ for _, val in namespace.imports {
+ if !first {
+ out += ', '
+ }
+ first = false
+ out += val
+ }
+ out += ') {\n\t'
+ namespace_code := namespace.out.str()
+ if g.pref.sourcemap {
+ // calculate current output start line
+ mut current_line := u32(out.count('\n') + 1)
+ mut sm_pos := u32(0)
+ for sourcemap_ns_entry in namespace.sourcemap_helper {
+ // calculate final generated location in output based on position
+ current_segment := namespace_code.substr(int(sm_pos), int(sourcemap_ns_entry.ns_pos))
+ current_line += u32(current_segment.count('\n'))
+ current_column := if last_nl_pos := current_segment.last_index('\n') {
+ u32(current_segment.len - last_nl_pos - 1)
+ } else {
+ u32(0)
+ }
+ g.sourcemap.add_mapping(sourcemap_ns_entry.src_path, sourcemap.SourcePosition{
+ source_line: sourcemap_ns_entry.src_line
+ source_column: 0 // sourcemap_ns_entry.src_column
+ }, current_line, current_column, '')
+ sm_pos = sourcemap_ns_entry.ns_pos
+ }
+ }
+ out += namespace_code
+
+ // public scope
+ out += '\n'
+ if g.enable_doc {
+ out += '\n\t/* module exports */'
+ }
+ out += '\n\treturn {'
+ // export builtin types
+ if name == 'builtin' {
+ for typ in js.v_types {
+ out += '\n\t\t$typ,'
+ }
+ }
+ for i, pub_var in namespace.pub_vars {
+ out += '\n\t\t$pub_var'
+ if i < namespace.pub_vars.len - 1 {
+ out += ','
+ }
+ }
+ if namespace.pub_vars.len > 0 {
+ out += '\n\t'
+ }
+ out += '};'
+ out += '\n})('
+ first = true
+ for key, _ in namespace.imports {
+ if !first {
+ out += ', '
+ }
+ first = false
+ out += key.replace('.', '_')
+ }
+ out += ');\n'
+ // generate builtin basic type casts
+ if name == 'builtin' {
+ out += '// builtin type casts\n'
+ out += 'const ['
+ for i, typ in js.v_types {
+ if i > 0 {
+ out += ', '
+ }
+ out += '$typ'
+ }
+ out += '] = ['
+ for i, typ in js.v_types {
+ if i > 0 {
+ out += ','
+ }
+ out += '\n\tfunction(val) { return new builtin.${typ}(val) }'
+ }
+ out += '\n]\n'
+ }
+ }
+ if pref.is_shared {
+ // Export, through CommonJS, the module of the entry file if `-shared` was passed
+ export := nodes[nodes.len - 1].name
+ out += 'if (typeof module === "object" && module.exports) module.exports = $export;\n'
+ }
+ out += '\n'
+ if g.pref.sourcemap {
+ out += g.create_sourcemap()
+ }
+ return out
+}
+
+fn (g JsGen) create_sourcemap() string {
+ mut sm := g.sourcemap
+ mut out := '\n//# sourceMappingURL=data:application/json;base64,'
+ out += base64.encode(sm.to_json().str().bytes())
+ out += '\n'
+
+ return out
+}
+
+pub fn (mut g JsGen) enter_namespace(name string) {
+ if g.namespaces[name] == 0 {
+ // create a new namespace
+ ns := &Namespace{
+ name: name
+ }
+ g.namespaces[name] = ns
+ g.ns = ns
+ } else {
+ g.ns = g.namespaces[name]
+ }
+ g.inside_builtin = name == 'builtin'
+}
+
+pub fn (mut g JsGen) escape_namespace() {
+ g.ns = &Namespace(0)
+ g.inside_builtin = false
+}
+
+pub fn (mut g JsGen) push_pub_var(s string) {
+ g.ns.pub_vars << g.js_name(s)
+}
+
+pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
+ for stmt in stmts {
+ match stmt {
+ ast.FnDecl {
+ if stmt.is_method {
+ // Found struct method, store it to be generated along with the class.
+ mut class_name := g.table.get_type_name(stmt.receiver.typ)
+ // Workaround until `map[key] << val` works.
+ mut arr := g.method_fn_decls[class_name]
+ arr << stmt
+ g.method_fn_decls[class_name] = arr
+ }
+ }
+ else {}
+ }
+ }
+}
+
+pub fn (mut g JsGen) init() {
+ g.definitions.writeln('// Generated by the V compiler\n')
+ g.definitions.writeln('"use strict";')
+ g.definitions.writeln('')
+ g.definitions.writeln('var \$global = (new Function("return this"))();')
+ g.definitions.writeln('function \$ref(value) { this.val = value; } ')
+ g.definitions.writeln('\$ref.prototype.valueOf = function() { return this.val; } ')
+ if g.pref.backend != .js_node {
+ g.definitions.writeln('const \$process = {')
+ g.definitions.writeln(' arch: "js",')
+ if g.pref.backend == .js_freestanding {
+ g.definitions.writeln(' platform: "freestanding"')
+ } else {
+ g.definitions.writeln(' platform: "browser"')
+ }
+ g.definitions.writeln('}')
+
+ g.definitions.writeln('const \$os = {')
+ g.definitions.writeln(' endianess: "LE",')
+
+ g.definitions.writeln('}')
+ } else {
+ g.definitions.writeln('const \$os = require("os");')
+ g.definitions.writeln('const \$process = process;')
+ }
+}
+
+pub fn (g JsGen) hashes() string {
+ mut res := '// V_COMMIT_HASH $version.vhash()\n'
+ res += '// V_CURRENT_COMMIT_HASH ${version.githash(g.pref.building_v)}\n'
+ return res
+}
+
+[noreturn]
+fn verror(msg string) {
+ eprintln('jsgen error: $msg')
+ exit(1)
+}
+
+[inline]
+pub fn (mut g JsGen) gen_indent() {
+ if g.ns.indent > 0 && g.empty_line {
+ g.ns.out.write_string(util.tabs(g.ns.indent))
+ }
+ g.empty_line = false
+}
+
+[inline]
+pub fn (mut g JsGen) inc_indent() {
+ g.ns.indent++
+}
+
+[inline]
+pub fn (mut g JsGen) dec_indent() {
+ g.ns.indent--
+}
+
+[inline]
+pub fn (mut g JsGen) write(s string) {
+ if g.ns == 0 {
+ verror('g.write: not in a namespace')
+ }
+ g.gen_indent()
+ g.ns.out.write_string(s)
+}
+
+[inline]
+pub fn (mut g JsGen) writeln(s string) {
+ if g.ns == 0 {
+ verror('g.writeln: not in a namespace')
+ }
+ g.gen_indent()
+ g.ns.out.writeln(s)
+ g.empty_line = true
+}
+
+[inline]
+pub fn (mut g JsGen) new_tmp_var() string {
+ g.tmp_count++
+ return '_tmp$g.tmp_count'
+}
+
+// 'mod1.mod2.fn' => 'mod1.mod2'
+// 'fn' => ''
+[inline]
+fn get_ns(s string) string {
+ idx := s.last_index('.') or { return '' }
+ return s.substr(0, idx)
+}
+
+fn (mut g JsGen) get_alias(name string) string {
+ ns := get_ns(name)
+ if ns == '' {
+ return name
+ }
+ alias := g.ns.imports[ns]
+ if alias == '' {
+ return name
+ }
+ return alias + '.' + name.split('.').last()
+}
+
+fn (mut g JsGen) js_name(name_ string) string {
+ mut is_js := false
+ mut name := name_
+ if name.starts_with('JS.') {
+ name = name[3..]
+ is_js = true
+ }
+ ns := get_ns(name)
+ name = 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('.')
+}
+
+fn (mut g JsGen) stmts(stmts []ast.Stmt) {
+ g.inc_indent()
+ for stmt in stmts {
+ g.stmt(stmt)
+ }
+ g.dec_indent()
+}
+
+[inline]
+fn (mut g JsGen) write_v_source_line_info(pos token.Position) {
+ // g.inside_ternary == 0 &&
+ if g.pref.sourcemap {
+ g.ns.sourcemap_helper << SourcemapHelper{
+ src_path: util.vlines_escape_path(g.file.path, g.pref.ccompiler)
+ src_line: u32(pos.line_nr + 1)
+ ns_pos: u32(g.ns.out.len)
+ }
+ }
+ if g.pref.is_vlines && g.is_vlines_enabled {
+ g.write(' /* ${pos.line_nr + 1} $g.ns.out.len */ ')
+ }
+}
+
+fn (mut g JsGen) gen_global_decl(node ast.GlobalDecl) {
+ mod := if g.pref.build_mode == .build_module { 'enumerable: false' } else { 'enumerable: true' }
+ for field in node.fields {
+ if field.has_expr {
+ tmp_var := g.new_tmp_var()
+ g.write('const $tmp_var = ')
+ g.expr(field.expr)
+ g.writeln(';')
+ g.writeln('Object.defineProperty(\$global,"$field.name", {
+ configurable: false,
+ $mod ,
+ writable: true,
+ value: $tmp_var
+ }
+ ); // global')
+ } else {
+ // TODO(playXE): Initialize with default value of type
+ }
+ }
+}
+
+fn (mut g JsGen) stmt(node ast.Stmt) {
+ g.stmt_start_pos = g.ns.out.len
+ match node {
+ ast.EmptyStmt {}
+ ast.AsmStmt {
+ panic('inline asm is not supported by js')
+ }
+ ast.AssertStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_assert_stmt(node)
+ }
+ ast.AssignStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_assign_stmt(node)
+ }
+ ast.Block {
+ g.write_v_source_line_info(node.pos)
+ g.gen_block(node)
+ g.writeln('')
+ }
+ ast.BranchStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_branch_stmt(node)
+ }
+ ast.CompFor {}
+ ast.ConstDecl {
+ g.write_v_source_line_info(node.pos)
+ g.gen_const_decl(node)
+ }
+ ast.DeferStmt {
+ g.defer_stmts << node
+ }
+ ast.EnumDecl {
+ g.write_v_source_line_info(node.pos)
+ g.gen_enum_decl(node)
+ g.writeln('')
+ }
+ ast.ExprStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_expr_stmt(node)
+ }
+ ast.FnDecl {
+ g.write_v_source_line_info(node.pos)
+ g.fn_decl = unsafe { &node }
+ g.gen_fn_decl(node)
+ }
+ ast.ForCStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_for_c_stmt(node)
+ g.writeln('')
+ }
+ ast.ForInStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_for_in_stmt(node)
+ g.writeln('')
+ }
+ ast.ForStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_for_stmt(node)
+ g.writeln('')
+ }
+ ast.GlobalDecl {
+ g.write_v_source_line_info(node.pos)
+ g.gen_global_decl(node)
+ g.writeln('')
+ }
+ ast.GotoLabel {
+ g.write_v_source_line_info(node.pos)
+ g.writeln('${g.js_name(node.name)}:')
+ }
+ ast.GotoStmt {
+ // skip: JS has no goto
+ }
+ ast.HashStmt {
+ g.write_v_source_line_info(node.pos)
+ g.gen_hash_stmt(node)
+ }
+ ast.Import {
+ g.ns.imports[node.mod] = node.alias
+ }
+ ast.InterfaceDecl {
+ g.write_v_source_line_info(node.pos)
+ g.gen_interface_decl(node)
+ }
+ ast.Module {
+ // skip: namespacing implemented externally
+ }
+ ast.NodeError {}
+ ast.Return {
+ if g.defer_stmts.len > 0 {
+ g.gen_defer_stmts()
+ }
+ g.gen_return_stmt(node)
+ }
+ ast.SqlStmt {}
+ ast.StructDecl {
+ g.write_v_source_line_info(node.pos)
+ g.gen_struct_decl(node)
+ }
+ ast.TypeDecl {
+ // skip JS has no typedecl
+ }
+ }
+}
+
+fn (mut g JsGen) expr(node ast.Expr) {
+ match node {
+ ast.NodeError {}
+ ast.EmptyExpr {}
+ ast.CTempVar {
+ g.write('/* ast.CTempVar: node.name */')
+ }
+ ast.DumpExpr {
+ g.write('/* ast.DumpExpr: $node.expr */')
+ }
+ ast.AnonFn {
+ g.gen_fn_decl(node.decl)
+ }
+ ast.ArrayInit {
+ g.gen_array_init_expr(node)
+ }
+ ast.AsCast {
+ // skip: JS has no types, so no need to cast
+ // TODO: Is jsdoc needed here for TS support?
+ }
+ ast.Assoc {
+ // TODO
+ }
+ ast.BoolLiteral {
+ if node.val == true {
+ g.write('true')
+ } else {
+ g.write('false')
+ }
+ }
+ ast.CallExpr {
+ g.gen_call_expr(node)
+ }
+ ast.ChanInit {
+ // TODO
+ }
+ ast.CastExpr {
+ g.gen_type_cast_expr(node)
+ }
+ ast.CharLiteral {
+ // todo(playX): char type?
+ g.write("new builtin.string('$node.val')")
+ }
+ ast.Comment {}
+ ast.ConcatExpr {
+ // TODO
+ }
+ ast.EnumVal {
+ sym := g.table.get_type_symbol(node.typ)
+ styp := g.js_name(sym.name)
+ g.write('${styp}.$node.val')
+ }
+ ast.FloatLiteral {
+ g.gen_float_literal_expr(node)
+ }
+ ast.GoExpr {
+ g.gen_go_expr(node)
+ }
+ ast.Ident {
+ g.gen_ident(node)
+ }
+ ast.IfExpr {
+ g.gen_if_expr(node)
+ }
+ ast.IfGuardExpr {
+ // TODO no optionals yet
+ }
+ ast.IndexExpr {
+ g.gen_index_expr(node)
+ }
+ ast.InfixExpr {
+ g.gen_infix_expr(node)
+ }
+ ast.IntegerLiteral {
+ g.gen_integer_literal_expr(node)
+ }
+ ast.LockExpr {
+ g.gen_lock_expr(node)
+ }
+ ast.MapInit {
+ g.gen_map_init_expr(node)
+ }
+ ast.MatchExpr {
+ // TODO
+ }
+ ast.None {
+ // TODO
+ }
+ ast.OrExpr {
+ // TODO
+ }
+ ast.ParExpr {
+ g.write('(')
+ g.expr(node.expr)
+ g.write(')')
+ }
+ ast.PostfixExpr {
+ g.expr(node.expr)
+ g.write(node.op.str())
+ }
+ ast.PrefixExpr {
+ if node.op in [.amp, .mul] {
+ // C pointers/references: ignore them
+ if node.op == .amp {
+ if !node.right_type.is_pointer() {
+ // kind of weird way to handle references but it allows us to access type methods easily.
+ g.write('(function(x) {')
+ g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ')
+ g.expr(node.right)
+ g.write(')')
+ } else {
+ g.expr(node.right)
+ }
+ } else {
+ g.write('(')
+ g.expr(node.right)
+ g.write(').valueOf()')
+ }
+ } else {
+ g.write(node.op.str())
+ g.write('(')
+ g.expr(node.right)
+ g.write('.valueOf()')
+ g.write(')')
+ }
+ }
+ ast.RangeExpr {
+ // Only used in IndexExpr, requires index type info
+ }
+ ast.SelectExpr {
+ // TODO: to be implemented
+ }
+ ast.SelectorExpr {
+ g.gen_selector_expr(node)
+ }
+ ast.SizeOf, ast.IsRefType {
+ // TODO
+ }
+ ast.OffsetOf {
+ // TODO
+ }
+ ast.SqlExpr {
+ // TODO
+ }
+ ast.StringInterLiteral {
+ g.gen_string_inter_literal(node)
+ }
+ ast.StringLiteral {
+ g.gen_string_literal(node)
+ }
+ ast.StructInit {
+ // TODO: once generic fns/unwrap_generic is implemented
+ // if node.unresolved {
+ // g.expr(ast.resolve_init(node, g.unwrap_generic(node.typ), g.table))
+ // } else {
+ // // `user := User{name: 'Bob'}`
+ // g.gen_struct_init(node)
+ // }
+ // `user := User{name: 'Bob'}`
+ g.gen_struct_init(node)
+ }
+ ast.TypeNode {
+ // skip: JS has no types
+ // TODO maybe?
+ }
+ ast.Likely {
+ g.write('(')
+ g.expr(node.expr)
+ g.write(')')
+ }
+ ast.TypeOf {
+ g.gen_typeof_expr(node)
+ // TODO: Should this print the V type or the JS type?
+ }
+ ast.AtExpr {
+ g.write('"$node.val"')
+ }
+ ast.ComptimeCall {
+ // TODO
+ }
+ ast.ComptimeSelector {
+ // TODO
+ }
+ ast.UnsafeExpr {
+ g.expr(node.expr)
+ }
+ ast.ArrayDecompose {}
+ }
+}
+
+// TODO
+fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
+ if !a.is_used {
+ return
+ }
+ g.writeln('// assert')
+ g.write('if( ')
+ g.expr(a.expr)
+ g.write(' ) {')
+ 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}()" );')
+ g.writeln('} else {')
+ g.writeln(' g_test_fails++;')
+ g.writeln(' cb_assertion_failed("$mod_path", ${a.pos.line_nr + 1}, "assert $s_assertion", "${g.fn_decl.name}()" );')
+ g.writeln(' exit(1);')
+ g.writeln('}')
+ return
+ }
+ g.writeln('} else {')
+ 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('}')
+}
+
+fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
+ if stmt.left.len > stmt.right.len {
+ // multi return
+ g.write('const [')
+ for i, left in stmt.left {
+ if !left.is_blank_ident() {
+ g.expr(left)
+ }
+ if i < stmt.left.len - 1 {
+ g.write(', ')
+ }
+ }
+ g.write('] = ')
+ g.expr(stmt.right[0])
+ g.writeln(';')
+ } else {
+ // `a := 1` | `a,b := 1,2`
+ for i, left in stmt.left {
+ mut op := stmt.op
+ if stmt.op == .decl_assign {
+ op = .assign
+ }
+ val := stmt.right[i]
+ mut is_mut := false
+ if left is ast.Ident {
+ is_mut = left.is_mut
+ if left.kind == .blank_ident || left.name in ['', '_'] {
+ tmp_var := g.new_tmp_var()
+ // TODO: Can the tmp_var declaration be omitted?
+ g.write('const $tmp_var = ')
+ g.expr(val)
+ g.writeln(';')
+ continue
+ }
+ }
+ mut styp := g.typ(stmt.left_types[i])
+ if !g.inside_loop && styp.len > 0 {
+ g.doc.gen_typ(styp)
+ }
+ if stmt.op == .decl_assign {
+ if g.inside_loop || is_mut {
+ g.write('let ')
+ } else {
+ g.write('const ')
+ }
+ }
+ g.expr(left)
+ mut is_ptr := false
+ if stmt.op == .assign && stmt.left_types[i].is_ptr() {
+ is_ptr = true
+ g.write('.val')
+ }
+ if g.inside_map_set && op == .assign {
+ g.inside_map_set = false
+ g.write(', ')
+ g.expr(val)
+ if is_ptr {
+ g.write('.val')
+ }
+ g.write(')')
+ } else {
+ g.write(' $op ')
+ // TODO: Multiple types??
+ should_cast :=
+ (g.table.type_kind(stmt.left_types.first()) in js.shallow_equatables)
+ && (g.cast_stack.len <= 0 || stmt.left_types.first() != g.cast_stack.last())
+
+ if should_cast {
+ g.cast_stack << stmt.left_types.first()
+ if g.file.mod.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('${g.typ(stmt.left_types.first())}(')
+ }
+ g.expr(val)
+ if is_ptr {
+ g.write('.val')
+ }
+ if should_cast {
+ g.write(')')
+ g.cast_stack.delete_last()
+ }
+ }
+ if g.inside_loop {
+ g.write('; ')
+ } else {
+ g.writeln(';')
+ }
+ }
+ }
+}
+
+fn (mut g JsGen) gen_attrs(attrs []ast.Attr) {
+ for attr in attrs {
+ g.writeln('/* [$attr.name] */')
+ }
+}
+
+fn (mut g JsGen) gen_block(it ast.Block) {
+ g.writeln('{')
+ g.stmts(it.stmts)
+ g.writeln('}')
+}
+
+fn (mut g JsGen) gen_branch_stmt(it ast.BranchStmt) {
+ // continue or break
+ g.write(it.kind.str())
+ g.writeln(';')
+}
+
+fn (mut g JsGen) gen_const_decl(it ast.ConstDecl) {
+ for field in it.fields {
+ g.doc.gen_const(g.typ(field.typ))
+ if field.is_pub {
+ g.push_pub_var(field.name)
+ }
+ g.write('const ${g.js_name(field.name)} = ')
+ g.expr(field.expr)
+ g.writeln(';')
+ }
+ g.writeln('')
+}
+
+fn (mut g JsGen) gen_defer_stmts() {
+ g.writeln('(function defer() {')
+ for defer_stmt in g.defer_stmts {
+ g.stmts(defer_stmt.stmts)
+ }
+ g.defer_stmts = []
+ g.writeln('})();')
+}
+
+fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
+ g.doc.gen_enum()
+ g.writeln('const ${g.js_name(it.name)} = {')
+ g.inc_indent()
+ mut i := 0
+ for field in it.fields {
+ g.write('$field.name: ')
+ if field.has_expr && field.expr is ast.IntegerLiteral {
+ i = field.expr.val.int()
+ }
+ g.writeln('$i,')
+ i++
+ }
+ g.dec_indent()
+ g.writeln('};')
+ if it.is_pub {
+ g.push_pub_var(it.name)
+ }
+}
+
+fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) {
+ g.expr(it.expr)
+ 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.no_body || it.is_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)
+ 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) gen_method_decl(it ast.FnDecl) {
+ unsafe {
+ g.fn_decl = &it
+ }
+ 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(', ')
+ }
+ g.write('${it.params[0].name} = this')
+ }
+ g.writeln(') {')
+ for i, arg in args {
+ is_varg := i == args.len - 1 && it.is_variadic
+ if is_varg {
+ name := g.js_name(arg.name)
+ g.writeln('$name = new array($name);')
+ }
+ }
+
+ g.stmts(it.stmts)
+ g.write('}')
+ if is_main {
+ g.write(')();')
+ }
+ if !it.is_anon && !it.is_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 (')
+ if it.has_init {
+ g.stmt(it.init)
+ } else {
+ g.write('; ')
+ }
+ if it.has_cond {
+ g.write('+') // convert to number or boolean
+ g.expr(it.cond)
+ }
+ g.write('; ')
+ if it.has_inc {
+ g.stmt(it.inc)
+ }
+ g.writeln(') {')
+ g.stmts(it.stmts)
+ g.writeln('}')
+ g.inside_loop = false
+}
+
+fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
+ if it.is_range {
+ // `for x in 1..10 {`
+ mut i := it.val_var
+ if i in ['', '_'] {
+ i = g.new_tmp_var()
+ }
+ g.inside_loop = true
+ g.write('for (let $i = ')
+ g.expr(it.cond)
+ g.write('; $i < ')
+ g.expr(it.high)
+ g.writeln('; $i = new builtin.int($i + 1)) {')
+ g.inside_loop = false
+ g.stmts(it.stmts)
+ g.writeln('}')
+ } else if it.kind in [.array, .string] || it.cond_type.has_flag(.variadic) {
+ // `for num in nums {`
+ val := if it.val_var in ['', '_'] { '_' } else { it.val_var }
+ // styp := g.typ(it.val_type)
+ if it.key_var.len > 0 {
+ g.write('for (const [$it.key_var, $val] of ')
+ if it.kind == .string {
+ g.write('Array.from(')
+ g.expr(it.cond)
+ if it.cond_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.str.split(\'\').entries(), ([$it.key_var, $val]) => [$it.key_var, ')
+ if g.ns.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('byte($val)])')
+ } else {
+ g.expr(it.cond)
+ if it.cond_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.entries()')
+ }
+ } else {
+ g.write('for (const $val of ')
+ g.expr(it.cond)
+ if it.cond_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ if it.kind == .string {
+ g.write(".str.split('')")
+ }
+ // cast characters to bytes
+ if val !in ['', '_'] && it.kind == .string {
+ g.write('.map(c => ')
+ if g.ns.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('byte(c))')
+ }
+ }
+ g.writeln(') {')
+ g.stmts(it.stmts)
+ g.writeln('}')
+ } else if it.kind == .map {
+ // `for key, val in map[string]int {`
+ // key_styp := g.typ(it.key_type)
+ // val_styp := g.typ(it.val_type)
+ key := if it.key_var in ['', '_'] { '' } else { it.key_var }
+ val := if it.val_var in ['', '_'] { '' } else { it.val_var }
+ g.write('for (let [$key, $val] of ')
+ g.expr(it.cond)
+ if it.cond_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.writeln(') {')
+ g.stmts(it.stmts)
+ g.writeln('}')
+ }
+}
+
+fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
+ g.write('while (')
+ if it.is_inf {
+ g.write('true')
+ } else {
+ g.write('+') // convert expr to number or boolean
+ g.expr(it.cond)
+ }
+ g.writeln(') {')
+ g.stmts(it.stmts)
+ g.writeln('}')
+}
+
+fn (mut g JsGen) gen_go_expr(node ast.GoExpr) {
+ // TODO Handle joinable expressions
+ // node.is_expr
+ mut name := node.call_expr.name
+ if node.call_expr.is_method {
+ receiver_sym := g.table.get_type_symbol(node.call_expr.receiver_type)
+ name = receiver_sym.name + '.' + name
+ }
+ // todo: please add a name feild without the mod name for ast.CallExpr
+ if name.starts_with('${node.call_expr.mod}.') {
+ name = name[node.call_expr.mod.len + 1..]
+ }
+ g.writeln('await new Promise(function(resolve){')
+ g.inc_indent()
+ g.write('${name}(')
+ for i, arg in node.call_expr.args {
+ g.expr(arg.expr)
+ if i < node.call_expr.args.len - 1 {
+ g.write(', ')
+ }
+ }
+ g.writeln(');')
+ g.writeln('resolve();')
+ g.dec_indent()
+ g.writeln('});')
+}
+
+fn (mut g JsGen) gen_import_stmt(it ast.Import) {
+ g.ns.imports[it.mod] = it.alias
+}
+
+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
+ g.writeln('return;')
+ return
+ }
+ g.write('return ')
+ if it.exprs.len == 1 {
+ g.expr(it.exprs[0])
+ } else { // Multi return
+ g.gen_array_init_values(it.exprs)
+ }
+ g.writeln(';')
+}
+
+fn (mut g JsGen) gen_hash_stmt(it ast.HashStmt) {
+ g.writeln(it.val)
+}
+
+fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
+ mut name := node.name
+ if name.starts_with('JS.') {
+ return
+ }
+ if name in js.v_types && g.ns.name == 'builtin' {
+ return
+ }
+ js_name := g.js_name(name)
+ g.gen_attrs(node.attrs)
+ g.doc.gen_fac_fn(node.fields)
+ g.write('function ${js_name}({ ')
+ for i, field in node.fields {
+ g.write('$field.name = ')
+ if field.has_default_expr {
+ g.expr(field.default_expr)
+ } else {
+ g.write('${g.to_js_typ_val(field.typ)}')
+ }
+ if i < node.fields.len - 1 {
+ g.write(', ')
+ }
+ }
+ g.writeln(' }) {')
+ g.inc_indent()
+ for field in node.fields {
+ g.writeln('this.$field.name = $field.name')
+ }
+ g.dec_indent()
+ g.writeln('};')
+ g.writeln('${js_name}.prototype = {')
+ g.inc_indent()
+ for embed in node.embeds {
+ etyp := g.typ(embed.typ)
+ g.writeln('...${etyp}.prototype,')
+ }
+ fns := g.method_fn_decls[name]
+ for field in node.fields {
+ typ := g.typ(field.typ)
+ g.doc.gen_typ(typ)
+ g.write('$field.name: ${g.to_js_typ_val(field.typ)}')
+ g.writeln(',')
+ }
+ for cfn in fns {
+ g.gen_method_decl(cfn)
+ g.writeln(',')
+ }
+ // gen toString method
+ fn_names := fns.map(it.name)
+ if 'toString' !in fn_names {
+ g.writeln('toString() {')
+ g.inc_indent()
+ g.write('return `$js_name {')
+ for i, field in node.fields {
+ if i == 0 {
+ g.write(' ')
+ } else {
+ g.write(', ')
+ }
+ match g.typ(field.typ).split('.').last() {
+ 'string' { g.write('$field.name: "\${this["$field.name"].toString()}"') }
+ else { g.write('$field.name: \${this["$field.name"].toString()} ') }
+ }
+ }
+ g.writeln('}`')
+ g.dec_indent()
+ g.writeln('},')
+ }
+ g.writeln('\$toJS() { return this; }')
+ g.dec_indent()
+ g.writeln('};\n')
+ if node.is_pub {
+ g.push_pub_var(name)
+ }
+}
+
+fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
+ // 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
+ g.write('new array(')
+ g.inc_indent()
+
+ 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.writeln(');')
+ g.dec_indent()
+ g.writeln('};')
+ g.writeln('return $t1;')
+ g.dec_indent()
+ g.write('})()')
+ } else if it.is_fixed && it.exprs.len == 1 {
+ // [100]byte codegen
+ 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.exprs[0])
+ 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.writeln(');')
+ g.dec_indent()
+ g.writeln('};')
+ g.writeln('return $t1;')
+ g.dec_indent()
+ g.write('})()')
+ } else {
+ g.gen_array_init_values(it.exprs)
+ }
+ g.dec_indent()
+ g.write(')')
+}
+
+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) {
+ g.call_stack << it
+ mut name := g.js_name(it.name)
+ call_return_is_optional := it.return_type.has_flag(.optional)
+ if call_return_is_optional {
+ g.writeln('(function(){')
+ g.inc_indent()
+ g.writeln('try {')
+ g.inc_indent()
+ g.write('return builtin.unwrap(')
+ }
+ g.expr(it.left)
+
+ if it.is_method { // foo.bar.baz()
+ sym := g.table.get_type_symbol(it.receiver_type)
+ g.write('.')
+ if sym.kind == .array && it.name in ['map', 'filter'] {
+ // Prevent 'it' from getting shadowed inside the match
+ node := it
+ g.write(it.name)
+ g.write('(')
+ expr := node.args[0].expr
+ match expr {
+ ast.AnonFn {
+ g.gen_fn_decl(expr.decl)
+ g.write(')')
+ return
+ }
+ ast.Ident {
+ if expr.kind == .function {
+ g.write(g.js_name(expr.name))
+ g.write(')')
+ return
+ } else if expr.kind == .variable {
+ v_sym := g.table.get_type_symbol(expr.var_info().typ)
+ if v_sym.kind == .function {
+ g.write(g.js_name(expr.name))
+ g.write(')')
+ return
+ }
+ }
+ }
+ else {}
+ }
+
+ g.write('it => ')
+ g.expr(node.args[0].expr)
+ g.write(')')
+ return
+ }
+
+ left_sym := g.table.get_type_symbol(it.left_type)
+ if left_sym.kind == .array {
+ node := it
+ match node.name {
+ 'insert' {
+ arg2_sym := g.table.get_type_symbol(node.args[1].typ)
+ is_arg2_array := arg2_sym.kind == .array && node.args[1].typ == node.left_type
+ if is_arg2_array {
+ g.write('insert_many(')
+ } else {
+ g.write('insert(')
+ }
+
+ g.expr(node.args[0].expr)
+ g.write(',')
+ if is_arg2_array {
+ g.expr(node.args[1].expr)
+ g.write('.arr,')
+ g.expr(node.args[1].expr)
+ g.write('.len')
+ } else {
+ g.expr(node.args[1].expr)
+ }
+ g.write(')')
+ return
+ }
+ 'prepend' {
+ arg_sym := g.table.get_type_symbol(node.args[0].typ)
+ is_arg_array := arg_sym.kind == .array && node.args[0].typ == node.left_type
+ if is_arg_array {
+ g.write('prepend_many(')
+ } else {
+ g.write('prepend(')
+ }
+
+ if is_arg_array {
+ g.expr(node.args[0].expr)
+ g.write('.arr, ')
+ g.expr(node.args[0].expr)
+ g.write('.len')
+ } else {
+ g.expr(node.args[0].expr)
+ }
+ g.write(')')
+ return
+ }
+ else {}
+ }
+ }
+ } else {
+ if name in g.builtin_fns {
+ g.write('builtin.')
+ }
+ }
+ g.write('${name}(')
+ for i, arg in it.args {
+ g.expr(arg.expr)
+ if i != it.args.len - 1 {
+ g.write(', ')
+ }
+ }
+ // end method call
+ g.write(')')
+ if call_return_is_optional {
+ // end unwrap
+ g.writeln(')')
+ g.dec_indent()
+ // begin catch block
+ g.writeln('} catch(err) {')
+ g.inc_indent()
+ // gen or block contents
+ match it.or_block.kind {
+ .block {
+ if it.or_block.stmts.len > 1 {
+ g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
+ }
+ g.write('return ')
+ g.stmt(it.or_block.stmts.last())
+ }
+ .propagate {
+ panicstr := '`optional not set (\${err})`'
+ if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
+ g.writeln('return builtin.panic($panicstr)')
+ } else {
+ g.writeln('builtin.js_throw(err)')
+ }
+ }
+ else {}
+ }
+ // end catch
+ g.dec_indent()
+ g.writeln('}')
+ // end anon fn
+ g.dec_indent()
+ g.write('})()')
+ }
+ g.call_stack.delete_last()
+}
+
+fn (mut g JsGen) gen_ident(node ast.Ident) {
+ mut name := g.js_name(node.name)
+ if node.kind == .blank_ident || name in ['', '_'] {
+ name = g.new_tmp_var()
+ }
+ // TODO `is`
+ // TODO handle optionals
+ g.write(name)
+
+ // TODO: Generate .val for basic types
+}
+
+fn (mut g JsGen) gen_lock_expr(node ast.LockExpr) {
+ // TODO: implement this
+}
+
+fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
+ if node.is_comptime {
+ g.comp_if(node)
+ return
+ }
+ type_sym := g.table.get_type_symbol(node.typ)
+ // one line ?:
+ if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != .void {
+ // `x := if a > b { } else if { } else { }`
+ g.write('(')
+ g.inside_ternary = true
+ for i, branch in node.branches {
+ if i > 0 {
+ g.write(' : ')
+ }
+ if i < node.branches.len - 1 || !node.has_else {
+ g.write('(')
+ g.expr(branch.cond)
+ g.write(')')
+ g.write('.valueOf()')
+ g.write(' ? ')
+ }
+ g.stmts(branch.stmts)
+ }
+ g.inside_ternary = false
+ g.write(')')
+ } else {
+ // mut is_guard = false
+ for i, branch in node.branches {
+ if i == 0 {
+ match branch.cond {
+ ast.IfGuardExpr {
+ // TODO optionals
+ }
+ else {
+ g.write('if (')
+ if '$branch.cond' == 'js' {
+ g.write('true')
+ } else {
+ g.write('(')
+ g.expr(branch.cond)
+ g.write(')')
+ g.write('.valueOf()')
+ }
+ g.writeln(') {')
+ }
+ }
+ } else if i < node.branches.len - 1 || !node.has_else {
+ g.write('} else if (')
+ g.write('(')
+ g.expr(branch.cond)
+ g.write(')')
+ g.write('.valueOf()')
+ g.writeln(') {')
+ } else if i == node.branches.len - 1 && node.has_else {
+ /*
+ if is_guard {
+ //g.writeln('} if (!$guard_ok) { /* else */')
+ } else {
+ */
+ g.writeln('} else {')
+ // }
+ }
+ g.stmts(branch.stmts)
+ }
+ /*
+ if is_guard {
+ g.write('}')
+ }
+ */
+ g.writeln('}')
+ g.writeln('')
+ }
+}
+
+fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
+ left_typ := g.table.get_type_symbol(expr.left_type)
+ // TODO: Handle splice setting if it's implemented
+ if expr.index is ast.RangeExpr {
+ g.expr(expr.left)
+ if expr.left_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.slice(')
+ if expr.index.has_low {
+ g.expr(expr.index.low)
+ } else {
+ g.write('0')
+ }
+ g.write(', ')
+ if expr.index.has_high {
+ g.expr(expr.index.high)
+ } else {
+ g.expr(expr.left)
+ if expr.left_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.length')
+ }
+ g.write(')')
+ } else if left_typ.kind == .map {
+ g.expr(expr.left)
+ if expr.is_setter {
+ g.inside_map_set = true
+ g.write('.map.set(')
+ } else {
+ g.write('.map.get(')
+ }
+ g.expr(expr.index)
+ g.write('.toString()')
+ if !expr.is_setter {
+ g.write(')')
+ }
+ } else if left_typ.kind == .string {
+ if expr.is_setter {
+ // TODO: What's the best way to do this?
+ // 'string'[3] = `o`
+ } else {
+ // TODO: Maybe use u16 there? JS String returns values up to 2^16-1
+ g.write('new byte(')
+ g.expr(expr.left)
+ if expr.left_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.str.charCodeAt(')
+ g.expr(expr.index)
+ g.write('))')
+ }
+ } else {
+ // TODO Does this cover all cases?
+ g.expr(expr.left)
+ if expr.left_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.arr')
+ g.write('[+')
+ g.cast_stack << ast.int_type_idx
+ g.expr(expr.index)
+ g.cast_stack.delete_last()
+ g.write(']')
+ }
+}
+
+fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
+ l_sym := g.table.get_type_symbol(it.left_type)
+ r_sym := g.table.get_type_symbol(it.right_type)
+
+ is_not := it.op in [.not_in, .not_is, .ne]
+ if is_not {
+ g.write('!(')
+ }
+
+ if it.op == .eq || it.op == .ne {
+ // Shallow equatables
+ 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.write(')')
+ g.write('.eq(')
+ g.cast_stack << int(l_sym.kind)
+ g.expr(it.right)
+ g.cast_stack.delete_last()
+ g.write(')')
+ } else {
+ g.write('vEq(')
+ g.expr(it.left)
+ g.write(', ')
+ g.expr(it.right)
+ g.write(')')
+ }
+ } else if l_sym.kind == .array && it.op == .left_shift { // arr << 1
+ g.write('Array.prototype.push.call(')
+ g.expr(it.left)
+ g.write('.arr,')
+ array_info := l_sym.info as ast.Array
+ // arr << [1, 2]
+ if r_sym.kind == .array && array_info.elem_type != it.right_type {
+ g.write('...')
+ }
+ g.expr(it.right)
+ g.write(')')
+ } else if r_sym.kind in [.array, .map, .string] && it.op in [.key_in, .not_in] {
+ g.expr(it.right)
+ if r_sym.kind == .map {
+ g.write('.map.has(')
+ } else if r_sym.kind == .string {
+ g.write('.str.includes(')
+ } else {
+ g.write('.\$includes(')
+ }
+ g.expr(it.left)
+ if l_sym.kind == .string {
+ g.write('.str')
+ }
+ g.write(')')
+ } else if it.op in [.key_is, .not_is] { // foo is Foo
+ g.expr(it.left)
+ g.write(' instanceof ')
+ g.write(g.typ(it.right_type))
+ } else {
+ is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod]
+ mut needs_cast := is_arithmetic && it.left_type != it.right_type
+ mut greater_typ := 0
+ // todo(playX): looks like this cast is always required to perform .eq operation on types.
+ if true || needs_cast {
+ greater_typ = g.greater_typ(it.left_type, it.right_type)
+ if g.cast_stack.len > 0 {
+ needs_cast = g.cast_stack.last() != greater_typ
+ }
+ }
+
+ if true || needs_cast {
+ if g.ns.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('${g.typ(greater_typ)}(')
+ g.cast_stack << greater_typ
+ }
+ g.expr(it.left)
+ g.write(' $it.op ')
+ g.expr(it.right)
+
+ if true || needs_cast {
+ g.cast_stack.delete_last()
+ g.write(')')
+ }
+ }
+
+ if is_not {
+ g.write(')')
+ }
+}
+
+fn (mut g JsGen) greater_typ(left ast.Type, right ast.Type) ast.Type {
+ l := int(left)
+ r := int(right)
+ lr := [l, r]
+ if ast.string_type_idx in lr {
+ return ast.Type(ast.string_type_idx)
+ }
+ should_float := (l in ast.integer_type_idxs && r in ast.float_type_idxs)
+ || (r in ast.integer_type_idxs && l in ast.float_type_idxs)
+ if should_float {
+ if ast.f64_type_idx in lr {
+ return ast.Type(ast.f64_type_idx)
+ }
+ if ast.f32_type_idx in lr {
+ return ast.Type(ast.f32_type_idx)
+ }
+ return ast.Type(ast.float_literal_type)
+ }
+ should_int := (l in ast.integer_type_idxs && r in ast.integer_type_idxs)
+ if should_int {
+ // cant add to u64 - if (ast.u64_type_idx in lr) { return ast.Type(ast.u64_type_idx) }
+ // just guessing this order
+ if ast.i64_type_idx in lr {
+ return ast.Type(ast.i64_type_idx)
+ }
+ if ast.u32_type_idx in lr {
+ return ast.Type(ast.u32_type_idx)
+ }
+ if ast.int_type_idx in lr {
+ return ast.Type(ast.int_type_idx)
+ }
+ if ast.u16_type_idx in lr {
+ return ast.Type(ast.u16_type_idx)
+ }
+ if ast.i16_type_idx in lr {
+ return ast.Type(ast.i16_type_idx)
+ }
+ if ast.byte_type_idx in lr {
+ return ast.Type(ast.byte_type_idx)
+ }
+ if ast.i8_type_idx in lr {
+ return ast.Type(ast.i8_type_idx)
+ }
+ return ast.Type(ast.int_literal_type_idx)
+ }
+ return ast.Type(l)
+}
+
+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 := util.no_dots(key_typ_sym.name)
+ // value_typ_str := util.no_dots(value_typ_sym.name)
+ g.writeln('new map(')
+ g.inc_indent()
+ 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()')
+ }
+ g.dec_indent()
+ g.write(')')
+}
+
+fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
+ g.expr(it.expr)
+ if it.expr_type.is_ptr() {
+ g.write('.valueOf()')
+ }
+ g.write('.$it.field_name')
+}
+
+fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
+ should_cast := !(g.cast_stack.len > 0 && g.cast_stack.last() == ast.string_type_idx)
+ if should_cast {
+ if g.file.mod.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('string(')
+ }
+ g.write('`')
+ for i, val in it.vals {
+ escaped_val := val.replace('`', '\\`')
+ g.write(escaped_val)
+ if i >= it.exprs.len {
+ continue
+ }
+ expr := it.exprs[i]
+ fmt := it.fmts[i]
+ fwidth := it.fwidths[i]
+ precision := it.precisions[i]
+ g.write('\${')
+ if fmt != `_` || fwidth != 0 || precision != 987698 {
+ // TODO: Handle formatting
+ g.expr(expr)
+ } else {
+ sym := g.table.get_type_symbol(it.expr_types[i])
+ g.expr(expr)
+ if sym.kind == .struct_ && sym.has_method('str') {
+ g.write('.str()')
+ }
+ }
+ g.write('}')
+ }
+ g.write('`')
+ if should_cast {
+ g.write(')')
+ }
+}
+
+fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
+ text := it.val.replace("'", "\\'")
+ should_cast := !(g.cast_stack.len > 0 && g.cast_stack.last() == ast.string_type_idx)
+ if true || should_cast {
+ if g.file.mod.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('string(')
+ }
+ g.write("'$text'")
+ if true || should_cast {
+ 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 ast.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 ast.FnType
+ fn_info := info.func
+ mut repr := 'fn ('
+ for i, arg in fn_info.params {
+ if i > 0 {
+ repr += ', '
+ }
+ repr += g.table.get_type_name(arg.typ)
+ }
+ repr += ')'
+ if fn_info.return_type != ast.void_type {
+ repr += ' ${g.table.get_type_name(fn_info.return_type)}'
+ }
+ g.write('"$repr"')
+ } else {
+ g.write('"$sym.name"')
+ }
+}
+
+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)
+ || (it.expr is ast.FloatLiteral && it.typ in ast.float_type_idxs))
+ // Skip cast if type is the same as the parrent caster
+ if g.cast_stack.len > 0 && is_literal {
+ if it.typ == g.cast_stack[g.cast_stack.len - 1] {
+ return
+ }
+ }
+ g.cast_stack << it.typ
+ typ := g.typ(it.typ)
+ if !is_literal {
+ if typ !in js.v_types || g.ns.name == 'builtin' {
+ g.write('new ')
+ }
+ g.write('${typ}(')
+ }
+ g.expr(it.expr)
+ if typ == 'string' && it.expr !is ast.StringLiteral {
+ g.write('.toString()')
+ }
+ if !is_literal {
+ g.write(')')
+ }
+ g.cast_stack.delete_last()
+}
+
+fn (mut g JsGen) gen_integer_literal_expr(it ast.IntegerLiteral) {
+ typ := ast.Type(ast.int_type)
+
+ // Don't wrap integers for use in JS.foo functions.
+ // TODO: call.language always seems to be "v", parser bug?
+ if g.call_stack.len > 0 {
+ call := g.call_stack[g.call_stack.len - 1]
+ if call.language == .js {
+ for t in call.args {
+ if t.expr is ast.IntegerLiteral {
+ if t.expr == it {
+ g.write(it.val)
+ return
+ }
+ }
+ }
+ }
+ }
+
+ // Skip cast if type is the same as the parrent caster
+ if g.cast_stack.len > 0 {
+ if g.cast_stack[g.cast_stack.len - 1] in ast.integer_type_idxs {
+ g.write('new int($it.val)')
+ return
+ }
+ }
+
+ if g.ns.name == 'builtin' {
+ g.write('new ')
+ }
+
+ g.write('${g.typ(typ)}($it.val)')
+}
+
+fn (mut g JsGen) gen_float_literal_expr(it ast.FloatLiteral) {
+ typ := ast.Type(ast.f32_type)
+
+ // Don't wrap integers for use in JS.foo functions.
+ // TODO: call.language always seems to be "v", parser bug?
+ if g.call_stack.len > 0 {
+ call := g.call_stack[g.call_stack.len - 1]
+ // if call.language == .js {
+ for i, t in call.args {
+ if t.expr is ast.FloatLiteral {
+ if t.expr == it {
+ if call.expected_arg_types[i] in ast.integer_type_idxs {
+ g.write(int(it.val.f64()).str())
+ } else {
+ g.write(it.val)
+ }
+ return
+ }
+ }
+ }
+ //}
+ }
+
+ // Skip cast if type is the same as the parrent caster
+ if g.cast_stack.len > 0 {
+ if g.cast_stack[g.cast_stack.len - 1] in ast.float_type_idxs {
+ g.write('new f32($it.val)')
+ return
+ } else if g.cast_stack[g.cast_stack.len - 1] in ast.integer_type_idxs {
+ g.write(int(it.val.f64()).str())
+ return
+ }
+ }
+
+ if g.ns.name == 'builtin' {
+ g.write('new ')
+ }
+
+ g.write('${g.typ(typ)}($it.val)')
+}
+
+fn (mut g JsGen) unwrap_generic(typ ast.Type) ast.Type {
+ if typ.has_flag(.generic) {
+ if t_typ := g.table.resolve_generic_to_concrete(typ, g.table.cur_fn.generic_names,
+ g.table.cur_concrete_types)
+ {
+ return t_typ
+ }
+ }
+ return typ
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/jsdoc.v b/v_windows/v/old/vlib/v/gen/js/jsdoc.v
new file mode 100644
index 0000000..359687e
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/jsdoc.v
@@ -0,0 +1,96 @@
+module js
+
+import v.ast
+
+struct JsDoc {
+mut:
+ gen &JsGen
+}
+
+fn new_jsdoc(gen &JsGen) &JsDoc {
+ return &JsDoc{
+ gen: gen
+ }
+}
+
+fn (mut d JsDoc) write(s string) {
+ if !d.gen.enable_doc {
+ return
+ }
+ d.gen.write(s)
+}
+
+fn (mut d JsDoc) writeln(s string) {
+ if !d.gen.enable_doc {
+ return
+ }
+ d.gen.writeln(s)
+}
+
+fn (mut d JsDoc) gen_typ(typ string) {
+ d.writeln('/** @type {$typ} */')
+}
+
+fn (mut d JsDoc) gen_const(typ string) {
+ d.writeln('/** @constant {$typ} */')
+}
+
+fn (mut d JsDoc) gen_enum() {
+ // Enum values can only be ints for now
+ typ := 'number'
+ d.writeln('/** @enum {$typ} */')
+}
+
+fn (mut d JsDoc) gen_fac_fn(fields []ast.StructField) {
+ d.writeln('/**')
+ d.writeln(' * @constructor')
+ d.write(' * @param {{')
+ for i, field in fields {
+ // Marked as optional: structs have default default values,
+ // so all struct members don't have to be initialized.
+ d.write('$field.name?: ${d.gen.typ(field.typ)}')
+ if i < fields.len - 1 {
+ d.write(', ')
+ }
+ }
+ d.writeln('}} init')
+ d.writeln('*/')
+}
+
+fn (mut d JsDoc) gen_fn(it ast.FnDecl) {
+ type_name := d.gen.typ(it.return_type)
+ d.writeln('/**')
+ d.writeln(' * @function')
+ if it.is_deprecated {
+ d.writeln(' * @deprecated')
+ }
+ for i, arg in it.params {
+ if (it.is_method || it.receiver.typ == 0) && i == 0 {
+ continue
+ }
+ arg_type_name := d.gen.typ(arg.typ)
+ is_varg := i == it.params.len - 1 && it.is_variadic
+ name := d.gen.js_name(arg.name)
+ if is_varg {
+ d.writeln(' * @param {...$arg_type_name} $name')
+ } else {
+ d.writeln(' * @param {$arg_type_name} $name')
+ }
+ }
+ 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.params[1..], method.return_type)
+ method_name := d.gen.js_name(method.name)
+ d.writeln(' * @property {$typ} $method_name')
+ }
+ d.writeln(' */\n')
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/jsgen_test.v b/v_windows/v/old/vlib/v/gen/js/jsgen_test.v
new file mode 100644
index 0000000..06316e8
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/jsgen_test.v
@@ -0,0 +1,86 @@
+import os
+
+const (
+ test_dir = os.join_path('vlib', 'v', 'gen', 'js', 'tests')
+ output_dir = os.join_path(os.temp_dir(), '_js_tests/')
+ v_options = '-b js -w'
+ node_options = ''
+)
+
+fn testsuite_end() {
+ os.rmdir_all(output_dir) or {}
+}
+
+const there_is_node_available = is_nodejs_working()
+
+const there_is_grep_available = is_grep_working()
+
+fn test_example_compilation() {
+ vexe := os.getenv('VEXE')
+ os.chdir(os.dir(vexe))
+ os.mkdir_all(output_dir) or { panic(err) }
+ files := find_test_files()
+ for file in files {
+ path := os.join_path(test_dir, file)
+ println('Testing $file')
+ mut v_options_file := v_options
+ mut node_options_file := node_options
+ should_create_source_map := file.ends_with('_sourcemap.v')
+ if should_create_source_map {
+ println('activate -sourcemap creation')
+ v_options_file += ' -sourcemap' // activate souremap generation
+
+ println('add node option: --enable-source-maps') // requieres node >=12.12.0
+ node_options_file += ' --enable-source-maps' // activate souremap generation
+ }
+ v_code := os.system('$vexe $v_options_file -o $output_dir${file}.js $path')
+ if v_code != 0 {
+ assert false
+ }
+ // Compilation failed
+ assert v_code == 0
+ if !there_is_node_available {
+ println(' ... skipping running $file, there is no NodeJS present')
+ continue
+ }
+ js_code := os.system('node $output_dir${file}.js')
+ if js_code != 0 {
+ assert false
+ }
+ // Running failed
+ assert js_code == 0
+ if should_create_source_map {
+ if there_is_grep_available {
+ grep_code_sourcemap_found := os.system('grep -q -E "//#\\ssourceMappingURL=data:application/json;base64,[-A-Za-z0-9+/=]+$" $output_dir${file}.js')
+ assert grep_code_sourcemap_found == 0
+ println('file has a source map embeded')
+ } else {
+ println(' ... skipping testing for sourcemap $file, there is no grep present')
+ }
+ }
+ }
+}
+
+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
+}
+
+fn is_nodejs_working() bool {
+ node_res := os.execute('node --version')
+ if node_res.exit_code != 0 {
+ return false
+ }
+ return true
+}
+
+fn is_grep_working() bool {
+ node_res := os.execute('grep --version')
+ if node_res.exit_code != 0 {
+ return false
+ }
+ return true
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/program_test.v b/v_windows/v/old/vlib/v/gen/js/program_test.v
new file mode 100644
index 0000000..8ba06ed
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/program_test.v
@@ -0,0 +1,98 @@
+import os
+import term
+import rand
+import v.util.vtest
+import v.util.diff
+
+const vexe = @VEXE
+
+const vroot = @VMODROOT
+
+const diff_cmd = find_diff_cmd()
+
+fn find_diff_cmd() string {
+ return diff.find_working_diff_command() or { '' }
+}
+
+[noreturn]
+fn exit_because(msg string) {
+ eprintln('$msg, tests will not run')
+ exit(0)
+}
+
+fn test_node_exists() {
+ res := os.execute('node --version')
+ if res.exit_code != 0 {
+ exit_because('node does not exist')
+ }
+ if !res.output.starts_with('v') {
+ exit_because('invalid node version')
+ }
+ version := res.output.trim_left('v').int()
+ if version < 10 {
+ exit_because('node should be at least version 10, but is currently version: $version')
+ }
+ println('Using node version: $version')
+}
+
+fn test_running_programs_compiled_with_the_js_backend() ? {
+ os.setenv('VCOLORS', 'never', true)
+ os.chdir(vroot)
+ test_dir := 'vlib/v/gen/js/tests/testdata'
+ main_files := get_main_files_in_dir(test_dir)
+ fails := check_path(test_dir, main_files) ?
+ assert fails == 0
+}
+
+fn get_main_files_in_dir(dir string) []string {
+ mut mfiles := os.walk_ext(dir, '.v')
+ mfiles.sort()
+ return mfiles
+}
+
+fn check_path(dir string, tests []string) ?int {
+ mut nb_fail := 0
+ paths := vtest.filter_vtest_only(tests, basepath: vroot)
+ for path in paths {
+ program := path.replace(vroot + os.path_separator, '')
+ program_out := program.replace('.v', '.out')
+ if !os.exists(program_out) {
+ os.write_file(program_out, '') ?
+ }
+ print(program + ' ')
+ res := os.execute('$vexe -b js_node run $program')
+ if res.exit_code < 0 {
+ panic(res.output)
+ }
+ mut expected := os.read_file(program_out) ?
+ expected = clean_line_endings(expected)
+ found := clean_line_endings(res.output)
+ if expected != found {
+ println(term.red('FAIL'))
+ println('============')
+ println('expected $program_out content:')
+ println(expected)
+ println('============')
+ println('found:')
+ println(found)
+ println('============\n')
+ println('diff:')
+ println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected))
+ println('============\n')
+ nb_fail++
+ } else {
+ println(term.green('OK'))
+ assert true
+ }
+ }
+ return nb_fail
+}
+
+fn clean_line_endings(s string) string {
+ mut res := s.trim_space()
+ res = res.replace(' \n', '\n')
+ res = res.replace(' \r\n', '\n')
+ res = res.replace('\r\n', '\n')
+ res = res.trim('\n')
+ return res
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/basic_test.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/basic_test.v
new file mode 100644
index 0000000..fc61b55
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/basic_test.v
@@ -0,0 +1,158 @@
+module sourcemap
+
+fn test_simple() {
+ mut sg := generate_empty_map()
+ mut sm := sg.add_map('hello.js', '/', true, 0, 0)
+ sm.set_source_content('hello.v', "fn main(){nprintln('Hello World! Helo \$a')\n}")
+
+ mlist := [
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 0
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 2
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 9
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 7
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 10
+ }
+ name: 'hello_name'
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 8
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 13
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 14
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 12
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 27
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 28
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 2
+ gen_column: 29
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ MappingInput{
+ GenPosition: GenPosition{
+ gen_line: 3
+ gen_column: 0
+ }
+ name: ''
+ source_position: SourcePosition{
+ source_line: 1
+ source_column: 0
+ }
+ },
+ ]
+ sm.add_mapping_list('hello.v', mlist) or { panic('x') }
+
+ json_data := sm.to_json()
+
+ expected := '{"version":3,"file":"hello.js","sourceRoot":"\\/","sources":["hello.v"],"sourcesContent":["fn main(){nprintln(\'Hello World! Helo \$a\')\\n}"],"names":["hello_name"],"mappings":"AAAA;AAAA,EAAA,OAAO,CAACA,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA"}'
+ assert json_data.str() == expected
+}
+
+fn test_source_null() {
+ mut sg := generate_empty_map()
+ mut sm := sg.add_map('hello.js', '/', true, 0, 0)
+ sm.add_mapping('hello.v', SourcePosition{
+ source_line: 0
+ source_column: 0
+ }, 1, 1, '')
+ sm.add_mapping('hello_lib1.v', SourcePosition{
+ source_line: 0
+ source_column: 0
+ }, 2, 1, '')
+ sm.add_mapping('hello_lib2.v', SourcePosition{
+ source_line: 0
+ source_column: 0
+ }, 3, 1, '')
+ json_data := sm.to_json()
+
+ expected := '{"version":3,"file":"hello.js","sourceRoot":"\\/","sources":["hello.v","hello_lib1.v","hello_lib2.v"],"sourcesContent":[null,null,null],"names":[],"mappings":"CA+\\/\\/\\/\\/\\/HA;CCAA;CCAA"}'
+ assert json_data.str() == expected
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/compare_test.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/compare_test.v
new file mode 100644
index 0000000..0a755be
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/compare_test.v
@@ -0,0 +1,322 @@
+module sourcemap
+
+fn test_cmp_eq() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: IndexNumber(3)
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: IndexNumber(3)
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert !compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_name() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: IndexNumber(3)
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: IndexNumber(4)
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_name_empty() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: IndexNumber(3)
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_name_empty_empty() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert !compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_source_position_empty_eq() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: Empty{}
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: Empty{}
+ }
+
+ assert !compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_source_position_empty_diff() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: Empty{}
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_source_position_column_diff() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 99
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_source_position_line_diff() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 88
+ source_column: 99
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_sources() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 99
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_gen_column() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 99
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
+
+fn test_cmp_gen_line() {
+ a := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 0
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ b := Mapping{
+ GenPosition: GenPosition{
+ gen_line: 1
+ gen_column: 99
+ }
+ sources_ind: 2
+ names_ind: Empty{}
+ source_position: SourcePosition{
+ source_line: 4
+ source_column: 5
+ }
+ }
+
+ assert compare_by_generated_positions_inflated(a, b)
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/mappings.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/mappings.v
new file mode 100644
index 0000000..d7aff13
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/mappings.v
@@ -0,0 +1,170 @@
+module sourcemap
+
+import v.gen.js.sourcemap.vlq
+import io
+
+struct Empty {}
+
+pub struct SourcePosition {
+ source_line u32
+ source_column u32
+}
+
+type IndexNumber = u32
+type SourcePositionType = Empty | SourcePosition
+type NameIndexType = Empty | IndexNumber
+
+struct GenPosition {
+ gen_line u32
+ gen_column u32
+}
+
+struct MappingInput {
+ GenPosition
+ name string
+ source_position SourcePositionType
+}
+
+struct Mapping {
+ GenPosition
+ sources_ind u32
+ names_ind NameIndexType
+ source_position SourcePositionType
+}
+
+struct Mappings {
+mut:
+ sorted bool
+ last Mapping
+ values []Mapping
+}
+
+fn new_mappings() Mappings {
+ return Mappings{
+ last: Mapping{
+ GenPosition: GenPosition{
+ gen_column: 0
+ gen_line: 0
+ }
+ }
+ sorted: true
+ }
+}
+
+// Add the given source mapping
+fn (mut m Mappings) add_mapping(gen_line u32, gen_column u32, sources_ind u32, source_position SourcePositionType, names_ind NameIndexType) {
+ if !(gen_line > m.last.gen_line
+ || (gen_line == m.last.gen_line && gen_column >= m.last.gen_column)) {
+ m.sorted = false
+ }
+ m.values << Mapping{
+ GenPosition: GenPosition{
+ gen_line: gen_line
+ gen_column: gen_column
+ }
+ sources_ind: sources_ind
+ names_ind: names_ind
+ source_position: source_position
+ }
+}
+
+// Returns the flat, sorted array of mappings. The mappings are sorted by generated position.
+
+fn (mut m Mappings) get_sorted_array() []Mapping {
+ if !m.sorted {
+ panic('not implemented')
+ }
+ return m.values
+}
+
+fn (mut m Mappings) export_mappings(mut output io.Writer) ? {
+ mut previous_generated_line := u32(1)
+ mut previous_generated_column := u32(0)
+ mut previous_source_index := i64(0)
+ mut previous_source_line := i64(0)
+ mut previous_source_column := i64(0)
+ mut previous_name_index := i64(0)
+
+ line_mappings := m.get_sorted_array()
+ len := line_mappings.len
+ for i := 0; i < len; i++ {
+ mapping := line_mappings[i]
+
+ cloned_generated_line := mapping.gen_line
+ if cloned_generated_line > 0 {
+ // Write a ';' for each line between this and last line, way more efficient than storing empty lines or looping...
+ output.write(';'.repeat(int(cloned_generated_line - previous_generated_line)).bytes()) or {
+ panic('Writing vql failed!')
+ }
+ }
+ if cloned_generated_line != previous_generated_line {
+ previous_generated_column = 0
+ previous_generated_line = cloned_generated_line
+ } else {
+ if i > 0 {
+ if !compare_by_generated_positions_inflated(mapping, line_mappings[i - 1]) {
+ continue
+ }
+ output.write(','.bytes()) or { panic('Writing vql failed!') }
+ }
+ }
+
+ vlq.encode(i64(mapping.gen_column - previous_generated_column), mut &output) ?
+ previous_generated_column = mapping.gen_column
+ match mapping.source_position {
+ Empty {}
+ SourcePosition {
+ vlq.encode(i64(mapping.sources_ind - previous_source_index), mut &output) ?
+ previous_source_index = mapping.sources_ind
+ // lines are stored 0-based in SourceMap spec version 3
+ vlq.encode(i64(mapping.source_position.source_line - 1 - previous_source_line), mut
+ output) ?
+ previous_source_line = mapping.source_position.source_line - 1
+ vlq.encode(i64(mapping.source_position.source_column - previous_source_column), mut
+ output) ?
+ previous_source_column = mapping.source_position.source_column
+
+ match mapping.names_ind {
+ Empty {}
+ IndexNumber {
+ vlq.encode(i64(mapping.names_ind - previous_name_index), mut &output) ?
+ previous_name_index = mapping.names_ind
+ }
+ }
+ }
+ }
+ }
+}
+
+fn compare_by_generated_positions_inflated(mapping_a Mapping, mapping_b Mapping) bool {
+ if mapping_a.gen_line != mapping_b.gen_line {
+ return true
+ }
+ if mapping_a.gen_column != mapping_b.gen_column {
+ return true
+ }
+
+ if mapping_a.sources_ind != mapping_b.sources_ind {
+ return true
+ }
+
+ if mapping_a.source_position.type_name() == mapping_b.source_position.type_name()
+ && mapping_a.source_position is SourcePosition
+ && mapping_b.source_position is SourcePosition {
+ if mapping_a.source_position.source_line != mapping_b.source_position.source_line
+ || mapping_a.source_position.source_column != mapping_b.source_position.source_column {
+ return true
+ }
+ } else {
+ if mapping_a.source_position.type_name() != mapping_b.source_position.type_name() {
+ return true
+ }
+ }
+
+ if mapping_a.names_ind.type_name() == mapping_b.names_ind.type_name()
+ && mapping_a.names_ind is IndexNumber && mapping_b.names_ind is IndexNumber {
+ return mapping_a.names_ind != mapping_b.names_ind
+ } else {
+ return mapping_a.names_ind.type_name() != mapping_b.names_ind.type_name()
+ }
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/sets.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/sets.v
new file mode 100644
index 0000000..70f7482
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/sets.v
@@ -0,0 +1,16 @@
+module sourcemap
+
+struct Sets {
+mut:
+ value map[string]u32
+}
+
+// adds a new element to a Set if new and returns index position of new or existing element
+fn (mut s Sets) add(element string) u32 {
+ index := s.value[element] or {
+ index := u32(s.value.len)
+ s.value[element] = index
+ return index
+ }
+ return index
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/source_map.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/source_map.v
new file mode 100644
index 0000000..44f79d1
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/source_map.v
@@ -0,0 +1,131 @@
+module sourcemap
+
+import io
+import os
+import x.json2
+
+const (
+ source_map_version = 3
+)
+
+type SourceMapJson = map[string]json2.Any
+
+struct SourceMap {
+pub mut:
+ version int [json: version]
+ file string [json: file]
+ source_root string [json: source_root]
+ sources Sets [json: sources]
+ sources_content map[string]string
+ names Sets
+ mappings Mappings
+ sources_content_inline bool
+}
+
+struct StringWriter {
+pub mut:
+ bytes []byte
+}
+
+pub fn new_sourcemap(file string, source_root string, sources_content_inline bool) SourceMap {
+ return SourceMap{
+ version: sourcemap.source_map_version
+ file: file
+ source_root: source_root
+ mappings: new_mappings()
+ sources_content_inline: sources_content_inline
+ }
+}
+
+// Add a single mapping from original source line and column to the generated source's line and column for this source map being created.
+pub fn (mut sm SourceMap) add_mapping(source_name string, source_position SourcePositionType, gen_line u32, gen_column u32, name string) {
+ assert source_name.len != 0
+
+ sources_ind := sm.sources.add(source_name)
+
+ names_ind := if name.len != 0 {
+ NameIndexType(IndexNumber(sm.names.add(name)))
+ } else {
+ NameIndexType(Empty{})
+ }
+ sm.mappings.add_mapping(gen_line, gen_column, sources_ind, source_position, names_ind)
+}
+
+// Add multiple mappings from the same source
+pub fn (mut sm SourceMap) add_mapping_list(source_name string, mapping_list []MappingInput) ? {
+ assert source_name.len != 0
+
+ sources_ind := sm.sources.add(source_name)
+
+ for mapping in mapping_list {
+ names_ind := if mapping.name.len != 0 {
+ NameIndexType(IndexNumber(sm.names.add(mapping.name)))
+ } else {
+ NameIndexType(Empty{})
+ }
+ sm.mappings.add_mapping(mapping.gen_line, mapping.gen_column, sources_ind, mapping.source_position,
+ names_ind)
+ }
+}
+
+// Set the source content for a source file.
+pub fn (mut sm SourceMap) set_source_content(source_name string, source_content string) {
+ sm.sources_content[source_name] = source_content
+}
+
+fn (mut sm SourceMap) export_mappings(mut writer io.Writer) {
+ sm.mappings.export_mappings(mut writer) or { panic('export failed') }
+}
+
+fn (mut sm SourceMap) export_mappings_string() string {
+ mut output := StringWriter{}
+
+ sm.mappings.export_mappings(mut output) or { panic('export failed') }
+ return output.bytes.bytestr()
+}
+
+// create a JSON representing the sourcemap
+// Sourcemap Specs http://sourcemaps.info/spec.html
+pub fn (mut sm SourceMap) to_json() SourceMapJson {
+ mut source_map_json := map[string]json2.Any{}
+ source_map_json['version'] = sm.version
+ if sm.file != '' {
+ source_map_json['file'] = json2.Any(sm.file)
+ }
+ if sm.source_root != '' {
+ source_map_json['sourceRoot'] = json2.Any(sm.source_root)
+ }
+ mut sources_json := []json2.Any{}
+ mut sources_content_json := []json2.Any{}
+ for source_file, _ in sm.sources.value {
+ sources_json << source_file
+ if source_file in sm.sources_content {
+ sources_content_json << sm.sources_content[source_file]
+ } else {
+ if sm.sources_content_inline {
+ if source_file_content := os.read_file(source_file) {
+ sources_content_json << source_file_content
+ } else {
+ sources_content_json << json2.null
+ }
+ } else {
+ sources_content_json << json2.null
+ }
+ }
+ }
+ source_map_json['sources'] = json2.Any(sources_json)
+ source_map_json['sourcesContent'] = json2.Any(sources_content_json)
+
+ mut names_json := []json2.Any{}
+ for name, _ in sm.names.value {
+ names_json << name
+ }
+ source_map_json['names'] = json2.Any(names_json)
+ source_map_json['mappings'] = sm.export_mappings_string()
+ return source_map_json
+}
+
+fn (mut w StringWriter) write(buf []byte) ?int {
+ w.bytes << buf
+ return buf.len
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/source_map_generator.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/source_map_generator.v
new file mode 100644
index 0000000..f943286
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/source_map_generator.v
@@ -0,0 +1,46 @@
+module sourcemap
+
+struct V3 {
+ SourceMap
+pub:
+ sections []Section [json: sections]
+}
+
+struct Offset {
+pub mut:
+ line int [json: line]
+ column int [json: column]
+}
+
+struct Section {
+pub mut:
+ offset Offset [json: offset]
+ source_map SourceMap [json: map]
+}
+
+struct Generator {
+mut:
+ file string
+ // source_root string
+ sections []Section
+}
+
+pub fn generate_empty_map() &Generator {
+ return &Generator{}
+}
+
+pub fn (mut g Generator) add_map(file string, source_root string, sources_content_inline bool, line_offset int, column_offset int) &SourceMap {
+ source_map := new_sourcemap(file, source_root, sources_content_inline)
+
+ offset := Offset{
+ line: line_offset
+ column: column_offset
+ }
+
+ g.sections << Section{
+ offset: offset
+ source_map: source_map
+ }
+
+ return &source_map
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq.v
new file mode 100644
index 0000000..7dfef05
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq.v
@@ -0,0 +1,115 @@
+module vlq
+
+import io
+
+const (
+ shift = byte(5)
+ mask = byte((1 << shift) - 1)
+ continued = byte(1 << shift)
+ max_i64 = u64(9223372036854775807)
+
+ // index start is: byte - vlq.enc_char_special_plus
+ enc_index = [62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]!
+
+ enc_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+ enc_char_start_au = 65
+ enc_char_end_zu = 90
+ enc_char_start_al = 97
+ enc_char_end_zl = 122
+ enc_char_start_zero = 48
+ enc_char_end_nine = 57
+ enc_char_special_plus = 43
+ enc_char_special_slash = 47
+)
+
+[inline]
+fn abs64(x i64) u64 {
+ return if x < 0 { u64(-x) } else { u64(x) }
+}
+
+// Decode a single base64 digit.
+[inline]
+fn decode64(input byte) byte {
+ $if debug {
+ assert input >= vlq.enc_char_special_plus
+ assert input <= vlq.enc_char_end_zl
+ }
+ return byte(vlq.enc_index[input - vlq.enc_char_special_plus])
+}
+
+// Decode a single VLQ value from the input stream, returning the value.
+//
+// # Range
+//
+// Supports all numbers that can be represented by a sign bit and a 63 bit
+// absolute value: `[-(2^63 - 1), 2^63 - 1]`.
+//
+// Note that `i64::MIN = -(2^63)` cannot be represented in that form, and this
+// NOT IMPLEMENTED: function will return `Error::Overflowed` when attempting to decode it.
+pub fn decode(mut input io.Reader) ?i64 {
+ mut buf := []byte{len: 1}
+
+ mut accum := u64(0)
+ mut shifter := 0
+ mut digit := byte(0)
+
+ mut keep_going := true
+ for keep_going {
+ len := input.read(mut buf) or { return error('Unexpected EOF') }
+ if len == 0 {
+ return error('no content')
+ }
+ digit = decode64(buf[0])
+ keep_going = (digit & vlq.continued) != 0
+
+ digit_value := u64(digit & vlq.mask) << u32(shifter) // TODO: check Overflow
+
+ accum += digit_value
+ shifter += vlq.shift
+ }
+
+ abs_value := accum / 2
+ if abs_value > vlq.max_i64 {
+ return error('Overflow')
+ }
+
+ // The low bit holds the sign.
+ return if (accum & 1) != 0 { (-i64(abs_value)) } else { i64(abs_value) }
+}
+
+[inline]
+fn encode64(input byte) byte {
+ $if debug {
+ assert input < 64
+ }
+ return vlq.enc_table[input]
+}
+
+// Encode a value as Base64 VLQ, sending it to the writer
+pub fn encode(value i64, mut output io.Writer) ? {
+ signed := value < 0
+ mut value_u64 := abs64(value) << 1
+ if signed {
+ if value_u64 == 0 {
+ // Wrapped
+ value_u64 = vlq.max_i64 + 1
+ }
+ value_u64 |= 1
+ }
+ for {
+ mut digit := byte(value_u64) & vlq.mask
+ value_u64 >>= vlq.shift
+ if value_u64 > 0 {
+ digit |= vlq.continued
+ }
+ bytes := [encode64(digit)]
+ output.write(bytes) or { return error('Write failed') }
+ if value_u64 == 0 {
+ break
+ }
+ }
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v
new file mode 100644
index 0000000..fdb4acf
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v
@@ -0,0 +1,52 @@
+module vlq
+
+import io
+
+struct TestReader {
+pub:
+ bytes []byte
+mut:
+ i int
+}
+
+struct TestData {
+ decode_val string
+ expected i64
+}
+
+type TestDataList = []TestData
+
+fn test_decode_a() ? {
+ decode_values := [
+ TestData{'A', 0},
+ TestData{'C', 1},
+ TestData{'D', -1},
+ TestData{'2H', 123},
+ TestData{'qxmvrH', 123456789},
+ TestData{'+/////B', 1073741823} /* 2^30-1 */,
+ // TestData{'hgggggggggggI', 9_223_372_036_854_775_808} /* 2^63 */,
+ ]
+
+ for _, test_data in decode_values {
+ mut input := make_test_reader(test_data.decode_val)
+
+ res := decode(mut &input) ?
+ assert res == test_data.expected
+ }
+}
+
+fn (mut b TestReader) read(mut buf []byte) ?int {
+ if !(b.i < b.bytes.len) {
+ return none
+ }
+ n := copy(buf, b.bytes[b.i..])
+ b.i += n
+ return n
+}
+
+fn make_test_reader(data string) io.Reader {
+ buf := &TestReader{
+ bytes: data.bytes()
+ }
+ return io.new_buffered_reader(reader: buf)
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_encode_test.v b/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_encode_test.v
new file mode 100644
index 0000000..ad2db3b
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/sourcemap/vlq/vlq_encode_test.v
@@ -0,0 +1,35 @@
+module vlq
+
+struct TestData {
+ expected string
+ data_val i64
+}
+
+struct TestWriter {
+pub mut:
+ bytes []byte
+}
+
+fn test_encode_a() ? {
+ decode_values := [
+ TestData{'A', 0},
+ TestData{'C', 1},
+ TestData{'D', -1},
+ TestData{'2H', 123},
+ TestData{'qxmvrH', 123456789},
+ TestData{'+/////B', 1073741823} /* 2^30-1 */,
+ // TestData{'hgggggggggggI', 9_223_372_036_854_775_808} /* 2^63 */,
+ ]
+ for _, test_data in decode_values {
+ mut output := TestWriter{}
+
+ encode(test_data.data_val, mut &output) ?
+ // dump(output.bytes)
+ assert output.bytes == test_data.expected.bytes()
+ }
+}
+
+fn (mut w TestWriter) write(buf []byte) ?int {
+ w.bytes << buf
+ return buf.len
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/temp_fast_deep_equal.v b/v_windows/v/old/vlib/v/gen/js/temp_fast_deep_equal.v
new file mode 100644
index 0000000..bca6e61
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/temp_fast_deep_equal.v
@@ -0,0 +1,78 @@
+module js
+
+// TODO: Fix msvc bug that's preventing $embed_file('fast_deep_equal.js')
+const (
+ fast_deep_eq_fn = "// https://www.npmjs.com/package/fast-deep-equal - 3/3/2021
+const envHasBigInt64Array = typeof BigInt64Array !== 'undefined';
+function vEq(a, b) {
+ if (a === b) return true;
+
+ if (a && b && typeof a == 'object' && typeof b == 'object') {
+ if (a.constructor !== b.constructor) return false;
+ // we want to convert all V types to JS for comparison.
+ if ('\$toJS' in a)
+ a = a.\$toJS();
+
+ if ('\$toJS' in b)
+ b = b.\$toJS();
+
+ var length, i, keys;
+ if (Array.isArray(a)) {
+ length = a.length;
+ if (length != b.length) return false;
+ for (i = length; i-- !== 0;)
+ if (!vEq(a[i], b[i])) return false;
+ return true;
+ }
+
+
+ if ((a instanceof Map) && (b instanceof Map)) {
+ if (a.size !== b.size) return false;
+ for (i of a.entries())
+ if (!b.has(i[0])) return false;
+ for (i of a.entries())
+ if (!vEq(i[1], b.get(i[0]))) return false;
+ return true;
+ }
+
+ if ((a instanceof Set) && (b instanceof Set)) {
+ if (a.size !== b.size) return false;
+ for (i of a.entries())
+ if (!b.has(i[0])) return false;
+ return true;
+ }
+
+ if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
+ length = a.length;
+ if (length != b.length) return false;
+ for (i = length; i-- !== 0;)
+ if (a[i] !== b[i]) return false;
+ return true;
+ }
+
+
+ if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
+ if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
+ if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
+
+ keys = Object.keys(a);
+ length = keys.length;
+ if (length !== Object.keys(b).length) return false;
+
+ for (i = length; i-- !== 0;)
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
+
+ for (i = length; i-- !== 0;) {
+ var key = keys[i];
+
+ if (!vEq(a[key], b[key])) return false;
+ }
+
+ return true;
+ }
+
+ // true if both NaN, false otherwise
+ return a!==a && b!==b;
+};
+"
+)
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/.gitignore b/v_windows/v/old/vlib/v/gen/js/tests/.gitignore
new file mode 100644
index 0000000..4c43fe6
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/.gitignore
@@ -0,0 +1 @@
+*.js \ No newline at end of file
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/array.v b/v_windows/v/old/vlib/v/gen/js/tests/array.v
new file mode 100644
index 0000000..f07e1b6
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/array.v
@@ -0,0 +1,138 @@
+fn map_cb(s string) string {
+ return 'CB: $s'
+}
+
+fn filter_cb(n int) bool {
+ return n < 4
+}
+
+fn variadic(args ...int) {
+ println(args)
+ println(args[0])
+ println(args[1])
+}
+
+fn vararg_test() {
+ variadic(1, 2, 3)
+}
+
+// TODO Remove `fn main` once vet supports scripts
+fn main() {
+ 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)
+
+ // TODO: This does not work for now
+ // arr2[0..1] = arr2[3..4]
+ // println(arr2)
+
+ // Array push operator
+ arr2 << 6
+ arr2 << [7, 8, 9]
+ println(arr2)
+ println('\n\n')
+
+ // String slices
+ mut slice4 := idx1[..4]
+ print('Back\t=> ')
+ println(slice4) // 'Back'
+
+ // String indexes
+ idx2 := slice4[0]
+ print('66\t=> ')
+ println(idx2)
+ // TODO:
+ // slice4[3] = `c`
+
+ // Maps
+ mut m := map[string]string{}
+ key := 'key'
+ m[key] = 'value'
+ val := m['key']
+ print('value\t=> ')
+ println(val)
+
+ // 'in' / '!in'
+ print('true\t=> ')
+ println('JS' in arr1)
+ print('false\t=> ')
+ println(3 !in arr2)
+ 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 {}
+ println('0 to 8\t=>')
+ for i, _ in arr2 {
+ println(i)
+ }
+ println('\n\n4 to 5\t=> ')
+ for _, v in slice3 {
+ println(v)
+ }
+
+ println(int(1.5))
+
+ println('\n\n')
+
+ // map
+ a := arr1.map('VAL: $it')
+ b := arr1.map(map_cb)
+ c := arr1.map(map_cb(it))
+ d := arr1.map(fn (a string) string {
+ return 'ANON: $a'
+ })
+ // I don't know when this would ever be used,
+ // but it's what the C backend does ¯\_(ツ)_/¯
+ e := arr1.map(456)
+
+ println(a)
+ println(b)
+ println(c)
+ println(d)
+ println(e)
+
+ println('\n\n')
+
+ // filter
+ aa := arr2.filter(it < 4)
+ bb := arr2.filter(filter_cb)
+ cc := arr2.filter(filter_cb(it))
+ dd := arr2.filter(fn (a int) bool {
+ return a < 4
+ })
+
+ 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/v_windows/v/old/vlib/v/gen/js/tests/auto_deref_args.v b/v_windows/v/old/vlib/v/gen/js/tests/auto_deref_args.v
new file mode 100644
index 0000000..a9775e7
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/auto_deref_args.v
@@ -0,0 +1,13 @@
+struct Foo {
+ field &int
+}
+
+fn bar(x int) {
+ println(x)
+}
+
+fn main() {
+ x := 4
+ foo := Foo{&x}
+ bar(foo.field)
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/enum.v b/v_windows/v/old/vlib/v/gen/js/tests/enum.v
new file mode 100644
index 0000000..2d1bfc0
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/enum.v
@@ -0,0 +1,19 @@
+import v.gen.js.tests.hello
+
+enum Test {
+ foo = 2
+ bar = 5
+ baz
+}
+
+// TODO Remove `fn main` once vet supports scripts
+fn main() {
+ mut a := hello.Ccc.a
+ a = .b
+ a = .c
+ println(a)
+
+ mut b := Test.foo
+ b = .bar
+ println(b)
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/hello/hello.js.v b/v_windows/v/old/vlib/v/gen/js/tests/hello/hello.js.v
new file mode 100644
index 0000000..0b3fe40
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/hello/hello.js.v
@@ -0,0 +1,5 @@
+module hello
+
+pub fn raw_js_log() {
+ #console.log('hello')
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/hello/hello.v b/v_windows/v/old/vlib/v/gen/js/tests/hello/hello.v
new file mode 100644
index 0000000..9b75511
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/hello/hello.v
@@ -0,0 +1,33 @@
+module hello
+
+import v.gen.js.tests.hello.hello1
+
+pub const (
+ hello = 'Hello'
+)
+
+pub struct Aaa {
+pub mut:
+ foo string
+}
+
+pub fn (mut a Aaa) update(s string) {
+ a.foo = s
+}
+
+struct Bbb {}
+
+pub enum Ccc {
+ a
+ b = 5
+ c
+}
+
+pub fn debugger() string {
+ v := Bbb{}
+ return hello.hello
+}
+
+pub fn excited() string {
+ return '$hello1.nested() $debugger()!'
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/hello/hello1/hello1.v b/v_windows/v/old/vlib/v/gen/js/tests/hello/hello1/hello1.v
new file mode 100644
index 0000000..030e704
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/hello/hello1/hello1.v
@@ -0,0 +1,5 @@
+module hello1
+
+pub fn nested() string {
+ return 'Nested'
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/interface.v b/v_windows/v/old/vlib/v/gen/js/tests/interface.v
new file mode 100644
index 0000000..a43cadf
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/interface.v
@@ -0,0 +1,47 @@
+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!')
+ }
+}
+
+fn main() {
+ use(Dog{'Doggo', 5})
+ use(Cat{'Nyancat', 6})
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/interp.v b/v_windows/v/old/vlib/v/gen/js/tests/interp.v
new file mode 100644
index 0000000..5b00aa8
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/interp.v
@@ -0,0 +1,188 @@
+fn test_fn(s1 string, s2 string) {
+ print(if s1 == s2 { 'true' } else { 'false' })
+ print('\t=> ')
+ println('"$s1", "$s2"')
+}
+
+fn simple_string_interpolation() {
+ a := 'Hello'
+ b := 'World'
+ res := '$a $b'
+ test_fn(res, 'Hello World')
+}
+
+fn mixed_string_interpolation() {
+ num := 7
+ str := 'abc'
+ s1 := 'number=$num'
+ test_fn(s1, 'number=7')
+ s2 := 'string=$str'
+ test_fn(s2, 'string=abc')
+ s3 := 'a: $num | b: $str'
+ test_fn(s3, 'a: 7 | b: abc')
+}
+
+fn formatted_string_interpolation() {
+ x := 'abc'
+ axb := 'a:$x:b'
+ test_fn(axb, 'a:abc:b')
+ x_10 := 'a:${x:10s}:b'
+ x10_ := 'a:${x:-10s}:b'
+ test_fn(x_10, 'a: abc:b')
+ test_fn(x10_, 'a:abc :b')
+ i := 23
+ si_right := '${i:10d}'
+ si__left := '${i:-10d}'
+ test_fn(si_right, ' 23')
+ test_fn(si__left, '23 ')
+}
+
+/*
+excape_dollar_in_string()
+fn excape_dollar_in_string() {
+ i := 42
+ test_fn('($i)', '(42)')
+ println('(\$i)'.contains('i') && !'(\$i)'.contains('42'))
+ println(!'(\\$i)'.contains('i') && '(\\$i)'.contains('42') && '(\\$i)'.contains('\\'))
+ println('(\\\$i)'.contains('i') && !'(\\\$i)'.contains('42') && '(\\$i)'.contains('\\'))
+ println(!'(\\\\$i)'.contains('i') && '(\\\\$i)'.contains('42') && '(\\\\$i)'.contains('\\\\'))
+ test_fn('(${i})', '(42)')
+ println('(\${i})'.contains('i') && !'(\${i})'.contains('42'))
+ println(!'(\\${i})'.contains('i') && '(\\${i})'.contains('42') && '(\\${i})'.contains('\\'))
+ println('(\\\${i})'.contains('i') && !'(\\\${i})'.contains('42') && '(\\${i})'.contains('\\'))
+ println(!'(\\\\${i})'.contains('i') && '(\\\\${i})'.contains('42') && '(\\\\${i})'.contains('\\\\'))
+ test_fn(i, 42)
+}
+*/
+
+fn implicit_str() {
+ i := 42
+ test_fn('int $i', 'int 42')
+ test_fn('$i', '42')
+ check := '$i' == '42'
+ // println(check)
+ text := '$i' + '42'
+ test_fn(text, '4242')
+}
+
+fn string_interpolation_percent_escaping() {
+ test := 'hello'
+ hello := 'world'
+ x := '%.*s$hello$test |${hello:-30s}|'
+ test_fn(x, '%.*sworldhello |world |')
+}
+
+fn string_interpolation_string_prefix() {
+ // `r`, `c` and `js` are also used as a string prefix.
+ r := 'r'
+ rr := '$r$r'
+ test_fn(rr, 'rr')
+ c := 'c'
+ cc := '$c$c'
+ test_fn(cc, 'cc')
+ js := 'js'
+ jsjs := '$js$js'
+ test_fn(jsjs, 'jsjs')
+}
+
+fn interpolation_string_prefix_expr() {
+ r := 1
+ c := 2
+ js := 1
+ test_fn('>${3 + r}<', '>4<')
+ test_fn('${r == js} $js', 'true 1')
+ test_fn('>${js + c} ${js + r == c}<', '>3 true<')
+}
+
+/*
+inttypes_string_interpolation()
+fn inttypes_string_interpolation() {
+ c := i8(-103)
+ uc := byte(217)
+ uc2 := byte(13)
+ s := i16(-23456)
+ us := u16(54321)
+ i := -1622999040
+ ui := u32(3421958087)
+ vp := voidptr(ui)
+ bp := byteptr(15541149836)
+ l := i64(-7694555558525237396)
+ ul := u64(17234006112912956370)
+ test_fn('$s $us', '-23456 54321')
+ test_fn('$ui $i', '3421958087 -1622999040')
+ test_fn('$l $ul', '-7694555558525237396 17234006112912956370')
+ test_fn('>${s:11}:${us:-13}<', '> -23456:54321 <')
+ test_fn('0x${ul:-19x}:${l:22d}', '0xef2b7d4001165bd2 : -7694555558525237396')
+ test_fn('${c:5}${uc:-7}x', ' -103217 x')
+ test_fn('${c:x}:${uc:x}:${uc2:02X}', '99:d9:0D')
+ test_fn('${s:X}:${us:x}:${u16(uc):04x}', 'A460:d431:00d9')
+ test_fn('${i:x}:${ui:X}:${int(s):x}', '9f430000:CBF6EFC7:ffffa460')
+ test_fn('${l:x}:${ul:X}', '9537727cad98876c:EF2B7D4001165BD2')
+ // default pointer format is platform dependent, so try a few
+ println("platform pointer format: '${vp:p}:$bp'")
+ test_fn('${vp:p}:$bp', '0xcbf6efc7:0x39e53208c' ||
+ '${vp:p}:$bp' == 'CBF6EFC7:39E53208C' ||
+ '${vp:p}:$bp' == 'cbf6efc7:39e53208c' ||
+ '${vp:p}:$bp' == '00000000CBF6EFC7:000000039E53208C')
+}
+*/
+
+fn utf8_string_interpolation() {
+ a := 'à-côté'
+ st := 'Sträßle'
+ m := '10€'
+ test_fn('$a $st $m', 'à-côté Sträßle 10€')
+ zz := '>${a:10}< >${st:-8}< >${m:5}<-'
+ zz_expected := '> à-côté< >Sträßle < > 10€<-'
+ // println(' zz: $zz')
+ // println('zz_expected: $zz_expected')
+ test_fn(zz, zz_expected)
+ // e := '\u20AC' // Eurosign doesn' work with MSVC and tcc
+ e := '€'
+ test_fn('100.00 $e', '100.00 €')
+ m2 := 'Москва́' // cyrillic а́: combination of U+0430 and U+0301, UTF-8: d0 b0 cc 81
+ d := 'Antonín Dvořák' // latin á: U+00E1, UTF-8: c3 a1
+ test_fn(':${m2:7}:${d:-15}:', ': Москва́:Antonín Dvořák :')
+ g := 'Πελοπόννησος'
+ test_fn('>${g:-13}<', '>Πελοπόννησος <')
+}
+
+struct Sss {
+ v1 int
+ v2 f64
+}
+
+fn (s Sss) str() string {
+ return '[$s.v1, ${s.v2:.3f}]'
+}
+
+fn string_interpolation_str_evaluation() {
+ mut x := Sss{17, 13.455893}
+ test_fn('$x', '[17, 13.456]')
+}
+
+/*
+string_interpolation_with_negative_format_width_should_compile_and_run_without_segfaulting()
+fn string_interpolation_with_negative_format_width_should_compile_and_run_without_segfaulting() {
+ // discovered during debugging VLS
+ i := 3
+ input := '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
+ println('---------------------------------------------------------------------------------------------')
+ println('+60 ${i:10} | input.len: ${input.len:10} | ${input.bytes().hex():60} | $input')
+ println('-60 ${i:10} | input.len: ${input.len:10} | ${input.bytes().hex():-60} | $input')
+ println('---------------------------------------------------------------------------------------------')
+ println(true)
+}
+*/
+
+fn main() {
+ 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()
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/js.v b/v_windows/v/old/vlib/v/gen/js/tests/js.v
new file mode 100644
index 0000000..ee7ba08
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/js.v
@@ -0,0 +1,141 @@
+import v.gen.js.tests.hello as hl
+import v.gen.js.tests.hello.hello1 as hl1
+
+const (
+ i_am_a_const = 21214
+ super = 'amazing keyword'
+)
+
+struct Foo {
+mut:
+ a hl.Aaa
+}
+
+struct Companies {
+ google int
+ amazon bool
+ yahoo string
+}
+
+enum POSITION {
+ go_back
+ dont_go_back
+}
+
+fn class(extends string, instanceof int) {
+ delete := instanceof
+ _ = delete
+}
+
+fn main() {
+ println('Hello from V.js!')
+ println(JS.Math.atan2(1, 0))
+ println(JS.eval("console.log('Hello!')"))
+ mut a := 1
+ a *= 2
+ a += 3
+ println(a)
+ mut b := hl.Aaa{}
+ b.update('an update')
+ println(b)
+ mut c := Foo{hl.Aaa{}}
+ c.a.update('another update')
+ println(c)
+ println('int(1.5) == "${int(1.5)}"')
+ d := int(10) + f32(127)
+ println('typeof (int + f32) == "${typeof(d)}"')
+ _ = 'done'
+ {
+ _ = 'block'
+ }
+ _ = POSITION.go_back
+ _ = hl.Ccc.a
+ debugger := 'JS keywords'
+ // TODO: Implement interpolation
+ await := '$super: $debugger'
+ mut finally := 'implemented'
+ println('$await $finally')
+ dun := i_am_a_const * 20 + 2
+ dunn := hl.hello // External constant
+ _ = hl1.nested()
+ for i := 0; i < 10; i++ {
+ }
+ for i, x in 'hello' {
+ }
+ mut evens := []int{}
+ for x in 1 .. 10 {
+ y := error_if_even(x) or { x + 1 }
+ evens << y
+ }
+ println(evens)
+ arr := [1, 2, 3, 4, 5]
+ for i in arr {
+ }
+ ma := map{
+ 'str': 'done'
+ 'ddo': 'baba'
+ }
+ // panic('foo')
+ for m, n in ma {
+ iss := m
+ }
+ go async(0, 'hello')
+ fn_in_var := fn (number int) {
+ println('number: $number')
+ }
+ hl.debugger()
+ anon_consumer(hl.excited(), fn (message string) {
+ println(message)
+ })
+ hl.raw_js_log()
+ propagation() or { println(err) }
+}
+
+fn anon_consumer(greeting string, anon fn (string)) {
+ anon(greeting)
+}
+
+fn async(num int, def string) {
+}
+
+[deprecated; inline]
+fn hello(game_on int, dummy ...string) (int, int) {
+ defer {
+ do := 'not'
+ }
+ for dd in dummy {
+ l := dd
+ }
+ return game_on + 2, 221
+}
+
+fn (it Companies) method() int {
+ ss := Companies{
+ google: 2
+ amazon: true
+ yahoo: 'hello'
+ }
+ a, b := hello(2, 'google', 'not google')
+ glue := if a > 2 {
+ 'more_glue'
+ } else if a > 5 {
+ 'more glueee'
+ } else {
+ 'less glue'
+ }
+ if a != 2 {
+ }
+ return 0
+}
+
+fn error_if_even(num int) ?int {
+ if num % 2 == 0 {
+ return error('number is even')
+ }
+ return num
+}
+
+fn propagation() ? {
+ println('Propagation test:')
+ return error('"Task failed successfully" - Windows XP')
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/life.v b/v_windows/v/old/vlib/v/gen/js/tests/life.v
new file mode 100644
index 0000000..a89da5a
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/life.v
@@ -0,0 +1,98 @@
+fn clear() {
+ JS.console.clear()
+}
+
+const (
+ w = 30
+ h = 30
+)
+
+fn get(game [][]bool, x int, y int) bool {
+ if y < 0 || x < 0 {
+ return false
+ }
+ if y >= h || x >= w {
+ return false
+ }
+
+ return game[y][x]
+}
+
+fn neighbours(game [][]bool, x int, y int) int {
+ mut 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
+}
+
+fn step(game [][]bool) [][]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 in [2, 3]) || count == 3
+ }
+ }
+ return new_game
+}
+
+fn row_str(row []bool) string {
+ mut str := ''
+ for cell in row {
+ if cell {
+ str += '◼ '
+ } else {
+ str += '◻ '
+ }
+ }
+ return str
+}
+
+fn show(game [][]bool) {
+ clear()
+ for row in game {
+ println(row_str(row))
+ }
+}
+
+// TODO Remove `fn main` once vet supports scripts
+fn main() {
+ mut game := [][]bool{len: h, init: []bool{len: w}}
+
+ 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
+
+ JS.setInterval(fn () {
+ show(game)
+ game = step(game)
+ }, 500)
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/optional.v b/v_windows/v/old/vlib/v/gen/js/tests/optional.v
new file mode 100644
index 0000000..6d52eac
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/optional.v
@@ -0,0 +1,33 @@
+module main
+
+fn main() {
+ try_propagation() or { println('captured: $err') }
+}
+
+fn try_propagation() ? {
+ try_numbers() ?
+}
+
+fn try_numbers() ? {
+ for x in 1 .. 10 {
+ y := error_if_even(x) or { x + 1 }
+ println('$x rounded to $y')
+ error_if_prime(y) ?
+ }
+}
+
+fn error_if_even(num int) ?int {
+ if num % 2 == 0 {
+ return error('number is even')
+ }
+ return num
+}
+
+fn error_if_prime(num int) ?int {
+ for i in 2 .. num {
+ if num % i == 0 {
+ return error('$num is prime')
+ }
+ }
+ return num
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/simple.v b/v_windows/v/old/vlib/v/gen/js/tests/simple.v
new file mode 100644
index 0000000..ec46286
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/simple.v
@@ -0,0 +1,5 @@
+module main
+
+fn main() {
+ println('hello world')
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/simple_sourcemap.v b/v_windows/v/old/vlib/v/gen/js/tests/simple_sourcemap.v
new file mode 100644
index 0000000..0dd8a64
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/simple_sourcemap.v
@@ -0,0 +1,23 @@
+module main
+
+fn main() {
+ e := JS.Error{}
+ s := e.stack
+ node_version := js_node_process().version
+ node_main := get_node_main_version(node_version)
+ if node_main >= 12 {
+ if s.contains('simple_sourcemap.v:') {
+ panic('node found no source map!')
+ } else {
+ println('source map is working')
+ }
+ } else {
+ println('skiping test! node version >=12.12.0 required. Current Version is $node_version')
+ }
+}
+
+fn get_node_main_version(str string) int {
+ a := str.slice(1, int(str.len))
+ b := a.split('.')
+ return b[0].int()
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/struct.v b/v_windows/v/old/vlib/v/gen/js/tests/struct.v
new file mode 100644
index 0000000..306d46a
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/struct.v
@@ -0,0 +1,40 @@
+module main
+
+struct Int {
+mut:
+ value int
+ test map[string]int
+ hello []int
+}
+
+fn (mut i Int) add(value int) {
+ i.value += value
+}
+
+fn (i Int) get() int {
+ return i.value
+}
+
+struct Config {
+ foo int
+ bar string
+}
+
+fn use_config(c Config) {
+}
+
+fn main() {
+ mut a := Int{
+ value: 10
+ }
+ a.add(5)
+ println(a) // 15
+ mut b := Int{}
+ b.add(10)
+ println(b.get()) // 10
+ use_config(Config{2, 'bar'})
+ use_config(
+ foo: 2
+ bar: 'bar'
+ )
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/array.out b/v_windows/v/old/vlib/v/gen/js/tests/testdata/array.out
new file mode 100644
index 0000000..b375fcb
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/array.out
@@ -0,0 +1,231 @@
+3
+1
+2
+4
+255
+256
+2
+4
+131
+4
+1
+2
+3
+5
+4
+4
+[1,5,2,3,4]
+5
+4
+5
+[1,5,2,3,4]
+[5,2,3,4]
+4
+[5,3,4]
+3
+[5,3]
+2
+[2.5,3.25,4.5,5.75]
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+1
+2
+3
+10000
+234
+0
+1
+0
+1
+3
+[1,3]
+3
+2
+3
+4
+1
+4
+5
+2
+5
+0
+1
+1.1
+[1,2,3,4]
+[1,5,6,2,3,4]
+0
+1
+1
+0
+1
+1.1
+[1,2,3,4]
+[5,6,1,2,3,4]
+5
+true
+1.1
+1.1
+1.1
+-123
+-123
+-123
+123
+123
+123
+1.1
+1.1
+1.1
+1
+2
+1
+2
+1
+abc
+1
+abc
+0
+abc
+2
+3
+2
+3
+1
+2
+1
+2
+2
+1
+4
+6
+1
+4
+6
+[4,3,2,1]
+true
+true
+true
+true
+true
+true
+true
+0
+[0,0,0,0]
+[0,7,0,0]
+0
+[2,4,6,8,10,12,14,16,18,20]
+[2,4,6,8,10,12,14,16,18,20]
+[2,4,6,8,10]
+2
+[1,2]
+0
+1
+-1
+0
+3
+-1
+0
+2
+-1
+1
+2
+-1
+2
+3
+1
+3
+6
+true
+true
+true
+true
+true
+true
+true
+true
+true
+0
+0
+0
+0
+0
+[2,4,6]
+["is","awesome"]
+[2,3,4,6,8,9,10]
+[4,5,6]
+[5,10]
+[2,4]
+[2,4]
+[1,2,3,4,5,6]
+["v","is","awesome"]
+[0,0,0,0,0,0]
+0
+[10,20,30,40,50,60]
+[1,4,9,16,25,36]
+["1","2","3","4","5","6"]
+[false,true,false,true,false,true]
+["V","IS","AWESOME"]
+[false,false,true]
+[true,true,false]
+[7,7,7]
+[1,4,9,16,25,36]
+[3,4,5,6,7,8]
+[3,9,4,6,12,7]
+[]
+[true,true,true,true,true,true]
+["1a","2a","3a","4a","5a","6a"]
+[2,3,4,5,6,7]
+[2,3,8]
+["1v","2is","3awesome"]
+[1,4,9,16,25,36]
+[1,25,100]
+[1,2,3,4,5,6]
+["v","is","awesome"]
+[2,3,4]
+[2,3,4]
+[3,4,5]
+[2,3,4]
+["1","2","3"]
+["1","2","3"]
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+["1","3","5","hi"]
+[-3,7,42,67,108]
+["a","b","c","d","e","f"]
+0
+1
+79
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/array.v b/v_windows/v/old/vlib/v/gen/js/tests/testdata/array.v
new file mode 100644
index 0000000..8ef56bc
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/array.v
@@ -0,0 +1,771 @@
+struct Chunk {
+ val string
+}
+
+struct Kkk {
+ q []Chunk
+}
+
+const (
+ c_n = 5
+)
+
+struct User {
+ age int
+ name string
+}
+
+fn map_test_helper_1(i int) int {
+ return i * i
+}
+
+fn map_test_helper_2(i int, b string) int {
+ return i + b.len
+}
+
+fn map_test_helper_3(i int, b []string) int {
+ return i + b.map(it.len)[i % b.len]
+}
+
+fn filter_test_helper_1(a int) bool {
+ return a > 3
+}
+
+fn sum(prev int, curr int) int {
+ return prev + curr
+}
+
+fn sub(prev int, curr int) int {
+ return prev - curr
+}
+
+struct Foooj {
+ a [5]int // c_n
+}
+
+fn double_up(mut a []int) {
+ for i := 0; i < a.len; i++ {
+ a[i] = a[i] * 2
+ }
+}
+
+fn double_up_v2(mut a []int) {
+ for i, _ in a {
+ a[i] = a[i] * 2 // or val*2, doesn't matter
+ }
+}
+
+fn modify(mut numbers []int) {
+ numbers[0] = 777
+}
+
+fn main() {
+ {
+ // test pointer
+ mut arr := []&int{}
+ a := 1
+ b := 2
+ c := 3
+ arr << &a
+ arr << &b
+ arr << &c
+ assert *arr[0] == 1
+ arr[1] = &c
+ assert *arr[1] == 3
+ mut d_arr := [arr] // [][]&int
+ d_arr << arr
+ println(*d_arr[0][1]) // 3
+ println(*d_arr[1][0]) // 1
+ }
+ {
+ // test assign
+ mut arr := [2, 4, 8, 16, 32, 64, 128]
+ arr[0] = 2
+ arr[1] &= 255
+ arr[2] |= 255
+ arr[3] <<= 4
+ arr[4] >>= 4
+ arr[5] %= 5
+ arr[6] ^= 3
+ println(arr[0])
+ println(arr[1])
+ println(arr[2])
+ println(arr[3])
+ println(arr[4])
+ println(arr[5])
+ println(arr[6])
+ }
+ {
+ // test ints
+ mut a := [1, 5, 2, 3]
+ println(a.len) // 4
+ println(a[0])
+ println(a[2])
+ println(a.last())
+
+ a << 4
+ println(a.len)
+ println(a[4])
+ println(a.last())
+
+ s := a.str()
+ println(s)
+ println(a[1])
+ println(a.last())
+ }
+ {
+ // test deleting
+ mut a := [1, 5, 2, 3, 4]
+
+ println(a.len)
+ println(a.str())
+
+ a.delete(0)
+
+ println(a.str())
+ println(a.len) // 4
+
+ a.delete(1)
+
+ println(a.str())
+ println(a.len)
+ a.delete(a.len - 1)
+
+ println(a.str())
+ println(a.len)
+ }
+ {
+ // test slice delete
+ mut a := [1.5, 2.5, 3.25, 4.5, 5.75]
+ b := a[2..4]
+ a.delete(0)
+ // assert a == [2.5, 3.25, 4.5, 5.75]
+ // assert b == [3.25, 4.5]
+ println(a)
+ println(a == [2.5, 3.25, 4.5, 5.75])
+ println(b == [3.25, 4.5])
+ a = [3.75, 4.25, -1.5, 2.25, 6.0]
+ c := a[..3]
+ a.delete(2)
+ println(a == [3.75, 4.25, 2.25, 6.0])
+ println(c == [3.75, 4.25, -1.5])
+ }
+ {
+ // test delete many
+ mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9]
+ b := a[2..6]
+ a.delete_many(4, 3)
+ println(a == [1, 2, 3, 4, 8, 9])
+ println(b == [3, 4, 5, 6])
+
+ c := a[..a.len]
+ a.delete_many(2, 0) // this should just clone
+ a[1] = 17
+
+ println(a == [1, 17, 3, 4, 8, 9])
+ println(c == [1, 2, 3, 4, 8, 9])
+ a.delete_many(0, a.len)
+ println(a == []int{})
+ }
+ {
+ // test short
+ a := [1, 2, 3]
+ println(a.len == 3)
+ println(a.cap == 3)
+ println(a[0])
+ println(a[1])
+ println(a[2])
+ }
+ {
+ // test large
+ mut a := [0].repeat(0)
+ for i in 0 .. 10000 {
+ a << i
+ }
+ println(a.len)
+ println(a[234])
+ }
+ {
+ // test empty
+ mut chunks := []Chunk{}
+ a := Chunk{}
+ println(chunks.len)
+ chunks << a
+ println(chunks.len)
+ chunks = []
+ println(chunks.len)
+ chunks << a
+ println(chunks.len)
+ }
+ {
+ // test push
+ mut a := []int{}
+ a << 1
+ a << 3
+ println(a[1])
+ println(a.str())
+ }
+ {
+ // test insert
+ mut a := [1, 2]
+ a.insert(0, 3)
+ println(a[0])
+ println(a[2])
+ println(a.len)
+ a.insert(1, 4)
+ println(a[1])
+ println(a[2])
+ println(a.len)
+ a.insert(4, 5)
+ println(a[4])
+ println(a[3])
+ println(a.len)
+ mut b := []f64{}
+ println(b.len)
+ b.insert(0, f64(1.1))
+ println(b.len)
+ println(b[0])
+ }
+ {
+ // test insert many
+ mut a := [3, 4]
+ a.insert(0, [1, 2])
+ println(a)
+
+ b := [5, 6]
+ a.insert(1, b)
+ println(a)
+ }
+ {
+ // test prepend
+ mut a := []int{}
+ println(a.len)
+ a.prepend(1)
+ println(a.len)
+ println(a[0])
+ mut b := []f64{}
+
+ println(b.len)
+
+ b.prepend(f64(1.1))
+
+ println(b.len)
+
+ println(b[0])
+ }
+ {
+ // test prepend many
+ mut a := [3, 4]
+ a.prepend([1, 2])
+ println(a)
+ b := [5, 6]
+ a.prepend(b)
+ println(a)
+ }
+ {
+ // test repeat
+ {
+ a := [0].repeat(5)
+ println(a.len)
+ println(a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0 && a[4] == 0)
+ }
+ {
+ a := [1.1].repeat(10)
+ println(a[0])
+ println(a[5])
+ println(a[9])
+ }
+ {
+ a := [i64(-123)].repeat(10)
+ println(a[0])
+ println(a[5])
+ println(a[9])
+ }
+ {
+ a := [u64(123)].repeat(10)
+ println(a[0])
+ println(a[5])
+ println(a[9])
+ }
+ {
+ a := [1.1].repeat(10)
+ println(a[0])
+ println(a[5])
+ println(a[9])
+ }
+ {
+ a := [1, 2].repeat(2)
+ println(a[0])
+ println(a[1])
+ println(a[2])
+ println(a[3])
+ }
+ {
+ a := ['1', 'abc'].repeat(2)
+ println(a[0])
+ println(a[1])
+ println(a[2])
+ println(a[3])
+ }
+ {
+ mut a := ['1', 'abc'].repeat(0)
+ println(a.len)
+ a << 'abc'
+ println(a[0])
+ }
+ }
+ {
+ // todo(playX): deep repeat does not yet work.
+ /*
+ // test deep repeat
+ mut a3 := [[[1, 1], [2, 2], [3, 3]], [[4, 4], [5, 5], [6, 6]]]
+ r := a3.repeat(3)
+ a3[1][1][0] = 17
+ print(r)
+ assert r == [
+ [[1, 1], [2, 2], [3, 3]],
+ [[4, 4], [5, 5], [6, 6]],
+ [[1, 1], [2, 2], [3, 3]],
+ [[4, 4], [5, 5], [6, 6]],
+ [[1, 1], [2, 2], [3, 3]],
+ [[4, 4], [5, 5], [6, 6]],
+ ]
+ assert a3 == [[[1, 1], [2, 2], [3, 3]], [[4, 4], [17, 5],
+ [6, 6],
+ ]]
+ */
+ }
+ {
+ // test right
+ a := [1, 2, 3, 4]
+ c := a[1..a.len]
+ d := a[1..]
+ println(c[0])
+ println(c[1])
+ println(d[0])
+ println(d[1])
+ }
+ {
+ // test left
+ a := [1, 2, 3]
+ c := a[0..2]
+ d := a[..2]
+ println(c[0])
+ println(c[1])
+ println(d[0])
+ println(d[1])
+ }
+ {
+ // test slice
+ a := [1, 2, 3, 4]
+ b := a[2..4]
+ println(b.len)
+ println(a[1..2].len)
+ println(a.len)
+ }
+ {
+ // test push many
+ mut a := [1, 2, 3]
+ b := [4, 5, 6]
+ a << b
+ println(a.len)
+ println(a[0])
+ println(a[3])
+ println(a[5])
+ }
+ {
+ // test reverse
+ a := [1, 2, 3, 4]
+ b := ['test', 'array', 'reverse']
+ c := a.reverse()
+ println(c)
+ d := b.reverse()
+ for i, _ in c {
+ println(c[i] == a[a.len - i - 1])
+ }
+ for i, _ in d {
+ println(d[i] == b[b.len - i - 1])
+ }
+ e := []int{}
+ f := e.reverse()
+ println(f.len)
+ }
+ {
+ // test fixed
+ mut nums := [4]int{}
+ // x := nums[1..3]
+ // assert x.len == 2
+
+ println(nums)
+ nums[1] = 7
+ println(nums)
+ nums2 := [5]int{} // c_n
+ println(nums2[c_n - 1])
+ }
+ {
+ // test mut slice
+ /*
+ todo(playX): slices do not work yet. We have to implement custom wrapper for them.
+ mut n := [1, 2, 3]
+ // modify(mut n)
+ modify(mut n[..2])
+ assert n[0] == 777
+ modify(mut n[2..])
+ assert n[2] == 777
+ println(n)
+ */
+ }
+ {
+ // test mut arg
+ mut arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ double_up(mut arr)
+ println(arr.str())
+ arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ double_up_v2(mut arr)
+ println(arr.str())
+ }
+ {
+ // test doubling
+ mut nums := [1, 2, 3, 4, 5]
+ for i in 0 .. nums.len {
+ nums[i] *= 2
+ }
+ println(nums.str())
+ }
+ {
+ // test single element
+
+ mut a := [1]
+ a << 2
+ println(a.len)
+ assert a[0] == 1
+ assert a[1] == 2
+ println(a)
+ }
+ {
+ // test find index
+
+ // string
+ a := ['v', 'is', 'great']
+ println(a.index('v'))
+ println(a.index('is'))
+ println(a.index('gre'))
+ // int
+ b := [1, 2, 3, 4]
+ println(b.index(1))
+ println(b.index(4))
+ println(b.index(5))
+ // byte
+ c := [0x22, 0x33, 0x55]
+ println(c.index(0x22))
+ println(c.index(0x55))
+ println(c.index(0x99))
+ // char
+ d := [`a`, `b`, `c`]
+ println(d.index(`b`))
+ println(d.index(`c`))
+ println(d.index(`u`))
+ }
+ {
+ // test multi
+
+ a := [[1, 2, 3], [4, 5, 6]]
+ println(a.len)
+ println(a[0].len)
+ println(a[0][0])
+ println(a[0][2])
+ println(a[1][2])
+ }
+ {
+ // test in
+ a := [1, 2, 3]
+ println(1 in a)
+ println(2 in a)
+ println(3 in a)
+ println(!(4 in a))
+ println(!(0 in a))
+ println(0 !in a)
+ println(4 !in a)
+ b := [1, 4, 0]
+ c := [3, 6, 2, 0]
+ println(0 in b)
+ println(0 in c)
+ }
+ {
+ // test reduce
+ a := [1, 2, 3, 4, 5]
+ b := a.reduce(sum, 0)
+ c := a.reduce(sum, 5)
+ d := a.reduce(sum, -1)
+ println(b)
+ println(c)
+ println(d)
+ e := [1, 2, 3]
+ f := e.reduce(sub, 0)
+ g := e.reduce(sub, -1)
+ println(f)
+ println(g)
+ }
+ {
+ a := [1, 2, 3, 4, 5, 6]
+ b := a.filter(it % 2 == 0)
+ println(b)
+
+ c := ['v', 'is', 'awesome']
+ d := c.filter(it.len > 1)
+ println(d)
+ assert d[0] == 'is'
+ assert d[1] == 'awesome'
+ ////////
+ arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ println(arr.filter(it % 2 == 0 || it % 3 == 0))
+
+ mut mut_arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ mut_arr = mut_arr.filter(it < 4)
+ assert mut_arr.len == 3
+ println(a.filter(filter_test_helper_1))
+ println([1, 5, 10].filter(filter_test_helper_1))
+ }
+ {
+ // test anon fn filter
+ filter_num := fn (i int) bool {
+ return i % 2 == 0
+ }
+ println([1, 2, 3, 4, 5].filter(filter_num))
+ }
+ {
+ a := [1, 2, 3, 4].filter(fn (i int) bool {
+ return i % 2 == 0
+ })
+ println(a)
+ }
+ {
+ // test map
+ nums := [1, 2, 3, 4, 5, 6]
+ strs := ['v', 'is', 'awesome']
+ // assert nums.map() == <error>
+ // assert nums.map(it, 'excessive') == <error>
+ // identity
+ println(nums.map(it))
+ println(strs.map(it))
+ println(nums.map(it - it))
+ println(nums.map(it - it)[0])
+ // type switch
+ println(nums.map(it * 10))
+ println(nums.map(it * it))
+ println(nums.map('$it'))
+ println(nums.map(it % 2 == 0))
+ println(strs.map(it.to_upper()))
+ println(strs.map(it == 'awesome'))
+ println(strs.map(it.len in nums))
+ println(strs.map(int(7)))
+ // external func
+ println(nums.map(map_test_helper_1(it)))
+ println(nums.map(map_test_helper_2(it, 'bb')))
+ println(nums.map(map_test_helper_3(it, strs)))
+ // empty array as input
+ println([]int{len: 0}.map(it * 2))
+ // nested maps (where it is of same type)
+ println(nums.map(strs.map(int(7)) == [7, 7, 7]))
+ println(nums.map('$it' + strs.map('a')[0]))
+ // assert nums.map(it + strs.map(int(7))[0]) == [8, 9, 10, 11, 12, 13]
+ println(nums.map(it + strs.map(it.len)[0]))
+ println(strs.map(it.len + strs.map(it.len)[0]))
+ // nested (different it types)
+ // todo(playX): this one produces invalid JS code.
+ // assert strs.map(it[nums.map(it - it)[0]]) == [byte(`v`), `i`, `a`]
+ println(nums[0..3].map('$it' + strs.map(it)[it - 1]))
+ println(nums.map(map_test_helper_1))
+ println([1, 5, 10].map(map_test_helper_1))
+ println(nums)
+ println(strs)
+ }
+ {
+ // test anon fn map
+ add_num := fn (i int) int {
+ return i + 1
+ }
+ println([1, 2, 3].map(add_num))
+ }
+ {
+ // test multi anon fn map
+ a := [1, 2, 3].map(fn (i int) int {
+ return i + 1
+ })
+ b := [1, 2, 3].map(fn (i int) int {
+ return i + 2
+ })
+ println(a)
+ println(b)
+ }
+ {
+ // test anon fn arg map
+ a := [1, 2, 3].map(fn (i int) int {
+ return i + 1
+ })
+ println(a)
+ }
+ {
+ // test anon fn arg different type map
+ i_to_str := fn (i int) string {
+ return i.str()
+ }
+ a := [1, 2, 3].map(i_to_str)
+ println(a)
+ }
+ {
+ // test anon fn inline different type map
+ a := [1, 2, 3].map(fn (i int) string {
+ return i.str()
+ })
+ println(a)
+ }
+ {
+ // test array str
+ // todo(playX): JS array formatting should match what default builtin impl has.
+ /*
+ numbers := [1, 2, 3]
+ assert numbers == [1, 2, 3]
+ numbers2 := [numbers, [4, 5, 6]] // dup str() bug
+ println(numbers2)
+ assert true
+ assert numbers.str() == '[1, 2, 3]'
+ */
+ }
+ {
+ // test eq
+ println([5, 6, 7] != [6, 7])
+ println([`a`, `b`] == [`a`, `b`])
+ println([User{
+ age: 22
+ name: 'bob'
+ }] == [User{
+ age: 22
+ name: 'bob'
+ }])
+ // todo(playX): map cmp does not work yet
+ /*
+ assert [map{
+ 'bob': 22
+ }, map{
+ 'tom': 33
+ }] == [map{
+ 'bob': 22
+ }, map{
+ 'tom': 33
+ }]*/
+ println([[1, 2, 3], [4]] == [[1, 2, 3], [4]])
+ }
+ {
+ // test fixed array eq
+ a1 := [1, 2, 3]!
+ println(a1 == [1, 2, 3]!)
+ println(a1 != [2, 3, 4]!)
+
+ a2 := [[1, 2]!, [3, 4]!]!
+ println(a2 == [[1, 2]!, [3, 4]!]!)
+ println(a2 != [[3, 4]!, [1, 2]!]!)
+
+ a3 := [[1, 2], [3, 4]]!
+ println(a3 == [[1, 2], [3, 4]]!)
+ println(a3 != [[1, 1], [2, 2]]!)
+
+ a4 := [[`a`, `b`], [`c`, `d`]]!
+ println(a4 == [[`a`, `b`], [`c`, `d`]]!)
+ println(a4 != [[`c`, `a`], [`a`, `b`]]!)
+
+ a5 := [['aaa', 'bbb'], ['ccc', 'ddd']]!
+ println(a5 == [['aaa', 'bbb'], ['ccc', 'ddd']]!)
+ println(a5 != [['abc', 'def'], ['ccc', 'ddd']]!)
+
+ a6 := [['aaa', 'bbb']!, ['ccc', 'ddd']!]!
+ println(a6 == [['aaa', 'bbb']!, ['ccc', 'ddd']!]!)
+ println(a6 != [['aaa', 'bbb']!, ['aaa', 'ddd']!]!)
+
+ a7 := [[1, 2]!, [3, 4]!]
+ println(a7 == [[1, 2]!, [3, 4]!])
+ println(a7 != [[2, 3]!, [1, 2]!])
+
+ a8 := [['aaa', 'bbb']!, ['ccc', 'ddd']!]
+ println(a8 == [['aaa', 'bbb']!, ['ccc', 'ddd']!])
+ println(a8 != [['bbb', 'aaa']!, ['cccc', 'dddd']!])
+ }
+ {
+ // test fixed array literal eq
+ println([1, 2, 3]! == [1, 2, 3]!)
+ println([1, 1, 1]! != [1, 2, 3]!)
+
+ println([[1, 2], [3, 4]]! == [[1, 2], [3, 4]]!)
+ println([[1, 1], [2, 2]]! != [[1, 2], [3, 4]]!)
+
+ println([[1, 1]!, [2, 2]!]! == [[1, 1]!, [2, 2]!]!)
+ println([[1, 1]!, [2, 2]!]! != [[1, 2]!, [2, 3]!]!)
+
+ println([[1, 1]!, [2, 2]!] == [[1, 1]!, [2, 2]!])
+ println([[1, 1]!, [2, 2]!] != [[1, 2]!, [2, 3]!])
+ }
+ {
+ // test sort
+ mut a := ['hi', '1', '5', '3']
+ a.sort()
+ println(a)
+
+ mut nums := [67, -3, 108, 42, 7]
+ nums.sort()
+ println(nums)
+ assert nums[0] == -3
+ assert nums[1] == 7
+ assert nums[2] == 42
+ assert nums[3] == 67
+ assert nums[4] == 108
+ // todo(playX): add codegen for comparator fn passed
+ /*
+ nums.sort(a < b)
+ assert nums[0] == -3
+ assert nums[1] == 7
+ assert nums[2] == 42
+ assert nums[3] == 67
+ assert nums[4] == 108
+
+ mut users := [User{22, 'Peter'}, User{20, 'Bob'}, User{25, 'Alice'}]
+ users.sort(a.age < b.age)
+ assert users[0].age == 20
+ assert users[1].age == 22
+ assert users[2].age == 25
+ assert users[0].name == 'Bob'
+ assert users[1].name == 'Peter'
+ assert users[2].name == 'Alice'
+
+ users.sort(a.age > b.age)
+ assert users[0].age == 25
+ assert users[1].age == 22
+ assert users[2].age == 20
+
+ users.sort(a.name < b.name) // Test sorting by string fields
+ */
+ }
+ {
+ // test rune sort
+ mut bs := [`f`, `e`, `d`, `b`, `c`, `a`]
+ bs.sort()
+ println(bs)
+
+ /*
+ bs.sort(a > b)
+ println(bs)
+ assert '$bs' == '[`f`, `e`, `d`, `c`, `b`, `a`]'
+
+ bs.sort(a < b)
+ println(bs)
+ assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]'
+ */
+ }
+ {
+ // test f32 sort
+ mut f := [f32(50.0), 15, 1, 79, 38, 0, 27]
+ f.sort()
+ println(f[0])
+ println(f[1])
+ println(f[6])
+ }
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.out b/v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.out
new file mode 100644
index 0000000..d252328
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.out
@@ -0,0 +1,2 @@
+true
+false \ No newline at end of file
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.v b/v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.v
new file mode 100644
index 0000000..8d99196
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/byte_is_space.v
@@ -0,0 +1,4 @@
+x := ' x'
+
+println(x[0].is_space())
+println(x[1].is_space())
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.out b/v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.out
new file mode 100644
index 0000000..2db62ac
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.out
@@ -0,0 +1 @@
+2 > 1 \ No newline at end of file
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.v b/v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.v
new file mode 100644
index 0000000..f214466
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/compare_ints.v
@@ -0,0 +1,15 @@
+if 2 > 1 {
+ println('2 > 1')
+}
+
+if 2 < 1 {
+ println('2 < 1')
+}
+
+if 2 == 1 {
+ println('2 == 1')
+}
+
+if 2 == 0 {
+ println('2 == 0')
+}
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.out b/v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.out
new file mode 100644
index 0000000..95d09f2
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.out
@@ -0,0 +1 @@
+hello world \ No newline at end of file
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.v b/v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.v
new file mode 100644
index 0000000..2a082f9
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/hw.v
@@ -0,0 +1 @@
+println('hello world')
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.out b/v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.out
new file mode 100644
index 0000000..de2a355
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.out
@@ -0,0 +1,3 @@
+Hello V developer
+ Hello V
+Hello V \ No newline at end of file
diff --git a/v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.v b/v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.v
new file mode 100644
index 0000000..1594b48
--- /dev/null
+++ b/v_windows/v/old/vlib/v/gen/js/tests/testdata/string_methods.v
@@ -0,0 +1,3 @@
+println('d Hello V developer'.trim_left(' d'))
+println(' Hello V d'.trim_right(' d'))
+println('WorldHello V'.trim_prefix('World'))