From 7c9bb4478434175247d7366f483d6b03398b0abc Mon Sep 17 00:00:00 2001 From: spaceface777 Date: Fri, 15 May 2020 22:26:51 +0200 Subject: [PATCH] parser: allow JS methods with more than 1 dot --- vlib/v/gen/js/js.v | 7 ++++--- vlib/v/gen/js/tests/js.js | 8 ++++++-- vlib/v/gen/js/tests/js.v | 12 +++++++++--- vlib/v/parser/fn.v | 12 ++++++------ vlib/v/parser/parser.v | 22 ++++++++++++++++++++-- 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 2083fee71a..3752784e45 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -231,8 +231,8 @@ pub fn (g mut JsGen) new_tmp_var() string { } [inline] -fn js_name(name_ string) string { - name := name_.replace('.', '__') +fn js_name(name string) string { + // name := name_.replace('.', '__') if name in js_reserved { return 'v_$name' } @@ -358,12 +358,13 @@ fn (g mut JsGen) expr(node ast.Expr) { g.write("'$it.val'") } ast.CallExpr { + name := if it.name.starts_with('JS.') { it.name[3..] } else { it.name } g.expr(it.left) if it.is_method { // example: foo.bar.baz() g.write('.') } - g.write('${js_name(it.name)}(') + g.write('${js_name(name)}(') for i, arg in it.args { g.expr(arg.expr) if i != it.args.len - 1 { diff --git a/vlib/v/gen/js/tests/js.js b/vlib/v/gen/js/tests/js.js index f958962816..1a858bf15f 100644 --- a/vlib/v/gen/js/tests/js.js +++ b/vlib/v/gen/js/tests/js.js @@ -1,5 +1,5 @@ -// V_COMMIT_HASH d60233b -// V_CURRENT_COMMIT_HASH fc520d9 +// V_COMMIT_HASH 04744a5 +// V_CURRENT_COMMIT_HASH 04744a5 // Generated by the V compiler "use strict"; @@ -13,6 +13,8 @@ const CONSTANTS = Object.freeze({ /* namespace: main */ const main = (function () { + + class Companies { /** * @param {{google: number, amazon: boolean, yahoo: string}} values - values for this class fields @@ -61,6 +63,7 @@ class Companies { /* program entry point */ (async function() { + console.log("Hello from V.js!"); /** @type {string} - v */ const v = "done"; { @@ -76,6 +79,7 @@ class Companies { const v_await = CONSTANTS.v_super + v_debugger; /** @type {string} - v_finally */ let v_finally = "implemented"; + console.log(v_await, v_finally); /** @type {number} - dun */ const dun = CONSTANTS.i_am_a_const * 20; for (let i = 0; i < 10; i++) { diff --git a/vlib/v/gen/js/tests/js.v b/vlib/v/gen/js/tests/js.v index 719bf099ed..ff533d9096 100644 --- a/vlib/v/gen/js/tests/js.v +++ b/vlib/v/gen/js/tests/js.v @@ -1,3 +1,5 @@ +fn JS.alert(arg string) +fn JS.console.log(arg string) const ( i_am_a_const = 21214 @@ -21,6 +23,8 @@ fn class(extends string, instanceof int) { fn main() { + JS.console.log('Hello from V.js!') + v := "done" { _ := "block" @@ -33,6 +37,8 @@ fn main() { await := super + debugger mut finally := 'implemented' + JS.console.log(await, finally) + dun := i_am_a_const * 20 for i := 0; i < 10; i++ {} @@ -77,11 +83,11 @@ fn (it Companies) method() int { yahoo: "hello" } - a, b := hello(2, 'google', 'not google') + a, b := hello(2, 'google', 'not google') - glue := if a > 2 { 'more_glue' } else if a > 5 {'more glueee'} else { 'less glue' } + glue := if a > 2 { 'more_glue' } else if a > 5 {'more glueee'} else { 'less glue' } if a != 2 {} - return 0 + return 0 } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index e1243ba678..356e25e910 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -10,16 +10,16 @@ import v.util pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr { first_pos := p.tok.position() - name := p.check_name() fn_name := if is_c { - 'C.$name' + 'C.${p.check_name()}' } else if is_js { - 'JS.$name' + 'JS.${p.check_js_name()}' } else if mod.len > 0 { - '${mod}.$name' + '${mod}.${p.check_name()}' } else { - name + p.check_name() } + mut is_or_block_used := false if fn_name == 'json.decode' { p.expecting_type = true // Makes name_expr() parse the type (`User` in `json.decode(User, txt)`)` @@ -156,7 +156,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mut name := '' if p.tok.kind == .name { // TODO high order fn - name = p.check_name() + name = if is_js { p.check_js_name() } else { p.check_name() } if !is_js && !is_c && !p.pref.translated && util.contains_capital(name) { p.error('function names cannot contain uppercase letters, use snake_case instead') } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index b92155840e..1cceb0ca13 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -285,6 +285,22 @@ fn (mut p Parser) check(expected token.Kind) { p.next() } +// JS functions can have multiple dots in their name: +// JS.foo.bar.and.a.lot.more.dots() +fn (mut p Parser) check_js_name() string { + mut name := '' + for p.peek_tok.kind == .dot { + name += '${p.tok.lit}.' + p.next() // .name + p.next() // .dot + } + // last .name + name += p.tok.lit + p.next() + + return name +} + fn (mut p Parser) check_name() string { name := p.tok.lit if p.peek_tok.kind == .dot && name in p.imports { @@ -754,8 +770,7 @@ pub fn (mut p Parser) name_expr() ast.Expr { } else { // fn call // println('calling $p.tok.lit') - x := p.call_expr(is_c, is_js, mod) // TODO `node,typ :=` should work - node = x + node = p.call_expr(is_c, is_js, mod) } } else if p.peek_tok.kind == .lcbr && !p.inside_match && !p.inside_match_case && !p.inside_if && !p.inside_for { @@ -782,6 +797,9 @@ pub fn (mut p Parser) name_expr() ast.Expr { } else if p.peek_tok.kind == .colon && p.prev_tok.kind != .str_dollar { // `foo(key:val, key2:val2)` return p.struct_init(true) // short_syntax:true + // JS. function call with more than 1 dot + } else if is_js && p.peek_tok.kind == .dot && p.peek_tok2.kind == .name { + node = p.call_expr(is_c, is_js, mod) } else { node = p.parse_ident(is_c, is_js) }