v.gen.js: fix method calls and other codegen parts, rand module compiles (#11205)
parent
c51f83efba
commit
0121c8b4fd
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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'
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue