mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
tests are now passing on symbology
This commit is contained in:
58
Cakefile
58
Cakefile
@@ -1,33 +1,33 @@
|
||||
fs: require 'fs'
|
||||
{helpers}: require('./lib/helpers')
|
||||
CoffeeScript: require './lib/coffee-script'
|
||||
{spawn, exec}: require('child_process')
|
||||
fs = require 'fs'
|
||||
{helpers} = require './lib/helpers'
|
||||
CoffeeScript = require './lib/coffee-script'
|
||||
{spawn, exec} = require 'child_process'
|
||||
|
||||
# ANSI Terminal Colors.
|
||||
red: '\033[0;31m'
|
||||
green: '\033[0;32m'
|
||||
reset: '\033[0m'
|
||||
red = '\033[0;31m'
|
||||
green = '\033[0;32m'
|
||||
reset = '\033[0m'
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run: (args) ->
|
||||
proc: spawn 'bin/coffee', args
|
||||
run = (args) ->
|
||||
proc = spawn 'bin/coffee', args
|
||||
proc.stderr.on 'data', (buffer) -> puts buffer.toString()
|
||||
proc.on 'exit', (status) -> process.exit(1) if status != 0
|
||||
|
||||
# Log a message with a color.
|
||||
log: (message, color, explanation) ->
|
||||
log = (message, color, explanation) ->
|
||||
puts "$color$message$reset ${explanation or ''}"
|
||||
|
||||
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
|
||||
|
||||
task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) ->
|
||||
base: options.prefix or '/usr/local'
|
||||
lib: "$base/lib/coffee-script"
|
||||
bin: "$base/bin"
|
||||
node: "~/.node_libraries/coffee-script"
|
||||
puts "Installing CoffeeScript to $lib"
|
||||
puts "Linking to $node"
|
||||
puts "Linking 'coffee' to $bin/coffee"
|
||||
base = options.prefix or '/usr/local'
|
||||
lib = "$base/lib/coffee-script"
|
||||
bin = "$base/bin"
|
||||
node = "~/.node_libraries/coffee-script"
|
||||
puts "Installing CoffeeScript to $lib"
|
||||
puts "Linking to $node"
|
||||
puts "Linking 'coffee' to $bin/coffee"
|
||||
exec([
|
||||
"mkdir -p $lib $bin"
|
||||
"cp -rf bin lib LICENSE README package.json src $lib"
|
||||
@@ -41,8 +41,8 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||
|
||||
|
||||
task 'build', 'build the CoffeeScript language from source', ->
|
||||
files: fs.readdirSync 'src'
|
||||
files: 'src/' + file for file in files when file.match(/\.coffee$/)
|
||||
files = fs.readdirSync 'src'
|
||||
files = 'src/' + file for file in files when file.match(/\.coffee$/)
|
||||
run ['-c', '-o', 'lib'].concat(files)
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@ task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
require 'jison'
|
||||
parser: require('./lib/grammar').parser
|
||||
js: parser.generate()
|
||||
parserPath: 'lib/parser.js'
|
||||
parser = require('./lib/grammar').parser
|
||||
js = parser.generate()
|
||||
parserPath = 'lib/parser.js'
|
||||
fs.writeFile parserPath, js
|
||||
|
||||
|
||||
@@ -87,23 +87,23 @@ task 'doc:underscore', 'rebuild the Underscore.coffee documentation page', ->
|
||||
|
||||
|
||||
task 'loc', 'count the lines of source code in the CoffeeScript compiler', ->
|
||||
sources: ['src/coffee-script.coffee', 'src/grammar.coffee', 'src/helpers.coffee', 'src/lexer.coffee', 'src/nodes.coffee', 'src/rewriter.coffee', 'src/scope.coffee']
|
||||
sources = ['src/coffee-script.coffee', 'src/grammar.coffee', 'src/helpers.coffee', 'src/lexer.coffee', 'src/nodes.coffee', 'src/rewriter.coffee', 'src/scope.coffee']
|
||||
exec "cat ${ sources.join(' ') } | grep -v '^\\( *#\\|\\s*$\\)' | wc -l | tr -s ' '", (err, stdout) ->
|
||||
print stdout
|
||||
|
||||
|
||||
task 'test', 'run the CoffeeScript language test suite', ->
|
||||
helpers.extend global, require 'assert'
|
||||
passedTests: failedTests: 0
|
||||
startTime: new Date
|
||||
originalOk: ok
|
||||
passedTests = failedTests = 0
|
||||
startTime = new Date
|
||||
originalOk = ok
|
||||
helpers.extend global, {
|
||||
ok: (args...) -> passedTests += 1; originalOk(args...)
|
||||
CoffeeScript: CoffeeScript
|
||||
}
|
||||
process.on 'exit', ->
|
||||
time: ((new Date - startTime) / 1000).toFixed(2)
|
||||
message: "passed $passedTests tests in $time seconds$reset"
|
||||
time = ((new Date - startTime) / 1000).toFixed(2)
|
||||
message = "passed $passedTests tests in $time seconds$reset"
|
||||
if failedTests
|
||||
log "failed $failedTests and $message", red
|
||||
else
|
||||
@@ -111,7 +111,7 @@ task 'test', 'run the CoffeeScript language test suite', ->
|
||||
fs.readdir 'test', (err, files) ->
|
||||
files.forEach (file) ->
|
||||
return unless file.match(/\.coffee$/i)
|
||||
source: path.join 'test', file
|
||||
source = path.join 'test', file
|
||||
fs.readFile source, (err, code) ->
|
||||
try
|
||||
CoffeeScript.run code.toString(), {source: source}
|
||||
|
||||
@@ -76,16 +76,16 @@
|
||||
})
|
||||
],
|
||||
Assign: [
|
||||
o("Assignable ASSIGN Expression", function() {
|
||||
o("Assignable = Expression", function() {
|
||||
return new AssignNode($1, $3);
|
||||
})
|
||||
],
|
||||
AssignObj: [
|
||||
o("Identifier", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("AlphaNumeric"), o("Identifier ASSIGN Expression", function() {
|
||||
}), o("AlphaNumeric"), o("Identifier : Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'object');
|
||||
}), o("AlphaNumeric ASSIGN Expression", function() {
|
||||
}), o("AlphaNumeric : Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'object');
|
||||
}), o("Comment")
|
||||
],
|
||||
@@ -225,7 +225,7 @@
|
||||
ClassAssign: [
|
||||
o("AssignObj", function() {
|
||||
return $1;
|
||||
}), o("ThisProperty ASSIGN Expression", function() {
|
||||
}), o("ThisProperty : Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'this');
|
||||
})
|
||||
],
|
||||
@@ -609,7 +609,7 @@
|
||||
})
|
||||
]
|
||||
};
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||', 'OP?'], ["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']];
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||', 'OP?'], ["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", '=', ':', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']];
|
||||
tokens = [];
|
||||
_a = grammar;
|
||||
for (name in _a) {
|
||||
|
||||
13
lib/lexer.js
13
lib/lexer.js
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var ASSIGNED, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, _a, _b, _c, compact, count, helpers, include, starts;
|
||||
var ASSIGNED, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, _a, _b, _c, compact, count, helpers, include, starts;
|
||||
var __slice = Array.prototype.slice;
|
||||
if (typeof process !== "undefined" && process !== null) {
|
||||
_a = require('./rewriter');
|
||||
@@ -309,12 +309,10 @@
|
||||
value = value || this.chunk.substr(0, 1);
|
||||
prevSpaced = this.prev() && this.prev().spaced;
|
||||
tag = value;
|
||||
if (value.match(ASSIGNMENT)) {
|
||||
tag = 'ASSIGN';
|
||||
if (include(JS_FORBIDDEN, this.value)) {
|
||||
this.assignmentError();
|
||||
}
|
||||
} else if (value === ';') {
|
||||
if (value === '=' && include(JS_FORBIDDEN, this.value)) {
|
||||
this.assignmentError();
|
||||
}
|
||||
if (value === ';') {
|
||||
tag = 'TERMINATOR';
|
||||
} else if (value === '?' && prevSpaced) {
|
||||
tag = 'OP?';
|
||||
@@ -604,7 +602,6 @@
|
||||
MULTI_DENT = /^((\n([ \t]*))+)(\.)?/;
|
||||
LAST_DENTS = /\n([ \t]*)/g;
|
||||
LAST_DENT = /\n([ \t]*)/;
|
||||
ASSIGNMENT = /^[:=]$/;
|
||||
REGEX_START = /^\/[^\/ ]/;
|
||||
REGEX_INTERPOLATION = /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/;
|
||||
REGEX_END = /^(([imgy]{1,4})\b|\W|$)/;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -44,7 +44,7 @@ helpers.extend global, {
|
||||
# Run `cake`. Executes all of the tasks you pass, in order. Note that Node's
|
||||
# asynchrony may cause tasks to execute in a different order than you'd expect.
|
||||
# If no tasks are passed, print the help screen.
|
||||
exports.run: ->
|
||||
exports.run = ->
|
||||
path.exists 'Cakefile', (exists) ->
|
||||
throw new Error("Cakefile not found in ${process.cwd()}") unless exists
|
||||
args = process.argv[2...process.argv.length]
|
||||
@@ -55,7 +55,7 @@ exports.run: ->
|
||||
invoke arg for arg in options.arguments
|
||||
|
||||
# Display the list of Cake tasks in a format similar to `rake -T`
|
||||
printTasks: ->
|
||||
printTasks = ->
|
||||
puts ''
|
||||
for all name, task of tasks
|
||||
spaces = 20 - name.length
|
||||
@@ -65,6 +65,6 @@ printTasks: ->
|
||||
puts oparse.help() if switches.length
|
||||
|
||||
# Print an error and exit when attempting to all an undefined task.
|
||||
missingTask: (task) ->
|
||||
missingTask = (task) ->
|
||||
puts "No such task: \"$task\""
|
||||
process.exit 1
|
||||
|
||||
@@ -30,7 +30,7 @@ lexer = new Lexer
|
||||
# Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
# compiler.
|
||||
exports.compile = compile = (code, options) ->
|
||||
options = or {}
|
||||
options ||= {}
|
||||
try
|
||||
(parser.parse lexer.tokenize code).compile options
|
||||
catch err
|
||||
@@ -61,7 +61,7 @@ exports.run = ((code, options) ->
|
||||
parser.lexer = {
|
||||
lex: ->
|
||||
token = @tokens[@pos] or [""]
|
||||
@pos = + 1
|
||||
@pos += 1
|
||||
this.yylineno = token[2]
|
||||
this.yytext = token[1]
|
||||
token[0]
|
||||
|
||||
@@ -107,7 +107,7 @@ compileStdio = ->
|
||||
code = ''
|
||||
stdin = process.openStdin()
|
||||
stdin.on 'data', (buffer) ->
|
||||
code = + buffer.toString() if buffer
|
||||
code += buffer.toString() if buffer
|
||||
stdin.on 'end', ->
|
||||
compileScript 'stdio', code
|
||||
|
||||
@@ -156,7 +156,7 @@ printTokens = (tokens) ->
|
||||
parseOptions = ->
|
||||
optionParser = new optparse.OptionParser SWITCHES, BANNER
|
||||
o = options = optionParser.parse(process.argv[2...process.argv.length])
|
||||
options.compile = or !!o.output
|
||||
options.compile ||= !!o.output
|
||||
options.run = not (o.compile or o.print or o.lint)
|
||||
options.print = !! (o.print or (o.eval or o.stdio and o.compile))
|
||||
sources = options.arguments
|
||||
|
||||
@@ -139,7 +139,7 @@ grammar = {
|
||||
|
||||
# Assignment of a variable, property, or index to a value.
|
||||
Assign: [
|
||||
o "Assignable ASSIGN Expression", -> new AssignNode $1, $3
|
||||
o "Assignable = Expression", -> new AssignNode $1, $3
|
||||
]
|
||||
|
||||
# Assignment when it happens within an object literal. The difference from
|
||||
@@ -147,8 +147,8 @@ grammar = {
|
||||
AssignObj: [
|
||||
o "Identifier", -> new ValueNode $1
|
||||
o "AlphaNumeric"
|
||||
o "Identifier ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "AlphaNumeric ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "Identifier : Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "AlphaNumeric : Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "Comment"
|
||||
]
|
||||
|
||||
@@ -279,7 +279,7 @@ grammar = {
|
||||
# Assignments that can happen directly inside a class declaration.
|
||||
ClassAssign: [
|
||||
o "AssignObj", -> $1
|
||||
o "ThisProperty ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'this'
|
||||
o "ThisProperty : Expression", -> new AssignNode new ValueNode($1), $3, 'this'
|
||||
]
|
||||
|
||||
# A list of assignments to a class.
|
||||
@@ -575,7 +575,7 @@ grammar = {
|
||||
# And not:
|
||||
#
|
||||
# (2 + 3) * 4
|
||||
operators: [
|
||||
operators = [
|
||||
["left", '?']
|
||||
["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--']
|
||||
["left", '*', '/', '%']
|
||||
@@ -593,7 +593,7 @@ operators: [
|
||||
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
|
||||
["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS']
|
||||
["left", 'EXTENDS']
|
||||
["right", 'ASSIGN', 'RETURN']
|
||||
["right", '=', ':', 'RETURN']
|
||||
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']
|
||||
]
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ helpers.count = count = (string, letter) ->
|
||||
num = 0
|
||||
pos = indexOf string, letter
|
||||
while pos isnt -1
|
||||
num = + 1
|
||||
num += 1
|
||||
pos = indexOf string, letter, pos + 1
|
||||
num
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ exports.Lexer = class Lexer
|
||||
# though `is` means `===` otherwise.
|
||||
identifierToken: ->
|
||||
return false unless id = @match IDENTIFIER, 1
|
||||
@i = + id.length
|
||||
@i += id.length
|
||||
forcedIdentifier = @tagAccessor() or @match ASSIGNED, 1
|
||||
tag = 'IDENTIFIER'
|
||||
tag = id.toUpperCase() if include(JS_KEYWORDS, id) or (not forcedIdentifier and include(COFFEE_KEYWORDS, id))
|
||||
@@ -258,13 +258,11 @@ exports.Lexer = class Lexer
|
||||
value = match and match[1]
|
||||
space = match and match[2]
|
||||
@tagParameters() if value and value.match CODE
|
||||
value = or @chunk.substr 0, 1
|
||||
value ||= @chunk.substr 0, 1
|
||||
prevSpaced = @prev() and @prev().spaced
|
||||
tag = value
|
||||
if value.match ASSIGNMENT
|
||||
tag = 'ASSIGN'
|
||||
@assignmentError() if include JS_FORBIDDEN, @value
|
||||
else if value is ';'
|
||||
@assignmentError() if value is '=' and include JS_FORBIDDEN, @value
|
||||
if value is ';'
|
||||
tag = 'TERMINATOR'
|
||||
else if value is '?' and prevSpaced
|
||||
tag = 'OP?'
|
||||
@@ -325,7 +323,7 @@ exports.Lexer = class Lexer
|
||||
return if @tag() isnt ')'
|
||||
i = 0
|
||||
loop
|
||||
i = + 1
|
||||
i += 1
|
||||
tok = @prev i
|
||||
return if not tok
|
||||
switch tok[0]
|
||||
@@ -353,27 +351,27 @@ exports.Lexer = class Lexer
|
||||
# contents of the string. This method allows us to have strings within
|
||||
# interpolations within strings, ad infinitum.
|
||||
balancedString: (str, delimited, options) ->
|
||||
options = or {}
|
||||
options ||= {}
|
||||
slash = delimited[0][0] is '/'
|
||||
levels = []
|
||||
i = 0
|
||||
while i < str.length
|
||||
if levels.length and starts str, '\\', i
|
||||
i = + 1
|
||||
i += 1
|
||||
else
|
||||
for pair in delimited
|
||||
[open, close] = pair
|
||||
if levels.length and starts(str, close, i) and levels[levels.length - 1] is pair
|
||||
levels.pop()
|
||||
i = + close.length - 1
|
||||
i = + 1 unless levels.length
|
||||
i += close.length - 1
|
||||
i += 1 unless levels.length
|
||||
break
|
||||
else if starts str, open, i
|
||||
levels.push(pair)
|
||||
i = + open.length - 1
|
||||
i += open.length - 1
|
||||
break
|
||||
break if not levels.length or slash and starts str, '\n', i
|
||||
i = + 1
|
||||
i += 1
|
||||
if levels.length
|
||||
return false if slash
|
||||
throw new Error "SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}"
|
||||
@@ -390,7 +388,7 @@ exports.Lexer = class Lexer
|
||||
# new Lexer, tokenize the interpolated contents, and merge them into the
|
||||
# token stream.
|
||||
interpolateString: (str, options) ->
|
||||
options = or {}
|
||||
options ||= {}
|
||||
if str.length < 3 or not starts str, '"'
|
||||
@token 'STRING', str
|
||||
else
|
||||
@@ -400,13 +398,13 @@ exports.Lexer = class Lexer
|
||||
[i, pi] = [1, 1]
|
||||
while i < str.length - 1
|
||||
if starts str, '\\', i
|
||||
i = + 1
|
||||
i += 1
|
||||
else if match = str.substring(i).match INTERPOLATION
|
||||
[group, interp] = match
|
||||
interp = "this.${ interp.substring(1) }" if starts interp, '@'
|
||||
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i
|
||||
tokens.push ['IDENTIFIER', interp]
|
||||
i = + group.length - 1
|
||||
i += group.length - 1
|
||||
pi = i + 1
|
||||
else if (expr = @balancedString str.substring(i), [['${', '}']])
|
||||
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i
|
||||
@@ -419,9 +417,9 @@ exports.Lexer = class Lexer
|
||||
tokens.push ['TOKENS', nested]
|
||||
else
|
||||
tokens.push ['STRING', "$quote$quote"]
|
||||
i = + expr.length - 1
|
||||
i += expr.length - 1
|
||||
pi = i + 1
|
||||
i = + 1
|
||||
i += 1
|
||||
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i and pi < str.length - 1
|
||||
tokens.unshift ['STRING', '""'] unless tokens[0][0] is 'STRING'
|
||||
interpolated = tokens.length > 1
|
||||
@@ -524,7 +522,6 @@ CODE = /^((-|=)>)/
|
||||
MULTI_DENT = /^((\n([ \t]*))+)(\.)?/
|
||||
LAST_DENTS = /\n([ \t]*)/g
|
||||
LAST_DENT = /\n([ \t]*)/
|
||||
ASSIGNMENT = /^[:=]$/
|
||||
|
||||
# Regex-matching-regexes.
|
||||
REGEX_START = /^\/[^\/ ]/
|
||||
@@ -547,9 +544,7 @@ NEXT_CHARACTER = /^\s*(\S)/
|
||||
# See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
|
||||
#
|
||||
# Our list is shorter, due to sans-parentheses method calls.
|
||||
NOT_REGEX = [
|
||||
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'
|
||||
]
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']']
|
||||
|
||||
# Tokens which could legitimately be invoked or indexed. A opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
|
||||
@@ -76,7 +76,7 @@ exports.BaseNode = class BaseNode
|
||||
idt: (tabs) ->
|
||||
idt = @tab or ''
|
||||
num = (tabs or 0) + 1
|
||||
idt = + TAB while num = - 1
|
||||
idt += TAB while num -= 1
|
||||
idt
|
||||
|
||||
# Construct a node that returns the current node's result.
|
||||
@@ -112,7 +112,7 @@ exports.BaseNode = class BaseNode
|
||||
# `toString` representation of the node, for inspecting the parse tree.
|
||||
# This is what `coffee --nodes` prints out.
|
||||
toString: (idt, override) ->
|
||||
idt = or ''
|
||||
idt ||= ''
|
||||
children = (child.toString idt + TAB for child in @collectChildren()).join('')
|
||||
'\n' + idt + (override or @class) + children
|
||||
|
||||
@@ -180,7 +180,7 @@ exports.Expressions = class Expressions extends BaseNode
|
||||
makeReturn: ->
|
||||
idx = @expressions.length - 1
|
||||
last = @expressions[idx]
|
||||
last = @expressions[idx = - 1] if last instanceof CommentNode
|
||||
last = @expressions[idx -= 1] if last instanceof CommentNode
|
||||
return this if not last or last instanceof ReturnNode
|
||||
@expressions[idx] = last.makeReturn()
|
||||
this
|
||||
@@ -193,7 +193,7 @@ exports.Expressions = class Expressions extends BaseNode
|
||||
|
||||
# An **Expressions** is the only node that can serve as the root.
|
||||
compile: (o) ->
|
||||
o = or {}
|
||||
o ||= {}
|
||||
if o.scope then super(o) else @compileRoot(o)
|
||||
|
||||
compileNode: (o) ->
|
||||
@@ -229,7 +229,7 @@ exports.Expressions = class Expressions extends BaseNode
|
||||
|
||||
# Wrap up the given nodes as an **Expressions**, unless it already happens
|
||||
# to be one.
|
||||
Expressions.wrap: (nodes) ->
|
||||
Expressions.wrap = (nodes) ->
|
||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
|
||||
new Expressions(nodes)
|
||||
|
||||
@@ -354,7 +354,7 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||
only = del o, 'onlyFirst'
|
||||
op = del o, 'operation'
|
||||
props = if only then @properties[0...@properties.length - 1] else @properties
|
||||
o.chainRoot = or this
|
||||
o.chainRoot ||= this
|
||||
baseline = @base.compile o
|
||||
baseline = "($baseline)" if @hasProperties() and (@base instanceof ObjectNode or @isNumber())
|
||||
complete = @last = baseline
|
||||
@@ -366,11 +366,11 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||
temp = o.scope.freeVariable()
|
||||
complete = "(${ baseline = temp } = ($complete))"
|
||||
complete = "typeof $complete === \"undefined\" || $baseline" if i is 0 and @isStart(o)
|
||||
complete = + @SOAK + (baseline = + prop.compile(o))
|
||||
complete += @SOAK + (baseline += prop.compile(o))
|
||||
else
|
||||
part = prop.compile(o)
|
||||
baseline = + part
|
||||
complete = + part
|
||||
baseline += part
|
||||
complete += part
|
||||
@last = part
|
||||
|
||||
if op and @wrapped then "($complete)" else complete
|
||||
@@ -502,7 +502,7 @@ exports.AccessorNode = class AccessorNode extends BaseNode
|
||||
|
||||
compileNode: (o) ->
|
||||
name = @name.compile o
|
||||
o.chainRoot.wrapped = or @soakNode
|
||||
o.chainRoot.wrapped ||= @soakNode
|
||||
namePart = if name.match(IS_STRING) then "[$name]" else ".$name"
|
||||
@prototype + namePart
|
||||
|
||||
@@ -518,7 +518,7 @@ exports.IndexNode = class IndexNode extends BaseNode
|
||||
@index = index
|
||||
|
||||
compileNode: (o) ->
|
||||
o.chainRoot.wrapped = or @soakNode
|
||||
o.chainRoot.wrapped ||= @soakNode
|
||||
idx = @index.compile o
|
||||
prefix = if @proto then '.prototype' else ''
|
||||
"$prefix[$idx]"
|
||||
@@ -570,7 +570,7 @@ exports.RangeNode = class RangeNode extends BaseNode
|
||||
[from, to] = [parseInt(@fromNum, 10), parseInt(@toNum, 10)]
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
step = and "$idx += ${step.compile(o)}"
|
||||
step &&= "$idx += ${step.compile(o)}"
|
||||
if from <= to
|
||||
"$idx = $from; $idx <$@equals $to; ${step or "$idx++"}"
|
||||
else
|
||||
@@ -721,8 +721,8 @@ exports.ClassNode = class ClassNode extends BaseNode
|
||||
continue
|
||||
if func instanceof CodeNode and func.bound
|
||||
func.bound = false
|
||||
constScope = or new Scope(o.scope, constructor.body, constructor)
|
||||
me = or constScope.freeVariable()
|
||||
constScope ||= new Scope(o.scope, constructor.body, constructor)
|
||||
me ||= constScope.freeVariable()
|
||||
pname = pvar.compile(o)
|
||||
constructor.body.push new ReturnNode literal 'this' if constructor.body.empty()
|
||||
constructor.body.unshift literal "this.${pname} = function(){ return ${className}.prototype.${pname}.apply($me, arguments); }"
|
||||
@@ -883,7 +883,7 @@ exports.CodeNode = class CodeNode extends BaseNode
|
||||
splat.trailings.push(param)
|
||||
else
|
||||
params.push(param)
|
||||
i = + 1
|
||||
i += 1
|
||||
params = (param.compile(o) for param in params)
|
||||
@body.makeReturn()
|
||||
@body.rewriteThis() if @bound
|
||||
@@ -902,7 +902,7 @@ exports.CodeNode = class CodeNode extends BaseNode
|
||||
traverseChildren: (crossScope, func) -> super(crossScope, func) if crossScope
|
||||
|
||||
toString: (idt) ->
|
||||
idt = or ''
|
||||
idt ||= ''
|
||||
children = (child.toString(idt + TAB) for child in @collectChildren()).join('')
|
||||
"\n$idt$children"
|
||||
|
||||
@@ -1385,7 +1385,7 @@ exports.IfNode = class IfNode extends BaseNode
|
||||
# The **IfNode** only compiles into a statement if either of its bodies needs
|
||||
# to be a statement. Otherwise a ternary is safe.
|
||||
isStatement: ->
|
||||
@statement = or !!(@tags.statement or @bodyNode().isStatement() or (@elseBody and @elseBodyNode().isStatement()))
|
||||
@statement ||= !!(@tags.statement or @bodyNode().isStatement() or (@elseBody and @elseBodyNode().isStatement()))
|
||||
|
||||
compileCondition: (o) ->
|
||||
(cond.compile(o) for cond in flatten([@condition])).join(' || ')
|
||||
@@ -1395,8 +1395,8 @@ exports.IfNode = class IfNode extends BaseNode
|
||||
|
||||
makeReturn: ->
|
||||
if @isStatement()
|
||||
@body = and @ensureExpressions(@body.makeReturn())
|
||||
@elseBody = and @ensureExpressions(@elseBody.makeReturn())
|
||||
@body &&= @ensureExpressions(@body.makeReturn())
|
||||
@elseBody &&= @ensureExpressions(@elseBody.makeReturn())
|
||||
this
|
||||
else
|
||||
new ReturnNode this
|
||||
|
||||
@@ -30,7 +30,7 @@ exports.OptionParser = class OptionParser
|
||||
matchedRule = no
|
||||
for rule in @rules
|
||||
if rule.shortFlag is arg or rule.longFlag is arg
|
||||
options[rule.name] = if rule.hasArgument then args[i = + 1] else true
|
||||
options[rule.name] = if rule.hasArgument then args[i += 1] else true
|
||||
matchedRule = yes
|
||||
break
|
||||
throw new Error "unrecognized option: $arg" if isOption and not matchedRule
|
||||
|
||||
@@ -46,7 +46,7 @@ exports.Rewriter = class Rewriter
|
||||
loop
|
||||
break unless @tokens[i]
|
||||
move = block @tokens[i - 1], @tokens[i], @tokens[i + 1], i
|
||||
i = + move
|
||||
i += move
|
||||
true
|
||||
|
||||
# Massage newlines and indentations so that comments don't have to be
|
||||
@@ -94,20 +94,20 @@ exports.Rewriter = class Rewriter
|
||||
switch token[0]
|
||||
when 'CALL_START' then parens.push 0
|
||||
when 'INDEX_START' then brackets.push 0
|
||||
when '(' then parens[parens.length - 1] = + 1
|
||||
when '[' then brackets[brackets.length - 1] = + 1
|
||||
when '(' then parens[parens.length - 1] += 1
|
||||
when '[' then brackets[brackets.length - 1] += 1
|
||||
when ')'
|
||||
if parens[parens.length - 1] is 0
|
||||
parens.pop()
|
||||
token[0] = 'CALL_END'
|
||||
else
|
||||
parens[parens.length - 1] = - 1
|
||||
parens[parens.length - 1] -= 1
|
||||
when ']'
|
||||
if brackets[brackets.length - 1] == 0
|
||||
brackets.pop()
|
||||
token[0] = 'INDEX_END'
|
||||
else
|
||||
brackets[brackets.length - 1] = - 1
|
||||
brackets[brackets.length - 1] -= 1
|
||||
return 1
|
||||
|
||||
# Methods may be optionally called without parentheses, for simple cases.
|
||||
@@ -123,12 +123,12 @@ exports.Rewriter = class Rewriter
|
||||
size
|
||||
@scanTokens (prev, token, post, i) =>
|
||||
tag = token[0]
|
||||
stack[stack.length - 2] = + stack.pop() if tag is 'OUTDENT'
|
||||
stack[stack.length - 2] += stack.pop() if tag is 'OUTDENT'
|
||||
open = stack[stack.length - 1] > 0
|
||||
if prev and prev.spaced and include(IMPLICIT_FUNC, prev[0]) and include(IMPLICIT_CALL, tag) and
|
||||
not (tag is '!' and (post[0] in ['IN', 'OF']))
|
||||
@tokens.splice i, 0, ['CALL_START', '(', token[2]]
|
||||
stack[stack.length - 1] = + 1
|
||||
stack[stack.length - 1] += 1
|
||||
stack.push 0 if include(EXPRESSION_START, tag)
|
||||
return 2
|
||||
if include(EXPRESSION_START, tag)
|
||||
@@ -147,7 +147,7 @@ exports.Rewriter = class Rewriter
|
||||
stack.pop() if tag isnt 'OUTDENT' and include EXPRESSION_END, tag
|
||||
return size
|
||||
if tag isnt 'OUTDENT' and include EXPRESSION_END, tag
|
||||
stack[stack.length - 2] = + stack.pop()
|
||||
stack[stack.length - 2] += stack.pop()
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -174,7 +174,7 @@ exports.Rewriter = class Rewriter
|
||||
idx = i + 1
|
||||
parens = 0
|
||||
loop
|
||||
idx = + 1
|
||||
idx += 1
|
||||
tok = @tokens[idx]
|
||||
pre = @tokens[idx - 1]
|
||||
if (not tok or
|
||||
@@ -184,8 +184,8 @@ exports.Rewriter = class Rewriter
|
||||
insertion = if pre[0] is "," then idx - 1 else idx
|
||||
@tokens.splice insertion, 0, outdent
|
||||
break
|
||||
parens = + 1 if tok[0] is '('
|
||||
parens = - 1 if tok[0] is ')'
|
||||
parens += 1 if tok[0] is '('
|
||||
parens -= 1 if tok[0] is ')'
|
||||
return 1 unless token[0] is 'THEN'
|
||||
@tokens.splice i, 1
|
||||
return 0
|
||||
@@ -198,11 +198,11 @@ exports.Rewriter = class Rewriter
|
||||
@scanTokens (prev, token, post, i) =>
|
||||
for pair in pairs
|
||||
[open, close] = pair
|
||||
levels[open] = or 0
|
||||
levels[open] ||= 0
|
||||
if token[0] is open
|
||||
openLine[open] = token[2] if levels[open] == 0
|
||||
levels[open] = + 1
|
||||
levels[open] = - 1 if token[0] is close
|
||||
levels[open] += 1
|
||||
levels[open] -= 1 if token[0] is close
|
||||
throw new Error("too many ${token[1]} on line ${token[2] + 1}") if levels[open] < 0
|
||||
return 1
|
||||
unclosed = key for key, value of levels when value > 0
|
||||
@@ -239,7 +239,7 @@ exports.Rewriter = class Rewriter
|
||||
return 1
|
||||
else if include EXPRESSION_END, tag
|
||||
if debt[inv] > 0
|
||||
debt[inv] = - 1
|
||||
debt[inv] -= 1
|
||||
@tokens.splice i, 1
|
||||
return 0
|
||||
else
|
||||
@@ -247,7 +247,7 @@ exports.Rewriter = class Rewriter
|
||||
mtag = match[0]
|
||||
oppos = INVERSES[mtag]
|
||||
return 1 if tag is oppos
|
||||
debt[mtag] = + 1
|
||||
debt[mtag] += 1
|
||||
val = [oppos, if mtag is 'INDENT' then match[1] else oppos]
|
||||
if @tokens[i + 2]?[0] is mtag
|
||||
@tokens.splice i + 3, 0, val
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
area: (x, y, x1, y1) ->
|
||||
area = (x, y, x1, y1) ->
|
||||
(x - x1) * (x - y1)
|
||||
|
||||
x: y: 10
|
||||
x1: y1: 20
|
||||
x = y = 10
|
||||
x1 = y1 = 20
|
||||
|
||||
ok area(x, y, x1, y1) is 100
|
||||
|
||||
@@ -17,9 +17,9 @@ ok(area(
|
||||
) is 100)
|
||||
|
||||
|
||||
sumOfArgs: ->
|
||||
sum: 0
|
||||
sum: + val for val in arguments
|
||||
sumOfArgs = ->
|
||||
sum = 0
|
||||
sum += val for val in arguments
|
||||
sum
|
||||
|
||||
ok sumOfArgs(1, 2, 3, 4, 5) is 15
|
||||
@@ -1,29 +1,29 @@
|
||||
# Can assign the result of a try/catch block.
|
||||
result: try
|
||||
result = try
|
||||
nonexistent * missing
|
||||
catch error
|
||||
true
|
||||
|
||||
result2: try nonexistent * missing catch error then true
|
||||
result2 = try nonexistent * missing catch error then true
|
||||
|
||||
ok result is true and result2 is true
|
||||
|
||||
|
||||
# Can assign a conditional statement.
|
||||
getX: -> 10
|
||||
getX = -> 10
|
||||
|
||||
if x: getX() then 100
|
||||
if x = getX() then 100
|
||||
|
||||
ok x is 10
|
||||
|
||||
x: if getX() then 100
|
||||
x = if getX() then 100
|
||||
|
||||
ok x is 100
|
||||
|
||||
|
||||
# This-assignment.
|
||||
tester: ->
|
||||
@example: -> 'example function'
|
||||
tester = ->
|
||||
@example = -> 'example function'
|
||||
this
|
||||
|
||||
ok tester().example() is 'example function'
|
||||
@@ -1,14 +1,14 @@
|
||||
# Basic blocks.
|
||||
results: [1, 2, 3].map (x) ->
|
||||
results = [1, 2, 3].map (x) ->
|
||||
x * x
|
||||
|
||||
ok results.join(' ') is '1 4 9'
|
||||
|
||||
|
||||
# Chained blocks, with proper indentation levels:
|
||||
results: []
|
||||
results = []
|
||||
|
||||
counter: {
|
||||
counter = {
|
||||
tick: (func) ->
|
||||
results.push func()
|
||||
this
|
||||
@@ -26,8 +26,8 @@ ok results.join(' ') is '3 2 1'
|
||||
|
||||
|
||||
# Make incorrect indentation safe.
|
||||
func: ->
|
||||
obj: {
|
||||
func = ->
|
||||
obj = {
|
||||
key: 10
|
||||
}
|
||||
obj.key - 5
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Test with break at the top level.
|
||||
array: [1,2,3]
|
||||
callWithLambda: (l) -> null
|
||||
array = [1,2,3]
|
||||
callWithLambda = (l) -> null
|
||||
for i in array
|
||||
result: callWithLambda(->)
|
||||
result = callWithLambda(->)
|
||||
if i == 2
|
||||
puts "i = 2"
|
||||
else
|
||||
@@ -12,10 +12,10 @@ ok result is null
|
||||
|
||||
|
||||
# Test with break *not* at the top level.
|
||||
someFunc: (input) ->
|
||||
takesLambda: (l) -> null
|
||||
someFunc = (input) ->
|
||||
takesLambda = (l) -> null
|
||||
for i in [1,2]
|
||||
result: takesLambda(->)
|
||||
result = takesLambda(->)
|
||||
if input == 1
|
||||
return 1
|
||||
else
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Basic chained function calls.
|
||||
identityWrap: (x) ->
|
||||
identityWrap = (x) ->
|
||||
-> x
|
||||
|
||||
result: identityWrap(identityWrap(true))()()
|
||||
result = identityWrap(identityWrap(true))()()
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Chained accesses split on period/newline, backwards and forwards.
|
||||
str: 'god'
|
||||
str = 'god'
|
||||
|
||||
result: str.
|
||||
result = str.
|
||||
split('').
|
||||
reverse().
|
||||
reverse().
|
||||
@@ -18,7 +18,7 @@ result: str.
|
||||
|
||||
ok result.join('') is 'dog'
|
||||
|
||||
result: str
|
||||
result = str
|
||||
.split('')
|
||||
.reverse()
|
||||
.reverse()
|
||||
@@ -28,7 +28,7 @@ ok result.join('') is 'dog'
|
||||
|
||||
|
||||
# Newline suppression for operators.
|
||||
six:
|
||||
six =
|
||||
1 +
|
||||
2 +
|
||||
3
|
||||
@@ -37,7 +37,7 @@ ok six is 6
|
||||
|
||||
|
||||
# Ensure that indented array literals don't trigger whitespace rewriting.
|
||||
func: () ->
|
||||
func = () ->
|
||||
ok arguments.length is 1
|
||||
|
||||
func(
|
||||
|
||||
@@ -16,13 +16,13 @@ class SecondChild extends FirstChild
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: ->
|
||||
@array: [1, 2, 3]
|
||||
@array = [1, 2, 3]
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result: (new ThirdChild).func 'four'
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
@@ -30,7 +30,7 @@ ok Base.static('word') is 'static/word'
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop: 'top-' + arg
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
@@ -44,7 +44,7 @@ ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
class OneClass
|
||||
constructor: (name) -> @name: name
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
|
||||
@@ -52,45 +52,45 @@ ok (new TwoClass('three')).name is 'three'
|
||||
|
||||
|
||||
# And now the same tests, but written in the manual style:
|
||||
Base: ->
|
||||
Base::func: (string) ->
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func']: (string) ->
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-$string"
|
||||
|
||||
FirstChild: ->
|
||||
FirstChild = ->
|
||||
FirstChild extends Base
|
||||
FirstChild::func: (string) ->
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild: ->
|
||||
SecondChild = ->
|
||||
SecondChild extends FirstChild
|
||||
SecondChild::func: (string) ->
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
ThirdChild: ->
|
||||
@array: [1, 2, 3]
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
ThirdChild extends SecondChild
|
||||
ThirdChild::func: (string) ->
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result: (new ThirdChild).func 'four'
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
|
||||
TopClass: (arg) ->
|
||||
@prop: 'top-' + arg
|
||||
TopClass = (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
this
|
||||
|
||||
SuperClass: (arg) ->
|
||||
SuperClass = (arg) ->
|
||||
super 'super-' + arg
|
||||
this
|
||||
|
||||
SubClass: ->
|
||||
SubClass = ->
|
||||
super 'sub'
|
||||
this
|
||||
|
||||
@@ -105,18 +105,18 @@ class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
|
||||
obj: new ClassName
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
|
||||
|
||||
# super() calls in constructors of classes that are defined as object properties.
|
||||
class Hive
|
||||
constructor: (name) -> @name: name
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
|
||||
maya: new Hive.Bee 'Maya'
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
|
||||
instance: new Class
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
|
||||
@@ -134,14 +134,14 @@ ok instance.name() is 'class'
|
||||
class Dog
|
||||
|
||||
constructor: (name) ->
|
||||
@name: name
|
||||
@name = name
|
||||
|
||||
bark: =>
|
||||
"$@name woofs!"
|
||||
|
||||
spark: new Dog('Spark')
|
||||
fido: new Dog('Fido')
|
||||
fido.bark: spark.bark
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
|
||||
@@ -154,32 +154,32 @@ class Mini
|
||||
=>
|
||||
@num
|
||||
|
||||
m: new Mini
|
||||
m = new Mini
|
||||
ok (func() for func in m.generate()).join(' ') is '10 10 10'
|
||||
|
||||
|
||||
# Testing a contructor called with varargs.
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three]: [one, two, three]
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
|
||||
out: ->
|
||||
"$@one-$@two-$@three"
|
||||
|
||||
list: [3, 2, 1]
|
||||
conn: new Connection list...
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
|
||||
|
||||
# Test calling super and passing along all arguments.
|
||||
class Parent
|
||||
method: (args...) -> @args: args
|
||||
method: (args...) -> @args = args
|
||||
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
|
||||
c: new Child
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
|
||||
@@ -188,15 +188,15 @@ ok c.args.join(' ') is '1 2 3 4'
|
||||
class Base
|
||||
@extended: (subclass) ->
|
||||
for key, value of @
|
||||
subclass[key]: value
|
||||
subclass[key] = value
|
||||
|
||||
class Element extends Base
|
||||
@fromHTML: (html) ->
|
||||
node: "..."
|
||||
node = "..."
|
||||
new @(node)
|
||||
|
||||
constructor: (node) ->
|
||||
@node: node
|
||||
@node = node
|
||||
|
||||
ok Element.extended is Base.extended
|
||||
ok Element.__superClass__ is Base.prototype
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
# comment
|
||||
func: ->
|
||||
func = ->
|
||||
# comment
|
||||
false
|
||||
false # comment
|
||||
@@ -32,7 +32,7 @@ func
|
||||
func
|
||||
# Line3
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
# comment
|
||||
# comment
|
||||
# comment
|
||||
@@ -42,12 +42,12 @@ obj: {
|
||||
# comment
|
||||
}
|
||||
|
||||
result: if true # comment
|
||||
result = if true # comment
|
||||
false
|
||||
|
||||
ok not result
|
||||
|
||||
result: if false
|
||||
result = if false
|
||||
false
|
||||
else # comment
|
||||
45
|
||||
@@ -55,7 +55,7 @@ else # comment
|
||||
ok result is 45
|
||||
|
||||
|
||||
test:
|
||||
test =
|
||||
'test ' +
|
||||
'test ' + # comment
|
||||
'test'
|
||||
@@ -67,30 +67,30 @@ ok test is 'test test test'
|
||||
Kind of like a heredoc.
|
||||
###
|
||||
|
||||
func: ->
|
||||
func = ->
|
||||
###
|
||||
Another block comment.
|
||||
###
|
||||
code
|
||||
|
||||
func: ->
|
||||
one: ->
|
||||
two: ->
|
||||
three: ->
|
||||
func = ->
|
||||
one = ->
|
||||
two = ->
|
||||
three = ->
|
||||
###
|
||||
block.
|
||||
###
|
||||
four: ->
|
||||
four = ->
|
||||
|
||||
fn1: ->
|
||||
oneLevel: null
|
||||
fn1 = ->
|
||||
oneLevel = null
|
||||
###
|
||||
This isn't fine.
|
||||
###
|
||||
|
||||
ok ok
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
a: 'b'
|
||||
###
|
||||
comment
|
||||
@@ -98,7 +98,7 @@ obj: {
|
||||
c: 'd'
|
||||
}
|
||||
|
||||
arr: [
|
||||
arr = [
|
||||
1, 2, 3,
|
||||
###
|
||||
four
|
||||
@@ -107,7 +107,7 @@ arr: [
|
||||
]
|
||||
|
||||
# Spaced comments in if / elses.
|
||||
result: if false
|
||||
result = if false
|
||||
1
|
||||
|
||||
# comment
|
||||
@@ -121,14 +121,14 @@ else
|
||||
ok result is 3
|
||||
|
||||
|
||||
result: switch 'z'
|
||||
result = switch 'z'
|
||||
when 'z' then 7
|
||||
# comment
|
||||
ok result is 7
|
||||
|
||||
|
||||
# Trailing-line comment before an outdent.
|
||||
func: ->
|
||||
func = ->
|
||||
if true
|
||||
true # comment
|
||||
7
|
||||
@@ -137,10 +137,10 @@ ok func() is 7
|
||||
|
||||
|
||||
# Trailing herecomment in a function.
|
||||
fn: ->
|
||||
fn = ->
|
||||
code
|
||||
###
|
||||
debug code commented
|
||||
###
|
||||
|
||||
fn2: ->
|
||||
fn2 = ->
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Ensure that carriage returns don't break compilation on Windows.
|
||||
CoffeeScript: require('./../lib/coffee-script')
|
||||
Lexer: require('./../lib/lexer')
|
||||
CoffeeScript = require('./../lib/coffee-script')
|
||||
Lexer = require('./../lib/lexer')
|
||||
|
||||
js: CoffeeScript.compile("one\r\ntwo", {noWrap: on})
|
||||
js = CoffeeScript.compile("one\r\ntwo", {noWrap: on})
|
||||
|
||||
ok js is "one;\ntwo;"
|
||||
|
||||
|
||||
global.resultArray: []
|
||||
global.resultArray = []
|
||||
CoffeeScript.run("resultArray.push i for i of global", {noWrap: on, globals: on, source: 'tests'})
|
||||
|
||||
ok 'setInterval' in global.resultArray
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
num: 10
|
||||
num: - 5
|
||||
num = 10
|
||||
num -= 5
|
||||
|
||||
ok num is 5
|
||||
|
||||
num: -3
|
||||
num = -3
|
||||
|
||||
ok num is -3
|
||||
|
||||
num: +3
|
||||
num = +3
|
||||
|
||||
ok num is 3
|
||||
|
||||
num = * 10
|
||||
num *= 10
|
||||
|
||||
ok num is 30
|
||||
|
||||
num: / 10
|
||||
num /= 10
|
||||
|
||||
ok num is 3
|
||||
|
||||
|
||||
val: false
|
||||
val: or 'value'
|
||||
val = false
|
||||
val ||= 'value'
|
||||
|
||||
ok val is 'value'
|
||||
|
||||
val = and 'other'
|
||||
val &&= 'other'
|
||||
|
||||
ok val is 'other'
|
||||
|
||||
|
||||
val: null
|
||||
val: ? 'value'
|
||||
val = null
|
||||
val ?= 'value'
|
||||
|
||||
ok val is 'value'
|
||||
|
||||
|
||||
val: 6
|
||||
val: -(10)
|
||||
val = 6
|
||||
val = -(10)
|
||||
|
||||
ok val is -10
|
||||
|
||||
val: - (10)
|
||||
val -= (10)
|
||||
ok val is -20
|
||||
@@ -1,51 +1,51 @@
|
||||
# Basic array comprehensions.
|
||||
nums: n * n for n in [1, 2, 3] when n % 2 isnt 0
|
||||
results: n * 2 for n in nums
|
||||
nums = n * n for n in [1, 2, 3] when n % 2 isnt 0
|
||||
results = n * 2 for n in nums
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
|
||||
|
||||
# Basic object comprehensions.
|
||||
obj: {one: 1, two: 2, three: 3}
|
||||
names: prop + '!' for prop of obj
|
||||
odds: prop + '!' for prop, value of obj when value % 2 isnt 0
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = prop + '!' for prop of obj
|
||||
odds = prop + '!' for prop, value of obj when value % 2 isnt 0
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
|
||||
|
||||
# Basic range comprehensions.
|
||||
nums: i * 3 for i in [1..3]
|
||||
nums = i * 3 for i in [1..3]
|
||||
|
||||
negs: x for x in [-20..-5*2]
|
||||
negs: negs[0..2]
|
||||
negs = x for x in [-20..-5*2]
|
||||
negs = negs[0..2]
|
||||
|
||||
result: nums.concat(negs).join(', ')
|
||||
result = nums.concat(negs).join(', ')
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
|
||||
|
||||
# With range comprehensions, you can loop in steps.
|
||||
results: x for x in [0..25] by 5
|
||||
results = x for x in [0..25] by 5
|
||||
|
||||
ok results.join(' ') is '0 5 10 15 20 25'
|
||||
|
||||
|
||||
# And can loop downwards, with a negative step.
|
||||
results: x for x in [5..1]
|
||||
results = x for x in [5..1]
|
||||
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
|
||||
results: x for x in [10..1]
|
||||
results = x for x in [10..1]
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
|
||||
results: x for x in [10...0] by -2
|
||||
results = x for x in [10...0] by -2
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
|
||||
|
||||
# Multiline array comprehension with filter.
|
||||
evens: for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
@@ -58,10 +58,10 @@ ok 2 of evens
|
||||
|
||||
|
||||
# Ensure that the closure wrapper preserves local variables.
|
||||
obj: {}
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three']
|
||||
obj[method]: ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
@@ -70,9 +70,9 @@ ok obj.three() is "I'm three"
|
||||
|
||||
|
||||
# Even when referenced in the filter.
|
||||
list: ['one', 'two', 'three']
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
methods: for num, i in list when num isnt 'two' and i isnt 1
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
@@ -81,17 +81,17 @@ ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
# Naked ranges are expanded into arrays.
|
||||
array: [0..10]
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Nested comprehensions.
|
||||
multiLiner:
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
|
||||
singleLiner:
|
||||
singleLiner =
|
||||
[x, y] for y in [3..5] for x in [3..5]
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
@@ -100,29 +100,29 @@ ok 5 is singleLiner[2][2][1]
|
||||
|
||||
|
||||
# Comprehensions within parentheses.
|
||||
result: null
|
||||
store: (obj) -> result: obj
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
|
||||
ok result.join(' ') is '6 4 2'
|
||||
|
||||
|
||||
# Closure-wrapped comprehensions that refer to the "arguments" object.
|
||||
expr: ->
|
||||
result: item * item for item in arguments
|
||||
expr = ->
|
||||
result = item * item for item in arguments
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
|
||||
|
||||
# Fast object comprehensions over all properties, including prototypal ones.
|
||||
class Cat
|
||||
constructor: -> @name: 'Whiskers'
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
|
||||
whiskers: new Cat
|
||||
own: value for key, value of whiskers
|
||||
all: value for all key, value of whiskers
|
||||
whiskers = new Cat
|
||||
own = value for key, value of whiskers
|
||||
all = value for all key, value of whiskers
|
||||
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
ok(if mySpecialVariable? then false else true)
|
||||
|
||||
mySpecialVariable: false
|
||||
mySpecialVariable = false
|
||||
|
||||
ok(if mySpecialVariable? then true else false)
|
||||
|
||||
|
||||
# Existential assignment.
|
||||
a: 5
|
||||
a: null
|
||||
a = 5
|
||||
a = null
|
||||
a ?= 10
|
||||
b ?= 10
|
||||
|
||||
@@ -15,15 +15,15 @@ ok a is 10 and b is 10
|
||||
|
||||
|
||||
# The existential operator.
|
||||
z: null
|
||||
x: z ? "EX"
|
||||
z = null
|
||||
x = z ? "EX"
|
||||
|
||||
ok z is null and x is "EX"
|
||||
|
||||
|
||||
# Only evaluate once.
|
||||
counter: 0
|
||||
getNextNode: ->
|
||||
counter = 0
|
||||
getNextNode = ->
|
||||
throw "up" if counter
|
||||
counter++
|
||||
|
||||
@@ -31,7 +31,7 @@ ok(if getNextNode()? then true else false)
|
||||
|
||||
|
||||
# Existence chains, soaking up undefined properties:
|
||||
obj: {
|
||||
obj = {
|
||||
prop: "hello"
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ ok obj?['non']?['existent'].property is undefined
|
||||
|
||||
|
||||
# Soaks and caches method calls as well.
|
||||
arr: ["--", "----"]
|
||||
arr = ["--", "----"]
|
||||
|
||||
ok arr.pop()?.length is 4
|
||||
ok arr.pop()?.length is 2
|
||||
@@ -59,19 +59,19 @@ ok arr.pop()?.length?.non?.existent()?.property is undefined
|
||||
|
||||
|
||||
# Soaks method calls safely.
|
||||
value: undefined
|
||||
result: value?.toString().toLowerCase()
|
||||
value = undefined
|
||||
result = value?.toString().toLowerCase()
|
||||
|
||||
ok result is undefined
|
||||
|
||||
value: 10
|
||||
result: value?.toString().toLowerCase()
|
||||
value = 10
|
||||
result = value?.toString().toLowerCase()
|
||||
|
||||
ok result is '10'
|
||||
|
||||
|
||||
# Soaks constructor invocations.
|
||||
a: 0
|
||||
a = 0
|
||||
class Foo
|
||||
constructor: -> a += 1
|
||||
bar: "bat"
|
||||
@@ -81,20 +81,20 @@ ok a is 1
|
||||
|
||||
|
||||
# Safely existence test on soaks.
|
||||
result: not value?.property?
|
||||
result = not value?.property?
|
||||
ok result
|
||||
|
||||
|
||||
# Safely calls values off of non-existent variables.
|
||||
result: nothing?.value
|
||||
result = nothing?.value
|
||||
ok result is undefined
|
||||
|
||||
|
||||
# Assign to the result of an exsitential operation with a minus.
|
||||
x: null ? - 1
|
||||
x = null ? - 1
|
||||
ok x is - 1
|
||||
|
||||
|
||||
# Things that compile to ternaries should force parentheses, like operators do.
|
||||
duration: if options?.animated then 150 else 0
|
||||
duration = if options?.animated then 150 else 0
|
||||
ok duration is 0
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Ensure that we don't wrap Nodes that are "pureStatement" in a closure.
|
||||
items: [1, 2, 3, "bacon", 4, 5]
|
||||
items = [1, 2, 3, "bacon", 4, 5]
|
||||
|
||||
for item in items
|
||||
break if item is "bacon"
|
||||
|
||||
findit: (items) ->
|
||||
findit = (items) ->
|
||||
for item in items
|
||||
return item if item is "bacon"
|
||||
|
||||
@@ -13,10 +13,10 @@ ok findit(items) is "bacon"
|
||||
|
||||
# When when a closure wrapper is generated for expression conversion, make sure
|
||||
# that references to "this" within the wrapper are safely converted as well.
|
||||
obj: {
|
||||
obj = {
|
||||
num: 5
|
||||
func: ->
|
||||
this.result: if false
|
||||
this.result = if false
|
||||
10
|
||||
else
|
||||
"a"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
x: 1
|
||||
y: {}
|
||||
y.x: -> 3
|
||||
x = 1
|
||||
y = {}
|
||||
y.x = -> 3
|
||||
|
||||
ok x is 1
|
||||
ok typeof(y.x) is 'function'
|
||||
@@ -18,7 +18,7 @@ ok y.x() is 3
|
||||
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
|
||||
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
name: "Fred"
|
||||
|
||||
bound: ->
|
||||
@@ -33,15 +33,15 @@ obj.bound()
|
||||
|
||||
|
||||
# Python decorator style wrapper that memoizes any function
|
||||
memoize: (fn) ->
|
||||
cache: {}
|
||||
self: this
|
||||
memoize = (fn) ->
|
||||
cache = {}
|
||||
self = this
|
||||
(args...) ->
|
||||
key: args.toString()
|
||||
key = args.toString()
|
||||
return cache[key] if cache[key]
|
||||
cache[key] = fn.apply(self, args)
|
||||
|
||||
Math: {
|
||||
Math = {
|
||||
Add: (a, b) -> a + b
|
||||
AnonymousAdd: ((a, b) -> a + b)
|
||||
FastAdd: memoize (a, b) -> a + b
|
||||
@@ -57,21 +57,21 @@ ok 100 > 1 if 1 > 0
|
||||
ok true unless false
|
||||
ok true for i in [1..3]
|
||||
|
||||
okFunc: (f) -> ok(f())
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
# Optional parens can be used in a nested fashion.
|
||||
call: (func) -> func()
|
||||
call = (func) -> func()
|
||||
|
||||
result: call ->
|
||||
inner: call ->
|
||||
result = call ->
|
||||
inner = call ->
|
||||
Math.Add(5, 5)
|
||||
|
||||
ok result is 10
|
||||
|
||||
|
||||
# More fun with optional parens.
|
||||
fn: (arg) -> arg
|
||||
fn = (arg) -> arg
|
||||
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
|
||||
@@ -82,7 +82,7 @@ ok((fn (x) ->
|
||||
|
||||
|
||||
# Multi-blocks with optional parens.
|
||||
result: fn( ->
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
@@ -91,29 +91,29 @@ ok result()() is 'Wrapped'
|
||||
|
||||
|
||||
# And even with strange things like this:
|
||||
funcs: [((x) -> x), ((x) -> x * x)]
|
||||
result: funcs[1] 5
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
|
||||
ok result is 25
|
||||
|
||||
result: ("hello".slice) 3
|
||||
result = ("hello".slice) 3
|
||||
|
||||
ok result is 'lo'
|
||||
|
||||
|
||||
# And with multiple single-line functions on the same line.
|
||||
func: (x) -> (x) -> (x) -> x
|
||||
func = (x) -> (x) -> (x) -> x
|
||||
ok func(1)(2)(3) is 3
|
||||
|
||||
|
||||
# Ensure that functions with the same name don't clash with helper functions.
|
||||
del: -> 5
|
||||
del = -> 5
|
||||
ok del() is 5
|
||||
|
||||
# Ensure that functions can have a trailing comma in their argument list
|
||||
mult: (x, mids..., y) ->
|
||||
x: * n for n in mids
|
||||
x: * y
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
@@ -121,22 +121,22 @@ ok mult(10,[1..6]...,) is 7200
|
||||
|
||||
|
||||
# Test for inline functions with parentheses and implicit calls.
|
||||
combine: (func, num) -> func() * num
|
||||
result: combine (-> 1 + 2), 3
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
|
||||
ok result is 9
|
||||
|
||||
|
||||
# Test for calls/parens/multiline-chains.
|
||||
f: (x) -> x
|
||||
result: (f 1).toString()
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
|
||||
ok result is 1
|
||||
|
||||
|
||||
# Test implicit calls in functions in parens:
|
||||
result: ((val) ->
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
@@ -145,12 +145,12 @@ ok result is 10
|
||||
|
||||
|
||||
# More paren compilation tests:
|
||||
reverse: (obj) -> obj.reverse()
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
|
||||
# Passing multiple functions without paren-wrapping is legal, and should compile.
|
||||
sum: (one, two) -> one() + two()
|
||||
result: sum ->
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
@@ -159,32 +159,32 @@ ok result is 20
|
||||
|
||||
|
||||
# Implicit call with a trailing if statement as a param.
|
||||
func: -> arguments[1]
|
||||
result: func 'one', if false then 100 else 13
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
|
||||
# Test more function passing:
|
||||
result: sum( ->
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
ok result is 6
|
||||
|
||||
sum: (a, b) -> a + b
|
||||
result: sum(1
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
|
||||
ok result is 3
|
||||
|
||||
|
||||
# This is a crazy one.
|
||||
x: (obj, func) -> func obj
|
||||
ident: (x) -> x
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
|
||||
result: x {one: ident 1}, (obj) ->
|
||||
inner: ident(obj)
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
|
||||
ok result.one is 1
|
||||
@@ -192,7 +192,7 @@ ok result.one is 1
|
||||
|
||||
# Assignment to a Object.prototype-named variable should not leak to outer scope.
|
||||
(->
|
||||
constructor: 'word'
|
||||
constructor = 'word'
|
||||
)()
|
||||
|
||||
ok constructor isnt 'word'
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
a: """
|
||||
basic heredoc
|
||||
on two lines
|
||||
"""
|
||||
a = """
|
||||
basic heredoc
|
||||
on two lines
|
||||
"""
|
||||
|
||||
ok a is "basic heredoc\non two lines"
|
||||
|
||||
|
||||
a: '''
|
||||
a
|
||||
"b
|
||||
c
|
||||
'''
|
||||
a = '''
|
||||
a
|
||||
"b
|
||||
c
|
||||
'''
|
||||
|
||||
ok a is "a\n \"b\nc"
|
||||
|
||||
|
||||
a: '''one-liner'''
|
||||
a = '''one-liner'''
|
||||
|
||||
ok a is 'one-liner'
|
||||
|
||||
|
||||
a: """
|
||||
a = """
|
||||
out
|
||||
here
|
||||
"""
|
||||
@@ -28,16 +28,16 @@ a: """
|
||||
ok a is "out\nhere"
|
||||
|
||||
|
||||
a: '''
|
||||
a
|
||||
b
|
||||
c
|
||||
'''
|
||||
a = '''
|
||||
a
|
||||
b
|
||||
c
|
||||
'''
|
||||
|
||||
ok a is " a\n b\nc"
|
||||
|
||||
|
||||
a: '''
|
||||
a = '''
|
||||
a
|
||||
|
||||
|
||||
@@ -47,26 +47,26 @@ b c
|
||||
ok a is "a\n\n\nb c"
|
||||
|
||||
|
||||
a: '''more"than"one"quote'''
|
||||
a = '''more"than"one"quote'''
|
||||
|
||||
ok a is 'more"than"one"quote'
|
||||
|
||||
|
||||
val: 10
|
||||
val = 10
|
||||
|
||||
a: """
|
||||
basic heredoc $val
|
||||
on two lines
|
||||
"""
|
||||
a = """
|
||||
basic heredoc $val
|
||||
on two lines
|
||||
"""
|
||||
|
||||
b: '''
|
||||
basic heredoc $val
|
||||
on two lines
|
||||
'''
|
||||
b = '''
|
||||
basic heredoc $val
|
||||
on two lines
|
||||
'''
|
||||
|
||||
ok a is "basic heredoc 10\non two lines"
|
||||
ok b is "basic heredoc \$val\non two lines"
|
||||
|
||||
|
||||
a: '''here's an apostrophe'''
|
||||
a = '''here's an apostrophe'''
|
||||
ok a is "here's an apostrophe"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
a: b: d: true
|
||||
c: false
|
||||
a = b = d = true
|
||||
c = false
|
||||
|
||||
result: if a
|
||||
result = if a
|
||||
if b
|
||||
if c then false else
|
||||
if d
|
||||
@@ -10,13 +10,13 @@ result: if a
|
||||
ok result
|
||||
|
||||
|
||||
first: if false then false else second: if false then false else true
|
||||
first = if false then false else second = if false then false else true
|
||||
|
||||
ok first
|
||||
ok second
|
||||
|
||||
|
||||
result: if false
|
||||
result = if false
|
||||
false
|
||||
else if NaN
|
||||
false
|
||||
@@ -27,7 +27,7 @@ ok result
|
||||
|
||||
|
||||
# Testing unless.
|
||||
result: unless true
|
||||
result = unless true
|
||||
10
|
||||
else
|
||||
11
|
||||
@@ -36,24 +36,24 @@ ok result is 11
|
||||
|
||||
|
||||
# Nested inline if statements.
|
||||
echo: (x) -> x
|
||||
result: if true then echo((if false then 'xxx' else 'y') + 'a')
|
||||
echo = (x) -> x
|
||||
result = if true then echo((if false then 'xxx' else 'y') + 'a')
|
||||
ok result is 'ya'
|
||||
|
||||
|
||||
# Testing inline funcs with inline if-elses.
|
||||
func: -> if 1 < 0.5 then 1 else -1
|
||||
func = -> if 1 < 0.5 then 1 else -1
|
||||
ok func() is -1
|
||||
|
||||
|
||||
# Testing empty or commented if statements ... should compile:
|
||||
result: if false
|
||||
result = if false
|
||||
else if false
|
||||
else
|
||||
|
||||
ok result is undefined
|
||||
|
||||
result: if false
|
||||
result = if false
|
||||
# comment
|
||||
else if true
|
||||
# comment
|
||||
@@ -63,7 +63,7 @@ ok result is undefined
|
||||
|
||||
|
||||
# Return an if with no else.
|
||||
func: ->
|
||||
func = ->
|
||||
return (if false then callback())
|
||||
|
||||
ok func() is null
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
a: [((x) -> x), ((x) -> x * x)]
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
|
||||
ok a.length is 2
|
||||
|
||||
|
||||
regex: /match/i
|
||||
words: "I think there is a match in here."
|
||||
regex = /match/i
|
||||
words = "I think there is a match in here."
|
||||
|
||||
ok !!words.match(regex)
|
||||
|
||||
|
||||
neg: (3 -4)
|
||||
neg = (3 -4)
|
||||
|
||||
ok neg is -1
|
||||
|
||||
|
||||
# Decimal number literals.
|
||||
value: .25 + .75
|
||||
value = .25 + .75
|
||||
ok value is 1
|
||||
value: 0.0 + -.25 - -.75 + 0.0
|
||||
value = 0.0 + -.25 - -.75 + 0.0
|
||||
ok value is 0.5
|
||||
|
||||
# Decimals don't interfere with ranges.
|
||||
@@ -29,44 +29,44 @@ ok [0...10].join(' ') is '0 1 2 3 4 5 6 7 8 9'
|
||||
4.valueOf() is 4
|
||||
|
||||
|
||||
func: ->
|
||||
func = ->
|
||||
return if true
|
||||
|
||||
ok func() is null
|
||||
|
||||
|
||||
str: "\\"
|
||||
reg: /\\/
|
||||
str = "\\"
|
||||
reg = /\\/
|
||||
|
||||
ok reg(str) and str is '\\'
|
||||
|
||||
trailingComma: [1, 2, 3,]
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
|
||||
trailingComma: [
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum: (sum or 0) + n) for n in trailingComma
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
|
||||
trailingComma: {k1: "v1", k2: 4, k3: (-> true),}
|
||||
trailingComma = {k1: "v1", k2: 4, k3: (-> true),}
|
||||
ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1")
|
||||
|
||||
multiline: {a: 15,
|
||||
multiline = {a: 15,
|
||||
b: 26}
|
||||
|
||||
ok multiline.b is 26
|
||||
|
||||
|
||||
money$: 'dollars'
|
||||
money$ = 'dollars'
|
||||
|
||||
ok money$ is 'dollars'
|
||||
|
||||
|
||||
multiline: "one
|
||||
two
|
||||
three"
|
||||
multiline = "one
|
||||
two
|
||||
three"
|
||||
|
||||
ok multiline is 'one two three'
|
||||
|
||||
@@ -74,7 +74,7 @@ ok multiline is 'one two three'
|
||||
ok {a: (num) -> num is 10 }.a 10
|
||||
|
||||
|
||||
moe: {
|
||||
moe = {
|
||||
name: 'Moe'
|
||||
greet: (salutation) ->
|
||||
salutation + " " + @name
|
||||
@@ -86,13 +86,13 @@ moe: {
|
||||
ok moe.hello() is "Hello Moe"
|
||||
ok moe[10] is 'number'
|
||||
|
||||
moe.hello: ->
|
||||
moe.hello = ->
|
||||
this['greet'] "Hello"
|
||||
|
||||
ok moe.hello() is 'Hello Moe'
|
||||
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
is: -> yes,
|
||||
'not': -> no,
|
||||
}
|
||||
@@ -102,7 +102,7 @@ ok not obj.not()
|
||||
|
||||
|
||||
# Funky indentation within non-comma-seperated arrays.
|
||||
result: [['a']
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
|
||||
ok result[0][0] is 'a'
|
||||
@@ -110,14 +110,14 @@ ok result[1]['b'] is 'c'
|
||||
|
||||
|
||||
# Object literals should be able to include keywords.
|
||||
obj: {class: 'höt'}
|
||||
obj.function: 'dog'
|
||||
obj = {class: 'höt'}
|
||||
obj.function = 'dog'
|
||||
|
||||
ok obj.class + obj.function is 'hötdog'
|
||||
|
||||
|
||||
# But keyword assignment should be smart enough not to stringify variables.
|
||||
func: ->
|
||||
func = ->
|
||||
this == 'this'
|
||||
|
||||
ok func() is false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This file is imported by `testImporting.coffee`
|
||||
|
||||
local: "from over there"
|
||||
local = "from over there"
|
||||
|
||||
exports.func: -> local
|
||||
exports.func = -> local
|
||||
@@ -12,15 +12,15 @@ ok 50 > 10 > 5 is parseInt('5', 10)
|
||||
|
||||
# Make sure that each argument is only evaluated once, even if used
|
||||
# more than once.
|
||||
i: 0
|
||||
func: -> i++
|
||||
i = 0
|
||||
func = -> i++
|
||||
|
||||
ok 1 > func() < 1
|
||||
|
||||
|
||||
# `:` and `=` should be interchangeable, as should be `==` and `is`.
|
||||
a: 1
|
||||
b: 1
|
||||
a = 1
|
||||
b = 1
|
||||
|
||||
ok a is 1 and b is 1
|
||||
ok a == b
|
||||
@@ -29,30 +29,30 @@ ok a is b
|
||||
|
||||
# Ensure that chained operations don't cause functions to be evaluated more
|
||||
# than once.
|
||||
val: 0
|
||||
func: -> val: + 1
|
||||
val = 0
|
||||
func = -> val = + 1
|
||||
|
||||
ok 2 > (func null) < 2
|
||||
ok val is 1
|
||||
|
||||
|
||||
# Allow "if x not in y"
|
||||
obj: {a: true}
|
||||
obj = {a: true}
|
||||
ok 'a' of obj
|
||||
ok 'b' not of obj
|
||||
|
||||
# And for "a in b" with array presence.
|
||||
ok 100 in [100, 200, 300]
|
||||
array: [100, 200, 300]
|
||||
array = [100, 200, 300]
|
||||
ok 100 in array
|
||||
ok 1 not in array
|
||||
|
||||
list: [1, 2, 7]
|
||||
result: if list[2] in [7, 10] then 100 else -1
|
||||
list = [1, 2, 7]
|
||||
result = if list[2] in [7, 10] then 100 else -1
|
||||
ok result is 100
|
||||
|
||||
# And with array presence on an instance variable.
|
||||
obj: {
|
||||
obj = {
|
||||
list: [1, 2, 3, 4, 5]
|
||||
in_list: (value) -> value in @list
|
||||
}
|
||||
@@ -60,8 +60,8 @@ ok obj.in_list 4
|
||||
ok not obj.in_list 0
|
||||
|
||||
# Non-spaced values still work.
|
||||
x: 10
|
||||
y: -5
|
||||
x = 10
|
||||
y = -5
|
||||
|
||||
ok x*-y is 50
|
||||
ok x*+y is -50
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Ensure that the OptionParser handles arguments correctly.
|
||||
|
||||
{OptionParser}: require './../lib/optparse'
|
||||
{OptionParser} = require './../lib/optparse'
|
||||
|
||||
opt: new OptionParser [
|
||||
opt = new OptionParser [
|
||||
['-r', '--required [DIR]', 'desc required']
|
||||
['-o', '--optional', 'desc optional']
|
||||
]
|
||||
|
||||
result: opt.parse ['one', 'two', 'three', '-r', 'dir']
|
||||
result = opt.parse ['one', 'two', 'three', '-r', 'dir']
|
||||
|
||||
ok result.arguments.length is 5
|
||||
ok result.arguments[3] is '-r'
|
||||
|
||||
result: opt.parse ['--optional', '-r', 'folder', 'one', 'two']
|
||||
result = opt.parse ['--optional', '-r', 'folder', 'one', 'two']
|
||||
|
||||
ok result.optional is true
|
||||
ok result.required is 'folder'
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
# Simple variable swapping.
|
||||
a: -1
|
||||
b: -2
|
||||
a = -1
|
||||
b = -2
|
||||
|
||||
[a, b]: [b, a]
|
||||
[a, b] = [b, a]
|
||||
|
||||
ok a is -2
|
||||
ok b is -1
|
||||
|
||||
func: ->
|
||||
[a, b]: [b, a]
|
||||
func = ->
|
||||
[a, b] = [b, a]
|
||||
|
||||
ok func().join(' ') is '-1 -2'
|
||||
|
||||
noop: ->
|
||||
noop = ->
|
||||
|
||||
noop [a,b]: [c,d]: [1,2]
|
||||
noop [a,b] = [c,d] = [1,2]
|
||||
|
||||
ok a is 1 and b is 2
|
||||
|
||||
|
||||
# Array destructuring, including splats.
|
||||
arr: [1, 2, 3]
|
||||
arr = [1, 2, 3]
|
||||
|
||||
[a, b, c]: arr
|
||||
[a, b, c] = arr
|
||||
|
||||
ok a is 1
|
||||
ok b is 2
|
||||
ok c is 3
|
||||
|
||||
[x,y...,z]: [1,2,3,4,5]
|
||||
[x,y...,z] = [1,2,3,4,5]
|
||||
|
||||
ok x is 1
|
||||
ok y.length is 3
|
||||
ok z is 5
|
||||
|
||||
[x, [y, mids..., last], z..., end]: [1, [10, 20, 30, 40], 2,3,4, 5]
|
||||
[x, [y, mids..., last], z..., end] = [1, [10, 20, 30, 40], 2,3,4, 5]
|
||||
|
||||
ok x is 1
|
||||
ok y is 10
|
||||
@@ -45,15 +45,15 @@ ok end is 5
|
||||
|
||||
|
||||
# Object destructuring.
|
||||
obj: {x: 10, y: 20, z: 30}
|
||||
obj = {x: 10, y: 20, z: 30}
|
||||
|
||||
{x: a, y: b, z: c}: obj
|
||||
{x: a, y: b, z: c} = obj
|
||||
|
||||
ok a is 10
|
||||
ok b is 20
|
||||
ok c is 30
|
||||
|
||||
person: {
|
||||
person = {
|
||||
name: "Moe"
|
||||
family: {
|
||||
'elder-brother': {
|
||||
@@ -68,12 +68,12 @@ person: {
|
||||
}
|
||||
}
|
||||
|
||||
{name: a, family: {'elder-brother': {addresses: [one, {city: b}]}}}: person
|
||||
{name: a, family: {'elder-brother': {addresses: [one, {city: b}]}}} = person
|
||||
|
||||
ok a is "Moe"
|
||||
ok b is "Moquasset NY, 10021"
|
||||
|
||||
test: {
|
||||
test = {
|
||||
person: {
|
||||
address: [
|
||||
"------"
|
||||
@@ -84,13 +84,13 @@ test: {
|
||||
}
|
||||
}
|
||||
|
||||
{person: {address: [ignore, addr...]}}: test
|
||||
{person: {address: [ignore, addr...]}} = test
|
||||
|
||||
ok addr.join(', ') is "Street 101, Apt 101, City 101"
|
||||
|
||||
|
||||
# Pattern matching against an expression.
|
||||
[a, b]: if true then [2, 1] else [1, 2]
|
||||
[a, b] = if true then [2, 1] else [1, 2]
|
||||
|
||||
ok a is 2
|
||||
ok b is 1
|
||||
@@ -98,13 +98,13 @@ ok b is 1
|
||||
|
||||
# Pattern matching with object shorthand.
|
||||
|
||||
person: {
|
||||
person = {
|
||||
name: "Bob"
|
||||
age: 26
|
||||
dogs: ["Prince", "Bowie"]
|
||||
}
|
||||
|
||||
{name, age, dogs: [first, second]}: person
|
||||
{name, age, dogs: [first, second]} = person
|
||||
|
||||
ok name is "Bob"
|
||||
ok age is 26
|
||||
@@ -113,27 +113,27 @@ ok second is "Bowie"
|
||||
|
||||
# Pattern matching within for..loops
|
||||
|
||||
persons: {
|
||||
persons = {
|
||||
George: { name: "Bob" },
|
||||
Bob: { name: "Alice" }
|
||||
Christopher: { name: "Stan" }
|
||||
}
|
||||
|
||||
join1: "$key: $name" for key, { name } of persons
|
||||
join1 = "$key: $name" for key, { name } of persons
|
||||
|
||||
deepEqual join1, ["George: Bob", "Bob: Alice", "Christopher: Stan"]
|
||||
|
||||
persons: [
|
||||
persons = [
|
||||
{ name: "Bob", parent: { name: "George" } },
|
||||
{ name: "Alice", parent: { name: "Bob" } },
|
||||
{ name: "Stan", parent: { name: "Christopher" } }
|
||||
]
|
||||
|
||||
join2: "$parent: $name" for { name, parent: { name: parent } } in persons
|
||||
join2 = "$parent: $name" for { name, parent: { name: parent } } in persons
|
||||
|
||||
deepEqual join1, join2
|
||||
|
||||
persons: [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]]
|
||||
join3: "$parent: $name" for [name, [parent]] in persons
|
||||
persons = [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]]
|
||||
join3 = "$parent: $name" for [name, [parent]] in persons
|
||||
|
||||
deepEqual join2, join3
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
# Slice.
|
||||
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
a: array[7..9]
|
||||
b: array[2...4]
|
||||
a = array[7..9]
|
||||
b = array[2...4]
|
||||
|
||||
result: a.concat(b).join(' ')
|
||||
result = a.concat(b).join(' ')
|
||||
|
||||
ok result is "7 8 9 2 3"
|
||||
|
||||
a: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
a = [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
deepEqual a[2...6], [2, 3, 4, 5]
|
||||
|
||||
|
||||
# Ranges.
|
||||
countdown: [10..1].join(' ')
|
||||
countdown = [10..1].join(' ')
|
||||
ok countdown is "10 9 8 7 6 5 4 3 2 1"
|
||||
|
||||
a: 1
|
||||
b: 5
|
||||
nums: [a...b]
|
||||
a = 1
|
||||
b = 5
|
||||
nums = [a...b]
|
||||
ok nums.join(' ') is '1 2 3 4'
|
||||
|
||||
b: -5
|
||||
nums: [a..b]
|
||||
b = -5
|
||||
nums = [a..b]
|
||||
ok nums.join(' ') is '1 0 -1 -2 -3 -4 -5'
|
||||
|
||||
|
||||
# Expression-based range.
|
||||
array: [(1+5)..1+9]
|
||||
array = [(1+5)..1+9]
|
||||
ok array.join(' ') is "6 7 8 9 10"
|
||||
|
||||
|
||||
# String slicing (at least on Node).
|
||||
hello: "Hello World"
|
||||
hello = "Hello World"
|
||||
|
||||
ok hello[1...1] is ""
|
||||
ok hello[1..1] is "e"
|
||||
@@ -41,9 +41,9 @@ ok hello[0..4] is "Hello"
|
||||
|
||||
|
||||
# Splice literals.
|
||||
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
array[5..10]: [0, 0, 0]
|
||||
array[5..10] = [0, 0, 0]
|
||||
|
||||
ok array.join(' ') is '0 1 2 3 4 0 0 0'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Interpolate regular expressions.
|
||||
name: 'Moe'
|
||||
name = 'Moe'
|
||||
|
||||
ok not not '"Moe"'.match(/^"${name}"$/i)
|
||||
ok '"Moe!"'.match(/^"${name}"$/i) is null
|
||||
@@ -11,10 +11,10 @@ ok 'Moe!'.match(/${"${"${"$name"}"}"}/imgy)
|
||||
|
||||
ok '$a$b$c'.match(/\$A\$B\$C/i)
|
||||
|
||||
a: 1
|
||||
b: 2
|
||||
c: 3
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
ok '123'.match(/$a$b$c/i)
|
||||
|
||||
[a, b, c]: [1, 2, /\d+/]
|
||||
[a, b, c] = [1, 2, /\d+/]
|
||||
ok (/$a$b$c$/i).toString() is '/12/\\d+/$/i'
|
||||
|
||||
@@ -6,18 +6,18 @@ ok 'x'.match /x/
|
||||
|
||||
ok 4 / 2 / 1 is 2
|
||||
|
||||
y: 4
|
||||
x: 2
|
||||
g: 1
|
||||
y = 4
|
||||
x = 2
|
||||
g = 1
|
||||
|
||||
ok y / x/g is 2
|
||||
|
||||
ok 'http://google.com'.match(/:\/\/goog/)
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
width: -> 10
|
||||
height: -> 20
|
||||
}
|
||||
id: 2
|
||||
id = 2
|
||||
|
||||
ok (obj.width()/id - obj.height()/id) is -5
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Expression conversion under explicit returns.
|
||||
first: ->
|
||||
first = ->
|
||||
return 'do' for x in [1,2,3]
|
||||
|
||||
second: ->
|
||||
second = ->
|
||||
return ['re' for x in [1,2,3]]
|
||||
|
||||
third: ->
|
||||
third = ->
|
||||
return ('mi' for x in [1,2,3])
|
||||
|
||||
ok first().join(' ') is 'do do do'
|
||||
@@ -14,7 +14,7 @@ ok third().join(' ') is 'mi mi mi'
|
||||
|
||||
|
||||
# Testing returns with multiple branches.
|
||||
func: ->
|
||||
func = ->
|
||||
if false
|
||||
for a in b
|
||||
return c if d
|
||||
@@ -25,7 +25,7 @@ ok func() is 'word'
|
||||
|
||||
|
||||
# And with switches.
|
||||
func: ->
|
||||
func = ->
|
||||
switch 'a'
|
||||
when 'a' then 42
|
||||
else return 23
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
func: (first, second, rest...) ->
|
||||
func = (first, second, rest...) ->
|
||||
rest.join ' '
|
||||
|
||||
result: func 1, 2, 3, 4, 5
|
||||
result = func 1, 2, 3, 4, 5
|
||||
|
||||
ok result is "3 4 5"
|
||||
|
||||
|
||||
gold: silver: bronze: theField: last: null
|
||||
gold = silver = bronze = theField = last = null
|
||||
|
||||
medalists: (first, second, third, rest..., unlucky) ->
|
||||
gold: first
|
||||
silver: second
|
||||
bronze: third
|
||||
theField: rest.concat([last])
|
||||
last: unlucky
|
||||
medalists = (first, second, third, rest..., unlucky) ->
|
||||
gold = first
|
||||
silver = second
|
||||
bronze = third
|
||||
theField = rest.concat([last])
|
||||
last = unlucky
|
||||
|
||||
contenders: [
|
||||
contenders = [
|
||||
"Michael Phelps"
|
||||
"Liu Xiang"
|
||||
"Yao Ming"
|
||||
@@ -49,24 +49,24 @@ medalists contenders..., 'Tim', 'Moe', 'Jim'
|
||||
ok last is 'Jim'
|
||||
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
name: 'moe'
|
||||
accessor: (args...) ->
|
||||
[@name].concat(args).join(' ')
|
||||
getNames: ->
|
||||
args: ['jane', 'ted']
|
||||
args = ['jane', 'ted']
|
||||
@accessor(args...)
|
||||
}
|
||||
|
||||
ok obj.getNames() is 'moe jane ted'
|
||||
|
||||
|
||||
crowd: [
|
||||
crowd = [
|
||||
contenders...
|
||||
"Mighty Mouse"
|
||||
]
|
||||
|
||||
bests: [
|
||||
bests = [
|
||||
"Mighty Mouse"
|
||||
contenders[0..3]...
|
||||
]
|
||||
@@ -86,16 +86,16 @@ class Parent
|
||||
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums: [3, 2, 1]
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
|
||||
# Functions with splats being called with too few arguments.
|
||||
pen: null
|
||||
method: (first, variable..., penultimate, ultimate) ->
|
||||
pen: penultimate
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
@@ -108,8 +108,8 @@ ok pen is 2
|
||||
|
||||
|
||||
# Array splat expansions with assigns.
|
||||
nums: [1, 2, 3]
|
||||
list: [a: 0, nums..., b: 4]
|
||||
nums = [1, 2, 3]
|
||||
list = [a = 0, nums..., b = 4]
|
||||
ok a is 0
|
||||
ok b is 4
|
||||
ok list.join(' ') is '0 1 2 3 4'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
hello: 'Hello'
|
||||
world: 'World'
|
||||
hello = 'Hello'
|
||||
world = 'World'
|
||||
ok '$hello $world!' is '$hello $world!'
|
||||
ok '${hello} ${world}!' is '${hello} ${world}!'
|
||||
ok "$hello $world!" is 'Hello World!'
|
||||
@@ -12,7 +12,7 @@ ok "Hello ${ 1 + 2 } World" is 'Hello 3 World'
|
||||
ok "$hello ${ 1 + 2 } $world" is "Hello 3 World"
|
||||
|
||||
|
||||
[s, t, r, i, n, g]: ['s', 't', 'r', 'i', 'n', 'g']
|
||||
[s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g']
|
||||
ok "$s$t$r$i$n$g" is 'string'
|
||||
ok "${s}${t}${r}${i}${n}${g}" is 'string'
|
||||
ok "\$s\$t\$r\$i\$n\$g" is '$s$t$r$i$n$g'
|
||||
@@ -47,12 +47,12 @@ ok "${hello + world}" is 'HelloWorld'
|
||||
ok "${hello + ' ' + world + '!'}" is 'Hello World!'
|
||||
|
||||
|
||||
list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
ok "values: ${list.join(', ')}, length: ${list.length}." is 'values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, length: 10.'
|
||||
ok "values: ${list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9'
|
||||
|
||||
|
||||
obj: {
|
||||
obj = {
|
||||
name: 'Joe'
|
||||
hi: -> "Hello $@name."
|
||||
cya: -> "Hello $@name.".replace('Hello','Goodbye')
|
||||
@@ -73,23 +73,23 @@ ok "Hello ${world ? "$hello"}" is 'Hello World'
|
||||
ok "Hello ${"${"${obj["name"]}" + '!'}"}" is 'Hello Joe!'
|
||||
|
||||
|
||||
a: """
|
||||
Hello ${ "Joe" }
|
||||
"""
|
||||
a = """
|
||||
Hello ${ "Joe" }
|
||||
"""
|
||||
ok a is "Hello Joe"
|
||||
|
||||
|
||||
a: 1
|
||||
b: 2
|
||||
c: 3
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
ok "$a$b$c" is '123'
|
||||
|
||||
|
||||
result: null
|
||||
stash: (str) -> result: str
|
||||
result = null
|
||||
stash = (str) -> result = str
|
||||
stash "a ${ ('aa').replace /a/g, 'b' } c"
|
||||
ok result is 'a bb c'
|
||||
|
||||
|
||||
foo: "hello"
|
||||
foo = "hello"
|
||||
ok "${foo.replace("\"", "")}" is 'hello'
|
||||
@@ -1,6 +1,6 @@
|
||||
num: 10
|
||||
num = 10
|
||||
|
||||
result: switch num
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
@@ -17,7 +17,7 @@ result: switch num
|
||||
ok result
|
||||
|
||||
|
||||
func: (num) ->
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
true
|
||||
@@ -32,8 +32,8 @@ ok !func(8)
|
||||
|
||||
|
||||
# Should cache the switch value, if anything fancier than a literal.
|
||||
num: 5
|
||||
result: switch num: + 5
|
||||
num = 5
|
||||
result = switch num += 5
|
||||
when 5 then false
|
||||
when 15 then false
|
||||
when 10 then true
|
||||
@@ -43,29 +43,29 @@ ok result
|
||||
|
||||
|
||||
# Ensure that trailing switch elses don't get rewritten.
|
||||
result: false
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result: true unless false
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
result: false
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result: true unless false
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to handle switches sans-condition.
|
||||
result: switch
|
||||
result = switch
|
||||
when null then 1
|
||||
when 'truthful string' then 2
|
||||
else 3
|
||||
@@ -74,7 +74,7 @@ ok result is 2
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch clause.
|
||||
obj: {
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# Basic exception throwing.
|
||||
block: -> (throw 'up')
|
||||
block = -> (throw 'up')
|
||||
throws block, 'up'
|
||||
|
||||
|
||||
# Basic try/catch.
|
||||
result: try
|
||||
result = try
|
||||
10
|
||||
finally
|
||||
15
|
||||
|
||||
ok result is 10
|
||||
|
||||
result: try
|
||||
result = try
|
||||
throw 'up'
|
||||
catch err
|
||||
err.length
|
||||
@@ -19,7 +19,7 @@ catch err
|
||||
ok result is 2
|
||||
|
||||
|
||||
result: try throw 'error' catch err then err.length
|
||||
result = try throw 'error' catch err then err.length
|
||||
|
||||
ok result is 5
|
||||
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
i: 5
|
||||
list: while i -= 1
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
|
||||
|
||||
i: 5
|
||||
list: (i * 3 while i -= 1)
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
|
||||
|
||||
i: 5
|
||||
func: (num) -> i -= num
|
||||
assert: -> ok i < 5 > 0
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
|
||||
results: while func 1
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
|
||||
i: 10
|
||||
results: while i -= 1 when i % 2 is 0
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
|
||||
|
||||
value: false
|
||||
i: 0
|
||||
results: until value
|
||||
value: true if i is 5
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i += 1
|
||||
|
||||
ok i is 6
|
||||
|
||||
|
||||
# And, the loop form of while.
|
||||
i: 5
|
||||
list: []
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i: - 1
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user