js: use prefixed names for functions and global symbols (#11387)
parent
96d4a0777f
commit
72089c4feb
|
@ -119,7 +119,7 @@ pub fn (mut a array) insert_many(i int, val voidptr, size int) {
|
|||
|
||||
pub fn (mut a array) join(separator string) string {
|
||||
mut res := ''
|
||||
#res = new builtin.string(a.val.arr.join(separator +''));
|
||||
#res = new string(a.val.arr.join(separator +''));
|
||||
|
||||
return res
|
||||
}
|
||||
|
@ -128,16 +128,9 @@ fn (a array) push(val voidptr) {
|
|||
#a.arr.push(val)
|
||||
}
|
||||
|
||||
pub fn (a array) str() string {
|
||||
mut res := ''
|
||||
#res = new builtin.string(a + '')
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); }
|
||||
#array.prototype.entries = function () { let result = []; for (const [key,val] of this.arr.entries()) { result.push([new int(key), val]); } return result[Symbol.iterator](); }
|
||||
#array.prototype.map = function(callback) { return new builtin.array(this.arr.map(callback)); }
|
||||
#array.prototype.map = function(callback) { return new array(this.arr.map(callback)); }
|
||||
#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); }
|
||||
#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
|
||||
#array.prototype.any = function (value) {
|
||||
|
@ -251,3 +244,21 @@ 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('[')
|
||||
for i in 0 .. a.len {
|
||||
val := a[i]
|
||||
sb.write_string("'")
|
||||
sb.write_string(val)
|
||||
sb.write_string("'")
|
||||
if i < a.len - 1 {
|
||||
sb.write_string(', ')
|
||||
}
|
||||
}
|
||||
sb.write_string(']')
|
||||
res := sb.str()
|
||||
return res
|
||||
}*/
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
module builtin
|
||||
|
||||
import strings
|
||||
// used to generate JS throw statements.
|
||||
|
||||
pub fn js_throw(s any) {
|
||||
#throw s
|
||||
}
|
||||
|
@ -68,3 +70,12 @@ pub fn unwrap(opt string) string {
|
|||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (r rune) str() string {
|
||||
res := ''
|
||||
mut sb := strings.new_builder(5)
|
||||
#res.str = r.valueOf().toString()
|
||||
sb.write_string(res)
|
||||
|
||||
return sb.str()
|
||||
}
|
||||
|
|
|
@ -14,3 +14,10 @@ pub fn (c byte) is_letter() bool {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
pub fn (c byte) str() string {
|
||||
res := ''
|
||||
#res.str = c.val.toString()
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
module builtin
|
||||
|
||||
pub fn (x f32) str() string {
|
||||
res := ''
|
||||
#res.str = x.val + ''
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (x f64) str() string {
|
||||
res := ''
|
||||
#res.str = x.val + ''
|
||||
|
||||
return res
|
||||
}
|
|
@ -2,7 +2,49 @@ module builtin
|
|||
|
||||
pub fn (i int) str() string {
|
||||
mut res := ''
|
||||
#res = new builtin.string( i )
|
||||
#res = new string( i )
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (i i64) str() string {
|
||||
mut res := ''
|
||||
#res = new string( i )
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (i u32) str() string {
|
||||
mut res := ''
|
||||
#res = new string( i )
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (i u64) str() string {
|
||||
mut res := ''
|
||||
#res = new string( i )
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (i bool) str() string {
|
||||
mut res := ''
|
||||
#res = new string( i )
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (i any) str() string {
|
||||
mut res := ''
|
||||
#res = new string( i.toString() )
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (i int_literal) str() string {
|
||||
res := ''
|
||||
#res.str = i.val.toString()
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -718,3 +718,11 @@ pub fn (s string) split_into_lines() []string {
|
|||
|
||||
return res
|
||||
}
|
||||
|
||||
// replace_once replaces the first occurence of `rep` with the string passed in `with`.
|
||||
pub fn (s string) replace_once(rep string, with_ string) string {
|
||||
s2 := ''
|
||||
#s2.val = s.str.replace(rep.str,with_.str)
|
||||
|
||||
return s2
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn setenv(key string, val string, overwrite bool) {
|
|||
// `getenv` returns the value of the environment variable named by the key.
|
||||
pub fn getenv(key string) string {
|
||||
mut res := ''
|
||||
#if ($ENV[key]) res = new builtin.string($ENV[key])
|
||||
#if ($ENV[key]) res = new string($ENV[key])
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub const (
|
|||
)
|
||||
|
||||
$if js_node {
|
||||
#$process.argv.forEach(function(val,index) { args.arr[index] = new string(val); })
|
||||
#$process.argv.forEach(function(val,index) { os__args.arr[index] = new string(val); })
|
||||
}
|
||||
|
||||
// real_path returns the full absolute path for fpath, with all relative ../../, symlinks and so on resolved.
|
||||
|
@ -55,7 +55,7 @@ pub fn chown(path string, owner int, group int) {
|
|||
pub fn temp_dir() string {
|
||||
mut res := ''
|
||||
$if js_node {
|
||||
#res = new builtin.string($os.tmpdir())
|
||||
#res = new string($os.tmpdir())
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ pub fn temp_dir() string {
|
|||
pub fn home_dir() string {
|
||||
mut res := ''
|
||||
$if js_node {
|
||||
#res = new builtin.string($os.homedir())
|
||||
#res = new string($os.homedir())
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ pub fn execute(cmd string) Result {
|
|||
mut stdout := ''
|
||||
#let commands = cmd.str.split(' ');
|
||||
#let output = $child_process.spawnSync(commands[0],commands.slice(1,commands.length));
|
||||
#exit_code = new builtin.int(output.status)
|
||||
#stdout = new builtin.string(output.stdout + '')
|
||||
#exit_code = new int(output.status)
|
||||
#stdout = newstring(output.stdout + '')
|
||||
|
||||
return Result{
|
||||
exit_code: exit_code
|
||||
|
|
|
@ -45,7 +45,7 @@ pub fn ls(path string) ?[]string {
|
|||
result := []string{}
|
||||
$if js_node {
|
||||
#let i = 0
|
||||
#$fs.readdirSync(path.str).forEach((path) => result.arr[i++] = new builtin.string(path))
|
||||
#$fs.readdirSync(path.str).forEach((path) => result.arr[i++] = new string(path))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ pub fn (mut p Process) stdin_write(s string) {
|
|||
pub fn (mut p Process) stdout_slurp() string {
|
||||
p.check_redirection_call('stdout_slurp')
|
||||
mut res := ''
|
||||
#p.val.pid.stdout.on('data', function (data) { res = new builtin.string(data) })
|
||||
#p.val.pid.stdout.on('data', function (data) { res = new string(data) })
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ pub fn (mut b Builder) writeln(s string) {
|
|||
}
|
||||
|
||||
pub fn (mut b Builder) str() string {
|
||||
b.buf << byte(0)
|
||||
s := ''
|
||||
|
||||
#for (const c of b.val.buf.arr)
|
||||
|
|
|
@ -25,8 +25,8 @@ pub fn (mut b Builder) build_js(v_files []string, out_file string) {
|
|||
}
|
||||
|
||||
pub fn (mut b Builder) compile_js() {
|
||||
mut files := b.get_user_files()
|
||||
files << b.get_builtin_files()
|
||||
mut files := b.get_builtin_files()
|
||||
files << b.get_user_files()
|
||||
b.set_module_lookup_paths()
|
||||
if b.pref.is_verbose {
|
||||
println('all .v files:')
|
||||
|
|
|
@ -1,19 +1,81 @@
|
|||
module js
|
||||
|
||||
import v.ast
|
||||
import strings
|
||||
|
||||
const (
|
||||
special_array_methods = [
|
||||
'sort',
|
||||
'insert',
|
||||
'prepend',
|
||||
'index',
|
||||
'contains',
|
||||
]
|
||||
)
|
||||
|
||||
fn (mut g JsGen) gen_array_index_method(left_type ast.Type) string {
|
||||
unwrap_left_type := g.unwrap_generic(left_type)
|
||||
mut left_sym := g.table.get_type_symbol(unwrap_left_type)
|
||||
mut left_type_str := g.typ(unwrap_left_type).trim('*')
|
||||
fn_name := '${left_type_str}_index'
|
||||
|
||||
if !left_sym.has_method('index') {
|
||||
info := left_sym.info as ast.Array
|
||||
elem_sym := g.table.get_type_symbol(info.elem_type)
|
||||
if elem_sym.kind == .function {
|
||||
left_type_str = 'Array_voidptr'
|
||||
}
|
||||
|
||||
mut fn_builder := strings.new_builder(512)
|
||||
fn_builder.writeln('function ${fn_name}(a, v) {')
|
||||
fn_builder.writeln('\tlet pelem = a.arr;')
|
||||
fn_builder.writeln('\tfor (let i = 0; i < pelem.length; ++i) {')
|
||||
if elem_sym.kind == .string {
|
||||
fn_builder.writeln('\t\tif (pelem[i].str == v.str) {')
|
||||
} else if elem_sym.kind == .array && !info.elem_type.is_ptr() {
|
||||
fn_builder.writeln('\t\tif (vEq(pelem[i], v)) {')
|
||||
} else if elem_sym.kind == .function && !info.elem_type.is_ptr() {
|
||||
fn_builder.writeln('\t\tif ( vEq(pelem[i], v)) {')
|
||||
} else if elem_sym.kind == .map && !info.elem_type.is_ptr() {
|
||||
fn_builder.writeln('\t\tif (vEq(pelem[i], v)) {')
|
||||
} else if elem_sym.kind == .struct_ && !info.elem_type.is_ptr() {
|
||||
fn_builder.writeln('\t\tif (vEq(pelem[i], v)) {')
|
||||
} else {
|
||||
fn_builder.writeln('\t\tif (pelem[i].valueOf() == v.valueOf()) {')
|
||||
}
|
||||
fn_builder.writeln('\t\t\treturn new int(i);')
|
||||
fn_builder.writeln('\t\t}')
|
||||
fn_builder.writeln('\t}')
|
||||
fn_builder.writeln('\treturn new int(-1);')
|
||||
fn_builder.writeln('}')
|
||||
g.definitions.writeln(fn_builder.str())
|
||||
left_sym.register_method(&ast.Fn{
|
||||
name: 'index'
|
||||
params: [ast.Param{
|
||||
typ: unwrap_left_type
|
||||
}, ast.Param{
|
||||
typ: info.elem_type
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
return fn_name
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
||||
node := it
|
||||
|
||||
match node.name {
|
||||
'index' {
|
||||
g.gen_array_index(node)
|
||||
return
|
||||
}
|
||||
'contains' {
|
||||
g.gen_array_contains(node)
|
||||
return
|
||||
}
|
||||
'insert' {
|
||||
g.write('array_')
|
||||
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 {
|
||||
|
@ -21,7 +83,13 @@ fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
|||
} else {
|
||||
g.write('insert(')
|
||||
}
|
||||
|
||||
g.expr(it.left)
|
||||
mut ltyp := it.left_type
|
||||
for ltyp.is_ptr() {
|
||||
g.write('.val')
|
||||
ltyp = ltyp.deref()
|
||||
}
|
||||
g.write(',')
|
||||
g.expr(node.args[0].expr)
|
||||
g.write(',')
|
||||
if is_arg2_array {
|
||||
|
@ -36,6 +104,7 @@ fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
|||
return
|
||||
}
|
||||
'prepend' {
|
||||
g.write('array_')
|
||||
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 {
|
||||
|
@ -43,7 +112,13 @@ fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
|||
} else {
|
||||
g.write('prepend(')
|
||||
}
|
||||
|
||||
g.expr(it.left)
|
||||
mut ltyp := it.left_type
|
||||
for ltyp.is_ptr() {
|
||||
g.write('.val')
|
||||
ltyp = ltyp.deref()
|
||||
}
|
||||
g.write(',')
|
||||
if is_arg_array {
|
||||
g.expr(node.args[0].expr)
|
||||
g.write('.arr, ')
|
||||
|
@ -56,6 +131,7 @@ fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
|||
return
|
||||
}
|
||||
'sort' {
|
||||
g.write('array')
|
||||
rec_sym := g.table.get_type_symbol(node.receiver_type)
|
||||
if rec_sym.kind != .array {
|
||||
println(node.name)
|
||||
|
@ -67,9 +143,24 @@ fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
|||
// `users.sort(a.age > b.age)`
|
||||
|
||||
if node.args.len == 0 {
|
||||
g.write('sort()')
|
||||
g.write('_sort(')
|
||||
g.expr(it.left)
|
||||
mut ltyp := it.left_type
|
||||
for ltyp.is_ptr() {
|
||||
g.write('.val')
|
||||
ltyp = ltyp.deref()
|
||||
}
|
||||
|
||||
g.write(')')
|
||||
return
|
||||
} else {
|
||||
g.expr(it.left)
|
||||
mut ltyp := it.left_type
|
||||
for ltyp.is_ptr() {
|
||||
g.write('.val')
|
||||
ltyp = ltyp.deref()
|
||||
}
|
||||
g.write('.')
|
||||
infix_expr := node.args[0].expr as ast.InfixExpr
|
||||
left_name := infix_expr.left.str()
|
||||
is_reverse := (left_name.starts_with('a') && infix_expr.op == .gt)
|
||||
|
@ -87,3 +178,73 @@ fn (mut g JsGen) gen_array_method_call(it ast.CallExpr) {
|
|||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_array_index(node ast.CallExpr) {
|
||||
fn_name := g.gen_array_index_method(node.left_type)
|
||||
g.write('${fn_name}(')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write(',')
|
||||
g.expr(node.args[0].expr)
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_array_contains(node ast.CallExpr) {
|
||||
fn_name := g.gen_array_contains_method(node.left_type)
|
||||
g.write('${fn_name}(')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write(',')
|
||||
g.expr(node.args[0].expr)
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_array_contains_method(left_type ast.Type) string {
|
||||
mut unwrap_left_type := g.unwrap_generic(left_type)
|
||||
if unwrap_left_type.share() == .shared_t {
|
||||
unwrap_left_type = unwrap_left_type.clear_flag(.shared_f)
|
||||
}
|
||||
mut left_sym := g.table.get_type_symbol(unwrap_left_type)
|
||||
left_final_sym := g.table.get_final_type_symbol(unwrap_left_type)
|
||||
mut left_type_str := g.typ(unwrap_left_type).replace('*', '')
|
||||
fn_name := '${left_type_str}_contains'
|
||||
if !left_sym.has_method('contains') {
|
||||
left_info := left_final_sym.info as ast.Array
|
||||
elem_sym := g.table.get_type_symbol(left_info.elem_type)
|
||||
if elem_sym.kind == .function {
|
||||
left_type_str = 'Array_voidptr'
|
||||
}
|
||||
|
||||
mut fn_builder := strings.new_builder(512)
|
||||
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[i].str == v.str) {')
|
||||
} else if elem_sym.kind == .array && left_info.elem_type.nr_muls() == 0 {
|
||||
fn_builder.writeln('\t\tif (vEq(a.arr[i], v)) {')
|
||||
} else if elem_sym.kind == .function {
|
||||
fn_builder.writeln('\t\tif (a.arr[i] == v) {')
|
||||
} else if elem_sym.kind == .map && left_info.elem_type.nr_muls() == 0 {
|
||||
fn_builder.writeln('\t\tif (vEq(a.arr[i], v)) {')
|
||||
} else if elem_sym.kind == .struct_ && left_info.elem_type.nr_muls() == 0 {
|
||||
fn_builder.writeln('\t\tif (vEq(a.arr[i],v)) {')
|
||||
} else {
|
||||
fn_builder.writeln('\t\tif (a.arr[i].valueOf() == v.valueOf()) {')
|
||||
}
|
||||
fn_builder.writeln('\t\t\treturn new bool(true);')
|
||||
fn_builder.writeln('\t\t}')
|
||||
fn_builder.writeln('\t}')
|
||||
fn_builder.writeln('\treturn new bool(false);')
|
||||
fn_builder.writeln('}')
|
||||
g.definitions.writeln(fn_builder.str())
|
||||
left_sym.register_method(&ast.Fn{
|
||||
name: 'contains'
|
||||
params: [ast.Param{
|
||||
typ: unwrap_left_type
|
||||
}, ast.Param{
|
||||
typ: left_info.elem_type
|
||||
}]
|
||||
})
|
||||
}
|
||||
return fn_name
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
module js
|
|
@ -0,0 +1,789 @@
|
|||
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||
module js
|
||||
|
||||
import v.ast
|
||||
import v.util
|
||||
import strings
|
||||
|
||||
pub enum StrIntpType {
|
||||
si_no_str = 0 // no parameter to print only fix string
|
||||
si_c
|
||||
si_u8
|
||||
si_i8
|
||||
si_u16
|
||||
si_i16
|
||||
si_u32
|
||||
si_i32
|
||||
si_u64
|
||||
si_i64
|
||||
si_e32
|
||||
si_e64
|
||||
si_f32
|
||||
si_f64
|
||||
si_g32
|
||||
si_g64
|
||||
si_s
|
||||
si_p
|
||||
si_vp
|
||||
}
|
||||
|
||||
pub fn type_to_str(x StrIntpType) string {
|
||||
match x {
|
||||
.si_no_str { return 'no_str' }
|
||||
.si_c { return 'c' }
|
||||
.si_u8 { return 'u8' }
|
||||
.si_i8 { return 'i8' }
|
||||
.si_u16 { return 'u16' }
|
||||
.si_i16 { return 'i16' }
|
||||
.si_u32 { return 'u32' }
|
||||
.si_i32 { return 'i32' }
|
||||
.si_u64 { return 'u64' }
|
||||
.si_i64 { return 'i64' }
|
||||
.si_f32 { return 'f32' }
|
||||
.si_f64 { return 'f64' }
|
||||
.si_g32 { return 'f32' } // g32 format use f32 data
|
||||
.si_g64 { return 'f64' } // g64 format use f64 data
|
||||
.si_e32 { return 'f32' } // e32 format use f32 data
|
||||
.si_e64 { return 'f64' } // e64 format use f64 data
|
||||
.si_s { return 's' }
|
||||
.si_p { return 'p' }
|
||||
.si_vp { return 'vp' }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_str(x StrIntpType) string {
|
||||
match x {
|
||||
.si_no_str { return 'no_str' }
|
||||
.si_c { return 'd_c' }
|
||||
.si_u8 { return 'd_u8' }
|
||||
.si_i8 { return 'd_i8' }
|
||||
.si_u16 { return 'd_u16' }
|
||||
.si_i16 { return 'd_i16' }
|
||||
.si_u32 { return 'd_u32' }
|
||||
.si_i32 { return 'd_i32' }
|
||||
.si_u64 { return 'd_u64' }
|
||||
.si_i64 { return 'd_i64' }
|
||||
.si_f32 { return 'd_f32' }
|
||||
.si_f64 { return 'd_f64' }
|
||||
.si_g32 { return 'd_f32' } // g32 format use f32 data
|
||||
.si_g64 { return 'd_f64' } // g64 format use f64 data
|
||||
.si_e32 { return 'd_f32' } // e32 format use f32 data
|
||||
.si_e64 { return 'd_f64' } // e64 format use f64 data
|
||||
.si_s { return 'd_s' }
|
||||
.si_p { return 'd_p' }
|
||||
.si_vp { return 'd_vp' }
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// BUG: this const is not released from the memory! use a const for now
|
||||
// si_s_code = "0x" + int(StrIntpType.si_s).hex() // code for a simple string
|
||||
si_s_code = '0xfe10'
|
||||
)
|
||||
|
||||
fn should_use_indent_func(kind ast.Kind) bool {
|
||||
return kind in [.struct_, .alias, .array, .array_fixed, .map, .sum_type, .interface_]
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name string) {
|
||||
mut convertor := ''
|
||||
mut typename_ := ''
|
||||
if sym.parent_idx in ast.integer_type_idxs {
|
||||
convertor = 'int'
|
||||
typename_ = 'int'
|
||||
} else if sym.parent_idx == ast.f32_type_idx {
|
||||
convertor = 'float'
|
||||
typename_ = 'f32'
|
||||
} else if sym.parent_idx == ast.f64_type_idx {
|
||||
convertor = 'double'
|
||||
typename_ = 'f64'
|
||||
} else if sym.parent_idx == ast.bool_type_idx {
|
||||
convertor = 'bool'
|
||||
typename_ = 'bool'
|
||||
} else {
|
||||
panic("could not generate string method for type '$styp'")
|
||||
}
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(it) {')
|
||||
if convertor == 'bool' {
|
||||
g.definitions.writeln('\tlet tmp1 = string__plus(new string("${styp}("), it.valueOf() ? new string("true") : new string("false"));')
|
||||
} else {
|
||||
g.definitions.writeln('\tlet tmp1 = string__plus(new string("${styp}("), new string(${typename_}_str(($convertor)it).str));')
|
||||
}
|
||||
g.definitions.writeln('\tstring tmp2 = string__plus(tmp1, new string(")"));')
|
||||
g.definitions.writeln('\treturn tmp2;')
|
||||
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)
|
||||
|
||||
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('\tlet res;')
|
||||
g.definitions.writeln('\tif (it.state == 0) {')
|
||||
if sym.kind == .string {
|
||||
tmp_res := '${parent_str_fn_name}(it.data)'
|
||||
g.definitions.writeln('\t\tres = ${str_intp_sq(tmp_res)};')
|
||||
} else if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||
g.definitions.writeln('\t\tres = indent_${parent_str_fn_name}(it.data, indent_count);')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tres = ${parent_str_fn_name}(it.data);')
|
||||
}
|
||||
g.definitions.writeln('\t} else {')
|
||||
|
||||
tmp_str := str_intp_sub('error: %%', 'IError_str(it.err)')
|
||||
g.definitions.writeln('\t\tres = $tmp_str;')
|
||||
g.definitions.writeln('\t}')
|
||||
|
||||
g.definitions.writeln('\treturn ${str_intp_sub('Option(%%)', 'res')};')
|
||||
g.definitions.writeln('}')
|
||||
}
|
||||
|
||||
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)
|
||||
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('\tlet indents = string_repeat(new string(" "), indent_count);')
|
||||
g.definitions.writeln('\tlet tmp_ds = ${parent_str_fn_name}(it);')
|
||||
g.definitions.writeln('\tlet res = new string("TODO");')
|
||||
g.definitions.writeln('\treturn res;')
|
||||
g.definitions.writeln('}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_multi_return(info ast.MultiReturn, styp string, str_fn_name string) {
|
||||
mut fn_builder := strings.new_builder(512)
|
||||
fn_builder.writeln('function ${str_fn_name}(a) {')
|
||||
fn_builder.writeln('\tlet sb = strings__new_builder($info.types.len * 10);')
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, new string("("));')
|
||||
for i, typ in info.types {
|
||||
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)
|
||||
|
||||
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));')
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
if sym.kind == .f32 {
|
||||
tmp_val := str_intp_g32('a.arg$i')
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, $tmp_val);')
|
||||
} else {
|
||||
tmp_val := str_intp_g64('a.arg$i')
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, $tmp_val);')
|
||||
}
|
||||
} else if sym.kind == .string {
|
||||
tmp_str := str_intp_sq('a.arg$i')
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, $tmp_str);')
|
||||
} else if sym.kind == .function {
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}());')
|
||||
} else {
|
||||
deref, deref_label := deref_kind(str_method_expects_ptr, is_arg_ptr, typ)
|
||||
fn_builder.writeln('\t\tstrings__Builder_write_string(sb, new string("$deref_label"));')
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}( $deref a.arg$i));')
|
||||
}
|
||||
if i != info.types.len - 1 {
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, new string(", "));')
|
||||
}
|
||||
}
|
||||
fn_builder.writeln('\tstrings__Builder_write_string(sb, new string(")"));')
|
||||
fn_builder.writeln('\tlet res = strings__Builder_str(sb);')
|
||||
fn_builder.writeln('\treturn res;')
|
||||
fn_builder.writeln('}')
|
||||
g.definitions.writeln(fn_builder.str())
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string) {
|
||||
s := util.no_dots(styp)
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(it) { /* gen_str_for_enum */')
|
||||
// Enums tagged with `[flag]` are special in that they can be a combination of enum values
|
||||
if info.is_flag {
|
||||
clean_name := util.strip_main_name(styp.replace('__', '.'))
|
||||
g.definitions.writeln('\tlet ret = new string("$clean_name{");')
|
||||
g.definitions.writeln('\tlet first = 1;')
|
||||
for i, val in info.vals {
|
||||
g.definitions.writeln('\tif (it & (1 << $i)) {if (!first) {ret = string__plus(ret, new string(" | "));} ret = string__plus(ret, new string(".$val")); first = 0;}')
|
||||
}
|
||||
g.definitions.writeln('\tret = string__plus(ret, new string("}"));')
|
||||
g.definitions.writeln('\treturn ret;')
|
||||
} else {
|
||||
g.definitions.writeln('\tswitch(it) {')
|
||||
// Only use the first multi value on the lookup
|
||||
mut seen := []string{len: info.vals.len}
|
||||
for val in info.vals {
|
||||
if info.is_multi_allowed && val in seen {
|
||||
continue
|
||||
} else if info.is_multi_allowed {
|
||||
seen << val
|
||||
}
|
||||
g.definitions.writeln('\t\tcase ${s}.$val: return new string("$val");')
|
||||
}
|
||||
g.definitions.writeln('\t\tdefault: return new string("unknown enum value");')
|
||||
g.definitions.writeln('\t}')
|
||||
}
|
||||
g.definitions.writeln('}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_interface(info ast.Interface, styp string, str_fn_name string) {
|
||||
// _str() functions should have a single argument, the indenting ones take 2:
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(x) { return indent_${str_fn_name}(x, 0); }')
|
||||
|
||||
mut fn_builder := strings.new_builder(512)
|
||||
mut clean_interface_v_type_name := styp.replace('__', '.')
|
||||
if styp.ends_with('*') {
|
||||
clean_interface_v_type_name = '&' + clean_interface_v_type_name.replace('*', '')
|
||||
}
|
||||
if clean_interface_v_type_name.contains('_T_') {
|
||||
clean_interface_v_type_name =
|
||||
clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
||||
'>'
|
||||
}
|
||||
clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name)
|
||||
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)
|
||||
sym_has_str_method, _, _ := subtype.str_method_info()
|
||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||
func_name = 'indent_$func_name'
|
||||
}
|
||||
|
||||
// str_intp
|
||||
|
||||
if typ == ast.string_type {
|
||||
/*
|
||||
mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname'
|
||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||
val += ', indent_count'
|
||||
}
|
||||
val += ')'
|
||||
val = val
|
||||
*/
|
||||
res := '"TODO"'
|
||||
fn_builder.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)')
|
||||
fn_builder.write_string(' return $res;')
|
||||
} else {
|
||||
/*
|
||||
mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname'
|
||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||
val += ', indent_count'
|
||||
}
|
||||
val += ')'
|
||||
val = val
|
||||
*/
|
||||
res := '"TODO'
|
||||
fn_builder.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)')
|
||||
fn_builder.write_string(' return $res;\n')
|
||||
}
|
||||
}
|
||||
fn_builder.writeln('\treturn new string("unknown interface value");')
|
||||
fn_builder.writeln('}')
|
||||
g.definitions.writeln(fn_builder.str())
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_name string) {
|
||||
}
|
||||
|
||||
fn (mut g JsGen) fn_decl_str(info ast.FnType) string {
|
||||
mut fn_str := 'fn ('
|
||||
for i, arg in info.func.params {
|
||||
if arg.is_mut {
|
||||
fn_str += 'mut '
|
||||
}
|
||||
if i > 0 {
|
||||
fn_str += ', '
|
||||
}
|
||||
fn_str += util.strip_main_name(g.table.get_type_name(g.unwrap_generic(arg.typ)))
|
||||
}
|
||||
fn_str += ')'
|
||||
if info.func.return_type == ast.ovoid_type {
|
||||
fn_str += ' ?'
|
||||
} else if info.func.return_type != ast.void_type {
|
||||
x := util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.func.return_type)))
|
||||
if info.func.return_type.has_flag(.optional) {
|
||||
fn_str += ' ?$x'
|
||||
} else {
|
||||
fn_str += ' $x'
|
||||
}
|
||||
}
|
||||
return fn_str
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_fn_type(info ast.FnType, styp string, str_fn_name string) {
|
||||
g.definitions.writeln('function ${str_fn_name}() { return new string("${g.fn_decl_str(info)}");}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_chan(info ast.Chan, styp string, str_fn_name string) {
|
||||
elem_type_name := util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.elem_type)))
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(x) { return sync__Channel_auto_str(x, new string("$elem_type_name")); }')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_thread(info ast.Thread, styp string, str_fn_name string) {
|
||||
ret_type_name := util.strip_main_name(g.table.get_type_name(info.return_type))
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(_) { return new string("thread($ret_type_name)");}')
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn styp_to_str_fn_name(styp string) string {
|
||||
return styp.replace_each(['*', '', '.', '__', ' ', '__']) + '_str'
|
||||
}
|
||||
|
||||
fn deref_kind(str_method_expects_ptr bool, is_elem_ptr bool, typ ast.Type) (string, string) {
|
||||
if str_method_expects_ptr != is_elem_ptr {
|
||||
if is_elem_ptr {
|
||||
return '.val'.repeat(typ.nr_muls()), 'new \$ref('.repeat(typ.nr_muls())
|
||||
} else {
|
||||
return 'new \$ref', ''
|
||||
}
|
||||
}
|
||||
return '', ''
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_array(info ast.Array, styp string, str_fn_name string) {
|
||||
mut typ := info.elem_type
|
||||
mut sym := g.table.get_type_symbol(info.elem_type)
|
||||
if mut sym.info is ast.Alias {
|
||||
typ = sym.info.parent_type
|
||||
sym = g.table.get_type_symbol(typ)
|
||||
}
|
||||
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)
|
||||
if sym.kind == .byte {
|
||||
elem_str_fn_name = elem_str_fn_name + '_escaped'
|
||||
}
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(a) { return indent_${str_fn_name}(a, 0);}')
|
||||
g.definitions.writeln('function indent_${str_fn_name}(a, indent_count) {')
|
||||
g.definitions.writeln('\tlet sb = strings__new_builder(a.len * 10);')
|
||||
g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("["));')
|
||||
g.definitions.writeln('\tfor (let i = 0; i < a.len; ++i) {')
|
||||
if sym.kind == .function {
|
||||
g.definitions.writeln('\t\tlet it = ${elem_str_fn_name}();')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tlet it = a.arr[i];')
|
||||
|
||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||
if is_elem_ptr {
|
||||
g.definitions.writeln('\t\tlet x = indent_${elem_str_fn_name}(it.val, indent_count);')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tlet x = indent_${elem_str_fn_name}(it, indent_count);')
|
||||
}
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
g.definitions.writeln('\t\tlet x = new string( it.val + "");')
|
||||
} else if sym.kind == .rune {
|
||||
// Rune are managed at this level as strings
|
||||
// g.definitions.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{new string("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {new string("\`"), 0, {.d_c = 0 }}}));\n')
|
||||
} else if sym.kind == .string {
|
||||
g.definitions.writeln('\t\tlet x = new string(it);')
|
||||
// g.definitions.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{new string("\'"), $c.si_s_code, {.d_s = it }}, {new string("\'"), 0, {.d_c = 0 }}}));\n')
|
||||
} else {
|
||||
// There is a custom .str() method, so use it.
|
||||
// NB: we need to take account of whether the user has defined
|
||||
// `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly
|
||||
deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ)
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("$deref_label"));')
|
||||
g.definitions.writeln('\t\tlet x = ${elem_str_fn_name}( $deref it);')
|
||||
}
|
||||
}
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, x);')
|
||||
|
||||
g.definitions.writeln('\t\tif (i < a.len-1) {')
|
||||
g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string(", "));')
|
||||
g.definitions.writeln('\t\t}')
|
||||
g.definitions.writeln('\t}')
|
||||
g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("]"));')
|
||||
g.definitions.writeln('\tlet res = strings__Builder_str(sb);')
|
||||
g.definitions.writeln('\treturn res;')
|
||||
g.definitions.writeln('}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_name string) {
|
||||
mut typ := info.elem_type
|
||||
mut sym := g.table.get_type_symbol(info.elem_type)
|
||||
if mut sym.info is ast.Alias {
|
||||
typ = sym.info.parent_type
|
||||
sym = g.table.get_type_symbol(typ)
|
||||
}
|
||||
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)
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(a) { return indent_${str_fn_name}(a, 0);}')
|
||||
|
||||
g.definitions.writeln('function indent_${str_fn_name}(a, indent_count) {')
|
||||
g.definitions.writeln('\tlet sb = strings__new_builder($info.size * 10);')
|
||||
g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("["));')
|
||||
g.definitions.writeln('\tfor (let i = 0; i < $info.size; ++i) {')
|
||||
if sym.kind == .function {
|
||||
g.definitions.writeln('\t\tstring x = ${elem_str_fn_name}();')
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, x);')
|
||||
} else {
|
||||
deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ)
|
||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||
if is_elem_ptr {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("$deref_label"));')
|
||||
g.definitions.writeln('\t\tif ( 0 == a.arr[i] ) {')
|
||||
g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string("0"));')
|
||||
g.definitions.writeln('\t\t}else{')
|
||||
g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr[i] $deref) );')
|
||||
g.definitions.writeln('\t\t}')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr[i]) );')
|
||||
}
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(a.arr[i].val.toString()) );')
|
||||
} else if sym.kind == .string {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, a.arr[i].str);')
|
||||
} else if sym.kind == .rune {
|
||||
// tmp_str := str_intp_rune('${elem_str_fn_name}( a[i] $deref)')
|
||||
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr[i] $deref));')
|
||||
}
|
||||
}
|
||||
g.definitions.writeln('\t\tif (i < ${info.size - 1}) {')
|
||||
g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string(", "));')
|
||||
g.definitions.writeln('\t\t}')
|
||||
g.definitions.writeln('\t}')
|
||||
g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("]"));')
|
||||
g.definitions.writeln('\tlet res = strings__Builder_str(sb);')
|
||||
g.definitions.writeln('\treturn res;')
|
||||
g.definitions.writeln('}')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) {
|
||||
mut key_typ := info.key_type
|
||||
mut key_sym := g.table.get_type_symbol(key_typ)
|
||||
if mut key_sym.info is ast.Alias {
|
||||
key_typ = key_sym.info.parent_type
|
||||
key_sym = g.table.get_type_symbol(key_typ)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
mut val_typ := info.value_type
|
||||
mut val_sym := g.table.get_type_symbol(val_typ)
|
||||
if mut val_sym.info is ast.Alias {
|
||||
val_typ = val_sym.info.parent_type
|
||||
val_sym = g.table.get_type_symbol(val_typ)
|
||||
}
|
||||
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.definitions.writeln('function ${str_fn_name}(m) { return indent_${str_fn_name}(m, 0);}')
|
||||
|
||||
g.definitions.writeln('function indent_${str_fn_name}(m, indent_count) { /* gen_str_for_map */')
|
||||
g.definitions.writeln('\tlet sb = strings__new_builder(m.map.length*10);')
|
||||
g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("{"));')
|
||||
g.definitions.writeln('\tlet i = 0;')
|
||||
g.definitions.writeln('\tfor (let [key,value] of m.map) {')
|
||||
|
||||
if key_sym.kind == .string {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(key));')
|
||||
} else if key_sym.kind == .rune {
|
||||
// tmp_str := str_intp_rune('${key_str_fn_name}(key)')
|
||||
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${key_str_fn_name}(key));')
|
||||
}
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(": "));')
|
||||
if val_sym.kind == .function {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}());')
|
||||
} else if val_sym.kind == .string {
|
||||
// tmp_str := str_intp_sq('*($val_styp*)DenseArray_value(&m.key_values, i)')
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, value);')
|
||||
} else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, indent_${elem_str_fn_name}(value, indent_count));')
|
||||
} else if val_sym.kind in [.f32, .f64] {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, value.val + "");')
|
||||
} else if val_sym.kind == .rune {
|
||||
// tmp_str := str_intp_rune('${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))')
|
||||
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(value));')
|
||||
}
|
||||
g.definitions.writeln('\t\tif (i != m.map.size-1) {')
|
||||
g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string(", "));')
|
||||
g.definitions.writeln('\t\t}')
|
||||
g.definitions.writeln('\t\ti++;')
|
||||
g.definitions.writeln('\t}')
|
||||
g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("}"));')
|
||||
g.definitions.writeln('\tlet res = strings__Builder_str(sb);')
|
||||
g.definitions.writeln('\treturn res;')
|
||||
g.definitions.writeln('}')
|
||||
}
|
||||
|
||||
fn (g &JsGen) type_to_fmt1(typ ast.Type) StrIntpType {
|
||||
if typ == ast.byte_type_idx {
|
||||
return .si_u8
|
||||
}
|
||||
if typ == ast.char_type_idx {
|
||||
return .si_c
|
||||
}
|
||||
if typ in ast.voidptr_types || typ in ast.byteptr_types {
|
||||
return .si_p
|
||||
}
|
||||
if typ in ast.charptr_types {
|
||||
// return '%C\\000' // a C string
|
||||
return .si_s
|
||||
}
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
||||
return .si_s
|
||||
} else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .interface_,
|
||||
.sum_type, .function, .alias, .chan] {
|
||||
return .si_s
|
||||
} else if sym.kind == .string {
|
||||
return .si_s
|
||||
// return "'%.*s\\000'"
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
if sym.kind == .f32 {
|
||||
return .si_g32
|
||||
}
|
||||
return .si_g64
|
||||
} else if sym.kind == .int {
|
||||
return .si_i32
|
||||
} else if sym.kind == .u32 {
|
||||
return .si_u32
|
||||
} else if sym.kind == .u64 {
|
||||
return .si_u64
|
||||
} else if sym.kind == .i64 {
|
||||
return .si_i64
|
||||
}
|
||||
return .si_i32
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string) {
|
||||
// _str() functions should have a single argument, the indenting ones take 2:
|
||||
|
||||
g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0);}')
|
||||
|
||||
mut fn_builder := strings.new_builder(512)
|
||||
defer {
|
||||
g.definitions.writeln(fn_builder.str())
|
||||
}
|
||||
fn_builder.writeln('function indent_${str_fn_name}(it, indent_count) {')
|
||||
mut clean_struct_v_type_name := styp.replace('__', '.')
|
||||
if clean_struct_v_type_name.contains('_T_') {
|
||||
// TODO: this is a bit hacky. styp shouldn't be even parsed with _T_
|
||||
// use something different than g.typ for styp
|
||||
clean_struct_v_type_name =
|
||||
clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
||||
'>'
|
||||
}
|
||||
clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name)
|
||||
// generate ident / indent length = 4 spaces
|
||||
if info.fields.len == 0 {
|
||||
fn_builder.writeln('\treturn new string("$clean_struct_v_type_name{}");')
|
||||
fn_builder.writeln('}')
|
||||
return
|
||||
}
|
||||
|
||||
fn_builder.writeln('\tlet res = /*struct name*/new string("$clean_struct_v_type_name{\\n")')
|
||||
|
||||
for i, field in info.fields {
|
||||
mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' }
|
||||
mut prefix := ''
|
||||
// manage prefix and quote symbol for the filed
|
||||
/*
|
||||
mut quote_str := ''
|
||||
|
||||
|
||||
if sym.kind == .string {
|
||||
quote_str = "'"
|
||||
} else if field.typ in ast.charptr_types {
|
||||
quote_str = '\\"'
|
||||
prefix = 'C'
|
||||
}
|
||||
quote_str = quote_str
|
||||
*/
|
||||
sym := g.table.get_type_symbol(g.unwrap_generic(field.typ))
|
||||
// first fields doesn't need \n
|
||||
if i == 0 {
|
||||
fn_builder.write_string('res.str += " $field.name: $ptr_amp$prefix" + ')
|
||||
} else {
|
||||
fn_builder.write_string('res.str += "\\n $field.name: $ptr_amp$prefix" + ')
|
||||
}
|
||||
|
||||
// custom methods management
|
||||
has_custom_str := sym.has_method('str')
|
||||
mut field_styp := g.typ(field.typ).replace('*', '')
|
||||
field_styp_fn_name := if has_custom_str {
|
||||
'${field_styp}_str'
|
||||
} else {
|
||||
g.gen_str_for_type(field.typ)
|
||||
}
|
||||
|
||||
mut func := struct_auto_str_func1(mut g, sym, field.typ, field_styp_fn_name, field.name)
|
||||
if field.typ in ast.cptr_types {
|
||||
func = '(voidptr) it.$field.name'
|
||||
} else if field.typ.is_ptr() {
|
||||
// reference types can be "nil"
|
||||
fn_builder.write_string('isnil(it.${g.js_name(field.name)})')
|
||||
fn_builder.write_string(' ? new string("nil") : ')
|
||||
// struct, floats and ints have a special case through the _str function
|
||||
if sym.kind != .struct_ && !field.typ.is_int_valptr() && !field.typ.is_float_valptr() {
|
||||
fn_builder.write_string('*')
|
||||
}
|
||||
}
|
||||
// handle circular ref type of struct to the struct itself
|
||||
if styp == field_styp {
|
||||
fn_builder.write_string('res.str += new string("<circular>")')
|
||||
} else {
|
||||
// manage C charptr
|
||||
if field.typ in ast.charptr_types {
|
||||
fn_builder.write_string('tos2((byteptr)$func)')
|
||||
} else {
|
||||
if field.typ.is_ptr() && sym.kind == .struct_ {
|
||||
fn_builder.write_string('(indent_count > 25) ? new string("<probably circular>") : ')
|
||||
}
|
||||
fn_builder.write_string(func)
|
||||
}
|
||||
}
|
||||
|
||||
fn_builder.writeln('')
|
||||
}
|
||||
fn_builder.writeln('res.str += "\\n}"')
|
||||
// fn_builder.writeln('\t\t{new string("\\n"), $c.si_s_code, {.d_s=indents}}, {new string("}"), 0, {.d_c=0}},')
|
||||
fn_builder.writeln('\treturn res;')
|
||||
fn_builder.writeln('}')
|
||||
}
|
||||
|
||||
fn struct_auto_str_func1(mut g JsGen, sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string {
|
||||
has_custom_str, expects_ptr, _ := sym.str_method_info()
|
||||
if sym.kind == .enum_ {
|
||||
return '${fn_name}(it.${g.js_name(field_name)})'
|
||||
} else if should_use_indent_func(sym.kind) {
|
||||
mut obj := 'it.${g.js_name(field_name)}'
|
||||
if field_type.is_ptr() && !expects_ptr {
|
||||
obj = '*$obj'
|
||||
}
|
||||
if has_custom_str {
|
||||
return '${fn_name}($obj)'
|
||||
}
|
||||
return 'indent_${fn_name}($obj, indent_count + 1)'
|
||||
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
|
||||
if has_custom_str {
|
||||
return '${fn_name}(it.${g.js_name(field_name)})'
|
||||
}
|
||||
return 'indent_${fn_name}(it.${g.js_name(field_name)}, indent_count + 1)'
|
||||
} else if sym.kind == .function {
|
||||
return '${fn_name}()'
|
||||
} else {
|
||||
if sym.kind == .chan {
|
||||
return '${fn_name}(it.${g.js_name(field_name)})'
|
||||
}
|
||||
mut method_str := 'it.${g.js_name(field_name)}'
|
||||
if sym.kind == .bool {
|
||||
method_str += ' ? new string("true") : new string("false")'
|
||||
} else if (field_type.is_int_valptr() || field_type.is_float_valptr())
|
||||
&& field_type.is_ptr() && !expects_ptr {
|
||||
// ptr int can be "nil", so this needs to be casted to a string
|
||||
if sym.kind == .f32 {
|
||||
return 'str_intp(1, _MOV((StrIntpData[]){
|
||||
{_SLIT0, $si_g32_code, {.d_f32 = *$method_str }}
|
||||
}))'
|
||||
} else if sym.kind == .f64 {
|
||||
return 'str_intp(1, _MOV((StrIntpData[]){
|
||||
{_SLIT0, $si_g64_code, {.d_f64 = *$method_str }}
|
||||
}))'
|
||||
} else if sym.kind == .u64 {
|
||||
fmt_type := StrIntpType.si_u64
|
||||
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))'
|
||||
}
|
||||
fmt_type := StrIntpType.si_i32
|
||||
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))'
|
||||
}
|
||||
return method_str
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ fn (mut g JsGen) to_js_typ_def_val(s string) string {
|
|||
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 { 'new builtin.' }
|
||||
mut prefix := 'new '
|
||||
match sym.kind {
|
||||
.i8, .i16, .int, .i64, .byte, .u8, .u16, .u32, .u64, .f32, .f64, .int_literal,
|
||||
.float_literal, .size_t {
|
||||
|
@ -114,8 +114,22 @@ fn (mut g JsGen) sym_to_js_typ(sym ast.TypeSymbol) string {
|
|||
return styp
|
||||
}
|
||||
|
||||
// V type to JS type
|
||||
pub fn (mut g JsGen) base_type(t ast.Type) string {
|
||||
mut styp := g.cc_type(t, true)
|
||||
return styp
|
||||
}
|
||||
|
||||
pub fn (mut g JsGen) typ(t ast.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
if sym.kind == .voidptr {
|
||||
return 'any'
|
||||
}
|
||||
styp := g.base_type(t)
|
||||
return styp
|
||||
}
|
||||
|
||||
// V type to JS type
|
||||
pub fn (mut g JsGen) doc_typ(t ast.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := ''
|
||||
match sym.kind {
|
||||
|
@ -263,7 +277,7 @@ struct BuiltinPrototypeConfig {
|
|||
constructor string = 'this.val = val'
|
||||
value_of string = 'this.val'
|
||||
to_string string = 'this.val.toString()'
|
||||
eq string = 'this.val === other.val'
|
||||
eq string = 'self.val === other.val'
|
||||
to_jsval string = 'this'
|
||||
extras string
|
||||
has_strfn bool
|
||||
|
@ -277,21 +291,22 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
|
|||
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, .struct_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('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')
|
||||
g.writeln('function ${c.typ_name}__eq(self,other) { return $c.eq; } ')
|
||||
for method in g.method_fn_decls[c.typ_name] {
|
||||
g.inside_def_typ_decl = true
|
||||
g.gen_method_decl(method, .struct_method)
|
||||
g.inside_def_typ_decl = false
|
||||
}
|
||||
}
|
||||
|
||||
// generate builtin type definitions, used for casting and methods.
|
||||
|
@ -308,7 +323,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.val = Number(val)'
|
||||
value_of: 'Number(this.val)'
|
||||
to_string: 'this.valueOf().toString()'
|
||||
eq: 'this.valueOf() === other.valueOf()'
|
||||
eq: 'new bool(self.valueOf() === other.valueOf())'
|
||||
to_jsval: '+this'
|
||||
)
|
||||
}
|
||||
|
@ -320,7 +335,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.val = BigInt.asUintN(64,BigInt(val))'
|
||||
value_of: 'this.val'
|
||||
to_string: 'this.val.toString()'
|
||||
eq: 'this.valueOf() === other.valueOf()'
|
||||
eq: 'new bool(self.valueOf() === other.valueOf())'
|
||||
to_jsval: 'this.val'
|
||||
)
|
||||
}
|
||||
|
@ -331,7 +346,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.val = BigInt.asIntN(64,BigInt(val))'
|
||||
value_of: 'this.val'
|
||||
to_string: 'this.val.toString()'
|
||||
eq: 'this.valueOf() === other.valueOf()'
|
||||
eq: 'new bool(self.valueOf() === other.valueOf())'
|
||||
to_jsval: 'this.val'
|
||||
)
|
||||
}
|
||||
|
@ -342,7 +357,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'if (typeof(val) == "string") { this.val = val.charCodeAt() } else if (val instanceof string) { this.val = val.str.charCodeAt(); } else { this.val = val | 0 }'
|
||||
value_of: 'this.val | 0'
|
||||
to_string: 'new string(this.val + "")'
|
||||
eq: 'this.valueOf() === other.valueOf()'
|
||||
eq: 'new bool(self.valueOf() === other.valueOf())'
|
||||
to_jsval: '+this'
|
||||
)
|
||||
}
|
||||
|
@ -356,11 +371,11 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
}
|
||||
'bool' {
|
||||
g.gen_builtin_prototype(
|
||||
constructor: 'this.val = +val !== 0'
|
||||
constructor: 'this.val = val instanceof bool ? val.val : +val !== 0'
|
||||
typ_name: typ_name
|
||||
default_value: 'new Boolean(false)'
|
||||
to_jsval: '+this != 0'
|
||||
eq: 'this.val === other.valueOf()'
|
||||
eq: 'new bool(self.val === other.valueOf())'
|
||||
)
|
||||
}
|
||||
'string' {
|
||||
|
@ -371,7 +386,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.str = str.toString(); this.len = this.str.length'
|
||||
value_of: 'this.str'
|
||||
to_string: 'this.str'
|
||||
eq: 'this.str === other.str'
|
||||
eq: 'new bool(self.str === other.str)'
|
||||
has_strfn: false
|
||||
to_jsval: 'this.str'
|
||||
)
|
||||
|
@ -384,7 +399,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.map = map'
|
||||
value_of: 'this'
|
||||
to_string: 'this.map.toString()'
|
||||
eq: 'vEq(this, other)'
|
||||
eq: 'new bool(vEq(self, other))'
|
||||
to_jsval: 'this.map'
|
||||
)
|
||||
}
|
||||
|
@ -396,7 +411,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.arr = arr'
|
||||
value_of: 'this'
|
||||
to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))'
|
||||
eq: 'vEq(this, other)'
|
||||
eq: 'new bool(vEq(self, other))'
|
||||
to_jsval: 'this.arr'
|
||||
)
|
||||
}
|
||||
|
@ -408,7 +423,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
|||
constructor: 'this.val = any'
|
||||
value_of: 'this.val'
|
||||
to_string: '"&" + this.val'
|
||||
eq: 'this == other' // compare by ptr
|
||||
eq: 'new bool(self == other)' // compare by ptr
|
||||
to_jsval: 'this.val.\$toJS()'
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,99 @@
|
|||
module js
|
||||
|
||||
import v.ast
|
||||
import v.util
|
||||
|
||||
fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
||||
g.call_stack << it
|
||||
fn (mut g JsGen) js_mname(name_ string) string {
|
||||
mut is_js := false
|
||||
is_overload := ['+', '-', '*', '/', '==', '<', '>']
|
||||
mut name := name_
|
||||
if name.starts_with('JS.') {
|
||||
name = name[3..]
|
||||
is_js = true
|
||||
}
|
||||
ns := get_ns(name)
|
||||
name = if name in is_overload {
|
||||
match name {
|
||||
'+' {
|
||||
'\$add'
|
||||
}
|
||||
'-' {
|
||||
'\$sub'
|
||||
}
|
||||
'/' {
|
||||
'\$div'
|
||||
}
|
||||
'*' {
|
||||
'\$mul'
|
||||
}
|
||||
'%' {
|
||||
'\$mod'
|
||||
}
|
||||
'==' {
|
||||
'eq'
|
||||
}
|
||||
'>' {
|
||||
'\$gt'
|
||||
}
|
||||
'<' {
|
||||
'\$lt'
|
||||
}
|
||||
else {
|
||||
''
|
||||
}
|
||||
}
|
||||
} else 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_reserved {
|
||||
parts[i] = 'v_$p'
|
||||
}
|
||||
}
|
||||
}
|
||||
return parts.join('.')
|
||||
}
|
||||
|
||||
mut name := g.js_name(it.name)
|
||||
fn (mut g JsGen) js_call(node ast.CallExpr) {
|
||||
g.call_stack << node
|
||||
it := node
|
||||
g.write('${g.js_mname(it.name)}(')
|
||||
for i, arg in it.args {
|
||||
g.expr(arg.expr)
|
||||
if i != it.args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
// end call
|
||||
g.write(')')
|
||||
g.call_stack.delete_last()
|
||||
}
|
||||
|
||||
fn (mut g JsGen) js_method_call(node ast.CallExpr) {
|
||||
g.call_stack << node
|
||||
it := node
|
||||
g.expr(it.left)
|
||||
g.write('.${g.js_mname(it.name)}(')
|
||||
for i, arg in it.args {
|
||||
g.expr(arg.expr)
|
||||
if i != it.args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
// end method call
|
||||
g.write(')')
|
||||
g.call_stack.delete_last()
|
||||
}
|
||||
|
||||
fn (mut g JsGen) method_call(node ast.CallExpr) {
|
||||
g.call_stack << node
|
||||
it := node
|
||||
call_return_is_optional := it.return_type.has_flag(.optional)
|
||||
if call_return_is_optional {
|
||||
g.writeln('(function(){')
|
||||
|
@ -14,9 +102,45 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
|||
g.inc_indent()
|
||||
g.write('return builtin.unwrap(')
|
||||
}
|
||||
sym := g.table.get_type_symbol(it.receiver_type)
|
||||
if sym.kind == .array {
|
||||
if sym.kind == .array && it.name in ['map', 'filter'] {
|
||||
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)
|
||||
} else {
|
||||
sym := g.table.get_type_symbol(node.receiver_type)
|
||||
match sym.info {
|
||||
ast.Struct, ast.Interface, ast.SumType {
|
||||
generic_names := sym.info.generic_types.map(g.table.get_type_symbol(it).name)
|
||||
if utyp := g.table.resolve_generic_to_concrete(node.receiver_type, generic_names,
|
||||
sym.info.concrete_types)
|
||||
{
|
||||
unwrapped_rec_type = utyp
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
mut typ_sym := g.table.get_type_symbol(unwrapped_rec_type)
|
||||
rec_cc_type := g.cc_type(unwrapped_rec_type, false)
|
||||
mut receiver_type_name := util.no_dots(rec_cc_type)
|
||||
// alias type that undefined this method (not include `str`) need to use parent type
|
||||
if typ_sym.kind == .alias && node.name != 'str' && !typ_sym.has_method(node.name) {
|
||||
unwrapped_rec_type = (typ_sym.info as ast.Alias).parent_type
|
||||
typ_sym = g.table.get_type_symbol(unwrapped_rec_type)
|
||||
}
|
||||
|
||||
if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method(node.name) {
|
||||
// g.write('${g.js_name(receiver_type_name)}_name_table')
|
||||
// g.expr(node.left)
|
||||
g.writeln('/* TODO: Interface call */')
|
||||
return
|
||||
}
|
||||
|
||||
left_sym := g.table.get_type_symbol(node.left_type)
|
||||
final_left_sym := g.table.get_final_type_symbol(node.left_type)
|
||||
|
||||
if final_left_sym.kind == .array {
|
||||
if final_left_sym.kind == .array && it.name in ['map', 'filter'] {
|
||||
g.expr(it.left)
|
||||
mut ltyp := it.left_type
|
||||
for ltyp.is_ptr() {
|
||||
|
@ -25,7 +149,7 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
|||
}
|
||||
g.write('.')
|
||||
// Prevent 'it' from getting shadowed inside the match
|
||||
node := it
|
||||
|
||||
g.write(it.name)
|
||||
g.write('(')
|
||||
expr := node.args[0].expr
|
||||
|
@ -33,19 +157,19 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
|||
ast.AnonFn {
|
||||
g.gen_fn_decl(expr.decl)
|
||||
g.write(')')
|
||||
return true
|
||||
return
|
||||
}
|
||||
ast.Ident {
|
||||
if expr.kind == .function {
|
||||
g.write(g.js_name(expr.name))
|
||||
g.write(')')
|
||||
return true
|
||||
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 true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,61 +179,36 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
|||
g.write('it => ')
|
||||
g.expr(node.args[0].expr)
|
||||
g.write(')')
|
||||
return true
|
||||
return
|
||||
}
|
||||
|
||||
left_sym := g.table.get_type_symbol(it.left_type)
|
||||
if left_sym.kind == .array {
|
||||
if final_left_sym.kind == .array {
|
||||
if it.name in special_array_methods {
|
||||
g.expr(it.left)
|
||||
mut ltyp := it.left_type
|
||||
for ltyp.is_ptr() {
|
||||
g.write('.val')
|
||||
ltyp = ltyp.deref()
|
||||
}
|
||||
g.write('.')
|
||||
|
||||
g.gen_array_method_call(it)
|
||||
return true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mut ltyp := it.left_type
|
||||
mut lsym := g.table.get_type_symbol(ltyp)
|
||||
if lsym.kind == .interface_ {
|
||||
g.write(g.js_name(lsym.name))
|
||||
g.write('.${name}.call(')
|
||||
g.expr(it.left)
|
||||
g.write(',')
|
||||
for i, arg in it.args {
|
||||
g.expr(arg.expr)
|
||||
if i != it.args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
if final_left_sym.kind == .array
|
||||
&& node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice', 'pointers'] {
|
||||
if !(left_sym.info is ast.Alias && typ_sym.has_method(node.name)) {
|
||||
// `array_Xyz_clone` => `array_clone`
|
||||
receiver_type_name = 'array'
|
||||
}
|
||||
// end method call
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('Object.getPrototypeOf(')
|
||||
g.expr(it.left)
|
||||
|
||||
for ltyp.is_ptr() {
|
||||
g.write('.val')
|
||||
ltyp = ltyp.deref()
|
||||
}
|
||||
g.write(').$name .call(')
|
||||
g.expr(it.left)
|
||||
g.write(',')
|
||||
for i, arg in it.args {
|
||||
g.expr(arg.expr)
|
||||
if i != it.args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
// end method call
|
||||
g.write(')')
|
||||
}
|
||||
mut name := util.no_dots('${receiver_type_name}_$node.name')
|
||||
|
||||
name = g.generic_fn_name(node.concrete_types, name, false)
|
||||
g.write('${name}(')
|
||||
g.expr(it.left)
|
||||
g.write(',')
|
||||
for i, arg in it.args {
|
||||
g.expr(arg.expr)
|
||||
if i != it.args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.write(')')
|
||||
|
||||
if call_return_is_optional {
|
||||
// end unwrap
|
||||
|
@ -145,14 +244,19 @@ fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
|
|||
g.write('})()')
|
||||
}
|
||||
g.call_stack.delete_last()
|
||||
return true
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||
if it.is_method && g.table.get_type_symbol(it.receiver_type).name.starts_with('JS.') {
|
||||
g.js_method_call(it)
|
||||
return
|
||||
} else if it.name.starts_with('JS.') {
|
||||
g.js_call(it)
|
||||
return
|
||||
}
|
||||
if it.is_method {
|
||||
if g.gen_method_call(it) {
|
||||
return
|
||||
}
|
||||
g.method_call(it)
|
||||
return
|
||||
}
|
||||
node := it
|
||||
g.call_stack << it
|
||||
|
@ -162,9 +266,6 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
ret_sym := g.table.get_type_symbol(it.return_type)
|
||||
if it.language == .js && ret_sym.name in v_types && ret_sym.name != 'void' {
|
||||
g.write('new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
g.write(ret_sym.name)
|
||||
g.write('(')
|
||||
}
|
||||
|
@ -174,23 +275,19 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
g.inc_indent()
|
||||
g.writeln('try {')
|
||||
g.inc_indent()
|
||||
g.write('return builtin.unwrap(')
|
||||
g.write('return unwrap(')
|
||||
}
|
||||
if is_print {
|
||||
mut typ := node.args[0].typ
|
||||
|
||||
expr := node.args[0].expr
|
||||
g.write('builtin.$print_method (')
|
||||
g.write('$print_method (')
|
||||
g.gen_expr_to_string(expr, typ)
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
g.expr(it.left)
|
||||
|
||||
if name in g.builtin_fns {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.write('${name}(')
|
||||
for i, arg in it.args {
|
||||
g.expr(arg.expr)
|
||||
|
@ -220,9 +317,9 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
.propagate {
|
||||
panicstr := '`optional not set (\${err})`'
|
||||
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
|
||||
g.writeln('return builtin.panic($panicstr)')
|
||||
g.writeln('return panic($panicstr)')
|
||||
} else {
|
||||
g.writeln('builtin.js_throw(err)')
|
||||
g.writeln('js_throw(err)')
|
||||
}
|
||||
}
|
||||
else {}
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
module js
|
||||
|
||||
import v.util
|
||||
import v.ast
|
||||
|
||||
fn (mut g JsGen) gen_plain_infix_expr(node ast.InfixExpr) {
|
||||
it := node
|
||||
l_sym := g.table.get_final_type_symbol(it.left_type)
|
||||
r_sym := g.table.get_final_type_symbol(it.right_type)
|
||||
greater_typ := g.greater_typ(it.left_type, it.right_type)
|
||||
g.write('new ${g.typ(greater_typ)}( ')
|
||||
g.cast_stack << greater_typ
|
||||
if (l_sym.kind == .i64 || l_sym.kind == .u64) || (r_sym.kind == .i64 || r_sym.kind == .u64) {
|
||||
g.write('BigInt(')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write('.valueOf())')
|
||||
g.write(' $node.op.str() ')
|
||||
g.write('BigInt(')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write('.valueOf())')
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write('.valueOf()')
|
||||
g.write(' $node.op.str() ')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write('.valueOf()')
|
||||
}
|
||||
|
||||
g.cast_stack.delete_last()
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_expr_arithmetic_op(node ast.InfixExpr) {
|
||||
left := g.unwrap(node.left_type)
|
||||
right := g.unwrap(node.right_type)
|
||||
method := g.table.type_find_method(left.sym, node.op.str()) or {
|
||||
g.gen_plain_infix_expr(node)
|
||||
return
|
||||
}
|
||||
left_styp := g.typ(left.typ.set_nr_muls(0))
|
||||
g.write(left_styp)
|
||||
g.write('_')
|
||||
g.write(util.replace_op(node.op.str()))
|
||||
g.write('(')
|
||||
g.op_arg(node.left, method.params[0].typ, left.typ)
|
||||
g.write(', ')
|
||||
g.op_arg(node.right, method.params[1].typ, right.typ)
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) op_arg(expr ast.Expr, expected ast.Type, got ast.Type) {
|
||||
mut needs_closing := 0
|
||||
mut nr_muls := got.nr_muls()
|
||||
if expected.is_ptr() {
|
||||
if nr_muls > 0 {
|
||||
nr_muls--
|
||||
} else {
|
||||
g.write('new \$ref(')
|
||||
needs_closing++
|
||||
}
|
||||
}
|
||||
g.expr(expr)
|
||||
g.write('.val'.repeat(nr_muls))
|
||||
for i := 0; i < needs_closing; i++ {
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_expr_eq_op(node ast.InfixExpr) {
|
||||
left := g.unwrap(node.left_type)
|
||||
right := g.unwrap(node.right_type)
|
||||
has_operator_overloading := g.table.type_has_method(left.sym, '==')
|
||||
g.write('new bool(')
|
||||
if (left.typ.is_ptr() && right.typ.is_int()) || (right.typ.is_ptr() && left.typ.is_int()) {
|
||||
g.gen_plain_infix_expr(node)
|
||||
} else if has_operator_overloading {
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
g.write(g.typ(left.unaliased.set_nr_muls(0)))
|
||||
g.write('__eq(')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write(',')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.right_type)
|
||||
g.write(')')
|
||||
} else if left.typ.idx() == right.typ.idx()
|
||||
&& left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] {
|
||||
// TODO: Actually generate equality methods
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
g.write('vEq(')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write(',')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.right_type)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write('.valueOf() $node.op.str() ')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.right_type)
|
||||
g.write('.valueOf()')
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_expr_cmp_op(node ast.InfixExpr) {
|
||||
left := g.unwrap(node.left_type)
|
||||
right := g.unwrap(node.right_type)
|
||||
has_operator_overloading := g.table.type_has_method(left.sym, '<')
|
||||
g.write('new bool(')
|
||||
if left.sym.kind == right.sym.kind && has_operator_overloading {
|
||||
if node.op in [.le, .ge] {
|
||||
g.write('!')
|
||||
}
|
||||
g.write(g.typ(left.typ.set_nr_muls(0)))
|
||||
g.write('__lt')
|
||||
if node.op in [.lt, .ge] {
|
||||
g.write('(')
|
||||
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(left.typ)
|
||||
g.write(', ')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(right.typ)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('(')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(left.typ)
|
||||
g.write(', ')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(right.typ)
|
||||
g.write(')')
|
||||
}
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write('.valueOf() $node.op.str() ')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.right_type)
|
||||
g.write('.valueOf()')
|
||||
}
|
||||
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_expr_left_shift_op(node ast.InfixExpr) {
|
||||
left := g.unwrap(node.left_type)
|
||||
right := g.unwrap(node.right_type)
|
||||
if left.unaliased_sym.kind == .array {
|
||||
// arr << val
|
||||
array_info := left.unaliased_sym.info as ast.Array
|
||||
g.write('Array.prototype.push.call(')
|
||||
//&& 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,...')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(right.typ)
|
||||
g.write('.arr')
|
||||
g.write(')')
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(left.typ)
|
||||
g.write('.arr,')
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
}
|
||||
} else {
|
||||
g.gen_plain_infix_expr(node)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) {
|
||||
l_sym := g.table.get_final_type_symbol(node.left_type)
|
||||
r_sym := g.table.get_final_type_symbol(node.right_type)
|
||||
if node.op == .not_in {
|
||||
g.write('!')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(node.right_type)
|
||||
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(node.left)
|
||||
if l_sym.kind == .string {
|
||||
g.write('.str')
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_is_not_is_op(node ast.InfixExpr) {
|
||||
g.expr(node.left)
|
||||
rsym := g.table.get_type_symbol(g.unwrap(node.right_type).typ)
|
||||
|
||||
g.gen_deref_ptr(node.left_type)
|
||||
g.write(' instanceof ')
|
||||
g.write(g.js_name(rsym.name))
|
||||
}
|
||||
|
||||
fn (mut g JsGen) infix_expr(node ast.InfixExpr) {
|
||||
match node.op {
|
||||
.plus, .minus, .mul, .div, .mod {
|
||||
g.infix_expr_arithmetic_op(node)
|
||||
}
|
||||
.eq, .ne {
|
||||
g.infix_expr_eq_op(node)
|
||||
}
|
||||
.gt, .ge, .lt, .le {
|
||||
g.infix_expr_cmp_op(node)
|
||||
}
|
||||
.logical_or, .and {
|
||||
g.gen_plain_infix_expr(node)
|
||||
}
|
||||
.left_shift {
|
||||
g.infix_expr_left_shift_op(node)
|
||||
}
|
||||
.not_in, .key_in {
|
||||
g.infix_in_not_in_op(node)
|
||||
}
|
||||
.key_is, .not_is {
|
||||
g.infix_is_not_is_op(node)
|
||||
}
|
||||
else {
|
||||
g.gen_plain_infix_expr(node)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ struct SourcemapHelper {
|
|||
struct Namespace {
|
||||
name string
|
||||
mut:
|
||||
out strings.Builder = strings.new_builder(128)
|
||||
pub_vars []string
|
||||
imports map[string]string
|
||||
indent int
|
||||
|
@ -80,6 +79,7 @@ mut:
|
|||
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
|
||||
out strings.Builder = strings.new_builder(128)
|
||||
}
|
||||
|
||||
fn (mut g JsGen) write_tests_definitions() {
|
||||
|
@ -121,24 +121,27 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
g.find_class_methods(file.stmts)
|
||||
g.escape_namespace()
|
||||
}
|
||||
|
||||
for file in files {
|
||||
g.file = file
|
||||
g.enter_namespace(g.file.mod.name)
|
||||
if g.enable_doc {
|
||||
g.writeln('/** @namespace $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.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return new int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } }); ')
|
||||
g.writeln('Object.defineProperty(string.prototype,"len", { get: function() {return new int(this.str.length);}, set: function(l) {/* ignore */ } }); ')
|
||||
g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new int(this.map.length);}, set: function(l) { this.map.length = l.valueOf(); } }); ')
|
||||
g.writeln('Object.defineProperty(array.prototype,"length", { get: function() {return new int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } }); ')
|
||||
g.generated_builtin = true
|
||||
}
|
||||
if g.is_test && !tests_inited {
|
||||
|
@ -146,7 +149,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
tests_inited = true
|
||||
}
|
||||
g.stmts(file.stmts)
|
||||
g.writeln('try { init() } catch (_) {}')
|
||||
// store the current namespace
|
||||
g.escape_namespace()
|
||||
}
|
||||
|
@ -157,7 +159,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
deps_resolved := graph.resolve()
|
||||
nodes := deps_resolved.nodes
|
||||
|
||||
mut out := g.hashes() + g.definitions.str()
|
||||
mut out := g.definitions.str() + g.hashes()
|
||||
// equality check for js objects
|
||||
// TODO: Fix msvc bug that's preventing $embed_file('fast_deep_equal.js')
|
||||
// unsafe {
|
||||
|
@ -165,30 +167,32 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
// out += eq_fn.data().vstring()
|
||||
//}
|
||||
out += fast_deep_eq_fn
|
||||
|
||||
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'
|
||||
out += g.out.str()
|
||||
|
||||
/*
|
||||
for node in nodes {
|
||||
name := g.js_name(node.name).replace('.', '_')
|
||||
if g.enable_doc {
|
||||
out += '/** @namespace $name */\n'
|
||||
}
|
||||
out += 'const $name = (function ('
|
||||
// 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_segment := g.out.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)
|
||||
|
@ -202,66 +206,11 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
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()
|
||||
}
|
||||
|
@ -429,7 +378,7 @@ fn verror(msg string) {
|
|||
[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.out.write_string(util.tabs(g.ns.indent))
|
||||
}
|
||||
g.empty_line = false
|
||||
}
|
||||
|
@ -450,7 +399,7 @@ pub fn (mut g JsGen) write(s string) {
|
|||
verror('g.write: not in a namespace')
|
||||
}
|
||||
g.gen_indent()
|
||||
g.ns.out.write_string(s)
|
||||
g.out.write_string(s)
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
@ -459,7 +408,7 @@ pub fn (mut g JsGen) writeln(s string) {
|
|||
verror('g.writeln: not in a namespace')
|
||||
}
|
||||
g.gen_indent()
|
||||
g.ns.out.writeln(s)
|
||||
g.out.writeln(s)
|
||||
g.empty_line = true
|
||||
}
|
||||
|
||||
|
@ -490,6 +439,7 @@ fn (mut g JsGen) get_alias(name string) string {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) js_name(name_ string) string {
|
||||
/*
|
||||
mut is_js := false
|
||||
is_overload := ['+', '-', '*', '/', '==', '<', '>']
|
||||
mut name := name_
|
||||
|
@ -543,7 +493,18 @@ fn (mut g JsGen) js_name(name_ string) string {
|
|||
}
|
||||
}
|
||||
}
|
||||
return parts.join('.')
|
||||
return parts.join('.')*/
|
||||
|
||||
mut name := name_
|
||||
if name.starts_with('JS.') {
|
||||
name = name[3..]
|
||||
return name
|
||||
}
|
||||
name = name_.replace('.', '__')
|
||||
if name in js.js_reserved {
|
||||
return '_v_$name'
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
fn (mut g JsGen) stmts(stmts []ast.Stmt) {
|
||||
|
@ -561,11 +522,11 @@ fn (mut g JsGen) write_v_source_line_info(pos token.Position) {
|
|||
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)
|
||||
ns_pos: u32(g.out.len)
|
||||
}
|
||||
}
|
||||
if g.pref.is_vlines && g.is_vlines_enabled {
|
||||
g.write(' /* ${pos.line_nr + 1} $g.ns.out.len */ ')
|
||||
g.write(' /* ${pos.line_nr + 1} $g.out.len */ ')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,7 +570,7 @@ fn (mut g JsGen) gen_global_decl(node ast.GlobalDecl) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) stmt_no_semi(node ast.Stmt) {
|
||||
g.stmt_start_pos = g.ns.out.len
|
||||
g.stmt_start_pos = g.out.len
|
||||
match node {
|
||||
ast.EmptyStmt {}
|
||||
ast.AsmStmt {
|
||||
|
@ -712,7 +673,7 @@ fn (mut g JsGen) stmt_no_semi(node ast.Stmt) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||
g.stmt_start_pos = g.ns.out.len
|
||||
g.stmt_start_pos = g.out.len
|
||||
match node {
|
||||
ast.EmptyStmt {}
|
||||
ast.AsmStmt {
|
||||
|
@ -840,11 +801,13 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
// TODO
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
g.write('new bool(')
|
||||
if node.val == true {
|
||||
g.write('true')
|
||||
} else {
|
||||
g.write('false')
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
ast.CallExpr {
|
||||
g.gen_call_expr(node)
|
||||
|
@ -856,7 +819,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
g.gen_type_cast_expr(node)
|
||||
}
|
||||
ast.CharLiteral {
|
||||
g.write("new builtin.byte('$node.val')")
|
||||
g.write("new byte('$node.val')")
|
||||
}
|
||||
ast.Comment {}
|
||||
ast.ConcatExpr {
|
||||
|
@ -886,7 +849,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
g.gen_index_expr(node)
|
||||
}
|
||||
ast.InfixExpr {
|
||||
g.gen_infix_expr(node)
|
||||
g.infix_expr(node)
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.gen_integer_literal_expr(node)
|
||||
|
@ -898,7 +861,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
g.gen_map_init_expr(node)
|
||||
}
|
||||
ast.None {
|
||||
g.write('builtin.none__')
|
||||
g.write('none__')
|
||||
}
|
||||
ast.MatchExpr {
|
||||
g.match_expr(node)
|
||||
|
@ -988,8 +951,8 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
ast.TypeNode {
|
||||
typ := g.unwrap_generic(node.typ)
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
name := sym.name.replace_once('${g.ns.name}.', '')
|
||||
g.write('$name')
|
||||
|
||||
g.write('${g.js_name(sym.name)}')
|
||||
}
|
||||
ast.Likely {
|
||||
g.write('(')
|
||||
|
@ -1023,9 +986,9 @@ fn (mut g JsGen) gen_assert_metainfo(node ast.AssertStmt) string {
|
|||
src := node.expr.str()
|
||||
metaname := 'v_assert_meta_info_$g.new_tmp_var()'
|
||||
g.writeln('let $metaname = {}')
|
||||
g.writeln('${metaname}.fpath = new builtin.string("$mod_path");')
|
||||
g.writeln('${metaname}.line_nr = new builtin.int("$line_nr")')
|
||||
g.writeln('${metaname}.fn_name = new builtin.string("$fn_name")')
|
||||
g.writeln('${metaname}.fpath = new string("$mod_path");')
|
||||
g.writeln('${metaname}.line_nr = new int("$line_nr")')
|
||||
g.writeln('${metaname}.fn_name = new string("$fn_name")')
|
||||
metasrc := src
|
||||
g.writeln('${metaname}.src = "$metasrc"')
|
||||
|
||||
|
@ -1034,18 +997,18 @@ fn (mut g JsGen) gen_assert_metainfo(node ast.AssertStmt) string {
|
|||
expr_op_str := node.expr.op.str()
|
||||
expr_left_str := node.expr.left.str()
|
||||
expr_right_str := node.expr.right.str()
|
||||
g.writeln('\t${metaname}.op = new builtin.string("$expr_op_str");')
|
||||
g.writeln('\t${metaname}.llabel = new builtin.string("$expr_left_str");')
|
||||
g.writeln('\t${metaname}.rlabel = new builtin.string("$expr_right_str");')
|
||||
g.write('\t${metaname}.lvalue = new builtin.string("')
|
||||
g.writeln('\t${metaname}.op = new string("$expr_op_str");')
|
||||
g.writeln('\t${metaname}.llabel = new string("$expr_left_str");')
|
||||
g.writeln('\t${metaname}.rlabel = new string("$expr_right_str");')
|
||||
g.write('\t${metaname}.lvalue = new string("')
|
||||
g.gen_assert_single_expr(node.expr.left, node.expr.left_type)
|
||||
g.writeln('");')
|
||||
g.write('\t${metaname}.rvalue = new builtin.string("')
|
||||
g.write('\t${metaname}.rvalue = new string("')
|
||||
g.gen_assert_single_expr(node.expr.right, node.expr.right_type)
|
||||
g.writeln('");')
|
||||
}
|
||||
ast.CallExpr {
|
||||
g.writeln('\t${metaname}.op = new builtin.string("call");')
|
||||
g.writeln('\t${metaname}.op = new string("call");')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
|
@ -1081,25 +1044,25 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
|||
g.writeln('// assert')
|
||||
g.write('if( ')
|
||||
g.expr(a.expr)
|
||||
g.write(' ) {')
|
||||
g.write('.valueOf() ) {')
|
||||
s_assertion := a.expr.str().replace('"', "'")
|
||||
mut mod_path := g.file.path.replace('\\', '\\\\')
|
||||
if g.is_test {
|
||||
metaname_ok := g.gen_assert_metainfo(a)
|
||||
g.writeln(' g_test_oks++;')
|
||||
g.writeln(' cb_assertion_ok($metaname_ok);')
|
||||
g.writeln(' main__cb_assertion_ok($metaname_ok);')
|
||||
g.writeln('} else {')
|
||||
metaname_fail := g.gen_assert_metainfo(a)
|
||||
g.writeln(' g_test_fails++;')
|
||||
g.writeln(' cb_assertion_failed($metaname_fail);')
|
||||
g.writeln(' builtin.exit(1);')
|
||||
g.writeln(' main__cb_assertion_failed($metaname_fail);')
|
||||
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.writeln('eprintln(new string("$mod_path:${a.pos.line_nr + 1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion"));')
|
||||
g.writeln('exit(1);')
|
||||
g.dec_indent()
|
||||
g.writeln('}')
|
||||
}
|
||||
|
@ -1228,9 +1191,6 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
|
|||
if should_cast {
|
||||
g.cast_stack << stmt.left_types.first()
|
||||
g.write('new ')
|
||||
if g.file.mod.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
g.write('${g.typ(stmt.left_types.first())}(')
|
||||
}
|
||||
g.expr(val)
|
||||
|
@ -1345,10 +1305,14 @@ fn (g &JsGen) fn_gen_type(it &ast.FnDecl) FnGenType {
|
|||
|
||||
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||
res := g.fn_gen_type(it)
|
||||
if it.language == .js {
|
||||
return
|
||||
}
|
||||
/*
|
||||
if res == .struct_method {
|
||||
// Struct methods are handled by class generation code.
|
||||
return
|
||||
}
|
||||
}*/
|
||||
if g.inside_builtin {
|
||||
g.builtin_fns << it.name
|
||||
}
|
||||
|
@ -1370,15 +1334,131 @@ fn fn_has_go(node ast.FnDecl) bool {
|
|||
return has_go
|
||||
}
|
||||
|
||||
// cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo)
|
||||
fn (mut g JsGen) cc_type(typ ast.Type, is_prefix_struct bool) string {
|
||||
sym := g.table.get_type_symbol(g.unwrap_generic(typ))
|
||||
mut styp := sym.cname
|
||||
match mut sym.info {
|
||||
ast.Struct, ast.Interface, ast.SumType {
|
||||
if sym.info.is_generic {
|
||||
mut sgtyps := '_T'
|
||||
for gt in sym.info.generic_types {
|
||||
gts := g.table.get_type_symbol(g.unwrap_generic(gt))
|
||||
sgtyps += '_$gts.cname'
|
||||
}
|
||||
styp += sgtyps
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return styp
|
||||
}
|
||||
|
||||
fn (mut g JsGen) generic_fn_name(types []ast.Type, before string, is_decl bool) string {
|
||||
if types.len == 0 {
|
||||
return before
|
||||
}
|
||||
|
||||
mut name := before + '_T'
|
||||
for typ in types {
|
||||
name += '_' + strings.repeat_string('__ptr__', typ.nr_muls()) + g.typ(typ.set_nr_muls(0))
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
|
||||
unsafe {
|
||||
g.fn_decl = &it
|
||||
}
|
||||
cur_fn_save := g.table.cur_fn
|
||||
defer {
|
||||
g.table.cur_fn = cur_fn_save
|
||||
}
|
||||
unsafe {
|
||||
g.table.cur_fn = &it
|
||||
}
|
||||
node := it
|
||||
mut name := it.name
|
||||
if name in ['+', '-', '*', '/', '%', '<', '=='] {
|
||||
name = util.replace_op(name)
|
||||
}
|
||||
|
||||
if node.is_method {
|
||||
unwrapped_rec_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver.typ))
|
||||
if unwrapped_rec_sym.kind == .placeholder {
|
||||
return
|
||||
}
|
||||
name = g.cc_type(node.receiver.typ, false) + '_' + name
|
||||
}
|
||||
|
||||
name = g.js_name(name)
|
||||
|
||||
name = g.generic_fn_name(g.table.cur_concrete_types, name, true)
|
||||
|
||||
has_go := fn_has_go(it)
|
||||
if it.is_pub && !it.is_method {
|
||||
g.push_pub_var(name)
|
||||
}
|
||||
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 {
|
||||
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 ')
|
||||
}
|
||||
|
||||
g.write('function ')
|
||||
|
||||
g.write('${name}(')
|
||||
if it.is_pub && !it.is_method {
|
||||
g.push_pub_var(name)
|
||||
}
|
||||
}
|
||||
mut args := it.params
|
||||
|
||||
g.fn_args(args, it.is_variadic)
|
||||
g.write(') {')
|
||||
for i, arg in args {
|
||||
is_varg := i == args.len - 1 && it.is_variadic
|
||||
arg_name := g.js_name(arg.name)
|
||||
if is_varg {
|
||||
g.writeln('$arg_name = new array($arg_name);')
|
||||
} else {
|
||||
if arg.typ.is_ptr() || arg.is_mut {
|
||||
g.writeln('$arg_name = new \$ref($arg_name)')
|
||||
}
|
||||
}
|
||||
}
|
||||
g.stmts(it.stmts)
|
||||
g.writeln('}')
|
||||
|
||||
if is_main {
|
||||
g.write(')();')
|
||||
}
|
||||
g.writeln('')
|
||||
/*
|
||||
if typ == .alias_method || typ == .iface_method {
|
||||
sym := g.table.get_final_type_symbol(it.params[0].typ.set_nr_muls(0))
|
||||
name := g.js_name(sym.name)
|
||||
if name in js.v_types {
|
||||
g.writeln('builtin.')
|
||||
g.writeln('')
|
||||
}
|
||||
g.writeln('${name}.prototype.$it.name = function ')
|
||||
}
|
||||
|
@ -1468,7 +1548,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
|
|||
if typ == .struct_method || typ == .alias_method || typ == .iface_method {
|
||||
g.writeln('\n')
|
||||
}
|
||||
|
||||
*/
|
||||
g.fn_decl = voidptr(0)
|
||||
}
|
||||
|
||||
|
@ -1522,7 +1602,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
|
|||
g.expr(it.cond)
|
||||
g.write('; $i < ')
|
||||
g.expr(it.high)
|
||||
g.writeln('; $i = new builtin.int($i + 1)) {')
|
||||
g.writeln('; $i = new int($i + 1)) {')
|
||||
g.inside_loop = false
|
||||
g.stmts(it.stmts)
|
||||
g.writeln('}')
|
||||
|
@ -1539,9 +1619,9 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
|
|||
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('new ')
|
||||
|
||||
g.write('byte($val)])')
|
||||
} else {
|
||||
g.expr(it.cond)
|
||||
|
@ -1562,9 +1642,9 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
|
|||
// cast characters to bytes
|
||||
if val !in ['', '_'] && it.kind == .string {
|
||||
g.write('.map(c => ')
|
||||
if g.ns.name == 'builtin' {
|
||||
g.write('new ')
|
||||
}
|
||||
|
||||
g.write('new ')
|
||||
|
||||
g.write('byte(c))')
|
||||
}
|
||||
}
|
||||
|
@ -1604,15 +1684,12 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
|
|||
fn (mut g JsGen) gen_go_expr(node ast.GoExpr) {
|
||||
// TODO Handle joinable expressions
|
||||
// node.is_expr
|
||||
mut name := node.call_expr.name
|
||||
mut name := g.js_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}(')
|
||||
|
@ -1644,7 +1721,7 @@ fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_optional_error(expr ast.Expr) {
|
||||
g.write('new builtin.Option({ state: new builtin.byte(2),err: ')
|
||||
g.write('new Option({ state: new byte(2),err: ')
|
||||
g.expr(expr)
|
||||
g.write('})')
|
||||
}
|
||||
|
@ -1682,9 +1759,7 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
|||
if fn_return_is_optional {
|
||||
tmp := g.new_tmp_var()
|
||||
g.write('const $tmp = new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.writeln('Option({});')
|
||||
g.write('${tmp}.data = ')
|
||||
if it.exprs.len == 1 {
|
||||
|
@ -1746,17 +1821,6 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
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, .struct_method)
|
||||
g.writeln(',')
|
||||
}
|
||||
// gen toString method
|
||||
fn_names := fns.map(it.name)
|
||||
if 'toString' !in fn_names {
|
||||
|
@ -1778,9 +1842,22 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
g.dec_indent()
|
||||
g.writeln('},')
|
||||
}
|
||||
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(',')
|
||||
}
|
||||
g.writeln('\$toJS() { return this; }')
|
||||
g.dec_indent()
|
||||
|
||||
g.writeln('};\n')
|
||||
g.dec_indent()
|
||||
|
||||
/*
|
||||
for cfn in fns {
|
||||
g.gen_method_decl(cfn, .struct_method)
|
||||
}*/
|
||||
|
||||
if node.is_pub {
|
||||
g.push_pub_var(name)
|
||||
}
|
||||
|
@ -2104,7 +2181,7 @@ fn (mut g JsGen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) {
|
|||
g.expr(stmt.expr)
|
||||
g.writeln(';')
|
||||
} else {
|
||||
g.write('builtin.opt_ok(')
|
||||
g.write('opt_ok(')
|
||||
g.stmt(stmt)
|
||||
g.writeln(', $tmp_var);')
|
||||
}
|
||||
|
@ -2167,9 +2244,7 @@ fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var M
|
|||
g.expr(branch.exprs[sumtype_index])
|
||||
} else {
|
||||
g.write(' instanceof ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.write('None__')
|
||||
}
|
||||
}
|
||||
|
@ -2352,11 +2427,16 @@ 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 {
|
||||
if left_typ.kind == .array {
|
||||
g.write('array_slice(')
|
||||
} else {
|
||||
g.write('string_slice(')
|
||||
}
|
||||
g.expr(expr.left)
|
||||
if expr.left_type.is_ptr() {
|
||||
g.write('.valueOf()')
|
||||
}
|
||||
g.write('.slice(')
|
||||
g.write(',')
|
||||
if expr.index.has_low {
|
||||
g.expr(expr.index.low)
|
||||
} else {
|
||||
|
@ -2370,7 +2450,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
|
|||
if expr.left_type.is_ptr() {
|
||||
g.write('.valueOf()')
|
||||
}
|
||||
g.write('.length')
|
||||
g.write('.len')
|
||||
}
|
||||
g.write(')')
|
||||
} else if left_typ.kind == .map {
|
||||
|
@ -2444,9 +2524,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
it.right_type
|
||||
} // g.greater_typ(it.left_type, it.right_type)
|
||||
g.write('new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.write('${g.typ(greater_typ)}(')
|
||||
g.cast_stack << greater_typ
|
||||
g.write('BigInt((')
|
||||
|
@ -2466,10 +2544,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
return
|
||||
}
|
||||
if it.op == .logical_or || it.op == .and {
|
||||
if g.ns.name == 'builtin' {
|
||||
g.write('new ')
|
||||
}
|
||||
g.write('bool(')
|
||||
g.write('new bool(')
|
||||
g.expr(it.left)
|
||||
g.write('.valueOf()')
|
||||
g.write(it.op.str())
|
||||
|
@ -2477,6 +2552,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
g.write('.valueOf()')
|
||||
g.write(')')
|
||||
} else if it.op == .eq || it.op == .ne {
|
||||
/*
|
||||
has_operator_overloading := g.table.type_has_method(l_sym, '==')
|
||||
if has_operator_overloading {
|
||||
g.expr(it.left)
|
||||
|
@ -2506,6 +2582,32 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
g.expr(it.right)
|
||||
g.gen_deref_ptr(it.right_type)
|
||||
g.write(')')
|
||||
}*/
|
||||
node := it
|
||||
left := g.unwrap(node.left_type)
|
||||
right := g.unwrap(node.right_type)
|
||||
has_operator_overloading := g.table.type_has_method(left.sym, '==')
|
||||
if has_operator_overloading
|
||||
|| (l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables) {
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
g.write(g.typ(left.unaliased.set_nr_muls(0)))
|
||||
g.write('__eq(')
|
||||
g.expr(node.left)
|
||||
g.gen_deref_ptr(left.typ)
|
||||
g.write(',')
|
||||
g.expr(node.right)
|
||||
g.gen_deref_ptr(right.typ)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('vEq(')
|
||||
g.expr(it.left)
|
||||
g.gen_deref_ptr(it.left_type)
|
||||
g.write(', ')
|
||||
g.expr(it.right)
|
||||
g.gen_deref_ptr(it.right_type)
|
||||
g.write(')')
|
||||
}
|
||||
} else if l_sym.kind == .array && it.op == .left_shift { // arr << 1
|
||||
g.write('Array.prototype.push.call(')
|
||||
|
@ -2609,14 +2711,14 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
}
|
||||
|
||||
if is_arithmetic {
|
||||
if g.ns.name == 'builtin' {
|
||||
g.write('new ')
|
||||
}
|
||||
g.write('new ')
|
||||
|
||||
g.write('${g.typ(greater_typ)}(')
|
||||
g.cast_stack << greater_typ
|
||||
}
|
||||
|
||||
g.expr(it.left)
|
||||
|
||||
g.gen_deref_ptr(it.left_type)
|
||||
// g.write('.val')
|
||||
g.write(' $it.op ')
|
||||
|
@ -2732,7 +2834,7 @@ fn (mut g JsGen) type_name(raw_type ast.Type) {
|
|||
} else {
|
||||
s = g.table.type_to_str(g.unwrap_generic(typ))
|
||||
}
|
||||
g.write('new builtin.string("$s")')
|
||||
g.write('new string("$s")')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
||||
|
@ -2744,7 +2846,7 @@ fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
|||
return
|
||||
}
|
||||
.typ {
|
||||
g.write('new builtin.int(')
|
||||
g.write('new int(')
|
||||
|
||||
g.write('${int(g.unwrap_generic(it.name_type))}')
|
||||
g.write(')')
|
||||
|
@ -2756,7 +2858,7 @@ fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
|||
g.type_name(it.name_type)
|
||||
return
|
||||
} else if node.field_name == 'idx' {
|
||||
g.write('new builtin.int(')
|
||||
g.write('new int(')
|
||||
g.write('${int(g.unwrap_generic(it.name_type))}')
|
||||
g.write(')')
|
||||
return
|
||||
|
@ -2777,9 +2879,8 @@ fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
|||
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('new ')
|
||||
|
||||
g.write('string(')
|
||||
}
|
||||
g.write('`')
|
||||
|
@ -2817,9 +2918,8 @@ fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
|
|||
text = text.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('new ')
|
||||
|
||||
g.write('string(')
|
||||
}
|
||||
if it.is_raw {
|
||||
|
@ -2892,10 +2992,8 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
|
|||
tsym := g.table.get_final_type_symbol(it.typ)
|
||||
if it.expr is ast.IntegerLiteral && (tsym.kind == .i64 || tsym.kind == .u64) {
|
||||
g.write('new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
g.write(tsym.kind.str())
|
||||
|
||||
g.write('$tsym.kind.str()')
|
||||
g.write('(BigInt(')
|
||||
g.write(it.expr.val)
|
||||
g.write('n))')
|
||||
|
@ -2913,9 +3011,9 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
|
|||
if it.typ.is_ptr() {
|
||||
g.write('new \$ref(')
|
||||
}
|
||||
if typ !in js.v_types || g.ns.name == 'builtin' {
|
||||
g.write('new ')
|
||||
}
|
||||
|
||||
g.write('new ')
|
||||
|
||||
g.write('${typ}(')
|
||||
}
|
||||
g.expr(it.expr)
|
||||
|
@ -2954,17 +3052,12 @@ fn (mut g JsGen) gen_integer_literal_expr(it ast.IntegerLiteral) {
|
|||
if g.cast_stack.len > 0 {
|
||||
if g.cast_stack[g.cast_stack.len - 1] in ast.integer_type_idxs {
|
||||
g.write('new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.write('int($it.val)')
|
||||
return
|
||||
}
|
||||
}
|
||||
g.write('new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.write('${g.typ(typ)}($it.val)')
|
||||
}
|
||||
|
@ -3003,9 +3096,6 @@ fn (mut g JsGen) gen_float_literal_expr(it ast.FloatLiteral) {
|
|||
}
|
||||
}
|
||||
g.write('new ')
|
||||
if g.ns.name != 'builtin' {
|
||||
g.write('builtin.')
|
||||
}
|
||||
|
||||
g.write('${g.typ(typ)}($it.val)')
|
||||
}
|
||||
|
@ -3020,3 +3110,17 @@ fn (mut g JsGen) unwrap_generic(typ ast.Type) ast.Type {
|
|||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
fn replace_op(s string) string {
|
||||
return match s {
|
||||
'+' { '_plus' }
|
||||
'-' { '_minus' }
|
||||
'*' { '_mult' }
|
||||
'/' { '_div' }
|
||||
'%' { '_mod' }
|
||||
'<' { '_lt' }
|
||||
'>' { '_gt' }
|
||||
'==' { '_eq' }
|
||||
else { '' }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,14 @@ 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
|
||||
if etype.has_flag(.shared_f) {
|
||||
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') {
|
||||
|
@ -17,69 +18,58 @@ fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||
sym = parent_sym
|
||||
}
|
||||
}
|
||||
|
||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||
is_var_mut := expr.is_auto_deref_var()
|
||||
if typ.has_flag(.variadic) {
|
||||
// todo(playX): generate str method just like in the C backend
|
||||
g.write('new string(')
|
||||
str_fn_name := g.gen_str_for_type(typ)
|
||||
g.write('${str_fn_name}(')
|
||||
g.expr(expr)
|
||||
g.write('.valueOf()')
|
||||
g.write('.toString())')
|
||||
g.write(')')
|
||||
} else if typ == ast.string_type {
|
||||
g.expr(expr)
|
||||
} else if typ == ast.bool_type {
|
||||
g.write('new string(')
|
||||
g.write('new string((')
|
||||
g.expr(expr)
|
||||
g.write('.valueOf() ? "true" : "false")')
|
||||
g.write(').valueOf() ? "true" : "false")')
|
||||
} else if sym.kind == .none_ {
|
||||
g.write('new string("<none>")')
|
||||
} else if sym.kind == .enum_ {
|
||||
g.write('new string(')
|
||||
if expr !is ast.EnumVal {
|
||||
str_fn_name := g.gen_str_for_type(typ)
|
||||
g.write('${str_fn_name}(')
|
||||
g.expr(expr)
|
||||
g.write('.valueOf()')
|
||||
g.write('.toString()')
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('"')
|
||||
g.write('new string("')
|
||||
g.expr(expr)
|
||||
g.write('"')
|
||||
g.write('")')
|
||||
}
|
||||
g.write(')')
|
||||
} else if sym.kind == .interface_ && sym_has_str_method {
|
||||
} else if sym_has_str_method
|
||||
|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] {
|
||||
is_ptr := typ.is_ptr()
|
||||
g.write(sym.mod.replace_once('${g.ns.name}.', ''))
|
||||
g.write('.')
|
||||
g.write(sym.name)
|
||||
g.write('.prototype.str.call(')
|
||||
g.expr(expr)
|
||||
if !str_method_expects_ptr && is_ptr {
|
||||
g.gen_deref_ptr(typ)
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
//|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return,.sum_type, .interface_]
|
||||
else if sym_has_str_method {
|
||||
g.write('new string(')
|
||||
g.write('Object.getPrototypeOf(/*str exists*/')
|
||||
g.expr(expr)
|
||||
is_ptr := typ.is_ptr()
|
||||
g.gen_deref_ptr(typ)
|
||||
g.write(').str.call(')
|
||||
g.expr(expr)
|
||||
if !str_method_expects_ptr && is_ptr {
|
||||
g.gen_deref_ptr(typ)
|
||||
str_fn_name := g.gen_str_for_type(typ)
|
||||
g.write('${str_fn_name}(')
|
||||
if str_method_expects_ptr && !is_ptr {
|
||||
g.write('new \$ref(')
|
||||
g.expr(expr)
|
||||
g.write(')')
|
||||
} else if (!str_method_expects_ptr && is_ptr && !is_shared) || is_var_mut {
|
||||
g.expr(expr)
|
||||
g.gen_deref_ptr(etype)
|
||||
}
|
||||
|
||||
g.write('))')
|
||||
} else if sym.kind == .struct_ && !sym_has_str_method {
|
||||
g.write('new string(')
|
||||
g.expr(expr)
|
||||
g.gen_deref_ptr(typ)
|
||||
g.write('.toString())')
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('new string(')
|
||||
g.expr(expr)
|
||||
g.gen_deref_ptr(typ)
|
||||
g.write('.valueOf().toString())')
|
||||
str_fn_name := g.gen_str_for_type(typ)
|
||||
g.write('${str_fn_name}(')
|
||||
|
||||
if sym.kind != .function {
|
||||
g.expr(expr)
|
||||
if expr.is_auto_deref_var() {
|
||||
g.write('.val')
|
||||
}
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,16 +60,16 @@ true
|
|||
0
|
||||
1
|
||||
1.1
|
||||
[[1, 2], 3, 4]
|
||||
[[1, 2], [5, 6], 3, 4]
|
||||
[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]
|
||||
[1, 2, 3, 4]
|
||||
[5, 6, 1, 2, 3, 4]
|
||||
5
|
||||
true
|
||||
1.1
|
||||
|
@ -135,8 +135,8 @@ true
|
|||
0
|
||||
2
|
||||
-1
|
||||
-1
|
||||
-1
|
||||
1
|
||||
2
|
||||
-1
|
||||
2
|
||||
3
|
||||
|
@ -226,7 +226,6 @@ true
|
|||
true
|
||||
[1, 3, 5, hi]
|
||||
[-3, 7, 42, 67, 108]
|
||||
[97, 98, 99, 100, 101, 102]
|
||||
0
|
||||
1
|
||||
79
|
||||
|
@ -278,15 +277,15 @@ a
|
|||
123
|
||||
123
|
||||
[[1, 2, 3]]
|
||||
[[[1, 2, 3]]]
|
||||
[[1, 2, 3]]
|
||||
[[[1, 2, 3]]]
|
||||
[[1, 2, 3]]
|
||||
[[1, 2, 3]]
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
||||
false
|
||||
true
|
||||
true
|
||||
true
|
||||
|
@ -297,7 +296,13 @@ true
|
|||
[[], [], [], []]
|
||||
[[], [], [123], []]
|
||||
[{}, {}, {}, {}]
|
||||
[{}, {}, {'123': 123}, {}]
|
||||
Numbers { odds: [1, 3, 5] , evens: [2, 4] }
|
||||
Numbers { odds: [3, 5, 7] , evens: [2, 6, 10] }
|
||||
[{}, {}, {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]]
|
|
@ -798,10 +798,11 @@ fn main() {
|
|||
*/
|
||||
}
|
||||
{
|
||||
/*
|
||||
// test rune sort
|
||||
mut bs := [`f`, `e`, `d`, `b`, `c`, `a`]
|
||||
bs.sort()
|
||||
println(bs)
|
||||
println(bs)*/
|
||||
|
||||
/*
|
||||
bs.sort(a > b)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
Foo { x: 5 , y: 5 }
|
||||
Foo{
|
||||
x: 5
|
||||
y: 5
|
||||
}
|
||||
true
|
||||
true
|
|
@ -0,0 +1,35 @@
|
|||
module js
|
||||
|
||||
import v.ast
|
||||
|
||||
struct Type {
|
||||
// typ is the original type
|
||||
typ ast.Type [required]
|
||||
sym &ast.TypeSymbol [required]
|
||||
// unaliased is `typ` once aliased have been resolved
|
||||
// it may not contain informations such as flags and nr_muls
|
||||
unaliased ast.Type [required]
|
||||
unaliased_sym &ast.TypeSymbol [required]
|
||||
}
|
||||
|
||||
// unwrap returns the following variants of a type:
|
||||
// * generics unwrapped
|
||||
// * alias unwrapped
|
||||
fn (mut g JsGen) unwrap(typ ast.Type) Type {
|
||||
no_generic := g.unwrap_generic(typ)
|
||||
no_generic_sym := g.table.get_type_symbol(no_generic)
|
||||
if no_generic_sym.kind != .alias {
|
||||
return Type{
|
||||
typ: no_generic
|
||||
sym: no_generic_sym
|
||||
unaliased: no_generic
|
||||
unaliased_sym: no_generic_sym
|
||||
}
|
||||
}
|
||||
return Type{
|
||||
typ: no_generic
|
||||
sym: no_generic_sym
|
||||
unaliased: no_generic_sym.parent_idx
|
||||
unaliased_sym: g.table.get_type_symbol(no_generic_sym.parent_idx)
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
module stats_import
|
Loading…
Reference in New Issue