js: support running `.js.v` tests in `v test-self`, fixes for array methods & codegen (#12011)

pull/12018/head
playX 2021-09-29 15:33:14 +03:00 committed by GitHub
parent 4ff061927b
commit 4333a53f28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1803 additions and 1610 deletions

View File

@ -268,7 +268,18 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
tls_bench.no_cstep = true tls_bench.no_cstep = true
mut relative_file := os.real_path(p.get_item<string>(idx)) mut relative_file := os.real_path(p.get_item<string>(idx))
mut cmd_options := [ts.vargs] mut cmd_options := [ts.vargs]
if relative_file.contains('global') && !ts.vargs.contains('fmt') { mut run_js := false
is_fmt := ts.vargs.contains('fmt')
if relative_file.ends_with('js.v') {
if !is_fmt {
cmd_options << ' -b js'
}
run_js = true
}
if relative_file.contains('global') && !is_fmt {
cmd_options << ' -enable-globals' cmd_options << ' -enable-globals'
} }
if ts.root_relative { if ts.root_relative {
@ -279,8 +290,10 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
// Ensure that the generated binaries will be stored in the temporary folder. // Ensure that the generated binaries will be stored in the temporary folder.
// Remove them after a test passes/fails. // Remove them after a test passes/fails.
fname := os.file_name(file) fname := os.file_name(file)
generated_binary_fname := if os.user_os() == 'windows' { generated_binary_fname := if os.user_os() == 'windows' && !run_js {
fname.replace('.v', '.exe') fname.replace('.v', '.exe')
} else if !run_js {
fname.replace('.v', '')
} else { } else {
fname.replace('.v', '') fname.replace('.v', '')
} }
@ -290,6 +303,7 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
os.rm(generated_binary_fpath) or {} os.rm(generated_binary_fpath) or {}
} }
} }
if !ts.vargs.contains('fmt') { if !ts.vargs.contains('fmt') {
cmd_options << ' -o "$generated_binary_fpath"' cmd_options << ' -o "$generated_binary_fpath"'
} }

View File

@ -91,6 +91,7 @@ const (
'vlib/net/http/header_test.v', 'vlib/net/http/header_test.v',
'vlib/net/http/server_test.v', 'vlib/net/http/server_test.v',
'vlib/net/http/response_test.v', 'vlib/net/http/response_test.v',
'vlib/builtin/js/array_test.js.v',
] ]
skip_on_linux = [ skip_on_linux = [
'do_not_remove', 'do_not_remove',
@ -142,7 +143,8 @@ fn main() {
args_string := args[1..].join(' ') args_string := args[1..].join(' ')
cmd_prefix := args_string.all_before('test-self') cmd_prefix := args_string.all_before('test-self')
title := 'testing vlib' title := 'testing vlib'
all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v') mut all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v')
all_test_files << os.walk_ext(os.join_path(vroot, 'vlib'), '_test.js.v')
testing.eheader(title) testing.eheader(title)
mut tsession := testing.new_test_session(cmd_prefix, true) mut tsession := testing.new_test_session(cmd_prefix, true)
tsession.files << all_test_files.filter(!it.contains('testdata' + os.path_separator)) tsession.files << all_test_files.filter(!it.contains('testdata' + os.path_separator))

View File

@ -1,7 +1,9 @@
module builtin module builtin
import strings
/// Internal representation of `array` type. It is used to implement slices and to make slices behave correctly /// Internal representation of `array` type. It is used to implement slices and to make slices behave correctly
/// it simply stores reference to original array and to index them properly it does index array relative to `index_start`. /// it simply stores reference to original array and to index them properly it does index array relative to `index_start`.
struct array_buffer { struct array_buffer {
arr JS.Array arr JS.Array
index_start int index_start int
@ -43,6 +45,7 @@ fn (mut a array_buffer) set(ix int, val voidptr) {
#array_buffer.prototype.set = function(ix,val) { array_buffer_set(this,ix,val); } #array_buffer.prototype.set = function(ix,val) { array_buffer_set(this,ix,val); }
struct array { struct array {
mut:
arr array_buffer arr array_buffer
pub: pub:
len int len int
@ -175,8 +178,9 @@ pub fn (a array) index(v string) int {
pub fn (a array) slice(start int, end int) array { pub fn (a array) slice(start int, end int) array {
mut result := a mut result := a
#let slice = a.arr.arr.slice(start,end) #let slice = a.arr.arr.slice(start,end)
#result = new array(new array_buffer({arr: a.arr.arr, len: new int(slice.length),cap: new int(slice.length),index_start: new int(start)})) #result = new array(new array_buffer({arr: a.arr.arr, len: new int(slice.length),cap: new int(slice.length),index_start: new int(start),has_slice: new bool(true)}))
#a.arr.has_slice = true #a.arr.has_slice = true
//#v_makeSlice(result)
return result return result
} }
@ -199,7 +203,10 @@ pub fn (mut a array) join(separator string) string {
fn (mut a array) push(val voidptr) { fn (mut a array) push(val voidptr) {
#a.val.arr.make_copy() #a.val.arr.make_copy()
#if (arguments[2] && arguments[2].valueOf()) {a.val.arr.arr.push(...val)} else {
#a.val.arr.arr.push(val) #a.val.arr.arr.push(val)
#}
#a.val.arr.len.val += 1
} }
fn v_filter(arr array, callback fn (voidptr) bool) array { fn v_filter(arr array, callback fn (voidptr) bool) array {
@ -271,6 +278,12 @@ pub fn (mut a array) delete(i int) {
a.delete_many(i, 1) a.delete_many(i, 1)
} }
fn arr_copy(mut dst array, src array, count int) {
for i := 0; i < count; i++ {
dst.arr.set(i, src.arr.get(i))
}
}
// delete_many deletes `size` elements beginning with index `i` // delete_many deletes `size` elements beginning with index `i`
pub fn (mut a array) delete_many(i int, size int) { pub fn (mut a array) delete_many(i int, size int) {
#a.val.arr.make_copy() #a.val.arr.make_copy()
@ -301,6 +314,11 @@ pub fn (mut a array) reverse_in_place() {
#array.prototype.$includes = function (elem) { return this.arr.arr.find(function(e) { return vEq(elem,e); }) !== undefined;} #array.prototype.$includes = function (elem) { return this.arr.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
pub fn (mut a array) clear() {
#a.val.arr.make_copy()
#a.val.arr.arr.clear()
}
// reduce executes a given reducer function on each element of the array, // reduce executes a given reducer function on each element of the array,
// resulting in a single output value. // resulting in a single output value.
pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int { pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
@ -319,6 +337,7 @@ pub fn (mut a array) pop() voidptr {
mut res := voidptr(0) mut res := voidptr(0)
#a.val.arr.make_copy() #a.val.arr.make_copy()
#res = a.val.arr.arr.pop() #res = a.val.arr.arr.pop()
#a.val.arr.len.val -= 1
return res return res
} }
@ -361,7 +380,6 @@ pub fn (a array) bytestr() string {
return res return res
} }
/*
pub fn (a []string) str() string { pub fn (a []string) str() string {
mut sb := strings.new_builder(a.len * 3) mut sb := strings.new_builder(a.len * 3)
sb.write_string('[') sb.write_string('[')
@ -377,4 +395,4 @@ pub fn (a []string) str() string {
sb.write_string(']') sb.write_string(']')
res := sb.str() res := sb.str()
return res return res
}*/ }

File diff suppressed because it is too large Load Diff

View File

@ -121,7 +121,7 @@ fn (mut b Builder) run_compiled_executable_and_exit() {
mut exefile := os.real_path(b.pref.out_name) mut exefile := os.real_path(b.pref.out_name)
mut cmd := '"$exefile"' mut cmd := '"$exefile"'
if b.pref.backend.is_js() { if b.pref.backend.is_js() {
exefile = os.real_path('${b.pref.out_name}.js') exefile = os.real_path('${b.pref.out_name}.js').replace('.js.js', '.js')
cmd = 'node "$exefile"' cmd = 'node "$exefile"'
} }
for arg in b.pref.run_args { for arg in b.pref.run_args {

View File

@ -180,20 +180,20 @@ fn (mut g JsGen) gen_array_contains_method(left_type ast.Type) string {
fn_builder.writeln('function ${fn_name}(a,v) {') fn_builder.writeln('function ${fn_name}(a,v) {')
fn_builder.writeln('\tfor (let i = 0; i < a.len; ++i) {') fn_builder.writeln('\tfor (let i = 0; i < a.len; ++i) {')
if elem_sym.kind == .string { if elem_sym.kind == .string {
fn_builder.writeln('\t\tif (a.arr.arr[i].str == v.str) {') fn_builder.writeln('\t\tif (a.arr.get(new int(i)).str == v.str) {')
} else if elem_sym.kind == .array && left_info.elem_type.nr_muls() == 0 { } else if elem_sym.kind == .array && left_info.elem_type.nr_muls() == 0 {
ptr_typ := g.gen_array_equality_fn(left_info.elem_type) ptr_typ := g.gen_array_equality_fn(left_info.elem_type)
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(a.arr.arr[i],v)) {') fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq(a.arr.get(new int(i)),v).val) {')
} else if elem_sym.kind == .function { } else if elem_sym.kind == .function {
fn_builder.writeln('\t\tif (a.arr.arr[i] == v) {') fn_builder.writeln('\t\tif (a.arr.get(new int(i)) == v) {')
} else if elem_sym.kind == .map && left_info.elem_type.nr_muls() == 0 { } else if elem_sym.kind == .map && left_info.elem_type.nr_muls() == 0 {
ptr_typ := g.gen_map_equality_fn(left_info.elem_type) ptr_typ := g.gen_map_equality_fn(left_info.elem_type)
fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(a.arr.arr[i],v)) {') fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(a.arr.get(new int(i)),v).val) {')
} else if elem_sym.kind == .struct_ && left_info.elem_type.nr_muls() == 0 { } else if elem_sym.kind == .struct_ && left_info.elem_type.nr_muls() == 0 {
ptr_typ := g.gen_struct_equality_fn(left_info.elem_type) ptr_typ := g.gen_struct_equality_fn(left_info.elem_type)
fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(a.arr.arr[i],v)) {') fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq(a.arr.get(new int(i)),v).val) {')
} else { } else {
fn_builder.writeln('\t\tif (vEq(a.arr.arr[i],v)) {') fn_builder.writeln('\t\tif (vEq(a.arr.get(new int(i)),v)) {')
} }
fn_builder.writeln('\t\t\treturn new bool(true);') fn_builder.writeln('\t\t\treturn new bool(true);')
fn_builder.writeln('\t\t}') fn_builder.writeln('\t\t}')

View File

@ -237,22 +237,22 @@ fn (mut g JsGen) gen_fixed_array_equality_fn(left_type ast.Type) string {
fn_builder.writeln('\t\tif (a.arr.get(new int(i)).str != b.arr.get(new int(i)).str) {') fn_builder.writeln('\t\tif (a.arr.get(new int(i)).str != b.arr.get(new int(i)).str) {')
} else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() { } else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
eq_fn := g.gen_sumtype_equality_fn(elem.typ) eq_fn := g.gen_sumtype_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(a.arr.get(new int(i)), b.arr.get(new int(i)))) {') fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
} else if elem.sym.kind == .struct_ && !elem.typ.is_ptr() { } else if elem.sym.kind == .struct_ && !elem.typ.is_ptr() {
eq_fn := g.gen_struct_equality_fn(elem.typ) eq_fn := g.gen_struct_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(a.arr.get(new int(i)), b.arr.get(new int(i)))) {') fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
} else if elem.sym.kind == .array && !elem.typ.is_ptr() { } else if elem.sym.kind == .array && !elem.typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(elem.typ) eq_fn := g.gen_array_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)), b.arr.get(new int(i)))) {') fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
} else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() { } else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(elem.typ) eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)), b.arr.get(new int(i)))) {') fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
} else if elem.sym.kind == .map && !elem.typ.is_ptr() { } else if elem.sym.kind == .map && !elem.typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(elem.typ) eq_fn := g.gen_map_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(a.arr.get(new int(i)), b.arr.get(new int(i)))) {') fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
} else if elem.sym.kind == .alias && !elem.typ.is_ptr() { } else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
eq_fn := g.gen_alias_equality_fn(elem.typ) eq_fn := g.gen_alias_equality_fn(elem.typ)
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(a.arr.get(new int(i)), b.arr.get(new int(i)))) {') fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(a.arr.get(new int(i)), b.arr.get(new int(i))).val) {')
} else if elem.sym.kind == .function { } else if elem.sym.kind == .function {
fn_builder.writeln('\t\tif (a.arr.get(new int(i)) != b.arr.get(new int(i))) {') fn_builder.writeln('\t\tif (a.arr.get(new int(i)) != b.arr.get(new int(i))) {')
} else { } else {

View File

@ -6,6 +6,102 @@ import v.ast
import v.util import v.util
import strings import strings
struct StrType {
styp string
mut:
typ ast.Type
}
fn (mut g JsGen) get_str_fn(typ ast.Type) string {
mut unwrapped := g.unwrap_generic(typ).set_nr_muls(0).clear_flag(.variadic)
if g.pref.nofloat {
if typ == ast.f32_type {
unwrapped = ast.u32_type
} else if typ == ast.f64_type {
unwrapped = ast.u64_type
}
}
if typ.has_flag(.optional) {
unwrapped.set_flag(.optional)
}
styp := g.typ(unwrapped)
mut sym := g.table.get_type_symbol(unwrapped)
mut str_fn_name := styp_to_str_fn_name(styp)
if mut sym.info is ast.Alias {
if sym.info.is_import {
sym = g.table.get_type_symbol(sym.info.parent_type)
str_fn_name = styp_to_str_fn_name(sym.name)
}
}
g.str_types << StrType{
typ: unwrapped
styp: styp
}
return str_fn_name
}
fn (mut g JsGen) final_gen_str(typ StrType) {
if typ in g.generated_str_fns {
return
}
g.generated_str_fns << typ
sym := g.table.get_type_symbol(typ.typ)
if sym.has_method('str') && !typ.typ.has_flag(.optional) {
return
}
styp := typ.styp
str_fn_name := styp_to_str_fn_name(styp)
if typ.typ.has_flag(.optional) {
g.gen_str_for_option(typ.typ, styp, str_fn_name)
return
}
match mut sym.info {
ast.Alias {
if sym.info.is_import {
g.gen_str_default(sym, styp, str_fn_name)
} else {
g.gen_str_for_alias(sym.info, styp, str_fn_name)
}
}
ast.Array {
g.gen_str_for_array(sym.info, styp, str_fn_name)
}
ast.ArrayFixed {
g.gen_str_for_array_fixed(sym.info, styp, str_fn_name)
}
ast.Enum {
g.gen_str_for_enum(sym.info, styp, str_fn_name)
}
ast.FnType {
g.gen_str_for_fn_type(sym.info, styp, str_fn_name)
}
ast.Struct {
g.gen_str_for_struct(sym.info, styp, str_fn_name)
}
ast.Map {
g.gen_str_for_map(sym.info, styp, str_fn_name)
}
ast.MultiReturn {
g.gen_str_for_multi_return(sym.info, styp, str_fn_name)
}
ast.SumType {
g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name)
}
ast.Interface {
g.gen_str_for_interface(sym.info, styp, str_fn_name)
}
ast.Chan {
g.gen_str_for_chan(sym.info, styp, str_fn_name)
}
ast.Thread {
g.gen_str_for_thread(sym.info, styp, str_fn_name)
}
else {
verror("could not generate string method $str_fn_name for type '$styp'")
}
}
}
pub enum StrIntpType { pub enum StrIntpType {
si_no_str = 0 // no parameter to print only fix string si_no_str = 0 // no parameter to print only fix string
si_c si_c
@ -116,85 +212,11 @@ fn (mut g JsGen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name st
g.definitions.writeln('}') g.definitions.writeln('}')
} }
fn (mut g JsGen) gen_str_for_type(typ ast.Type) string {
styp := g.typ(typ).replace('*', '')
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut str_fn_name := styp_to_str_fn_name(styp)
if mut sym.info is ast.Alias {
if sym.info.is_import {
sym = g.table.get_type_symbol(sym.info.parent_type)
str_fn_name = styp_to_str_fn_name(sym.name)
}
}
sym_has_str_method, str_method_expects_ptr, str_nr_args := sym.str_method_info()
already_generated_key := '$styp:$str_fn_name'
if !sym_has_str_method && already_generated_key !in g.str_types && !typ.has_flag(.optional) {
$if debugautostr ? {
eprintln('> gen_str_for_type: |typ: ${typ:5}, ${sym.name:20}|has_str: ${sym_has_str_method:5}|expects_ptr: ${str_method_expects_ptr:5}|nr_args: ${str_nr_args:1}|fn_name: ${str_fn_name:20}')
}
g.str_types << already_generated_key
match mut sym.info {
ast.Alias {
if sym.info.is_import {
g.gen_str_default(sym, styp, str_fn_name)
} else {
g.gen_str_for_alias(sym.info, styp, str_fn_name)
}
}
ast.Array {
g.gen_str_for_array(sym.info, styp, str_fn_name)
}
ast.ArrayFixed {
g.gen_str_for_array_fixed(sym.info, styp, str_fn_name)
}
ast.Enum {
g.gen_str_for_enum(sym.info, styp, str_fn_name)
}
ast.FnType {
g.gen_str_for_fn_type(sym.info, styp, str_fn_name)
}
ast.Struct {
g.gen_str_for_struct(sym.info, styp, str_fn_name)
}
ast.Map {
g.gen_str_for_map(sym.info, styp, str_fn_name)
}
ast.MultiReturn {
g.gen_str_for_multi_return(sym.info, styp, str_fn_name)
}
ast.SumType {
g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name)
}
ast.Interface {
g.gen_str_for_interface(sym.info, styp, str_fn_name)
}
ast.Chan {
g.gen_str_for_chan(sym.info, styp, str_fn_name)
}
ast.Thread {
g.gen_str_for_thread(sym.info, styp, str_fn_name)
}
else {
panic("could not generate string method $str_fn_name for type '$styp'")
}
}
}
if typ.has_flag(.optional) {
option_already_generated_key := 'option_$already_generated_key'
if option_already_generated_key !in g.str_types {
g.gen_str_for_option(typ, styp, str_fn_name)
g.str_types << option_already_generated_key
}
return str_fn_name
}
return str_fn_name
}
fn (mut g JsGen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string) { fn (mut g JsGen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string) {
parent_type := typ.clear_flag(.optional) parent_type := typ.clear_flag(.optional)
sym := g.table.get_type_symbol(parent_type) sym := g.table.get_type_symbol(parent_type)
sym_has_str_method, _, _ := sym.str_method_info() sym_has_str_method, _, _ := sym.str_method_info()
parent_str_fn_name := g.gen_str_for_type(parent_type) parent_str_fn_name := g.get_str_fn(parent_type)
g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }') g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }')
g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {') g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {')
@ -219,7 +241,7 @@ fn (mut g JsGen) gen_str_for_option(typ ast.Type, styp string, str_fn_name strin
} }
fn (mut g JsGen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string) { fn (mut g JsGen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string) {
parent_str_fn_name := g.gen_str_for_type(info.parent_type) parent_str_fn_name := g.get_str_fn(info.parent_type)
g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }') g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }')
g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {') g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {')
@ -239,7 +261,7 @@ fn (mut g JsGen) gen_str_for_multi_return(info ast.MultiReturn, styp string, str
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
is_arg_ptr := typ.is_ptr() is_arg_ptr := typ.is_ptr()
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
arg_str_fn_name := g.gen_str_for_type(typ) arg_str_fn_name := g.get_str_fn(typ)
if should_use_indent_func(sym.kind) && !sym_has_str_method { if should_use_indent_func(sym.kind) && !sym_has_str_method {
fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}(a.arg$i));') fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}(a.arg$i));')
@ -323,7 +345,7 @@ fn (mut g JsGen) gen_str_for_interface(info ast.Interface, styp string, str_fn_n
fn_builder.writeln('function indent_${str_fn_name}(x,indent_count) { /* gen_str_for_interface */') fn_builder.writeln('function indent_${str_fn_name}(x,indent_count) { /* gen_str_for_interface */')
for typ in info.types { for typ in info.types {
subtype := g.table.get_type_symbol(typ) subtype := g.table.get_type_symbol(typ)
mut func_name := g.gen_str_for_type(typ) mut func_name := g.get_str_fn(typ)
sym_has_str_method, _, _ := subtype.str_method_info() sym_has_str_method, _, _ := subtype.str_method_info()
if should_use_indent_func(subtype.kind) && !sym_has_str_method { if should_use_indent_func(subtype.kind) && !sym_has_str_method {
func_name = 'indent_$func_name' func_name = 'indent_$func_name'
@ -431,7 +453,7 @@ fn (mut g JsGen) gen_str_for_array(info ast.Array, styp string, str_fn_name stri
} }
is_elem_ptr := typ.is_ptr() is_elem_ptr := typ.is_ptr()
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
mut elem_str_fn_name := g.gen_str_for_type(typ) mut elem_str_fn_name := g.get_str_fn(typ)
if sym.kind == .byte { if sym.kind == .byte {
elem_str_fn_name = elem_str_fn_name + '_escaped' elem_str_fn_name = elem_str_fn_name + '_escaped'
} }
@ -490,7 +512,7 @@ fn (mut g JsGen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_f
} }
is_elem_ptr := typ.is_ptr() is_elem_ptr := typ.is_ptr()
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
elem_str_fn_name := g.gen_str_for_type(typ) elem_str_fn_name := g.get_str_fn(typ)
g.definitions.writeln('function ${str_fn_name}(a) { return indent_${str_fn_name}(a, 0);}') g.definitions.writeln('function ${str_fn_name}(a) { return indent_${str_fn_name}(a, 0);}')
@ -545,7 +567,7 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string)
key_styp := g.typ(key_typ) key_styp := g.typ(key_typ)
key_str_fn_name := key_styp.replace('*', '') + '_str' key_str_fn_name := key_styp.replace('*', '') + '_str'
if !key_sym.has_method('str') { if !key_sym.has_method('str') {
g.gen_str_for_type(key_typ) g.get_str_fn(key_typ)
} }
mut val_typ := info.value_type mut val_typ := info.value_type
@ -557,7 +579,7 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string)
val_styp := g.typ(val_typ) val_styp := g.typ(val_typ)
elem_str_fn_name := val_styp.replace('*', '') + '_str' elem_str_fn_name := val_styp.replace('*', '') + '_str'
if !val_sym.has_method('str') { if !val_sym.has_method('str') {
g.gen_str_for_type(val_typ) g.get_str_fn(val_typ)
} }
g.definitions.writeln('function ${str_fn_name}(m) { return indent_${str_fn_name}(m, 0);}') g.definitions.writeln('function ${str_fn_name}(m) { return indent_${str_fn_name}(m, 0);}')
@ -701,7 +723,7 @@ fn (mut g JsGen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name st
field_styp_fn_name := if has_custom_str { field_styp_fn_name := if has_custom_str {
'${field_styp}_str' '${field_styp}_str'
} else { } else {
g.gen_str_for_type(field.typ) g.get_str_fn(field.typ)
} }
mut func := struct_auto_str_func1(mut g, sym, field.typ, field_styp_fn_name, field.name) mut func := struct_auto_str_func1(mut g, sym, field.typ, field_styp_fn_name, field.name)

View File

@ -406,7 +406,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
typ_name: typ_name typ_name: typ_name
val_name: 'arr' val_name: 'arr'
default_value: 'new array_buffer({})' default_value: 'new array_buffer({})'
constructor: 'this.arr = arr\nif (arr.index_start.val != 0) { v_makeSlice(this); } ' constructor: 'this.arr = arr\nif (arr.index_start.val != 0 || arr.has_slice.val) { v_makeSlice(this); } '
value_of: 'this' value_of: 'this'
to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))' to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))'
eq: 'new bool(vEq(self, other))' eq: 'new bool(vEq(self, other))'

View File

@ -96,6 +96,10 @@ fn (mut g JsGen) js_method_call(node ast.CallExpr) {
fn (mut g JsGen) method_call(node ast.CallExpr) { fn (mut g JsGen) method_call(node ast.CallExpr) {
g.call_stack << node g.call_stack << node
it := node it := node
if it.name == 'str' {
g.gen_expr_to_string(node.left, node.left_type)
return
}
call_return_is_optional := it.return_type.has_flag(.optional) call_return_is_optional := it.return_type.has_flag(.optional)
if call_return_is_optional { if call_return_is_optional {
g.writeln('(function(){') g.writeln('(function(){')
@ -104,6 +108,13 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
g.inc_indent() g.inc_indent()
g.write('return builtin.unwrap(') g.write('return builtin.unwrap(')
} }
if node.name == 'str' {
mut rec_type := node.receiver_type
if rec_type.has_flag(.shared_f) {
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
}
g.get_str_fn(rec_type)
}
mut unwrapped_rec_type := node.receiver_type mut unwrapped_rec_type := node.receiver_type
if g.table.cur_fn.generic_names.len > 0 { if g.table.cur_fn.generic_names.len > 0 {
unwrapped_rec_type = g.unwrap_generic(node.receiver_type) unwrapped_rec_type = g.unwrap_generic(node.receiver_type)

View File

@ -89,6 +89,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} else if left.typ.idx() == right.typ.idx() } else if left.typ.idx() == right.typ.idx()
&& left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] { && left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] {
match left.sym.kind { match left.sym.kind {
@ -104,6 +107,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} }
.array { .array {
ptr_typ := g.gen_array_equality_fn(left.unaliased.clear_flag(.shared_f)) ptr_typ := g.gen_array_equality_fn(left.unaliased.clear_flag(.shared_f))
@ -117,6 +123,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} }
.array_fixed { .array_fixed {
ptr_typ := g.gen_fixed_array_equality_fn(left.unaliased) ptr_typ := g.gen_fixed_array_equality_fn(left.unaliased)
@ -130,6 +139,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} }
.map { .map {
ptr_typ := g.gen_map_equality_fn(left.unaliased) ptr_typ := g.gen_map_equality_fn(left.unaliased)
@ -143,6 +155,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} }
.struct_ { .struct_ {
ptr_typ := g.gen_struct_equality_fn(left.unaliased) ptr_typ := g.gen_struct_equality_fn(left.unaliased)
@ -156,6 +171,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} }
.sum_type { .sum_type {
ptr_typ := g.gen_sumtype_equality_fn(left.unaliased) ptr_typ := g.gen_sumtype_equality_fn(left.unaliased)
@ -170,6 +188,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write(')') g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} }
else {} else {}
} }
@ -231,22 +252,22 @@ fn (mut g JsGen) infix_expr_left_shift_op(node ast.InfixExpr) {
if left.unaliased_sym.kind == .array { if left.unaliased_sym.kind == .array {
// arr << val // arr << val
array_info := left.unaliased_sym.info as ast.Array array_info := left.unaliased_sym.info as ast.Array
g.write('Array.prototype.push.call(') g.write('array_push(')
//&& array_info.elem_type != g.unwrap_generic(node.right_type) //&& array_info.elem_type != g.unwrap_generic(node.right_type)
if right.unaliased_sym.kind == .array && array_info.elem_type != right.typ { if right.unaliased_sym.kind == .array && array_info.elem_type != right.typ {
g.expr(node.left) g.expr(node.left)
g.gen_deref_ptr(left.typ) g.gen_deref_ptr(left.typ)
g.write('.arr.arr,...') g.write(',')
g.expr(node.right) g.expr(node.right)
g.gen_deref_ptr(right.typ) g.gen_deref_ptr(right.typ)
g.write('.arr.arr') g.write('.arr.arr')
g.write(')') g.write(',true)')
} else { } else {
g.expr(node.left) g.expr(node.left)
g.gen_deref_ptr(left.typ) g.gen_deref_ptr(left.typ)
g.write('.arr.arr,') g.write(',')
g.expr(node.right) g.expr(node.right)
g.write(')') g.write(',false)')
} }
} else { } else {
g.gen_plain_infix_expr(node) g.gen_plain_infix_expr(node)

View File

@ -64,14 +64,15 @@ mut:
stmt_start_pos int stmt_start_pos int
defer_stmts []ast.DeferStmt defer_stmts []ast.DeferStmt
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
str_types []string // types that need automatic str() generation generated_str_fns []StrType
array_fn_definitions []string // array equality functions that have been defined str_types []StrType // types that need automatic str() generation
map_fn_definitions []string // map equality functions that have been defined array_fn_definitions []string // array equality functions that have been defined
struct_fn_definitions []string // struct equality functions that have been defined map_fn_definitions []string // map equality functions that have been defined
sumtype_fn_definitions []string // sumtype equality functions that have been defined struct_fn_definitions []string // struct equality functions that have been defined
alias_fn_definitions []string // alias equality functions that have been defined sumtype_fn_definitions []string // sumtype equality functions that have been defined
auto_fn_definitions []string // auto generated functions defination list alias_fn_definitions []string // alias equality functions that have been defined
anon_fn_definitions []string // anon generated functions defination list auto_fn_definitions []string // auto generated functions defination list
anon_fn_definitions []string // anon generated functions defination list
method_fn_decls map[string][]ast.FnDecl method_fn_decls map[string][]ast.FnDecl
builtin_fns []string // Functions defined in `builtin` builtin_fns []string // Functions defined in `builtin`
empty_line bool empty_line bool
@ -156,6 +157,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
// store the current namespace // store the current namespace
g.escape_namespace() g.escape_namespace()
} }
for i := 0; i < g.str_types.len; i++ {
g.final_gen_str(g.str_types[i])
}
if g.pref.is_test { if g.pref.is_test {
g.gen_js_main_for_tests() g.gen_js_main_for_tests()
} }
@ -1031,10 +1035,10 @@ fn (mut g JsGen) gen_assert_single_expr(expr ast.Expr, typ ast.Type) {
g.write('$sym.name') g.write('$sym.name')
} }
else { else {
g.writeln(unknown_value) g.write(unknown_value)
} }
} }
g.write(' /* typeof: ' + expr.type_name() + ' type: ' + typ.str() + ' */ ') // g.writeln(' /* typeof: ' + expr.type_name() + ' type: ' + typ.str() + ' */ ')
} }
// TODO // TODO
@ -1150,6 +1154,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
is_ptr = true is_ptr = true
g.write('.val') g.write('.val')
} }
if g.inside_map_set && op == .assign { if g.inside_map_set && op == .assign {
g.inside_map_set = false g.inside_map_set = false
g.write(', ') g.write(', ')
@ -1160,6 +1165,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.write(')') g.write(')')
} else { } else {
if is_assign && array_set { if is_assign && array_set {
g.write('new ${styp}(')
g.expr(left) g.expr(left)
if l_sym.kind == .string { if l_sym.kind == .string {
g.write('.str') g.write('.str')
@ -1272,6 +1278,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.write(')') g.write(')')
g.cast_stack.delete_last() g.cast_stack.delete_last()
} }
if is_assign && array_set {
g.write(')')
}
} }
if array_set { if array_set {
g.write(')') g.write(')')
@ -1741,7 +1750,13 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
g.expr(it.exprs[0]) g.expr(it.exprs[0])
g.write(')') g.write(')')
} else { } else {
c := g.gen_array_init_values(it.exprs) styp := g.typ(it.elem_type)
c := if styp in js.v_types {
g.gen_array_init_values_prim(it.exprs, styp)
} else {
g.gen_array_init_values(it.exprs)
}
g.write(', len: new int($c), cap: new int($c)') g.write(', len: new int($c), cap: new int($c)')
} }
g.dec_indent() g.dec_indent()
@ -1762,6 +1777,22 @@ fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) int {
return c return c
} }
fn (mut g JsGen) gen_array_init_values_prim(exprs []ast.Expr, typ string) int {
g.write('[')
mut c := 0
for i, expr in exprs {
g.write('new ${typ}(')
g.expr(expr)
g.write(')')
if i < exprs.len - 1 {
g.write(', ')
}
c++
}
g.write(']')
return c
}
fn (mut g JsGen) gen_ident(node ast.Ident) { fn (mut g JsGen) gen_ident(node ast.Ident) {
mut name := g.js_name(node.name) mut name := g.js_name(node.name)
if node.kind == .blank_ident || name in ['', '_'] { if node.kind == .blank_ident || name in ['', '_'] {
@ -2258,10 +2289,11 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
g.write('.valueOf()') g.write('.valueOf()')
} }
g.write(',') g.write(',')
if expr.index.has_low { if expr.index.has_low {
g.expr(expr.index.low) g.expr(expr.index.low)
} else { } else {
g.write('0') g.write('new int(0)')
} }
g.write(', ') g.write(', ')
if expr.index.has_high { if expr.index.has_high {
@ -2407,7 +2439,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.write(')') g.write(')')
} }
} else if l_sym.kind == .array && it.op == .left_shift { // arr << 1 } else if l_sym.kind == .array && it.op == .left_shift { // arr << 1
g.write('Array.prototype.push.call(') g.write('array_push(')
g.expr(it.left) g.expr(it.left)
mut ltyp := it.left_type mut ltyp := it.left_type
for ltyp.is_ptr() { for ltyp.is_ptr() {

View File

@ -2,6 +2,7 @@ module js
import v.ast import v.ast
/*
fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) { fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
is_shared := etype.has_flag(.shared_f) is_shared := etype.has_flag(.shared_f)
mut typ := etype mut typ := etype
@ -72,4 +73,75 @@ fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
} }
g.write(')') g.write(')')
} }
}*/
fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
is_shared := etype.has_flag(.shared_f)
mut typ := etype
if is_shared {
typ = typ.clear_flag(.shared_f).set_nr_muls(0)
}
mut sym := g.table.get_type_symbol(typ)
// when type is alias, print the aliased value
if mut sym.info is ast.Alias {
parent_sym := g.table.get_type_symbol(sym.info.parent_type)
if parent_sym.has_method('str') {
typ = sym.info.parent_type
sym = parent_sym
}
}
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
if typ.has_flag(.variadic) {
str_fn_name := g.get_str_fn(typ)
g.write('${str_fn_name}(')
g.expr(expr)
g.write(')')
} else if typ == ast.string_type {
g.expr(expr)
} else if typ == ast.bool_type {
g.expr(expr)
g.write('.valueOf() ? new string("true") : new string("false")')
} else if sym.kind == .none_ {
g.write('new string("<none>")')
} else if sym.kind == .enum_ {
if expr !is ast.EnumVal {
str_fn_name := g.get_str_fn(typ)
g.write('${str_fn_name}(')
g.expr(expr)
g.write(')')
} else {
g.write('new string("')
g.expr(expr)
g.write('")')
}
} else if sym_has_str_method
|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] {
is_ptr := typ.is_ptr()
is_var_mut := expr.is_auto_deref_var()
str_fn_name := g.get_str_fn(typ)
g.write('${str_fn_name}(')
if str_method_expects_ptr && !is_ptr {
g.write('new \$ref(')
}
g.expr(expr)
if (!str_method_expects_ptr && is_ptr && !is_shared) || is_var_mut {
g.write('.val')
}
g.write(')')
if str_method_expects_ptr && !is_ptr {
g.write(')')
}
} else {
str_fn_name := g.get_str_fn(typ)
g.write('${str_fn_name}(')
if sym.kind != .function {
g.expr(expr)
}
if expr.is_auto_deref_var() {
g.write('.val')
}
g.write(')')
}
} }

View File

@ -1,302 +0,0 @@
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
false
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
[]
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
false
false
false
false
true
true
15
20
14
-6
-7
[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]
[[1, 2, 3], [4, 5, 6]]
false
true
true
true
true
false
true
false
true
false
true
false
true
false
true
false
true
false
true
false
true
false
true
false
true
false
true
false
[1, 3, 5, hi]
[-3, 7, 42, 67, 108]
0
1
79
[0, 1, 15, 27, 38, 50, 79]
[0, 1, 15, 27, 38, 50, 79]
2
[14, 2, 3]
test b
[true, false, true]
1,1
2,2
3,3
4,4
1,1
2,2
3,3
4,4
{ val: 0 }
6
[2, 0, 2, 2]
[[1, 0, 0], [0, 0, 0]]
[[1, 0, 0], [1, 0, 0]]
[abc]
[0, 0, 0, 0]
[2, 2]
[1, 2, 3, 4]
[4, 3, 2, 1]
[c, b, a]
[[5, 6], [3, 4], [1, 2]]
5,5
4
1
xyz
def
abc
3
1
abc
a
3
4
def
a
11
33
[21, 24, 14, 20]
2
3
4
123
123
[[1, 2, 3]]
[[1, 2, 3]]
[[1, 2, 3]]
[[1, 2, 3]]
true
true
true
true
true
false
false
true
true
false
true
0
`exists`: true and `not exists`: false
[[], [], [], []]
[[], [], [123], []]
[{}, {}, {}, {}]
[{}, {}, {123: 123}, {}]
Numbers{
odds: [1, 3, 5]
evens: [2, 4]
}
Numbers{
odds: [3, 5, 7]
evens: [2, 6, 10]
}
[[10, 10, 10], [10, 10, 10], [10, 10, 10]]

File diff suppressed because it is too large Load Diff