parser: allow JS methods with more than 1 dot

pull/4905/head
spaceface777 2020-05-15 22:26:51 +02:00 committed by GitHub
parent 04744a5390
commit 7c9bb44784
5 changed files with 45 additions and 16 deletions

View File

@ -231,8 +231,8 @@ pub fn (g mut JsGen) new_tmp_var() string {
} }
[inline] [inline]
fn js_name(name_ string) string { fn js_name(name string) string {
name := name_.replace('.', '__') // name := name_.replace('.', '__')
if name in js_reserved { if name in js_reserved {
return 'v_$name' return 'v_$name'
} }
@ -358,12 +358,13 @@ fn (g mut JsGen) expr(node ast.Expr) {
g.write("'$it.val'") g.write("'$it.val'")
} }
ast.CallExpr { ast.CallExpr {
name := if it.name.starts_with('JS.') { it.name[3..] } else { it.name }
g.expr(it.left) g.expr(it.left)
if it.is_method { if it.is_method {
// example: foo.bar.baz() // example: foo.bar.baz()
g.write('.') g.write('.')
} }
g.write('${js_name(it.name)}(') g.write('${js_name(name)}(')
for i, arg in it.args { for i, arg in it.args {
g.expr(arg.expr) g.expr(arg.expr)
if i != it.args.len - 1 { if i != it.args.len - 1 {

View File

@ -1,5 +1,5 @@
// V_COMMIT_HASH d60233b // V_COMMIT_HASH 04744a5
// V_CURRENT_COMMIT_HASH fc520d9 // V_CURRENT_COMMIT_HASH 04744a5
// Generated by the V compiler // Generated by the V compiler
"use strict"; "use strict";
@ -13,6 +13,8 @@ const CONSTANTS = Object.freeze({
/* namespace: main */ /* namespace: main */
const main = (function () { const main = (function () {
class Companies { class Companies {
/** /**
* @param {{google: number, amazon: boolean, yahoo: string}} values - values for this class fields * @param {{google: number, amazon: boolean, yahoo: string}} values - values for this class fields
@ -61,6 +63,7 @@ class Companies {
/* program entry point */ /* program entry point */
(async function() { (async function() {
console.log("Hello from V.js!");
/** @type {string} - v */ /** @type {string} - v */
const v = "done"; const v = "done";
{ {
@ -76,6 +79,7 @@ class Companies {
const v_await = CONSTANTS.v_super + v_debugger; const v_await = CONSTANTS.v_super + v_debugger;
/** @type {string} - v_finally */ /** @type {string} - v_finally */
let v_finally = "implemented"; let v_finally = "implemented";
console.log(v_await, v_finally);
/** @type {number} - dun */ /** @type {number} - dun */
const dun = CONSTANTS.i_am_a_const * 20; const dun = CONSTANTS.i_am_a_const * 20;
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {

View File

@ -1,3 +1,5 @@
fn JS.alert(arg string)
fn JS.console.log(arg string)
const ( const (
i_am_a_const = 21214 i_am_a_const = 21214
@ -21,6 +23,8 @@ fn class(extends string, instanceof int) {
fn main() { fn main() {
JS.console.log('Hello from V.js!')
v := "done" v := "done"
{ {
_ := "block" _ := "block"
@ -33,6 +37,8 @@ fn main() {
await := super + debugger await := super + debugger
mut finally := 'implemented' mut finally := 'implemented'
JS.console.log(await, finally)
dun := i_am_a_const * 20 dun := i_am_a_const * 20
for i := 0; i < 10; i++ {} for i := 0; i < 10; i++ {}
@ -77,11 +83,11 @@ fn (it Companies) method() int {
yahoo: "hello" 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 {} if a != 2 {}
return 0 return 0
} }

View File

@ -10,16 +10,16 @@ import v.util
pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr { pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr {
first_pos := p.tok.position() first_pos := p.tok.position()
name := p.check_name()
fn_name := if is_c { fn_name := if is_c {
'C.$name' 'C.${p.check_name()}'
} else if is_js { } else if is_js {
'JS.$name' 'JS.${p.check_js_name()}'
} else if mod.len > 0 { } else if mod.len > 0 {
'${mod}.$name' '${mod}.${p.check_name()}'
} else { } else {
name p.check_name()
} }
mut is_or_block_used := false mut is_or_block_used := false
if fn_name == 'json.decode' { if fn_name == 'json.decode' {
p.expecting_type = true // Makes name_expr() parse the type (`User` in `json.decode(User, txt)`)` 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 := '' mut name := ''
if p.tok.kind == .name { if p.tok.kind == .name {
// TODO high order fn // 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) { if !is_js && !is_c && !p.pref.translated && util.contains_capital(name) {
p.error('function names cannot contain uppercase letters, use snake_case instead') p.error('function names cannot contain uppercase letters, use snake_case instead')
} }

View File

@ -285,6 +285,22 @@ fn (mut p Parser) check(expected token.Kind) {
p.next() 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 { fn (mut p Parser) check_name() string {
name := p.tok.lit name := p.tok.lit
if p.peek_tok.kind == .dot && name in p.imports { if p.peek_tok.kind == .dot && name in p.imports {
@ -754,8 +770,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
} else { } else {
// fn call // fn call
// println('calling $p.tok.lit') // println('calling $p.tok.lit')
x := p.call_expr(is_c, is_js, mod) // TODO `node,typ :=` should work node = p.call_expr(is_c, is_js, mod)
node = x
} }
} else if p.peek_tok.kind == .lcbr && !p.inside_match && !p.inside_match_case && !p.inside_if && } else if p.peek_tok.kind == .lcbr && !p.inside_match && !p.inside_match_case && !p.inside_if &&
!p.inside_for { !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 { } else if p.peek_tok.kind == .colon && p.prev_tok.kind != .str_dollar {
// `foo(key:val, key2:val2)` // `foo(key:val, key2:val2)`
return p.struct_init(true) // short_syntax:true 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 { } else {
node = p.parse_ident(is_c, is_js) node = p.parse_ident(is_c, is_js)
} }