diff --git a/Units/parser-javascript.r/js-async1.d/expected.tags b/Units/parser-javascript.r/js-async1.d/expected.tags new file mode 100644 index 0000000000..5c05e4a038 --- /dev/null +++ b/Units/parser-javascript.r/js-async1.d/expected.tags @@ -0,0 +1,3 @@ +add1 input.js /^async function add1(x) {$/;" f +add2 input.js /^async function add2(x) {$/;" f +resolveAfter2Seconds input.js /^function resolveAfter2Seconds(x) {$/;" f diff --git a/Units/parser-javascript.r/js-async1.d/input.js b/Units/parser-javascript.r/js-async1.d/input.js new file mode 100644 index 0000000000..0a2fb56617 --- /dev/null +++ b/Units/parser-javascript.r/js-async1.d/input.js @@ -0,0 +1,29 @@ +/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#Simple_example */ + +function resolveAfter2Seconds(x) { + return new Promise(resolve => { + setTimeout(() => { + resolve(x); + }, 2000); + }); +} + +async function add1(x) { + var a = resolveAfter2Seconds(20); + var b = resolveAfter2Seconds(30); + return x + await a + await b; +} + +add1(10).then(v => { + console.log(v); // prints 60 after 2 seconds. +}); + +async function add2(x) { + var a = await resolveAfter2Seconds(20); + var b = await resolveAfter2Seconds(30); + return x + a + b; +} + +add2(10).then(v => { + console.log(v); // prints 60 after 4 seconds. +}); diff --git a/Units/parser-javascript.r/js-async2.d/expected.tags b/Units/parser-javascript.r/js-async2.d/expected.tags new file mode 100644 index 0000000000..18b00b0834 --- /dev/null +++ b/Units/parser-javascript.r/js-async2.d/expected.tags @@ -0,0 +1,9 @@ +Class input.js /^var Class = {$/;" c +ES6Class input.js /^class ES6Class {$/;" c +asyncAnonymousFunc input.js /^var asyncAnonymousFunc = async function() {$/;" f +es6AsyncMethod input.js /^ async es6AsyncMethod() {}$/;" m class:ES6Class +es6Method input.js /^ es6Method() {}$/;" m class:ES6Class +method1 input.js /^ method1 : function() {$/;" m class:Class +method2 input.js /^ method2 : async function() {$/;" m class:Class +method3 input.js /^ method3() {$/;" m class:Class +method4 input.js /^ async method4() {$/;" m class:Class diff --git a/Units/parser-javascript.r/js-async2.d/input.js b/Units/parser-javascript.r/js-async2.d/input.js new file mode 100644 index 0000000000..b763f2e865 --- /dev/null +++ b/Units/parser-javascript.r/js-async2.d/input.js @@ -0,0 +1,21 @@ +var Class = { + method1 : function() { + return 0; + }, + method2 : async function() { + return await resolveAfter2Seconds(42); + }, + // ES6 shorthand methods + method3() { + }, + async method4() { + }, +}; + +var asyncAnonymousFunc = async function() { +} + +class ES6Class { + async es6AsyncMethod() {} + es6Method() {} +} diff --git a/parsers/jscript.c b/parsers/jscript.c index c32db7cf44..4e8c36488a 100644 --- a/parsers/jscript.c +++ b/parsers/jscript.c @@ -130,6 +130,7 @@ enum eKeywordId { KEYWORD_static, KEYWORD_default, KEYWORD_export, + KEYWORD_async, }; typedef int keywordId; /* to allow KEYWORD_NONE */ @@ -226,8 +227,9 @@ static const keywordTable JsKeywordTable [] = { { "class", KEYWORD_class }, { "extends", KEYWORD_extends }, { "static", KEYWORD_static }, - { "default", KEYWORD_default }, + { "default", KEYWORD_default }, { "export", KEYWORD_export }, + { "async", KEYWORD_async }, }; /* @@ -1293,6 +1295,9 @@ static bool parseMethods (tokenInfo *const token, const tokenInfo *const class, goto cleanUp; } + if (isKeyword (token, KEYWORD_async)) + readToken (token); + if (! isType (token, TOKEN_KEYWORD) && ! isType (token, TOKEN_SEMICOLON)) { @@ -1312,7 +1317,11 @@ static bool parseMethods (tokenInfo *const token, const tokenInfo *const class, if ( isType (token, TOKEN_COLON) || is_shorthand ) { if (! is_shorthand) + { readToken (token); + if (isKeyword (token, KEYWORD_async)) + readToken (token); + } if ( is_shorthand || isKeyword (token, KEYWORD_function) ) { JSCRIPT_DEBUG_PRINT("Seems to be a function or shorthand"); @@ -1778,6 +1787,9 @@ static bool parseStatement (tokenInfo *const token, tokenInfo *const parent, boo readToken (token); } + if (isKeyword (token, KEYWORD_async)) + readToken (token); + if ( isKeyword (token, KEYWORD_function) ) { vString *const signature = vStringNew (); @@ -2143,6 +2155,7 @@ static bool parseLine (tokenInfo *const token, tokenInfo *const parent, bool is_ parseSwitch (token); break; case KEYWORD_return: + case KEYWORD_async: readToken (token); is_terminated = parseLine (token, parent, is_inside_class); break;