v.gen.js: fix method calls and other codegen parts, rand module compiles (#11205)

pull/11229/head
playX 2021-08-18 11:33:37 +03:00 committed by GitHub
parent c51f83efba
commit 0121c8b4fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 301 additions and 130 deletions

View File

@ -84,11 +84,11 @@ fn (a &array) set_len(i int) {
} }
pub fn (mut a array) sort_with_compare(compare voidptr) { pub fn (mut a array) sort_with_compare(compare voidptr) {
#a.arr.sort(compare) #a.val.arr.sort(compare)
} }
pub fn (mut a array) sort() { pub fn (mut a array) sort() {
#a.arr.sort($sortComparator) #a.val.arr.sort($sortComparator)
} }
pub fn (a array) index(v string) int { pub fn (a array) index(v string) int {
@ -110,16 +110,16 @@ pub fn (a array) slice(start int, end int) array {
} }
pub fn (mut a array) insert(i int, val voidptr) { pub fn (mut a array) insert(i int, val voidptr) {
#a.arr.splice(i,0,val) #a.val.arr.splice(i,0,val)
} }
pub fn (mut a array) insert_many(i int, val voidptr, size int) { pub fn (mut a array) insert_many(i int, val voidptr, size int) {
#a.arr.splice(i,0,...val.slice(0,+size)) #a.val.arr.splice(i,0,...val.slice(0,+size))
} }
pub fn (mut a array) join(separator string) string { pub fn (mut a array) join(separator string) string {
mut res := '' mut res := ''
#res = new builtin.string(a.arr.join(separator +'')); #res = new builtin.string(a.val.arr.join(separator +''));
return res return res
} }
@ -164,7 +164,7 @@ pub fn (mut a array) delete(i int) {
// delete_many deletes `size` elements beginning with index `i` // delete_many deletes `size` elements beginning with index `i`
pub fn (mut a array) delete_many(i int, size int) { pub fn (mut a array) delete_many(i int, size int) {
#a.arr.splice(i.valueOf(),size.valueOf()) #a.val.arr.splice(i.valueOf(),size.valueOf())
} }
// prepend prepends one value to the array. // prepend prepends one value to the array.
@ -186,7 +186,7 @@ pub fn (a array) reverse() array {
} }
pub fn (mut a array) reverse_in_place() { pub fn (mut a array) reverse_in_place() {
#a.arr.reverse() #a.val.arr.reverse()
} }
#array.prototype.$includes = function (elem) { return this.arr.find(function(e) { return vEq(elem,e); }) !== undefined;} #array.prototype.$includes = function (elem) { return this.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
@ -195,7 +195,7 @@ pub fn (mut a array) reverse_in_place() {
// resulting in a single output value. // resulting in a single output value.
pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int { pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
mut accum_ := accum_start mut accum_ := accum_start
#for (let i of a) { #for (let i = 0;i < a.arr.length;i++) {
#accum_ = iter(accum_, a.arr[i]) #accum_ = iter(accum_, a.arr[i])
#} #}
@ -204,7 +204,7 @@ pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
pub fn (mut a array) pop() voidptr { pub fn (mut a array) pop() voidptr {
mut res := voidptr(0) mut res := voidptr(0)
#res = a.arr.pop() #res = a.val.arr.pop()
return res return res
} }
@ -237,5 +237,5 @@ pub fn (a array) contains(key voidptr) bool {
// delete_last effectively removes last element of an array. // delete_last effectively removes last element of an array.
pub fn (mut a array) delete_last() { pub fn (mut a array) delete_last() {
#a.arr.pop(); #a.val.arr.pop();
} }

View File

@ -4,3 +4,35 @@ module builtin
pub fn js_throw(s any) { pub fn js_throw(s any) {
#throw (s instanceof Error ? s : new Error(s)) #throw (s instanceof Error ? s : new Error(s))
} }
pub fn println(s any) {
$if js_freestanding {
#print(s.toString())
} $else {
#console.log(s.toString())
}
}
pub fn print(s any) {
$if js_node {
#$process.stdout.write(s.toString())
} $else {
panic('Cannot `print` in a browser, use `println` instead')
}
}
pub fn eprintln(s any) {
$if js_freestanding {
#print(s.toString())
} $else {
#console.error(s.toString())
}
}
pub fn eprint(s any) {
$if js_node {
#$process.stderr.write(s.toString())
} $else {
panic('Cannot `eprint` in a browser, use `println` instead')
}
}

View File

@ -6,34 +6,6 @@ module builtin
fn (a any) toString() fn (a any) toString()
pub fn println(s any) {
// Quickfix to properly print basic types
// TODO: Add proper detection code for this
JS.console.log(s.toString())
}
pub fn print(s any) {
// TODO
// $if js.node {
JS.process.stdout.write(s.toString())
// } $else {
// panic('Cannot `print` in a browser, use `println` instead')
// }
}
pub fn eprintln(s any) {
JS.console.error(s.toString())
}
pub fn eprint(s any) {
// TODO
// $if js.node {
JS.process.stderr.write(s.toString())
// } $else {
// panic('Cannot `eprint` in a browser, use `eprintln` instead')
// }
}
// Exits the process in node, and halts execution in the browser // Exits the process in node, and halts execution in the browser
// because `process.exit` is undefined. Workaround for not having // because `process.exit` is undefined. Workaround for not having
// a 'real' way to exit in the browser. // a 'real' way to exit in the browser.

View File

@ -0,0 +1,13 @@
module config
import rand.seed
// PRNGConfigStruct is a configuration struct for creating a new instance of the default RNG.
// Note that the RNGs may have a different number of u32s required for seeding. The default
// generator WyRand used 64 bits, ie. 2 u32s so that is the default. In case your desired generator
// uses a different number of u32s, use the `seed.time_seed_array()` method with the correct
// number of u32s.
pub struct PRNGConfigStruct {
pub:
seed_ []u32 = seed.time_seed_array(2)
}

View File

@ -3,18 +3,9 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module rand module rand
import rand.seed import rand.config
import rand.wyrand import rand.wyrand
// PRNGConfigStruct is a configuration struct for creating a new instance of the default RNG.
// Note that the RNGs may have a different number of u32s required for seeding. The default
// generator WyRand used 64 bits, ie. 2 u32s so that is the default. In case your desired generator
// uses a different number of u32s, use the `seed.time_seed_array()` method with the correct
// number of u32s.
pub struct PRNGConfigStruct {
seed_ []u32 = seed.time_seed_array(2)
}
// PRNG is a common interface for all PRNGs that can be used seamlessly with the rand // PRNG is a common interface for all PRNGs that can be used seamlessly with the rand
// modules's API. It defines all the methods that a PRNG (in the vlib or custom made) must // modules's API. It defines all the methods that a PRNG (in the vlib or custom made) must
// implement in order to ensure that _all_ functions can be used with the generator. // implement in order to ensure that _all_ functions can be used with the generator.
@ -52,7 +43,7 @@ fn init() {
} }
// new_default returns a new instance of the default RNG. If the seed is not provided, the current time will be used to seed the instance. // new_default returns a new instance of the default RNG. If the seed is not provided, the current time will be used to seed the instance.
pub fn new_default(config PRNGConfigStruct) &PRNG { pub fn new_default(config config.PRNGConfigStruct) &PRNG {
mut rng := &wyrand.WyRandRNG{} mut rng := &wyrand.WyRandRNG{}
rng.seed(config.seed_) rng.seed(config.seed_)
return rng return rng

View File

@ -0,0 +1,24 @@
module time
// parse returns time from a date string.
//
// TODO(playX): JS Date expects iso8061 format of strings and other formats
// are implementation dependant, we probably want to implement parsing in JS.
pub fn parse(s string) Time {
mut res := Time{}
#let date = new Date(s.str)
#res.year.val = date.getFullYear()
#res.month.val = date.getMonth()
#res.day.val = date.getDay()
#res.hour.val = date.getHours()
#res.minute.val = date.getMinutes()
#res.second.val = date.getSeconds()
#res.microsecond.val = date.getMilliseconds() * 1000
#res.unix.val = (date.getTime() / 1000).toFixed(0)
return res
}
pub fn parse_iso8601(s string) ?Time {
return parse(s)
}

View File

@ -304,8 +304,8 @@ fn (mut g JsGen) gen_builtin_type_defs() {
g.gen_builtin_prototype( g.gen_builtin_prototype(
typ_name: typ_name typ_name: typ_name
default_value: 'new Number(0)' default_value: 'new Number(0)'
constructor: 'this.val = val | 0' constructor: 'this.val = Number(val)'
value_of: 'this.val | 0' value_of: 'Number(this.val)'
to_string: 'this.valueOf().toString()' to_string: 'this.valueOf().toString()'
eq: 'this.valueOf() === other.valueOf()' eq: 'this.valueOf() === other.valueOf()'
to_jsval: '+this' to_jsval: '+this'

View File

@ -308,7 +308,7 @@ pub fn (mut g JsGen) init() {
g.definitions.writeln('"use strict";') g.definitions.writeln('"use strict";')
g.definitions.writeln('') g.definitions.writeln('')
g.definitions.writeln('var \$global = (new Function("return this"))();') g.definitions.writeln('var \$global = (new Function("return this"))();')
g.definitions.writeln('function \$ref(value) { this.val = value; } ') g.definitions.writeln('function \$ref(value) { if (value instanceof \$ref) { return value; } this.val = value; } ')
g.definitions.writeln('\$ref.prototype.valueOf = function() { return this.val; } ') g.definitions.writeln('\$ref.prototype.valueOf = function() { return this.val; } ')
if g.pref.backend != .js_node { if g.pref.backend != .js_node {
g.definitions.writeln('const \$process = {') g.definitions.writeln('const \$process = {')
@ -736,17 +736,16 @@ fn (mut g JsGen) expr(node ast.Expr) {
} }
ast.PrefixExpr { ast.PrefixExpr {
if node.op in [.amp, .mul] { if node.op in [.amp, .mul] {
// C pointers/references: ignore them
if node.op == .amp { if node.op == .amp {
if !node.right_type.is_pointer() { // if !node.right_type.is_pointer() {
// kind of weird way to handle references but it allows us to access type methods easily. // kind of weird way to handle references but it allows us to access type methods easily.
g.write('(function(x) {') g.write('(function(x) {')
g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ') g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ')
g.expr(node.right) g.expr(node.right)
g.write(')') g.write(')')
} else { //} else {
g.expr(node.right) // g.expr(node.right)
} // }
} else { } else {
g.write('(') g.write('(')
g.expr(node.right) g.expr(node.right)
@ -1150,14 +1149,22 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
if args.len > 0 { if args.len > 0 {
g.write(', ') g.write(', ')
} }
if it.params[0].is_mut {
g.write('${it.params[0].name} = new \$ref(this)')
} else {
g.write('${it.params[0].name} = this') g.write('${it.params[0].name} = this')
} }
}
g.writeln(') {') g.writeln(') {')
for i, arg in args { for i, arg in args {
is_varg := i == args.len - 1 && it.is_variadic is_varg := i == args.len - 1 && it.is_variadic
if is_varg {
name := g.js_name(arg.name) name := g.js_name(arg.name)
if is_varg {
g.writeln('$name = new array($name);') g.writeln('$name = new array($name);')
} else {
if arg.typ.is_ptr() || arg.is_mut {
g.writeln('$name = new \$ref($name)')
}
} }
} }
@ -1514,7 +1521,141 @@ fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) {
g.write(']') g.write(']')
} }
fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
g.call_stack << it
mut name := g.js_name(it.name)
call_return_is_optional := it.return_type.has_flag(.optional)
if call_return_is_optional {
g.writeln('(function(){')
g.inc_indent()
g.writeln('try {')
g.inc_indent()
g.write('return builtin.unwrap(')
}
sym := g.table.get_type_symbol(it.receiver_type)
if sym.kind == .array {
if sym.kind == .array && it.name in ['map', 'filter'] {
g.expr(it.left)
mut ltyp := it.left_type
for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
}
g.write('.')
// Prevent 'it' from getting shadowed inside the match
node := it
g.write(it.name)
g.write('(')
expr := node.args[0].expr
match expr {
ast.AnonFn {
g.gen_fn_decl(expr.decl)
g.write(')')
return true
}
ast.Ident {
if expr.kind == .function {
g.write(g.js_name(expr.name))
g.write(')')
return true
} 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
}
}
}
else {}
}
g.write('it => ')
g.expr(node.args[0].expr)
g.write(')')
return true
}
left_sym := g.table.get_type_symbol(it.left_type)
if 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
}
}
}
// interfaces require dynamic dispatch. To obtain method table we use getPrototypeOf
g.write('Object.getPrototypeOf(')
g.expr(it.left)
mut ltyp := it.left_type
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(')')
if call_return_is_optional {
// end unwrap
g.writeln(')')
g.dec_indent()
// begin catch block
g.writeln('} catch(err) {')
g.inc_indent()
// gen or block contents
match it.or_block.kind {
.block {
if it.or_block.stmts.len > 1 {
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
}
g.write('return ')
g.stmt(it.or_block.stmts.last())
}
.propagate {
panicstr := '`optional not set (\${err})`'
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
g.writeln('return builtin.panic($panicstr)')
} else {
g.writeln('builtin.js_throw(err)')
}
}
else {}
}
// end catch
g.dec_indent()
g.writeln('}')
// end anon fn
g.dec_indent()
g.write('})()')
}
g.call_stack.delete_last()
return true
}
fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
if it.is_method {
if g.gen_method_call(it) {
return
}
}
g.call_stack << it g.call_stack << it
mut name := g.js_name(it.name) mut name := g.js_name(it.name)
call_return_is_optional := it.return_type.has_flag(.optional) call_return_is_optional := it.return_type.has_flag(.optional)
@ -1525,59 +1666,13 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
g.inc_indent() g.inc_indent()
g.write('return builtin.unwrap(') g.write('return builtin.unwrap(')
} }
g.expr(it.left) g.expr(it.left)
if it.is_method { // foo.bar.baz()
sym := g.table.get_type_symbol(it.receiver_type)
g.write('.')
if sym.kind == .array && it.name in ['map', 'filter'] {
// Prevent 'it' from getting shadowed inside the match
node := it
g.write(it.name)
g.write('(')
expr := node.args[0].expr
match expr {
ast.AnonFn {
g.gen_fn_decl(expr.decl)
g.write(')')
return
}
ast.Ident {
if expr.kind == .function {
g.write(g.js_name(expr.name))
g.write(')')
return
} else if expr.kind == .variable {
v_sym := g.table.get_type_symbol(expr.var_info().typ)
if v_sym.kind == .function {
g.write(g.js_name(expr.name))
g.write(')')
return
}
}
}
else {}
}
g.write('it => ')
g.expr(node.args[0].expr)
g.write(')')
return
}
left_sym := g.table.get_type_symbol(it.left_type)
if left_sym.kind == .array {
node := it
if node.name in special_array_methods {
g.gen_array_method_call(it)
return
}
}
} else {
if name in g.builtin_fns { if name in g.builtin_fns {
g.write('builtin.') g.write('builtin.')
} }
}
g.write('${name}(') g.write('${name}(')
for i, arg in it.args { for i, arg in it.args {
g.expr(arg.expr) g.expr(arg.expr)
@ -1782,6 +1877,14 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
} }
} }
fn (mut g JsGen) gen_deref_ptr(ty ast.Type) {
mut t := ty
for t.is_ptr() {
g.write('.val')
t = t.deref()
}
}
fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
l_sym := g.table.get_type_symbol(it.left_type) l_sym := g.table.get_type_symbol(it.left_type)
r_sym := g.table.get_type_symbol(it.right_type) r_sym := g.table.get_type_symbol(it.right_type)
@ -1804,10 +1907,12 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.cast_stack << greater_typ g.cast_stack << greater_typ
g.write('BigInt((') g.write('BigInt((')
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write(').\$toJS())') g.write(').\$toJS())')
g.write(' $it.op ') g.write(' $it.op ')
g.write('BigInt((') g.write('BigInt((')
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.write(').\$toJS())') g.write(').\$toJS())')
g.cast_stack.delete_last() g.cast_stack.delete_last()
g.write(')') g.write(')')
@ -1820,30 +1925,41 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
has_operator_overloading := g.table.type_has_method(l_sym, '==') has_operator_overloading := g.table.type_has_method(l_sym, '==')
if has_operator_overloading { if has_operator_overloading {
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write('.eq(') g.write('.eq(')
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.write(')') g.write(')')
// Shallow equatables // Shallow equatables
} else if l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables { } else if l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables {
// wrap left expr in parens so binary operations will work correctly. // wrap left expr in parens so binary operations will work correctly.
g.write('(') g.write('(')
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write(')') g.write(')')
g.write('.eq(') g.write('.eq(')
g.cast_stack << int(l_sym.kind) g.cast_stack << int(l_sym.kind)
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.cast_stack.delete_last() g.cast_stack.delete_last()
g.write(')') g.write(')')
} else { } else {
g.write('vEq(') g.write('vEq(')
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write(', ') g.write(', ')
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.write(')') g.write(')')
} }
} else if l_sym.kind == .array && it.op == .left_shift { // arr << 1 } else if l_sym.kind == .array && it.op == .left_shift { // arr << 1
g.write('Array.prototype.push.call(') g.write('Array.prototype.push.call(')
g.expr(it.left) g.expr(it.left)
mut ltyp := it.left_type
for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
}
g.write('.arr,') g.write('.arr,')
array_info := l_sym.info as ast.Array array_info := l_sym.info as ast.Array
// arr << [1, 2] // arr << [1, 2]
@ -1854,6 +1970,12 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.write(')') g.write(')')
} else if r_sym.kind in [.array, .map, .string] && it.op in [.key_in, .not_in] { } else if r_sym.kind in [.array, .map, .string] && it.op in [.key_in, .not_in] {
g.expr(it.right) g.expr(it.right)
mut ltyp := it.right_type
for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
}
if r_sym.kind == .map { if r_sym.kind == .map {
g.write('.map.has(') g.write('.map.has(')
} else if r_sym.kind == .string { } else if r_sym.kind == .string {
@ -1868,6 +1990,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.write(')') g.write(')')
} else if it.op in [.key_is, .not_is] { // foo is Foo } else if it.op in [.key_is, .not_is] { // foo is Foo
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write(' instanceof ') g.write(' instanceof ')
g.write(g.typ(it.right_type)) g.write(g.typ(it.right_type))
} else if it.op in [.lt, .gt, .ge, .le] && g.table.type_has_method(l_sym, '<') } else if it.op in [.lt, .gt, .ge, .le] && g.table.type_has_method(l_sym, '<')
@ -1877,19 +2000,24 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
} }
if it.op in [.lt, .ge] { if it.op in [.lt, .ge] {
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write('.\$lt (') g.write('.\$lt (')
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.write(')') g.write(')')
} else { } else {
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.write('.\$lt (') g.write('.\$lt (')
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write(')') g.write(')')
} }
} else { } else {
has_operator_overloading := g.table.type_has_method(l_sym, it.op.str()) has_operator_overloading := g.table.type_has_method(l_sym, it.op.str())
if has_operator_overloading { if has_operator_overloading {
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
name := match it.op.str() { name := match it.op.str() {
'+' { '+' {
'\$add' '\$add'
@ -1913,6 +2041,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
} }
g.write('.$name (') g.write('.$name (')
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
g.write(')') g.write(')')
} else { } else {
mut greater_typ := 0 mut greater_typ := 0
@ -1933,10 +2062,11 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
} }
g.expr(it.left) g.expr(it.left)
g.gen_deref_ptr(it.left_type)
g.write(' $it.op ') g.write(' $it.op ')
g.expr(it.right) g.expr(it.right)
g.gen_deref_ptr(it.right_type)
if is_arithmetic { if is_arithmetic {
g.cast_stack.delete_last() g.cast_stack.delete_last()
@ -2033,8 +2163,10 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) { fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
g.expr(it.expr) g.expr(it.expr)
if it.expr_type.is_ptr() { mut ltyp := it.expr_type
g.write('.valueOf()') for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
} }
g.write('.$it.field_name') g.write('.$it.field_name')
} }
@ -2078,7 +2210,8 @@ fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
} }
fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) { fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
text := it.val.replace("'", "\\'") mut text := it.val.replace("'", "'")
text = text.replace('"', '\\"')
should_cast := !(g.cast_stack.len > 0 && g.cast_stack.last() == ast.string_type_idx) should_cast := !(g.cast_stack.len > 0 && g.cast_stack.last() == ast.string_type_idx)
if true || should_cast { if true || should_cast {
if g.file.mod.name == 'builtin' { if g.file.mod.name == 'builtin' {
@ -2086,7 +2219,7 @@ fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
} }
g.write('string(') g.write('string(')
} }
g.write("'$text'") g.write("\"$text\"")
if true || should_cast { if true || should_cast {
g.write(')') g.write(')')
} }
@ -2166,6 +2299,9 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
g.cast_stack << it.typ g.cast_stack << it.typ
typ := g.typ(it.typ) typ := g.typ(it.typ)
if !is_literal { if !is_literal {
if it.typ.is_ptr() {
g.write('new \$ref(')
}
if typ !in js.v_types || g.ns.name == 'builtin' { if typ !in js.v_types || g.ns.name == 'builtin' {
g.write('new ') g.write('new ')
} }
@ -2177,6 +2313,9 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
} }
if !is_literal { if !is_literal {
g.write(')') g.write(')')
if it.typ.is_ptr() {
g.write(')')
}
} }
g.cast_stack.delete_last() g.cast_stack.delete_last()
} }

View File

@ -60,16 +60,16 @@ true
0 0
1 1
1.1 1.1
[1, 2, 3, 4] [[1, 2], 3, 4]
[1, 5, 6, 2, 3, 4] [[1, 2], [5, 6], 3, 4]
0 0
1 1
1 1
0 0
1 1
1.1 1.1
[1, 2, 3, 4] [[1, 2], 3, 4]
[5, 6, 1, 2, 3, 4] [[5, 6], [1, 2], 3, 4]
5 5
true true
1.1 1.1
@ -152,11 +152,11 @@ true
true true
true true
true true
0 15
0 20
0 14
0 -6
0 -7
[2, 4, 6] [2, 4, 6]
[is, awesome] [is, awesome]
[2, 3, 4, 6, 8, 9, 10] [2, 3, 4, 6, 8, 9, 10]
@ -278,9 +278,9 @@ a
123 123
123 123
[[1, 2, 3]] [[1, 2, 3]]
[[[1, 2, 3]]]
[[1, 2, 3]] [[1, 2, 3]]
[[1, 2, 3]] [[[1, 2, 3]]]
[[1, 2, 3]]
true true
true true
true true