mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
adding a 'loop' keyword to CoffeeScript. Takes an expression or a block. Runs it until you break or return out.
This commit is contained in:
parent
a133e018cc
commit
0222d90fa3
12 changed files with 134 additions and 103 deletions
|
@ -21,7 +21,7 @@ match_here: (regexp, text) ->
|
|||
|
||||
# Search for a kleene star match at the beginning of the text.
|
||||
match_star: (c, regexp, text) ->
|
||||
while true
|
||||
loop
|
||||
return true if match_here(regexp, text)
|
||||
return false unless text and (text[0] is c or c is '.')
|
||||
text: text.slice(1)
|
||||
|
|
|
@ -94,7 +94,7 @@ while demand > supply
|
|||
|
||||
while supply > demand then buy()
|
||||
|
||||
while true
|
||||
loop
|
||||
break if broken
|
||||
continue if continuing
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ print(add(2, 4))
|
|||
|
||||
# loop: 'quaff' print.
|
||||
|
||||
while true
|
||||
print('quaff')
|
||||
loop print 'quaff'
|
||||
|
||||
|
||||
# ('cheese', 'bread', 'mayo') at (1) print
|
||||
|
|
|
@ -346,7 +346,7 @@
|
|||
return [] if len <= 0
|
||||
range: new Array len
|
||||
idx: 0
|
||||
while true
|
||||
loop
|
||||
return range if (if step > 0 then i - stop else stop - i) >= 0
|
||||
range[idx]: i
|
||||
idx++
|
||||
|
|
|
@ -484,6 +484,15 @@
|
|||
return $2.add_body(Expressions.wrap([$1]));
|
||||
}), o("Expression WhileSource", function() {
|
||||
return $2.add_body(Expressions.wrap([$1]));
|
||||
}), o("Loop", function() {
|
||||
return $1;
|
||||
})
|
||||
],
|
||||
Loop: [
|
||||
o("LOOP Block", function() {
|
||||
return new WhileNode(new LiteralNode('true')).add_body($2);
|
||||
}), o("LOOP Expression", function() {
|
||||
return new WhileNode(new LiteralNode('true')).add_body(Expressions.wrap([$2]));
|
||||
})
|
||||
],
|
||||
// Array, object, and range comprehensions, at the most generic level.
|
||||
|
@ -747,7 +756,7 @@
|
|||
// 2 + (3 * 4)
|
||||
// And not:
|
||||
// (2 + 3) * 4
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'WHILE', 'UNTIL', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']];
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']];
|
||||
// Wrapping Up
|
||||
// -----------
|
||||
// Finally, now what we have our **grammar** and our **operators**, we can create
|
||||
|
|
|
@ -658,7 +658,7 @@
|
|||
// CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
|
||||
// be used standalone, but you can reference them as an attached property.
|
||||
COFFEE_ALIASES = ["and", "or", "is", "isnt", "not"];
|
||||
COFFEE_KEYWORDS = COFFEE_ALIASES.concat(["then", "unless", "until", "yes", "no", "on", "off", "of", "by", "where", "when"]);
|
||||
COFFEE_KEYWORDS = COFFEE_ALIASES.concat(["then", "unless", "until", "loop", "yes", "no", "on", "off", "of", "by", "where", "when"]);
|
||||
// The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
// used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
// to avoid having a JavaScript error at runtime.
|
||||
|
|
184
lib/parser.js
184
lib/parser.js
File diff suppressed because one or more lines are too long
|
@ -423,7 +423,7 @@
|
|||
// Tokens indicating that the implicit call must enclose a block of expressions.
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
|
||||
// Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'TERMINATOR', 'INDENT'].concat(EXPRESSION_END);
|
||||
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'].concat(EXPRESSION_END);
|
||||
// Single-line flavors of block expressions that have unclosed endings.
|
||||
// The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
SINGLE_LINERS = ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN'];
|
||||
|
|
|
@ -416,6 +416,12 @@ grammar: {
|
|||
o "WhileSource Block", -> $1.add_body $2
|
||||
o "Statement WhileSource", -> $2.add_body Expressions.wrap [$1]
|
||||
o "Expression WhileSource", -> $2.add_body Expressions.wrap [$1]
|
||||
o "Loop", -> $1
|
||||
]
|
||||
|
||||
Loop: [
|
||||
o "LOOP Block", -> new WhileNode(new LiteralNode 'true').add_body $2
|
||||
o "LOOP Expression", -> new WhileNode(new LiteralNode 'true').add_body Expressions.wrap [$2]
|
||||
]
|
||||
|
||||
# Array, object, and range comprehensions, at the most generic level.
|
||||
|
@ -596,7 +602,7 @@ operators: [
|
|||
["right", 'INDENT']
|
||||
["left", 'OUTDENT']
|
||||
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
|
||||
["right", 'FOR', 'WHILE', 'UNTIL', 'NEW', 'SUPER', 'CLASS']
|
||||
["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS']
|
||||
["left", 'EXTENDS']
|
||||
["right", 'ASSIGN', 'RETURN']
|
||||
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']
|
||||
|
|
|
@ -323,7 +323,7 @@ exports.Lexer: class Lexer
|
|||
tag_parameters: ->
|
||||
return if @tag() isnt ')'
|
||||
i: 0
|
||||
while true
|
||||
loop
|
||||
i: + 1
|
||||
tok: @prev i
|
||||
return if not tok
|
||||
|
@ -466,7 +466,7 @@ JS_KEYWORDS: [
|
|||
# be used standalone, but you can reference them as an attached property.
|
||||
COFFEE_ALIASES: ["and", "or", "is", "isnt", "not"]
|
||||
COFFEE_KEYWORDS: COFFEE_ALIASES.concat [
|
||||
"then", "unless", "until",
|
||||
"then", "unless", "until", "loop",
|
||||
"yes", "no", "on", "off",
|
||||
"of", "by", "where", "when"
|
||||
]
|
||||
|
|
|
@ -43,7 +43,7 @@ exports.Rewriter: class Rewriter
|
|||
# our feet.
|
||||
scan_tokens: (block) ->
|
||||
i: 0
|
||||
while true
|
||||
loop
|
||||
break unless @tokens[i]
|
||||
move: block @tokens[i - 1], @tokens[i], @tokens[i + 1], i
|
||||
i: + move
|
||||
|
@ -162,7 +162,7 @@ exports.Rewriter: class Rewriter
|
|||
@tokens.splice i + 1, 0, indent
|
||||
idx: i + 1
|
||||
parens: 0
|
||||
while true
|
||||
loop
|
||||
idx: + 1
|
||||
tok: @tokens[idx]
|
||||
pre: @tokens[idx - 1]
|
||||
|
@ -286,7 +286,7 @@ IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_
|
|||
IMPLICIT_BLOCK: ['->', '=>', '{', '[', ',']
|
||||
|
||||
# Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'TERMINATOR', 'INDENT'].concat EXPRESSION_END
|
||||
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'].concat EXPRESSION_END
|
||||
|
||||
# Single-line flavors of block expressions that have unclosed endings.
|
||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
|
|
|
@ -36,3 +36,14 @@ results: until value
|
|||
i += 1
|
||||
|
||||
ok i is 6
|
||||
|
||||
|
||||
# And, the loop form of while.
|
||||
i: 5
|
||||
list: []
|
||||
loop
|
||||
i: - 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
|
|
Loading…
Add table
Reference in a new issue