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
mut relative_file := os.real_path(p.get_item<string>(idx))
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'
}
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.
// Remove them after a test passes/fails.
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')
} else if !run_js {
fname.replace('.v', '')
} else {
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 {}
}
}
if !ts.vargs.contains('fmt') {
cmd_options << ' -o "$generated_binary_fpath"'
}

View File

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

View File

@ -1,7 +1,9 @@
module builtin
import strings
/// 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`.
struct array_buffer {
arr JS.Array
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); }
struct array {
mut:
arr array_buffer
pub:
len int
@ -175,8 +178,9 @@ pub fn (a array) index(v string) int {
pub fn (a array) slice(start int, end int) array {
mut result := a
#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
//#v_makeSlice(result)
return result
}
@ -199,7 +203,10 @@ pub fn (mut a array) join(separator string) string {
fn (mut a array) push(val voidptr) {
#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.len.val += 1
}
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)
}
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`
pub fn (mut a array) delete_many(i int, size int) {
#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;}
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,
// resulting in a single output value.
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)
#a.val.arr.make_copy()
#res = a.val.arr.arr.pop()
#a.val.arr.len.val -= 1
return res
}
@ -361,7 +380,6 @@ pub fn (a array) bytestr() string {
return res
}
/*
pub fn (a []string) str() string {
mut sb := strings.new_builder(a.len * 3)
sb.write_string('[')
@ -377,4 +395,4 @@ pub fn (a []string) str() string {
sb.write_string(']')
res := sb.str()
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 cmd := '"$exefile"'
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"'
}
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('\tfor (let i = 0; i < a.len; ++i) {')
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 {
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 {
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 {
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 {
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 {
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}')

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) {')
} else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
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() {
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() {
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() {
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() {
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() {
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 {
fn_builder.writeln('\t\tif (a.arr.get(new int(i)) != b.arr.get(new int(i))) {')
} else {

View File

@ -6,6 +6,102 @@ import v.ast
import v.util
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 {
si_no_str = 0 // no parameter to print only fix string
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('}')
}
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) {
parent_type := typ.clear_flag(.optional)
sym := g.table.get_type_symbol(parent_type)
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 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) {
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 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)
is_arg_ptr := typ.is_ptr()
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 {
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 */')
for typ in info.types {
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()
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
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()
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 {
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()
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);}')
@ -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_str_fn_name := key_styp.replace('*', '') + '_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
@ -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)
elem_str_fn_name := val_styp.replace('*', '') + '_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);}')
@ -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}_str'
} 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)

View File

@ -406,7 +406,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
typ_name: typ_name
val_name: 'arr'
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'
to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))'
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) {
g.call_stack << 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)
if call_return_is_optional {
g.writeln('(function(){')
@ -104,6 +108,13 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
g.inc_indent()
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
if g.table.cur_fn.generic_names.len > 0 {
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.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
} else if left.typ.idx() == right.typ.idx()
&& left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] {
match left.sym.kind {
@ -104,6 +107,9 @@ fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
g.expr(node.right)
g.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
}
.array {
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.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
}
.array_fixed {
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.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
}
.map {
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.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
}
.struct_ {
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.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
}
.sum_type {
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.gen_deref_ptr(node.right_type)
g.write(')')
if node.op == .ne {
g.write('.valueOf()')
}
}
else {}
}
@ -231,22 +252,22 @@ fn (mut g JsGen) infix_expr_left_shift_op(node ast.InfixExpr) {
if left.unaliased_sym.kind == .array {
// arr << val
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)
if right.unaliased_sym.kind == .array && array_info.elem_type != right.typ {
g.expr(node.left)
g.gen_deref_ptr(left.typ)
g.write('.arr.arr,...')
g.write(',')
g.expr(node.right)
g.gen_deref_ptr(right.typ)
g.write('.arr.arr')
g.write(')')
g.write(',true)')
} else {
g.expr(node.left)
g.gen_deref_ptr(left.typ)
g.write('.arr.arr,')
g.write(',')
g.expr(node.right)
g.write(')')
g.write(',false)')
}
} else {
g.gen_plain_infix_expr(node)

View File

@ -64,7 +64,8 @@ mut:
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
generated_str_fns []StrType
str_types []StrType // types that need automatic str() generation
array_fn_definitions []string // array equality functions that have been defined
map_fn_definitions []string // map equality functions that have been defined
struct_fn_definitions []string // struct equality functions that have been defined
@ -156,6 +157,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
// store the current 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 {
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')
}
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
@ -1150,6 +1154,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
is_ptr = true
g.write('.val')
}
if g.inside_map_set && op == .assign {
g.inside_map_set = false
g.write(', ')
@ -1160,6 +1165,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.write(')')
} else {
if is_assign && array_set {
g.write('new ${styp}(')
g.expr(left)
if l_sym.kind == .string {
g.write('.str')
@ -1272,6 +1278,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.write(')')
g.cast_stack.delete_last()
}
if is_assign && array_set {
g.write(')')
}
}
if array_set {
g.write(')')
@ -1741,7 +1750,13 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
g.expr(it.exprs[0])
g.write(')')
} 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.dec_indent()
@ -1762,6 +1777,22 @@ fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) int {
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) {
mut name := g.js_name(node.name)
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(',')
if expr.index.has_low {
g.expr(expr.index.low)
} else {
g.write('0')
g.write('new int(0)')
}
g.write(', ')
if expr.index.has_high {
@ -2407,7 +2439,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.write(')')
}
} 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)
mut ltyp := it.left_type
for ltyp.is_ptr() {

View File

@ -2,6 +2,7 @@ module js
import v.ast
/*
fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
is_shared := etype.has_flag(.shared_f)
mut typ := etype
@ -72,4 +73,75 @@ fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
}
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