Skip to content

Commit

Permalink
Merge pull request #3240 from alubbe/master
Browse files Browse the repository at this point in the history
using 'yield' automatically turns functions into generators
  • Loading branch information
jashkenas committed Sep 19, 2014
2 parents b407a59 + efca286 commit a78cbe7
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 45 deletions.
6 changes: 6 additions & 0 deletions Cakefile
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ runTests = (CoffeeScript) ->

# Run every test in the `test` folder, recording failures.
files = fs.readdirSync 'test'

# Ignore generators test file if generators are not available
generatorsAreAvailable = '--harmony' in process.execArgv or
'--harmony-generators' in process.execArgv
files.splice files.indexOf('generators.coffee'), 1 if not generatorsAreAvailable

for file in files when helpers.isCoffee file
literate = helpers.isLiterate file
currentFile = filename = path.join 'test', file
Expand Down
8 changes: 7 additions & 1 deletion lib/coffee-script/grammar.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions lib/coffee-script/lexer.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 36 additions & 1 deletion lib/coffee-script/nodes.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 28 additions & 21 deletions lib/coffee-script/parser.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/coffee-script/rewriter.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
},
"preferGlobal": true,
"scripts": {
"test": "node ./bin/cake test"
"test": "node ./bin/cake test",
"test-harmony": "node --harmony ./bin/cake test"
},
"homepage": "http://coffeescript.org",
"bugs": "https://github.com/jashkenas/coffeescript/issues",
Expand Down
4 changes: 4 additions & 0 deletions src/grammar.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ grammar =
o 'UNARY_MATH Expression', -> new Op $1 , $2
o '- Expression', (-> new Op '-', $2), prec: 'UNARY_MATH'
o '+ Expression', (-> new Op '+', $2), prec: 'UNARY_MATH'
o 'YIELD Statement', -> new Op $1 , $2
o 'YIELD Expression', -> new Op $1 , $2
o 'YIELD FROM Expression', -> new Op $1.concat($2) , $3

o '-- SimpleAssignable', -> new Op '--', $2
o '++ SimpleAssignable', -> new Op '++', $2
Expand Down Expand Up @@ -586,6 +589,7 @@ operators = [
['nonassoc', '++', '--']
['left', '?']
['right', 'UNARY']
['right', 'YIELD']
['right', '**']
['right', 'UNARY_MATH']
['left', 'MATH']
Expand Down
11 changes: 7 additions & 4 deletions src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ exports.Lexer = class Lexer
if id is 'own' and @tag() is 'FOR'
@token 'OWN', id
return id.length
if id is 'from' and @tag() is 'YIELD'
@token 'FROM', id
return id.length
forcedIdentifier = colon or
(prev = last @tokens) and (prev[0] in ['.', '?.', '::', '?::'] or
not prev.spaced and prev[0] is '@')
Expand Down Expand Up @@ -688,7 +691,7 @@ exports.Lexer = class Lexer
# Are we in the midst of an unfinished expression?
unfinished: ->
LINE_CONTINUER.test(@chunk) or
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', 'YIELD',
'**', 'SHIFT', 'RELATION', 'COMPARE', 'LOGIC', 'THROW', 'EXTENDS']

# Remove newlines from beginning and (non escaped) from end of string literals.
Expand Down Expand Up @@ -729,7 +732,7 @@ exports.Lexer = class Lexer
JS_KEYWORDS = [
'true', 'false', 'null', 'this'
'new', 'delete', 'typeof', 'in', 'instanceof'
'return', 'throw', 'break', 'continue', 'debugger'
'return', 'throw', 'break', 'continue', 'debugger', 'yield'
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
'class', 'extends', 'super'
]
Expand Down Expand Up @@ -758,10 +761,10 @@ RESERVED = [
'case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum'
'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind'
'__indexOf', 'implements', 'interface', 'package', 'private', 'protected'
'public', 'static', 'yield'
'public', 'static'
]

STRICT_PROSCRIBED = ['arguments', 'eval']
STRICT_PROSCRIBED = ['arguments', 'eval', 'yield*']

# The superset of both JavaScript keywords and reserved words, none of which may
# be used as identifiers or properties.
Expand Down
40 changes: 30 additions & 10 deletions src/nodes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,6 @@ exports.Return = class Return extends Base
answer.push @makeCode ";"
return answer


#### Value

# A value, variable or literal or parenthesized, indexed or dotted into,
Expand Down Expand Up @@ -1315,9 +1314,11 @@ exports.Assign = class Assign extends Base
# has no *children* -- they're within the inner scope.
exports.Code = class Code extends Base
constructor: (params, body, tag) ->
@params = params or []
@body = body or new Block
@bound = tag is 'boundfunc'
@params = params or []
@body = body or new Block
@bound = tag is 'boundfunc'
@isGenerator = @body.contains (node) ->
node instanceof Op and node.operator in ['yield', 'yield*']

children: ['params', 'body']

Expand Down Expand Up @@ -1384,9 +1385,10 @@ exports.Code = class Code extends Base
node.error "multiple parameters named '#{name}'" if name in uniqs
uniqs.push name
@body.makeReturn() unless wasEmpty or @noReturn
code = 'function'
code += ' ' + @name if @ctor
code += '('
code = 'function'
code += '*' if @isGenerator
code += ' ' + @name if @ctor
code += '('
answer = [@makeCode(code)]
for p, i in params
if i then answer.push @makeCode ", "
Expand Down Expand Up @@ -1612,9 +1614,10 @@ exports.Op = class Op extends Base

# The map of conversions from CoffeeScript to JavaScript symbols.
CONVERSIONS =
'==': '==='
'!=': '!=='
'of': 'in'
'==': '==='
'!=': '!=='
'of': 'in'
'yieldfrom': 'yield*'

# The map of invertible operators.
INVERSIONS =
Expand All @@ -1625,6 +1628,9 @@ exports.Op = class Op extends Base

isSimpleNumber: NO

isYield: ->
@operator in ['yield', 'yield*']

isUnary: ->
not @second

Expand Down Expand Up @@ -1691,6 +1697,7 @@ exports.Op = class Op extends Base
@error 'delete operand may not be argument or var'
if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED
@error "cannot increment/decrement \"#{@first.unwrapAll().value}\""
return @compileYield o if @isYield()
return @compileUnary o if @isUnary()
return @compileChain o if isChain
switch @operator
Expand Down Expand Up @@ -1745,6 +1752,19 @@ exports.Op = class Op extends Base
parts.reverse() if @flip
@joinFragmentArrays parts, ''

compileYield: (o) ->
parts = []
op = @operator
if not o.scope.parent?
@error 'yield statements must occur within a function generator.'
if 'expression' in Object.keys @first
parts.push @first.expression.compileToFragments o, LEVEL_OP if @first.expression?
else
parts.push [@makeCode "(#{op} "]
parts.push @first.compileToFragments o, LEVEL_OP
parts.push [@makeCode ")"]
@joinFragmentArrays parts, ''

compilePower: (o) ->
# Make a Math.pow call
pow = new Value new Literal('Math'), [new Access new Literal 'pow']
Expand Down
2 changes: 1 addition & 1 deletion src/rewriter.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = [
'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS'
'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY',
'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'YIELD'
'UNARY_MATH', 'SUPER', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++'
]

Expand Down
Loading

0 comments on commit a78cbe7

Please sign in to comment.