v2 / vlib / v / gen / js / fn.v
861 lines · 807 sloc · 19.4 KB · 8e35f4d9848f7ad35d857a187dddbfd2eca5e19d
Raw
1module js
2
3import v.ast
4import v.util
5import strings
6
7pub const builtin_functions = ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit']
8
9fn (mut g JsGen) js_mname(name_ string) string {
10 mut is_js := false
11 is_overload := ['+', '-', '*', '/', '==', '<', '>']
12 mut name := name_
13 if name.starts_with('JS.') {
14 name = name[3..]
15 is_js = true
16 }
17 ns := get_ns(name)
18 name = if name in is_overload {
19 match name {
20 '+' {
21 '\$add'
22 }
23 '-' {
24 '\$sub'
25 }
26 '/' {
27 '\$div'
28 }
29 '*' {
30 '\$mul'
31 }
32 '%' {
33 '\$mod'
34 }
35 '==' {
36 'eq'
37 }
38 '>' {
39 '\$gt'
40 }
41 '<' {
42 '\$lt'
43 }
44 else {
45 ''
46 }
47 }
48 } else if unsafe { g.ns == 0 } {
49 name
50 } else if ns == g.ns.name {
51 name.split('.').last()
52 } else {
53 g.get_alias(name)
54 }
55 mut parts := name.split('.')
56 if !is_js {
57 for i, p in parts {
58 if p in js_reserved {
59 parts[i] = 'v_${p}'
60 }
61 }
62 }
63 return parts.join('.')
64}
65
66fn (mut g JsGen) js_call(node ast.CallExpr) {
67 g.call_stack << node
68 it := node
69 call_return_is_option := it.return_type.has_flag(.option)
70 is_await := node.name == 'JS.await'
71 if call_return_is_option {
72 if is_await {
73 g.writeln('await (async function () {')
74 } else {
75 g.writeln('(function () {')
76 }
77 g.writeln('try {')
78 g.writeln('let tmp = ')
79 }
80 if it.is_ctor_new {
81 g.write('new ')
82 }
83 if is_await {
84 g.write('await (')
85
86 g.expr(it.args[0].expr)
87 g.write(').promise')
88 } else {
89 g.write('${g.js_mname(it.name)}(')
90 for i, arg in it.args {
91 g.expr(arg.expr)
92 if i != it.args.len - 1 {
93 g.write(', ')
94 }
95 }
96 // end call
97 g.write(')')
98 }
99 if call_return_is_option {
100 g.write(';\n')
101 prev_inside_or := g.inside_or
102 g.inside_or = true
103 defer {
104 g.inside_or = prev_inside_or
105 }
106 g.writeln('if (tmp === null) throw "none";')
107 g.writeln('return tmp;')
108 g.writeln('} catch(err) {')
109 g.inc_indent()
110 // gen or block contents
111 match it.or_block.kind {
112 .block {
113 if it.or_block.stmts.len > 1 {
114 g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
115 }
116 // g.write('return ')
117 g.stmt(it.or_block.stmts.last())
118 }
119 .propagate_option {
120 panicstr := '`option not set (\${err + ""})`'
121 if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
122 g.writeln('return builtin__panic(${panicstr})')
123 } else {
124 g.writeln('throw new Option({ state: new u8(2), err: error(new string(${panicstr})) });')
125 }
126 }
127 else {}
128 }
129
130 // end catch
131 g.dec_indent()
132 g.writeln('}')
133 g.writeln('})()')
134 }
135 g.call_stack.delete_last()
136}
137
138fn (mut g JsGen) js_method_call(node ast.CallExpr) {
139 g.call_stack << node
140 it := node
141 call_return_is_option := it.return_type.has_flag(.option)
142 if call_return_is_option {
143 g.writeln('(function () {')
144 g.writeln('try {')
145 g.writeln('let tmp = ')
146 }
147 if it.is_ctor_new {
148 g.write('new ')
149 }
150 g.expr(it.left)
151 g.write('.${g.js_mname(it.name)}(')
152 for i, arg in it.args {
153 g.expr(arg.expr)
154 if i != it.args.len - 1 {
155 g.write(', ')
156 }
157 }
158 // end method call
159 g.write(')')
160 if call_return_is_option {
161 prev_inside_or := g.inside_or
162 g.inside_or = true
163 defer {
164 g.inside_or = prev_inside_or
165 }
166 g.write(';\n')
167 g.writeln('if (tmp === null) throw "none";')
168 g.writeln('return tmp;')
169 g.writeln('} catch(err) {')
170 g.inc_indent()
171 // gen or block contents
172 match it.or_block.kind {
173 .block {
174 if it.or_block.stmts.len > 1 {
175 g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
176 }
177 // g.write('return ')
178 g.stmt(it.or_block.stmts.last())
179 }
180 .propagate_option {
181 panicstr := '`option not set (\${err + ""})`'
182 if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
183 g.writeln('return builtin__panic(${panicstr})')
184 } else {
185 g.writeln('throw new option({ state: new u8(2), err: error(new string(${panicstr})) });')
186 }
187 }
188 else {}
189 }
190
191 // end catch
192 g.dec_indent()
193 g.writeln('}')
194 g.writeln('})()')
195 }
196 g.call_stack.delete_last()
197}
198
199fn (mut g JsGen) method_call(node ast.CallExpr) {
200 g.call_stack << node
201 it := node
202 if it.name == 'str' {
203 g.gen_expr_to_string(node.left, node.left_type)
204 return
205 }
206 is_async := node.name == 'wait' && g.table.sym(node.receiver_type).name.starts_with('Promise<')
207 call_return_is_option := it.return_type.has_flag(.option)
208 if call_return_is_option {
209 if is_async {
210 g.writeln('(async function (){')
211 } else {
212 g.writeln('(function(){')
213 }
214 g.inc_indent()
215 g.writeln('try {')
216 g.inc_indent()
217 g.write('return unwrap(')
218 }
219 if node.name == 'str' {
220 mut rec_type := node.receiver_type
221 if rec_type.has_flag(.shared_f) {
222 rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
223 }
224 g.get_str_fn(rec_type)
225 }
226 mut unwrapped_rec_type := node.receiver_type
227 if unsafe { g.fn_decl != 0 } && g.fn_decl.generic_names.len > 0 { // in generic fn
228 unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
229 } else { // in non-generic fn
230 sym := g.table.sym(node.receiver_type)
231 match sym.info {
232 ast.Struct, ast.Interface, ast.SumType {
233 generic_names := sym.info.generic_types.map(g.table.sym(it).name)
234 // see comment at top of vlib/v/gen/c/utils.v
235 mut muttable := unsafe { &ast.Table(g.table) }
236 if utyp := muttable.convert_generic_type(node.receiver_type, generic_names,
237 sym.info.concrete_types)
238 {
239 unwrapped_rec_type = utyp
240 }
241 }
242 else {}
243 }
244 }
245
246 mut typ_sym := g.table.sym(unwrapped_rec_type)
247 rec_cc_type := g.cc_type(unwrapped_rec_type, false)
248 mut receiver_type_name := util.no_dots(rec_cc_type)
249 // alias type that undefined this method (not include `str`) need to use parent type
250 if typ_sym.kind == .alias && node.name != 'str' && !typ_sym.has_method(node.name) {
251 unwrapped_rec_type = (typ_sym.info as ast.Alias).parent_type
252 typ_sym = g.table.sym(unwrapped_rec_type)
253 }
254
255 if typ_sym.kind == .interface && (typ_sym.info as ast.Interface).defines_method(node.name) {
256 g.expr(it.left)
257 g.gen_deref_ptr(it.left_type)
258 g.write('.${it.name}(')
259 for i, arg in it.args {
260 g.expr(arg.expr)
261 if i != it.args.len - 1 {
262 g.write(', ')
263 }
264 }
265 g.write(')')
266 return
267 }
268
269 left_sym := g.table.sym(node.left_type)
270 final_left_sym := g.table.final_sym(node.left_type)
271
272 if final_left_sym.kind == .map && it.name in special_map_methods {
273 g.gen_map_method_call(it)
274 return
275 } else if final_left_sym.kind == .array {
276 if it.name in ['map', 'filter'] {
277 g.expr(it.left)
278 mut ltyp := it.left_type
279 for ltyp.is_ptr() {
280 g.write('.valueOf()')
281 ltyp = ltyp.deref()
282 }
283 g.write('.')
284 // Prevent 'it' from getting shadowed inside the match
285
286 g.write(it.name)
287 g.write('(')
288 expr := node.args[0].expr
289 match expr {
290 ast.AnonFn {
291 g.gen_fn_decl(expr.decl)
292 g.write(')')
293 return
294 }
295 ast.Ident {
296 if expr.kind == .function {
297 g.write(g.js_name(expr.name))
298 g.write(')')
299 return
300 } else if expr.kind == .variable && expr.info is ast.IdentVar {
301 v_sym := g.table.sym(expr.var_info().typ)
302 if v_sym.kind == .function {
303 g.write(g.js_name(expr.name))
304 g.write(')')
305 return
306 }
307 }
308 }
309 else {}
310 }
311
312 g.write('it => ')
313 g.expr(node.args[0].expr)
314 g.write(')')
315 return
316 }
317
318 if it.name in special_array_methods {
319 g.gen_array_method_call(it)
320 return
321 }
322
323 if node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last',
324 'pop_left', 'pop', 'clone', 'reverse', 'slice', 'pointers'] {
325 if !(left_sym.info is ast.Alias && typ_sym.has_method(node.name)) {
326 // `array_Xyz_clone` => `array_clone`
327 receiver_type_name = 'array'
328 }
329 }
330 }
331
332 if is_async {
333 g.write('await ')
334 g.expr(it.left)
335 g.write('.promise')
336 } else {
337 mut name := util.no_dots('${receiver_type_name}_${node.name}')
338
339 name = g.generic_fn_name(node.concrete_types, name)
340 g.write('${name}(')
341 g.expr_with_expected_type(it.left, unwrapped_rec_type)
342 g.gen_deref_ptr(it.left_type)
343 g.write(',')
344 for i, arg in it.args {
345 expected_arg_type := if i < it.expected_arg_types.len {
346 it.expected_arg_types[i]
347 } else {
348 arg.typ
349 }
350 g.expr_with_expected_type(arg.expr, expected_arg_type)
351 if i != it.args.len - 1 {
352 g.write(', ')
353 }
354 }
355 g.write(')')
356 }
357
358 if call_return_is_option {
359 // end unwrap
360 g.writeln(')')
361 g.dec_indent()
362 prev_inside_or := g.inside_or
363 g.inside_or = true
364 defer {
365 g.inside_or = prev_inside_or
366 }
367 // begin catch block
368 g.writeln('} catch(err) {')
369 g.inc_indent()
370 // gen or block contents
371 match it.or_block.kind {
372 .block {
373 if it.or_block.stmts.len > 1 {
374 g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
375 }
376 // g.write('return ')
377 g.stmt(it.or_block.stmts.last())
378 }
379 .propagate_option {
380 panicstr := '`option not set (\${err.valueOf().msg})`'
381 if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
382 g.writeln('return builtin__panic(${panicstr})')
383 } else {
384 g.writeln('js_throw(err)')
385 }
386 }
387 else {}
388 }
389
390 // end catch
391 g.dec_indent()
392 g.writeln('}')
393 // end anon fn
394 g.dec_indent()
395 g.write('})()')
396 }
397 g.call_stack.delete_last()
398}
399
400fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
401 if it.should_be_skipped {
402 return
403 }
404 if it.is_method && (it.is_field || g.table.sym(it.receiver_type).name.starts_with('JS.')) {
405 g.js_method_call(it)
406 return
407 } else if it.name.starts_with('JS.') {
408 g.js_call(it)
409 return
410 }
411 if it.is_method {
412 g.method_call(it)
413 return
414 }
415 node := it
416 g.call_stack << it
417 mut name := g.js_name(it.name)
418
419 is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic']
420 if name in builtin_functions {
421 name = 'builtin__${name}'
422 }
423 print_method := name
424 ret_sym := g.table.sym(it.return_type)
425 if it.language == .js && ret_sym.name in v_types && ret_sym.name != 'void' {
426 g.write('new ')
427 g.write(ret_sym.name)
428 g.write('(')
429 }
430 call_return_is_option := it.return_type.has_flag(.option)
431 if call_return_is_option {
432 g.writeln('(function(){')
433 g.inc_indent()
434 g.writeln('try {')
435 g.inc_indent()
436 g.write('return unwrap(')
437 }
438 if is_print {
439 mut typ := node.args[0].typ
440
441 expr := node.args[0].expr
442 g.write('${print_method} (')
443 g.gen_expr_to_string(expr, typ)
444 g.write(')')
445 return
446 }
447 name = g.generic_fn_name(node.concrete_types, name)
448 g.expr(it.left)
449
450 g.write('${name}(')
451 for i, arg in it.args {
452 expected_arg_type := if i < it.expected_arg_types.len {
453 it.expected_arg_types[i]
454 } else {
455 arg.typ
456 }
457 g.expr_with_expected_type(arg.expr, expected_arg_type)
458 if i != it.args.len - 1 {
459 g.write(', ')
460 }
461 }
462 // end method call
463 g.write(')')
464 if call_return_is_option {
465 // end unwrap
466 prev_inside_or := g.inside_or
467 g.inside_or = true
468 defer {
469 g.inside_or = prev_inside_or
470 }
471 g.writeln(')')
472 g.dec_indent()
473 // begin catch block
474 g.writeln('} catch(err) {')
475 g.inc_indent()
476 // gen or block contents
477 match it.or_block.kind {
478 .block {
479 if it.or_block.stmts.len > 1 {
480 g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
481 }
482
483 // g.write('return ')
484 g.stmt(it.or_block.stmts.last())
485 }
486 .propagate_option {
487 panicstr := '`option not set (\${err.valueOf().msg})`'
488 if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
489 g.writeln('return builtin__panic(${panicstr})')
490 } else {
491 g.writeln('js_throw(err)')
492 }
493 }
494 else {}
495 }
496
497 // end catch
498 g.dec_indent()
499 g.writeln('}')
500 // end anon fn
501 g.dec_indent()
502 g.write('})()')
503 }
504 if it.language == .js && ret_sym.name in v_types && ret_sym.name != 'void' {
505 g.write(')')
506 }
507 g.call_stack.delete_last()
508}
509
510enum FnGenType {
511 function
512 struct_method
513 alias_method
514 iface_method
515}
516
517fn (g &JsGen) fn_gen_type(it &ast.FnDecl) FnGenType {
518 if it.is_method && g.table.sym(it.params[0].typ).kind == .alias {
519 return .alias_method
520 } else if it.is_method && g.table.sym(it.params[0].typ).kind == .interface {
521 return .iface_method
522 } else if it.is_method || it.no_body {
523 return .struct_method
524 } else {
525 return .function
526 }
527}
528
529fn (mut g JsGen) is_used_by_main(node ast.FnDecl) bool {
530 mut is_used_by_main := true
531 if g.pref.skip_unused {
532 fkey := node.fkey()
533 is_used_by_main = g.table.used_features.used_fns[fkey]
534 $if trace_skip_unused_fns ? {
535 println('> is_used_by_main: ${is_used_by_main} | node.name: ${node.name} | fkey: ${fkey} | node.is_method: ${node.is_method}')
536 }
537 if !is_used_by_main {
538 $if trace_skip_unused_fns_in_js_code ? {
539 g.writeln('// trace_skip_unused_fns_in_js_code, ${node.name}, fkey: ${fkey}')
540 }
541 }
542 } else {
543 $if trace_skip_unused_fns_in_js_code ? {
544 g.writeln('// trace_skip_unused_fns_in_js_code, ${node.name}, fkey: ${node.fkey()}')
545 }
546 }
547 return is_used_by_main
548}
549
550fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
551 res := g.fn_gen_type(it)
552 if it.language == .js && it.no_body {
553 for attr in it.attrs {
554 match attr.name {
555 'wasm_import' {
556 mut x := g.wasm_export[attr.arg] or { []string{} }
557 x << it.name
558 g.wasm_import[attr.arg] = x
559 }
560 else {}
561 }
562 }
563 return
564 }
565 if g.inside_builtin {
566 g.builtin_fns << it.name
567 }
568 if !g.is_used_by_main(it) {
569 return
570 }
571 if it.should_be_skipped {
572 return
573 }
574 cur_fn_decl := g.fn_decl
575 g.fn_decl = unsafe { &it }
576 g.gen_method_decl(it, res)
577 g.fn_decl = cur_fn_decl
578}
579
580fn fn_has_go(node ast.FnDecl) bool {
581 mut has_go := false
582 for stmt in node.stmts {
583 if stmt is ast.ExprStmt {
584 if stmt.expr is ast.GoExpr {
585 has_go = true
586 break
587 }
588 }
589 }
590 return has_go
591}
592
593fn (mut g JsGen) generic_fn_name(types []ast.Type, before string) string {
594 if types.len == 0 {
595 return before
596 }
597
598 mut name := before + '_T'
599 for typ in types {
600 name += '_' + strings.repeat_string('__ptr__', typ.nr_muls()) + g.styp(typ.set_nr_muls(0))
601 }
602 return name
603}
604
605fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
606 node := it
607 if node.generic_names.len > 0 && g.cur_concrete_types.len == 0 { // need the cur_concrete_type check to avoid inf. recursion
608 // loop thru each generic type and generate a function
609 for concrete_types in g.table.fn_generic_types[node.fkey()] {
610 if g.pref.is_verbose {
611 syms := concrete_types.map(g.table.sym(it))
612 the_type := syms.map(it.name).join(', ')
613 println('gen fn `${node.name}` for type `${the_type}`')
614 }
615 g.cur_concrete_types = concrete_types
616 g.gen_method_decl(node, typ)
617 }
618 g.cur_concrete_types = []
619 return
620 }
621 cur_fn_decl := g.fn_decl
622 unsafe {
623 g.fn_decl = &it
624 }
625 cur_fn_save := g.table.cur_fn
626 defer {
627 g.table.cur_fn = cur_fn_save
628 }
629 unsafe {
630 g.table.cur_fn = &it
631 }
632 mut name := it.name
633 if name in ['+', '-', '*', '**', '/', '%', '<', '==', '[]', '[]='] {
634 name = util.replace_op(name)
635 }
636
637 if node.is_method {
638 name = g.cc_type(node.receiver.typ, false) + '_' + name
639 }
640 name = g.js_name(name)
641
642 name = g.generic_fn_name(g.cur_concrete_types, name)
643 if name in builtin_functions {
644 name = 'builtin__${name}'
645 }
646 if it.is_pub && !it.is_method {
647 g.push_pub_var(name)
648 }
649 if it.language == .js && it.is_method {
650 g.writeln('${g.styp(it.receiver.typ)}.prototype.${it.name} = ')
651 }
652
653 mut has_go := fn_has_go(it) || it.has_await
654 for attr in it.attrs {
655 if attr.name == 'async' {
656 if g.pref.output_es5 {
657 verror('cannot use @[async] attribute when outputting ES5 source code')
658 }
659 has_go = true
660 break
661 }
662 }
663 is_main := it.name == 'main.main'
664 g.gen_attrs(it.attrs)
665 if is_main {
666 // there is no concept of main in JS but we do have iife
667 g.writeln('/* program entry point */')
668 if !g.pref.output_es5 {
669 // main function is always async
670 g.write('async ')
671 }
672 g.write('function js_main(')
673 } else if it.is_anon {
674 g.write('function (')
675 } else {
676 c := name[0]
677 if c in [`+`, `-`, `*`, `/`] {
678 name = util.replace_op(name)
679 }
680 // type_name := g.styp(it.return_type)
681 // generate jsdoc for the function
682 g.doc.gen_fn(it)
683 if has_go && !g.pref.output_es5 {
684 g.write('async ')
685 }
686
687 g.write('function ')
688
689 g.write('${name}(')
690 if it.is_pub && !it.is_method {
691 g.push_pub_var(name)
692 }
693 }
694 args := it.params
695
696 g.fn_args(args, it.is_variadic)
697 g.writeln(') {')
698 for i, arg in args {
699 is_varg := i == args.len - 1 && it.is_variadic
700 arg_name := g.js_name(arg.name)
701 if is_varg {
702 g.writeln('${arg_name} = new array(new array_buffer({arr: ${arg_name},len: new int(${arg_name}.length),index_start: new int(0)}));')
703 } else {
704 asym := g.table.sym(arg.typ)
705 if asym.kind != .interface && asym.language != .js {
706 if arg.typ.is_ptr() || arg.is_mut {
707 g.writeln('${arg_name} = new \$ref(${arg_name})')
708 }
709 }
710 }
711 }
712 g.inc_indent()
713 g.writeln('try {')
714 g.inc_indent()
715 g.stmts(it.stmts)
716 g.dec_indent()
717 g.writeln('} catch (e) { ')
718 g.writeln('\tif (e instanceof ReturnException) { return e.val; } ')
719 g.writeln('\tthrow e;')
720 g.writeln('}')
721 g.dec_indent()
722 g.writeln('}')
723
724 if is_main {
725 // g.write(')')
726 }
727 g.writeln('')
728 for attr in it.attrs {
729 match attr.name {
730 'export' {
731 g.writeln('globalThis.${attr.arg} = ${g.js_name(it.name)};')
732 }
733 'wasm_export' {
734 mut x := g.wasm_export[attr.arg] or { []string{} }
735 g.write('function \$wasm${g.js_name(it.name)}(')
736 g.fn_args(args, it.is_variadic)
737 g.writeln(') {')
738 g.write('\treturn ${name} (')
739 for i, arg in args {
740 is_varg := i == args.len - 1 && it.is_variadic
741 arg_name := g.js_name(arg.name)
742 if is_varg {
743 g.write('...${arg_name}')
744 } else {
745 g.gen_cast_tmp(arg_name, arg.typ)
746 }
747 if i != args.len - 1 {
748 g.write(',')
749 }
750 }
751 g.writeln(').valueOf();')
752 g.writeln('}')
753 x << it.name
754 g.wasm_export[attr.arg] = x
755 }
756 'wasm_import' {
757 mut x := g.wasm_export[attr.arg] or { []string{} }
758 x << name
759 g.wasm_import[attr.arg] = x
760 }
761 else {}
762 }
763 }
764
765 g.fn_decl = cur_fn_decl
766}
767
768fn (mut g JsGen) fn_args(args []ast.Param, is_variadic bool) {
769 for i, arg in args {
770 name := g.js_name(arg.name)
771 is_varg := i == args.len - 1 && is_variadic
772 if is_varg {
773 g.write('...${name}')
774 } else {
775 g.write(name)
776 }
777 // if its not the last argument
778 if i < args.len - 1 {
779 g.write(', ')
780 }
781 }
782}
783
784fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) {
785 mut fn_name := fun.decl.name
786 if fun.decl.generic_names.len > 0 {
787 fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name)
788 }
789 if fun.has_gen[fn_name] {
790 return
791 }
792 fun.has_gen[fn_name] = true
793 it := fun.decl
794 cur_fn_decl := g.fn_decl
795 unsafe {
796 g.fn_decl = &it
797 }
798 cur_fn_save := g.table.cur_fn
799 defer {
800 g.table.cur_fn = cur_fn_save
801 }
802 unsafe {
803 g.table.cur_fn = &it
804 }
805 mut name := it.name
806 if name in ['+', '-', '*', '**', '/', '%', '<', '==', '[]', '[]='] {
807 name = util.replace_op(name)
808 }
809 g.writeln('(function () { ')
810 mut inherited2copy := map[string]string{}
811 for inherited in fun.inherited_vars {
812 if !inherited.is_mut {
813 copy := g.copy_val(inherited.typ, inherited.name)
814 inherited2copy[inherited.name] = copy
815 }
816 }
817
818 name = g.js_name(name)
819
820 name = g.generic_fn_name(g.table.cur_concrete_types, name)
821 if name in builtin_functions {
822 name = 'builtin__${name}'
823 }
824 if it.is_pub && !it.is_method {
825 g.push_pub_var(name)
826 }
827 g.gen_attrs(it.attrs)
828
829 g.write('return function (')
830
831 args := it.params
832
833 g.fn_args(args, it.is_variadic)
834 g.writeln(') {')
835
836 g.inc_indent()
837 for i, arg in args {
838 is_varg := i == args.len - 1 && it.is_variadic
839 arg_name := g.js_name(arg.name)
840 if is_varg {
841 g.writeln('${arg_name} = new array(new array_buffer({arr: ${arg_name},len: new int(${arg_name}.length),index_start: new int(0)}));')
842 } else {
843 asym := g.table.sym(arg.typ)
844
845 if arg.typ.is_ptr() || (arg.is_mut && asym.kind != .interface && asym.language != .js) {
846 g.writeln('${arg_name} = new \$ref(${arg_name})')
847 }
848 }
849 }
850
851 for inherited in fun.inherited_vars {
852 if !inherited.is_mut {
853 g.writeln('let ${inherited.name} = ${inherited2copy[inherited.name]};')
854 }
855 }
856 g.stmts(it.stmts)
857 g.dec_indent()
858 g.writeln('}})()')
859
860 g.fn_decl = cur_fn_decl
861}
862