From 1cb06a2de4d774267ce8c99654137d1998d964c3 Mon Sep 17 00:00:00 2001 From: playX Date: Tue, 7 Dec 2021 12:11:54 +0300 Subject: [PATCH] js: ast.GoExpr support using promises on JS backend (#12749) --- vlib/{js/promise => builtin/js}/promise.js.v | 10 ++--- vlib/js/promise/promise.v | 3 -- vlib/js/promise/promise_test.js.v | 18 -------- vlib/v/ast/table.v | 44 ++++++++++++++++++++ vlib/v/checker/checker.v | 9 +++- vlib/v/gen/js/js.v | 6 +-- 6 files changed, 59 insertions(+), 31 deletions(-) rename vlib/{js/promise => builtin/js}/promise.js.v (89%) delete mode 100644 vlib/js/promise/promise.v delete mode 100644 vlib/js/promise/promise_test.js.v diff --git a/vlib/js/promise/promise.js.v b/vlib/builtin/js/promise.js.v similarity index 89% rename from vlib/js/promise/promise.js.v rename to vlib/builtin/js/promise.js.v index fc1f95efbb..35415b6c04 100644 --- a/vlib/js/promise/promise.js.v +++ b/vlib/builtin/js/promise.js.v @@ -1,4 +1,4 @@ -module promise +module builtin pub interface JS.Promise { then(onFullfilled JS.Any, onRejected JS.Any) @@ -19,7 +19,7 @@ mut: promise JS.Promise [noinit] } -pub fn new(executor fn (resolve fn (T), reject fn (E))) Promise { +pub fn promise_new(executor fn (resolve fn (T), reject fn (E))) Promise { promise := JS.Promise.prototype.constructor(executor) return Promise{promise} } @@ -40,20 +40,20 @@ pub fn (p Promise) finally(callback fn ()) Promise { } // reject returns promise which was rejected because of specified error -pub fn reject(error E) Promise { +pub fn promise_reject(error E) Promise { promise := JS.Promise.reject(error) return Promise{promise} } // resolve returns promise which was resolved with specified value -pub fn resolve(result T) Promise { +pub fn promise_resolve(result T) Promise { promise := JS.Promise.resolve(error) return Promise{promise} } // race returns returns a promise that fulfills or rejects as soon as one of // the promises in an iterable fulfills or rejects, with the value or reason from that promise. -pub fn race(promises []Promise) Promise { +pub fn promise_race(promises []Promise) Promise { promises_ := JS.Array.prototype.constructor() for elem in promises { diff --git a/vlib/js/promise/promise.v b/vlib/js/promise/promise.v deleted file mode 100644 index ba48de86a9..0000000000 --- a/vlib/js/promise/promise.v +++ /dev/null @@ -1,3 +0,0 @@ -// Promise API wrapper - -module promise diff --git a/vlib/js/promise/promise_test.js.v b/vlib/js/promise/promise_test.js.v deleted file mode 100644 index a9b52b972c..0000000000 --- a/vlib/js/promise/promise_test.js.v +++ /dev/null @@ -1,18 +0,0 @@ -module promise - -fn test_promise() { - // TODO: For some reason compiler errors: "error: unknown function: js.promise.new", fix this - /* - p := new(fn (resolve_ fn (x int), reject_ fn (x f64)) { - println('Promise code') - assert true - resolve_(42) - }) - p.then(fn (val int) { - println('resolved') - assert val == 42 - }, fn (fail f64) { - println('rejected') - assert false - })*/ -} diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index d045fa8b98..84477febfa 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -830,6 +830,26 @@ pub fn (t &Table) chan_cname(elem_type Type, is_mut bool) string { return 'chan_$elem_type_sym.cname' + suffix } +[inline] +pub fn (t &Table) promise_name(return_type Type) string { + if return_type.idx() == void_type_idx { + return 'Promise' + } + + return_type_sym := t.get_type_symbol(return_type) + return 'Promise<$return_type_sym.name, JS.Any>' +} + +[inline] +pub fn (t &Table) promise_cname(return_type Type) string { + if return_type == void_type { + return 'Promise_Any_Any' + } + + return_type_sym := t.get_type_symbol(return_type) + return 'Promise_${return_type_sym.name}_Any' +} + [inline] pub fn (t &Table) thread_name(return_type Type) string { if return_type.idx() == void_type_idx { @@ -943,6 +963,30 @@ pub fn (mut t Table) find_or_register_thread(return_type Type) int { return t.register_type_symbol(thread_typ) } +pub fn (mut t Table) find_or_register_promise(return_type Type) int { + name := t.promise_name(return_type) + + cname := t.promise_cname(return_type) + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx + } + + promise_type := TypeSymbol{ + parent_idx: t.type_idxs['Promise'] + kind: .struct_ + name: name + cname: cname + info: Struct{ + concrete_types: [return_type, t.type_idxs['JS.Any']] + } + } + + // register + return t.register_type_symbol(promise_type) +} + pub fn (mut t Table) find_or_register_array(elem_type Type) int { name := t.array_name(elem_type) // existing diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 433a15d166..4e622685f2 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2560,7 +2560,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) typ := c.expr(node.args[0].expr) tsym := c.table.get_type_symbol(typ) - if !tsym.name.starts_with('js.promise.Promise<') { + if !tsym.name.starts_with('Promise<') { c.error('JS.await: first argument must be a promise, got `$tsym.name`', node.pos) return ast.void_type } @@ -5040,7 +5040,12 @@ fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type { c.error('method in `go` statement cannot have non-reference mutable receiver', node.call_expr.left.position()) } - return c.table.find_or_register_thread(ret_type) + + if c.pref.backend.is_js() { + return c.table.find_or_register_promise(ret_type) + } else { + return c.table.find_or_register_thread(ret_type) + } } fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 557a3125c7..c5fb90a46f 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -17,7 +17,7 @@ const ( 'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package', 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield', 'Number', 'String', 'Boolean', - 'Array', 'Map', 'document'] + 'Array', 'Map', 'document', 'Promise'] // used to generate type structs v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64', 'int_literal', 'float_literal', 'bool', 'string', 'map', 'array', 'rune', 'any', 'voidptr'] @@ -1679,13 +1679,13 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) { } fn (mut g JsGen) gen_go_expr(node ast.GoExpr) { - g.writeln('await new Promise(function(resolve){') + g.writeln('new _v_Promise({promise: new Promise(function(resolve){') g.inc_indent() g.write('resolve(') g.expr(node.call_expr) g.write(');') g.dec_indent() - g.writeln('});') + g.writeln('})});') } fn (mut g JsGen) gen_import_stmt(it ast.Import) {