From 63e776382224664ed7b2ecff9ea76478c44f87af Mon Sep 17 00:00:00 2001 From: Audrey Tang Date: Sat, 27 Oct 2012 16:13:17 +0800 Subject: [PATCH 1/5] * Allow TERM before commas in function application --- lib/coffee-script/parser.js | 278 +++++++++++++++++--------------- src/grammar.pegjs | 16 +- test/function-invocation.coffee | 66 +++++--- 3 files changed, 200 insertions(+), 160 deletions(-) diff --git a/lib/coffee-script/parser.js b/lib/coffee-script/parser.js index ac085142..70f08f46 100644 --- a/lib/coffee-script/parser.js +++ b/lib/coffee-script/parser.js @@ -74,6 +74,7 @@ module.exports = module.exports = (function(){ "argumentListContents": parse_argumentListContents, "argument": parse_argument, "secondaryArgumentList": parse_secondaryArgumentList, + "secondaryArgumentRest": parse_secondaryArgumentRest, "secondaryArgument": parse_secondaryArgument, "callExpression": parse_callExpression, "newExpression": parse_newExpression, @@ -4865,7 +4866,7 @@ module.exports = module.exports = (function(){ return cachedResult.result; } - var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; + var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; r1 = clone(pos); r2 = clone(pos); @@ -4875,24 +4876,37 @@ module.exports = module.exports = (function(){ r6 = clone(pos); r7 = parse__(); if (r7 !== null) { - if (input.charCodeAt(pos.offset) === 44) { - r8 = ","; - advance(pos, 1); - } else { - r8 = null; - if (reportFailures === 0) { - matchFailed("\",\""); - } - } - if (r8 === null) { - r8 = parse_TERMINATOR(); - } + r8 = parse_TERM(); + r8 = r8 !== null ? r8 : ""; if (r8 !== null) { r9 = parse__(); if (r9 !== null) { - r10 = parse_argument(); + if (input.charCodeAt(pos.offset) === 44) { + r10 = ","; + advance(pos, 1); + } else { + r10 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (r10 === null) { + r10 = parse_TERMINATOR(); + } if (r10 !== null) { - r5 = [r7, r8, r9, r10]; + r11 = parse__(); + if (r11 !== null) { + r12 = parse_argument(); + if (r12 !== null) { + r5 = [r7, r8, r9, r10, r11, r12]; + } else { + r5 = null; + pos = clone(r6); + } + } else { + r5 = null; + pos = clone(r6); + } } else { r5 = null; pos = clone(r6); @@ -4914,24 +4928,37 @@ module.exports = module.exports = (function(){ r6 = clone(pos); r7 = parse__(); if (r7 !== null) { - if (input.charCodeAt(pos.offset) === 44) { - r8 = ","; - advance(pos, 1); - } else { - r8 = null; - if (reportFailures === 0) { - matchFailed("\",\""); - } - } - if (r8 === null) { - r8 = parse_TERMINATOR(); - } + r8 = parse_TERM(); + r8 = r8 !== null ? r8 : ""; if (r8 !== null) { r9 = parse__(); if (r9 !== null) { - r10 = parse_argument(); + if (input.charCodeAt(pos.offset) === 44) { + r10 = ","; + advance(pos, 1); + } else { + r10 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (r10 === null) { + r10 = parse_TERMINATOR(); + } if (r10 !== null) { - r5 = [r7, r8, r9, r10]; + r11 = parse__(); + if (r11 !== null) { + r12 = parse_argument(); + if (r12 !== null) { + r5 = [r7, r8, r9, r10, r11, r12]; + } else { + r5 = null; + pos = clone(r6); + } + } else { + r5 = null; + pos = clone(r6); + } } else { r5 = null; pos = clone(r6); @@ -4979,8 +5006,8 @@ module.exports = module.exports = (function(){ } if (r0 !== null) { r0 = (function(offset, line, column, e, es, t) { - var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3].raw; }).join('') + t; - return {list: [e].concat(es.map(function(e){ return e[3]; })), raw: raw}; + var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3] + e[4] + e[5].raw; }).join('') + t; + return {list: [e].concat(es.map(function(e){ return e[5]; })), raw: raw}; })(r1.offset, r1.line, r1.column, r3, r4, r5); } if (r0 === null) { @@ -5062,7 +5089,7 @@ module.exports = module.exports = (function(){ return cachedResult.result; } - var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14; + var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; r1 = clone(pos); r2 = clone(pos); @@ -5103,102 +5130,10 @@ module.exports = module.exports = (function(){ r5 = parse_secondaryArgument(); if (r5 !== null) { r6 = []; - r8 = clone(pos); - r9 = parse__(); - if (r9 !== null) { - if (input.charCodeAt(pos.offset) === 44) { - r10 = ","; - advance(pos, 1); - } else { - r10 = null; - if (reportFailures === 0) { - matchFailed("\",\""); - } - } - if (r10 !== null) { - r11 = parse__(); - if (r11 !== null) { - r12 = parse_TERMINATOR(); - r12 = r12 !== null ? r12 : ""; - if (r12 !== null) { - r13 = parse__(); - if (r13 !== null) { - r14 = parse_secondaryArgument(); - if (r14 !== null) { - r7 = [r9, r10, r11, r12, r13, r14]; - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } + r7 = parse_secondaryArgumentRest(); while (r7 !== null) { r6.push(r7); - r8 = clone(pos); - r9 = parse__(); - if (r9 !== null) { - if (input.charCodeAt(pos.offset) === 44) { - r10 = ","; - advance(pos, 1); - } else { - r10 = null; - if (reportFailures === 0) { - matchFailed("\",\""); - } - } - if (r10 !== null) { - r11 = parse__(); - if (r11 !== null) { - r12 = parse_TERMINATOR(); - r12 = r12 !== null ? r12 : ""; - if (r12 !== null) { - r13 = parse__(); - if (r13 !== null) { - r14 = parse_secondaryArgument(); - if (r14 !== null) { - r7 = [r9, r10, r11, r12, r13, r14]; - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } + r7 = parse_secondaryArgumentRest(); } if (r6 !== null) { r8 = clone(pos); @@ -5261,8 +5196,8 @@ module.exports = module.exports = (function(){ } if (r0 !== null) { r0 = (function(offset, line, column, ws0, e, es, obj) { - var raw = ws0 + e.raw + es.map(function(e){ return e[0] + ',' + e[2] + e[3] + e[4] + e[5].raw; }).join('') + (obj ? obj[0] + obj[1] + obj[2].raw + obj[3] : ''); - es = [e].concat(es.map(function(e){ return e[5]; })); + var raw = ws0 + e.raw + es.map(function(e){ return e.raw; }).join('') + (obj ? obj[0] + obj[1] + obj[2].raw + obj[3] : ''); + es = [e].concat(es.map(function(e){ return e.list[0]; })); if(obj) es.push(obj[2]); return {list: es, raw: raw}; })(r1.offset, r1.line, r1.column, r3, r5, r6, r7); @@ -5309,6 +5244,93 @@ module.exports = module.exports = (function(){ return r0; } + function parse_secondaryArgumentRest() { + var cacheKey = "secondaryArgumentRest@" + pos.offset; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = clone(cachedResult.nextPos); + return cachedResult.result; + } + + var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; + + r1 = clone(pos); + r2 = clone(pos); + r3 = parse__(); + if (r3 !== null) { + r4 = parse_TERM(); + r4 = r4 !== null ? r4 : ""; + if (r4 !== null) { + r5 = parse__(); + if (r5 !== null) { + if (input.charCodeAt(pos.offset) === 44) { + r6 = ","; + advance(pos, 1); + } else { + r6 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (r6 !== null) { + r7 = parse__(); + if (r7 !== null) { + r8 = parse_TERMINATOR(); + r8 = r8 !== null ? r8 : ""; + if (r8 !== null) { + r9 = parse__(); + if (r9 !== null) { + r10 = parse_secondaryArgument(); + if (r10 !== null) { + r0 = [r3, r4, r5, r6, r7, r8, r9, r10]; + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + if (r0 !== null) { + r0 = (function(offset, line, column, ws0, t0, ws1, ws2, t1, ws3, e) { + return {list: [e], raw: ws0 + t0 + ws1 + "," + ws2 + t1 + ws3 + e.raw}; + })(r1.offset, r1.line, r1.column, r3, r4, r5, r7, r8, r9, r10); + } + if (r0 === null) { + pos = clone(r1); + } + + cache[cacheKey] = { + nextPos: clone(pos), + result: r0 + }; + return r0; + } + function parse_secondaryArgument() { var cacheKey = "secondaryArgument@" + pos.offset; var cachedResult = cache[cacheKey]; diff --git a/src/grammar.pegjs b/src/grammar.pegjs index a9d98321..8ad1a4c4 100644 --- a/src/grammar.pegjs +++ b/src/grammar.pegjs @@ -398,9 +398,9 @@ leftHandSideExpression = callExpression / newExpression }; } argumentListContents - = e:argument es:(_ ("," / TERMINATOR) _ argument)* t:("," / TERMINATOR)? { - var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3].raw; }).join('') + t; - return {list: [e].concat(es.map(function(e){ return e[3]; })), raw: raw}; + = e:argument es:(_ TERM? _ ("," / TERMINATOR) _ argument)* t:("," / TERMINATOR)? { + var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3] + e[4] + e[5].raw; }).join('') + t; + return {list: [e].concat(es.map(function(e){ return e[5]; })), raw: raw}; } / t0:TERMINDENT a:argumentListContents d:DEDENT t1:TERMINATOR? { return {list: a.list, raw: t0 + a.raw + d + t1}; @@ -409,15 +409,19 @@ leftHandSideExpression = callExpression / newExpression = spread / expression secondaryArgumentList - = ws0:__ !([+-/] __) e:secondaryArgument es:(_ "," _ TERMINATOR? _ secondaryArgument)* obj:(","? TERMINDENT implicitObjectLiteral DEDENT)? { - var raw = ws0 + e.raw + es.map(function(e){ return e[0] + ',' + e[2] + e[3] + e[4] + e[5].raw; }).join('') + (obj ? obj[0] + obj[1] + obj[2].raw + obj[3] : ''); - es = [e].concat(es.map(function(e){ return e[5]; })); + = ws0:__ !([+-/] __) e:secondaryArgument es:(secondaryArgumentRest)* obj:(","? TERMINDENT implicitObjectLiteral DEDENT)? { + var raw = ws0 + e.raw + es.map(function(e){ return e.raw; }).join('') + (obj ? obj[0] + obj[1] + obj[2].raw + obj[3] : ''); + es = [e].concat(es.map(function(e){ return e.list[0]; })); if(obj) es.push(obj[2]); return {list: es, raw: raw}; } / t:TERMINDENT o:implicitObjectLiteral d:DEDENT { return {list: [o], raw: t + o.raw + d}; } + secondaryArgumentRest + = ws0:_ t0:TERM? ws1:_ "," ws2:_ t1:TERMINATOR? ws3:_ e:secondaryArgument { + return {list: [e], raw: ws0 + t0 + ws1 + "," + ws2 + t1 + ws3 + e.raw}; + } secondaryArgument = spread / secondaryExpression diff --git a/test/function-invocation.coffee b/test/function-invocation.coffee index a063fdb6..4c5e7697 100644 --- a/test/function-invocation.coffee +++ b/test/function-invocation.coffee @@ -121,38 +121,52 @@ suite 'Function Invocation', -> # ok obj.param is 101 # ok obj.rest.join(' ') is '102 103 104' - #test "Passing multiple functions without paren-wrapping is legal, and should compile.", -> - # sum = (one, two) -> one() + two() - # eq 20, sum -> - # 7 + 9 - # , -> - # 1 + 3 - # eq 16, sum -> 5 + 7, -> 2 + 3 - # eq 6, sum( -> - # 1 + 2 - # , -> - # 2 + 1 - # ) + test "Passing multiple functions without paren-wrapping is legal, and should compile.", -> + sum = (one, two) -> one() + two() + eq 20, sum -> + 7 + 9 + , -> + 1 + 3 + eq 17, sum -> 5 + 7, -> 2 + 3 + eq 6, sum( -> + 1 + 2 + , -> + 2 + 1 + ) test "Implicit call with a trailing if statement as a param.", -> func = -> arguments[1] result = func 'one', if false then 100 else 13 ok result is 13 - #test "Test more function passing:", -> - # sum = (one, two) -> one() + two() - # - # result = sum( -> - # 1 + 2 - # , -> - # 2 + 1 - # ) - # ok result is 6 - # - # sum = (a, b) -> a + b - # result = sum(1 - # , 2) - # ok result is 3 + test "Test more function passing:", -> + sum = (one, two) -> one() + two() + + result = sum( -> + 1 + 2 + , -> + 2 + 1 + ) + ok result is 6 + + sum = (a, b) -> a + b + result = sum(1 + , 2) + ok result is 3 + + test "Test more function passing, this time without parens:", -> + sum = (one, two) -> one() + two() + + result = sum -> + 1 + 2 + , -> + 2 + 1 + ok result is 6 + + sum = (a, b) -> a + b + result = sum 1 + , 2 + ok result is 3 #test "Chained blocks, with proper indentation levels:", -> # counter = From b6d3456bea1eaf9a4ea3d4321e57d93c6b1e1b34 Mon Sep 17 00:00:00 2001 From: Audrey Tang Date: Sat, 27 Oct 2012 16:43:43 +0800 Subject: [PATCH 2/5] * Move object literals into secondaryArgumentList This allows for forms such as: ```coffee console.log 1, 2: 3 , 4: 5 , 6 ``` --- lib/coffee-script/parser.js | 122 ++++++++++++++++++++++-------------- src/grammar.pegjs | 8 ++- test/objects.coffee | 86 ++++++++++++------------- 3 files changed, 123 insertions(+), 93 deletions(-) diff --git a/lib/coffee-script/parser.js b/lib/coffee-script/parser.js index 70f08f46..154db1ad 100644 --- a/lib/coffee-script/parser.js +++ b/lib/coffee-script/parser.js @@ -5089,7 +5089,7 @@ module.exports = module.exports = (function(){ return cachedResult.result; } - var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; + var r0, r1, r2, r3, r4, r5, r6, r7, r8; r1 = clone(pos); r2 = clone(pos); @@ -5136,48 +5136,7 @@ module.exports = module.exports = (function(){ r7 = parse_secondaryArgumentRest(); } if (r6 !== null) { - r8 = clone(pos); - if (input.charCodeAt(pos.offset) === 44) { - r9 = ","; - advance(pos, 1); - } else { - r9 = null; - if (reportFailures === 0) { - matchFailed("\",\""); - } - } - r9 = r9 !== null ? r9 : ""; - if (r9 !== null) { - r10 = parse_TERMINDENT(); - if (r10 !== null) { - r11 = parse_implicitObjectLiteral(); - if (r11 !== null) { - r12 = parse_DEDENT(); - if (r12 !== null) { - r7 = [r9, r10, r11, r12]; - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - } else { - r7 = null; - pos = clone(r8); - } - r7 = r7 !== null ? r7 : ""; - if (r7 !== null) { - r0 = [r3, r4, r5, r6, r7]; - } else { - r0 = null; - pos = clone(r2); - } + r0 = [r3, r4, r5, r6]; } else { r0 = null; pos = clone(r2); @@ -5195,12 +5154,11 @@ module.exports = module.exports = (function(){ pos = clone(r2); } if (r0 !== null) { - r0 = (function(offset, line, column, ws0, e, es, obj) { - var raw = ws0 + e.raw + es.map(function(e){ return e.raw; }).join('') + (obj ? obj[0] + obj[1] + obj[2].raw + obj[3] : ''); + r0 = (function(offset, line, column, ws0, e, es) { + var raw = ws0 + e.raw + es.map(function(e){ return e.raw; }).join(''); es = [e].concat(es.map(function(e){ return e.list[0]; })); - if(obj) es.push(obj[2]); return {list: es, raw: raw}; - })(r1.offset, r1.line, r1.column, r3, r5, r6, r7); + })(r1.offset, r1.line, r1.column, r3, r5, r6); } if (r0 === null) { pos = clone(r1); @@ -5323,6 +5281,76 @@ module.exports = module.exports = (function(){ if (r0 === null) { pos = clone(r1); } + if (r0 === null) { + r1 = clone(pos); + r2 = clone(pos); + r3 = parse__(); + if (r3 !== null) { + r4 = parse_TERM(); + r4 = r4 !== null ? r4 : ""; + if (r4 !== null) { + r5 = parse__(); + if (r5 !== null) { + if (input.charCodeAt(pos.offset) === 44) { + r6 = ","; + advance(pos, 1); + } else { + r6 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (r6 !== null) { + r7 = parse__(); + if (r7 !== null) { + r8 = parse_TERMINDENT(); + if (r8 !== null) { + r9 = parse_implicitObjectLiteral(); + if (r9 !== null) { + r10 = parse_DEDENT(); + if (r10 !== null) { + r0 = [r3, r4, r5, r6, r7, r8, r9, r10]; + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + if (r0 !== null) { + r0 = (function(offset, line, column, ws0, t0, ws1, ws2, t1, o, d) { + return {list: [o], raw: ws0 + t0 + ws1 + "," + ws2 + t1 + o.raw + d}; + })(r1.offset, r1.line, r1.column, r3, r4, r5, r7, r8, r9, r10); + } + if (r0 === null) { + pos = clone(r1); + } + } cache[cacheKey] = { nextPos: clone(pos), diff --git a/src/grammar.pegjs b/src/grammar.pegjs index 8ad1a4c4..d0d26228 100644 --- a/src/grammar.pegjs +++ b/src/grammar.pegjs @@ -409,10 +409,9 @@ leftHandSideExpression = callExpression / newExpression = spread / expression secondaryArgumentList - = ws0:__ !([+-/] __) e:secondaryArgument es:(secondaryArgumentRest)* obj:(","? TERMINDENT implicitObjectLiteral DEDENT)? { - var raw = ws0 + e.raw + es.map(function(e){ return e.raw; }).join('') + (obj ? obj[0] + obj[1] + obj[2].raw + obj[3] : ''); + = ws0:__ !([+-/] __) e:secondaryArgument es:(secondaryArgumentRest)* { + var raw = ws0 + e.raw + es.map(function(e){ return e.raw; }).join(''); es = [e].concat(es.map(function(e){ return e.list[0]; })); - if(obj) es.push(obj[2]); return {list: es, raw: raw}; } / t:TERMINDENT o:implicitObjectLiteral d:DEDENT { @@ -422,6 +421,9 @@ leftHandSideExpression = callExpression / newExpression = ws0:_ t0:TERM? ws1:_ "," ws2:_ t1:TERMINATOR? ws3:_ e:secondaryArgument { return {list: [e], raw: ws0 + t0 + ws1 + "," + ws2 + t1 + ws3 + e.raw}; } + / ws0:_ t0:TERM? ws1:_ "," ws2:_ t1:TERMINDENT o:implicitObjectLiteral d:DEDENT { + return {list: [o], raw: ws0 + t0 + ws1 + "," + ws2 + t1 + o.raw + d}; + } secondaryArgument = spread / secondaryExpression diff --git a/test/objects.coffee b/test/objects.coffee index 551b93c6..ab33e67d 100644 --- a/test/objects.coffee +++ b/test/objects.coffee @@ -87,37 +87,37 @@ suite 'Object Literals', -> # ok config.development.timeout is 10 # ok config.production.timeout is 1000 - #test 'implicit objects as part of chained calls', -> - # pluck = (x) -> x.a - # eq 100, pluck pluck pluck a: a: a: 100 + test 'implicit objects as part of chained calls', -> + pluck = (x) -> x.a + eq 100, pluck pluck pluck a: a: a: 100 #test 'explicit objects nested under implicit objects', -> - #test 'invoking functions with implicit object literals', -> - # generateGetter = (prop) -> (obj) -> obj[prop] - # getA = generateGetter 'a' - # getArgs = -> arguments - # a = b = 30 - # - # result = getA - # a: 10 - # eq 10, result - # - # result = getA - # 'a': 20 - # eq 20, result - # - # result = getA a, - # b:1 - # eq undefined, result - # - # result = getA b:1, - # a:43 - # eq 43, result - # - # result = getA b:1, - # a:62 - # eq undefined, result + test 'invoking functions with implicit object literals', -> + generateGetter = (prop) -> (obj) -> obj[prop] + getA = generateGetter 'a' + getArgs = -> arguments + a = b = 30 + + result = getA + a: 10 + eq 10, result + + result = getA + 'a': 20 + eq 20, result + + result = getA a, + b:1 + eq undefined, result + + result = getA b:1, + a:43 + eq 43, result + + result = getA b:1, + a:62 + eq undefined, result # # result = getA # b:1 @@ -137,21 +137,21 @@ suite 'Object Literals', -> # ok result.length is 3 # ok result[2].c is 1 # - # result = getA b: 13, a: 42, 2 - # eq 42, result - # - # result = getArgs a:1, (1 + 1) - # ok result[1] is 2 - # - # result = getArgs a:1, b - # ok result.length is 2 - # ok result[1] is 30 - # - # result = getArgs a:1, b, b:1, a - # ok result.length is 4 - # ok result[2].b is 1 - # - # throws -> CoffeeScript.compile 'a = b:1, c' + result = getA b: 13, a: 42, 2 + eq 42, result + + result = getArgs a:1, (1 + 1) + ok result[1] is 2 + + result = getArgs a:1, b + ok result.length is 2 + ok result[1] is 30 + + result = getArgs a:1, b, b:1, a + ok result.length is 4 + ok result[2].b is 1 + + throws -> CoffeeScript.compile 'a = b:1, c' #test 'multiple dedentations in implicit object literals', -> # nonce0 = {} From 018edd02ec4f8fb240a7c0a03e5a809ba652cd27 Mon Sep 17 00:00:00 2001 From: Audrey Tang Date: Sat, 27 Oct 2012 17:47:25 +0800 Subject: [PATCH 3/5] * Implicit object literals in parenthesized args. Supports the following forms (as generated by e.g. js2coffee): console.log(1, name: name , 2) console.log( name: name , 4) console.log(name: name , 8) And also this form with arbitrary indent/dedent around commas: console.log(1, 2, 4, ) --- lib/coffee-script/parser.js | 168 +++++++++++++++++++++++++++++++++--- src/grammar.pegjs | 5 +- test/objects.coffee | 68 +++++++++++++++ 3 files changed, 227 insertions(+), 14 deletions(-) diff --git a/lib/coffee-script/parser.js b/lib/coffee-script/parser.js index 154db1ad..9776352f 100644 --- a/lib/coffee-script/parser.js +++ b/lib/coffee-script/parser.js @@ -4866,7 +4866,7 @@ module.exports = module.exports = (function(){ return cachedResult.result; } - var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; + var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16; r1 = clone(pos); r2 = clone(pos); @@ -4881,15 +4881,46 @@ module.exports = module.exports = (function(){ if (r8 !== null) { r9 = parse__(); if (r9 !== null) { + r11 = clone(pos); if (input.charCodeAt(pos.offset) === 44) { - r10 = ","; + r12 = ","; advance(pos, 1); } else { - r10 = null; + r12 = null; if (reportFailures === 0) { matchFailed("\",\""); } } + if (r12 !== null) { + r13 = parse__(); + if (r13 !== null) { + r14 = parse_TERMINATOR(); + r14 = r14 !== null ? r14 : ""; + if (r14 !== null) { + r15 = []; + r16 = parse_INDENT(); + while (r16 !== null) { + r15.push(r16); + r16 = parse_INDENT(); + } + if (r15 !== null) { + r10 = [r12, r13, r14, r15]; + } else { + r10 = null; + pos = clone(r11); + } + } else { + r10 = null; + pos = clone(r11); + } + } else { + r10 = null; + pos = clone(r11); + } + } else { + r10 = null; + pos = clone(r11); + } if (r10 === null) { r10 = parse_TERMINATOR(); } @@ -4898,7 +4929,18 @@ module.exports = module.exports = (function(){ if (r11 !== null) { r12 = parse_argument(); if (r12 !== null) { - r5 = [r7, r8, r9, r10, r11, r12]; + r13 = []; + r14 = parse_DEDENT(); + while (r14 !== null) { + r13.push(r14); + r14 = parse_DEDENT(); + } + if (r13 !== null) { + r5 = [r7, r8, r9, r10, r11, r12, r13]; + } else { + r5 = null; + pos = clone(r6); + } } else { r5 = null; pos = clone(r6); @@ -4933,15 +4975,46 @@ module.exports = module.exports = (function(){ if (r8 !== null) { r9 = parse__(); if (r9 !== null) { + r11 = clone(pos); if (input.charCodeAt(pos.offset) === 44) { - r10 = ","; + r12 = ","; advance(pos, 1); } else { - r10 = null; + r12 = null; if (reportFailures === 0) { matchFailed("\",\""); } } + if (r12 !== null) { + r13 = parse__(); + if (r13 !== null) { + r14 = parse_TERMINATOR(); + r14 = r14 !== null ? r14 : ""; + if (r14 !== null) { + r15 = []; + r16 = parse_INDENT(); + while (r16 !== null) { + r15.push(r16); + r16 = parse_INDENT(); + } + if (r15 !== null) { + r10 = [r12, r13, r14, r15]; + } else { + r10 = null; + pos = clone(r11); + } + } else { + r10 = null; + pos = clone(r11); + } + } else { + r10 = null; + pos = clone(r11); + } + } else { + r10 = null; + pos = clone(r11); + } if (r10 === null) { r10 = parse_TERMINATOR(); } @@ -4950,7 +5023,18 @@ module.exports = module.exports = (function(){ if (r11 !== null) { r12 = parse_argument(); if (r12 !== null) { - r5 = [r7, r8, r9, r10, r11, r12]; + r13 = []; + r14 = parse_DEDENT(); + while (r14 !== null) { + r13.push(r14); + r14 = parse_DEDENT(); + } + if (r13 !== null) { + r5 = [r7, r8, r9, r10, r11, r12, r13]; + } else { + r5 = null; + pos = clone(r6); + } } else { r5 = null; pos = clone(r6); @@ -4977,15 +5061,46 @@ module.exports = module.exports = (function(){ } } if (r4 !== null) { + r6 = clone(pos); if (input.charCodeAt(pos.offset) === 44) { - r5 = ","; + r7 = ","; advance(pos, 1); } else { - r5 = null; + r7 = null; if (reportFailures === 0) { matchFailed("\",\""); } } + if (r7 !== null) { + r8 = parse__(); + if (r8 !== null) { + r9 = []; + r10 = parse_DEDENT(); + while (r10 !== null) { + r9.push(r10); + r10 = parse_DEDENT(); + } + if (r9 !== null) { + r10 = parse_TERMINATOR(); + r10 = r10 !== null ? r10 : ""; + if (r10 !== null) { + r5 = [r7, r8, r9, r10]; + } else { + r5 = null; + pos = clone(r6); + } + } else { + r5 = null; + pos = clone(r6); + } + } else { + r5 = null; + pos = clone(r6); + } + } else { + r5 = null; + pos = clone(r6); + } if (r5 === null) { r5 = parse_TERMINATOR(); } @@ -5067,11 +5182,40 @@ module.exports = module.exports = (function(){ return cachedResult.result; } - var r0; + var r0, r1, r2, r3, r4, r5; - r0 = parse_spread(); + r1 = clone(pos); + r2 = clone(pos); + r3 = parse_TERMINDENT(); + if (r3 !== null) { + r4 = parse_implicitObjectLiteral(); + if (r4 !== null) { + r5 = parse_DEDENT(); + if (r5 !== null) { + r0 = [r3, r4, r5]; + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } + if (r0 !== null) { + r0 = (function(offset, line, column, t, o, d) { return o; })(r1.offset, r1.line, r1.column, r3, r4, r5); + } if (r0 === null) { - r0 = parse_expression(); + pos = clone(r1); + } + if (r0 === null) { + r0 = parse_spread(); + if (r0 === null) { + r0 = parse_expression(); + } } cache[cacheKey] = { diff --git a/src/grammar.pegjs b/src/grammar.pegjs index d0d26228..d789f911 100644 --- a/src/grammar.pegjs +++ b/src/grammar.pegjs @@ -398,7 +398,7 @@ leftHandSideExpression = callExpression / newExpression }; } argumentListContents - = e:argument es:(_ TERM? _ ("," / TERMINATOR) _ argument)* t:("," / TERMINATOR)? { + = e:argument es:(_ TERM? _ ("," _ TERMINATOR? INDENT* / TERMINATOR) _ argument DEDENT*)* t:("," _ DEDENT* TERMINATOR? / TERMINATOR)? { var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3] + e[4] + e[5].raw; }).join('') + t; return {list: [e].concat(es.map(function(e){ return e[5]; })), raw: raw}; } @@ -406,7 +406,8 @@ leftHandSideExpression = callExpression / newExpression return {list: a.list, raw: t0 + a.raw + d + t1}; } argument - = spread + = t:TERMINDENT o:implicitObjectLiteral d:DEDENT { return o; } + / spread / expression secondaryArgumentList = ws0:__ !([+-/] __) e:secondaryArgument es:(secondaryArgumentRest)* { diff --git a/test/objects.coffee b/test/objects.coffee index ab33e67d..33e4720f 100644 --- a/test/objects.coffee +++ b/test/objects.coffee @@ -153,6 +153,74 @@ suite 'Object Literals', -> throws -> CoffeeScript.compile 'a = b:1, c' + test 'invoking functions with implicit object literals (with parens)', -> + generateGetter = (prop) -> (obj) -> obj[prop] + getA = generateGetter 'a' + getArgs = -> arguments + a = b = 30 + + result = getA( + a: 10 + ) + eq 10, result + + result = getA( + 'a': 20 + ) + eq 20, result + + result = getA(a, + b:1 + ) + eq undefined, result + + result = getA(b:1, + a:43 + ) + eq 43, result + + result = getA(b:1, + a:62 + ) + eq undefined, result + # result = getA( + # b:1 + # a + # ) + # eq undefined, result + + result = getA( + a: + b:2 + b:1 + ) + eq 2, result.b + + # result = getArgs( + # a:1 + # b + # c:1 + # ) + # ok result.length is 3 + # ok result[2].c is 1 + + result = getA(b: 13, a: 42, 2) + eq 42, result + + result = getArgs(a:1, (1 + 1)) + ok result[1] is 2 + + result = getArgs(a:1, b) + ok result.length is 2 + ok result[1] is 30 + + result = getArgs(a:1, b, b:1, a) + ok result.length is 4 + ok result[2].b is 1 + + throws -> CoffeeScript.compile 'a = b:1, c' + + #test 'multiple dedentations in implicit object literals', -> # nonce0 = {} # nonce1 = {} From 9c62d54ae23ce83ccd50335b861858afc47909d5 Mon Sep 17 00:00:00 2001 From: Audrey Tang Date: Sat, 27 Oct 2012 18:27:42 +0800 Subject: [PATCH 4/5] * Restore support for commaless calls. f( 1 2 3 ) Because d:DEDENT t1:TERMINATOR? is already part of argumentListContents, there's no need to specify them again before the closing paren. --- lib/coffee-script/parser.js | 173 +++++++++++++++++------------------- src/grammar.pegjs | 10 +-- 2 files changed, 85 insertions(+), 98 deletions(-) diff --git a/lib/coffee-script/parser.js b/lib/coffee-script/parser.js index 9776352f..f2518032 100644 --- a/lib/coffee-script/parser.js +++ b/lib/coffee-script/parser.js @@ -4876,12 +4876,12 @@ module.exports = module.exports = (function(){ r6 = clone(pos); r7 = parse__(); if (r7 !== null) { - r8 = parse_TERM(); - r8 = r8 !== null ? r8 : ""; - if (r8 !== null) { - r9 = parse__(); - if (r9 !== null) { - r11 = clone(pos); + r9 = clone(pos); + r10 = parse_TERM(); + r10 = r10 !== null ? r10 : ""; + if (r10 !== null) { + r11 = parse__(); + if (r11 !== null) { if (input.charCodeAt(pos.offset) === 44) { r12 = ","; advance(pos, 1); @@ -4904,47 +4904,47 @@ module.exports = module.exports = (function(){ r16 = parse_INDENT(); } if (r15 !== null) { - r10 = [r12, r13, r14, r15]; + r8 = [r10, r11, r12, r13, r14, r15]; } else { - r10 = null; - pos = clone(r11); + r8 = null; + pos = clone(r9); } } else { - r10 = null; - pos = clone(r11); + r8 = null; + pos = clone(r9); } } else { - r10 = null; - pos = clone(r11); + r8 = null; + pos = clone(r9); } } else { - r10 = null; - pos = clone(r11); - } - if (r10 === null) { - r10 = parse_TERMINATOR(); + r8 = null; + pos = clone(r9); } + } else { + r8 = null; + pos = clone(r9); + } + } else { + r8 = null; + pos = clone(r9); + } + if (r8 === null) { + r8 = parse_TERMINATOR(); + } + if (r8 !== null) { + r9 = parse__(); + if (r9 !== null) { + r10 = parse_argument(); if (r10 !== null) { - r11 = parse__(); + r11 = []; + r12 = parse_DEDENT(); + while (r12 !== null) { + r11.push(r12); + r12 = parse_DEDENT(); + } if (r11 !== null) { - r12 = parse_argument(); - if (r12 !== null) { - r13 = []; - r14 = parse_DEDENT(); - while (r14 !== null) { - r13.push(r14); - r14 = parse_DEDENT(); - } - if (r13 !== null) { - r5 = [r7, r8, r9, r10, r11, r12, r13]; - } else { - r5 = null; - pos = clone(r6); - } - } else { - r5 = null; - pos = clone(r6); - } + r5 = [r7, r8, r9, r10, r11]; } else { r5 = null; pos = clone(r6); @@ -4970,12 +4970,12 @@ module.exports = module.exports = (function(){ r6 = clone(pos); r7 = parse__(); if (r7 !== null) { - r8 = parse_TERM(); - r8 = r8 !== null ? r8 : ""; - if (r8 !== null) { - r9 = parse__(); - if (r9 !== null) { - r11 = clone(pos); + r9 = clone(pos); + r10 = parse_TERM(); + r10 = r10 !== null ? r10 : ""; + if (r10 !== null) { + r11 = parse__(); + if (r11 !== null) { if (input.charCodeAt(pos.offset) === 44) { r12 = ","; advance(pos, 1); @@ -4998,47 +4998,47 @@ module.exports = module.exports = (function(){ r16 = parse_INDENT(); } if (r15 !== null) { - r10 = [r12, r13, r14, r15]; + r8 = [r10, r11, r12, r13, r14, r15]; } else { - r10 = null; - pos = clone(r11); + r8 = null; + pos = clone(r9); } } else { - r10 = null; - pos = clone(r11); + r8 = null; + pos = clone(r9); } } else { - r10 = null; - pos = clone(r11); + r8 = null; + pos = clone(r9); } } else { - r10 = null; - pos = clone(r11); - } - if (r10 === null) { - r10 = parse_TERMINATOR(); + r8 = null; + pos = clone(r9); } + } else { + r8 = null; + pos = clone(r9); + } + } else { + r8 = null; + pos = clone(r9); + } + if (r8 === null) { + r8 = parse_TERMINATOR(); + } + if (r8 !== null) { + r9 = parse__(); + if (r9 !== null) { + r10 = parse_argument(); if (r10 !== null) { - r11 = parse__(); + r11 = []; + r12 = parse_DEDENT(); + while (r12 !== null) { + r11.push(r12); + r12 = parse_DEDENT(); + } if (r11 !== null) { - r12 = parse_argument(); - if (r12 !== null) { - r13 = []; - r14 = parse_DEDENT(); - while (r14 !== null) { - r13.push(r14); - r14 = parse_DEDENT(); - } - if (r13 !== null) { - r5 = [r7, r8, r9, r10, r11, r12, r13]; - } else { - r5 = null; - pos = clone(r6); - } - } else { - r5 = null; - pos = clone(r6); - } + r5 = [r7, r8, r9, r10, r11]; } else { r5 = null; pos = clone(r6); @@ -5121,8 +5121,8 @@ module.exports = module.exports = (function(){ } if (r0 !== null) { r0 = (function(offset, line, column, e, es, t) { - var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3] + e[4] + e[5].raw; }).join('') + t; - return {list: [e].concat(es.map(function(e){ return e[5]; })), raw: raw}; + var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3].raw; }).join('') + t; + return {list: [e].concat(es.map(function(e){ return e[3]; })), raw: raw}; })(r1.offset, r1.line, r1.column, r3, r4, r5); } if (r0 === null) { @@ -5135,20 +5135,7 @@ module.exports = module.exports = (function(){ if (r3 !== null) { r4 = parse_argumentListContents(); if (r4 !== null) { - r5 = parse_DEDENT(); - if (r5 !== null) { - r6 = parse_TERMINATOR(); - r6 = r6 !== null ? r6 : ""; - if (r6 !== null) { - r0 = [r3, r4, r5, r6]; - } else { - r0 = null; - pos = clone(r2); - } - } else { - r0 = null; - pos = clone(r2); - } + r0 = [r3, r4]; } else { r0 = null; pos = clone(r2); @@ -5158,9 +5145,9 @@ module.exports = module.exports = (function(){ pos = clone(r2); } if (r0 !== null) { - r0 = (function(offset, line, column, t0, a, d, t1) { - return {list: a.list, raw: t0 + a.raw + d + t1}; - })(r1.offset, r1.line, r1.column, r3, r4, r5, r6); + r0 = (function(offset, line, column, t0, a) { + return {list: a.list, raw: t0 + a.raw}; + })(r1.offset, r1.line, r1.column, r3, r4); } if (r0 === null) { pos = clone(r1); diff --git a/src/grammar.pegjs b/src/grammar.pegjs index d789f911..eeee4bc2 100644 --- a/src/grammar.pegjs +++ b/src/grammar.pegjs @@ -398,12 +398,12 @@ leftHandSideExpression = callExpression / newExpression }; } argumentListContents - = e:argument es:(_ TERM? _ ("," _ TERMINATOR? INDENT* / TERMINATOR) _ argument DEDENT*)* t:("," _ DEDENT* TERMINATOR? / TERMINATOR)? { - var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3] + e[4] + e[5].raw; }).join('') + t; - return {list: [e].concat(es.map(function(e){ return e[5]; })), raw: raw}; + = e:argument es:(_ (TERM? _ "," _ TERMINATOR? INDENT* / TERMINATOR) _ argument DEDENT*)* t:("," _ DEDENT* TERMINATOR? / TERMINATOR)? { + var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3].raw; }).join('') + t; + return {list: [e].concat(es.map(function(e){ return e[3]; })), raw: raw}; } - / t0:TERMINDENT a:argumentListContents d:DEDENT t1:TERMINATOR? { - return {list: a.list, raw: t0 + a.raw + d + t1}; + / t0:TERMINDENT a:argumentListContents { + return {list: a.list, raw: t0 + a.raw}; } argument = t:TERMINDENT o:implicitObjectLiteral d:DEDENT { return o; } From c5a9a38c1ab49683ba795769cfcf194d83ed7ce0 Mon Sep 17 00:00:00 2001 From: Audrey Tang Date: Sat, 27 Oct 2012 18:33:24 +0800 Subject: [PATCH 5/5] * Restore commaless single arg calls. --- lib/coffee-script/parser.js | 22 ++++++++++++++++++---- src/grammar.pegjs | 4 ++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/coffee-script/parser.js b/lib/coffee-script/parser.js index f2518032..801922da 100644 --- a/lib/coffee-script/parser.js +++ b/lib/coffee-script/parser.js @@ -5135,7 +5135,21 @@ module.exports = module.exports = (function(){ if (r3 !== null) { r4 = parse_argumentListContents(); if (r4 !== null) { - r0 = [r3, r4]; + r5 = parse_DEDENT(); + r5 = r5 !== null ? r5 : ""; + if (r5 !== null) { + r6 = parse_TERMINATOR(); + r6 = r6 !== null ? r6 : ""; + if (r6 !== null) { + r0 = [r3, r4, r5, r6]; + } else { + r0 = null; + pos = clone(r2); + } + } else { + r0 = null; + pos = clone(r2); + } } else { r0 = null; pos = clone(r2); @@ -5145,9 +5159,9 @@ module.exports = module.exports = (function(){ pos = clone(r2); } if (r0 !== null) { - r0 = (function(offset, line, column, t0, a) { - return {list: a.list, raw: t0 + a.raw}; - })(r1.offset, r1.line, r1.column, r3, r4); + r0 = (function(offset, line, column, t0, a, d, t1) { + return {list: a.list, raw: t0 + a.raw + d + t1}; + })(r1.offset, r1.line, r1.column, r3, r4, r5, r6); } if (r0 === null) { pos = clone(r1); diff --git a/src/grammar.pegjs b/src/grammar.pegjs index eeee4bc2..b74c4542 100644 --- a/src/grammar.pegjs +++ b/src/grammar.pegjs @@ -402,8 +402,8 @@ leftHandSideExpression = callExpression / newExpression var raw = e.raw + es.map(function(e){ return e[0] + e[1] + e[2] + e[3].raw; }).join('') + t; return {list: [e].concat(es.map(function(e){ return e[3]; })), raw: raw}; } - / t0:TERMINDENT a:argumentListContents { - return {list: a.list, raw: t0 + a.raw}; + / t0:TERMINDENT a:argumentListContents d:DEDENT? t1:TERMINATOR? { + return {list: a.list, raw: t0 + a.raw + d + t1}; } argument = t:TERMINDENT o:implicitObjectLiteral d:DEDENT { return o; }